From 0e7ae5ee7bc355380d256629f0a8a8caab9afc2a Mon Sep 17 00:00:00 2001 From: Administrator Date: Sun, 19 Apr 2026 22:24:10 +0200 Subject: [PATCH] fix(vidmoly): use new /api/upload/config endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Vidmoly SPA redesign removed the /?op=upload HTML form — the old regex-scrape of hidden inputs no longer works. The site now exposes GET /api/upload/config which returns { sess_id, upload_url } plus the allowed extensions. Rewrote getUploadParams() to use that endpoint; the rest of the multipart upload flow (sess_id + utype + file_0) is the same classic XFS shape. --- lib/vidmoly-upload.js | 80 +++++++++++++------------------------------ 1 file changed, 24 insertions(+), 56 deletions(-) diff --git a/lib/vidmoly-upload.js b/lib/vidmoly-upload.js index f4e70d5..a415730 100644 --- a/lib/vidmoly-upload.js +++ b/lib/vidmoly-upload.js @@ -111,75 +111,43 @@ class VidmolyUploader { throw new Error('Vidmoly Login fehlgeschlagen: Falscher Username oder Passwort'); } - // Verify session by fetching a logged-in-only page. Vidmoly redesigned - // the site and changed cookie names, so the old "has cookie 'login' or - // 'xfsts'" heuristic broke. Instead we hit /?op=my_account (or similar) - // and confirm we're not redirected to the login form. + // Verify session by hitting the new SPA dashboard at /my. On the old XFS + // site the login page included a
; the SPA dashboard + // doesn't contain that form when the session is valid (it's rendered by + // JS), so the absence of a password field + presence of any known marker + // (Dashboard / Logout / the user's own username) indicates we're in. if (this.cookies.size === 0) { throw new Error('Vidmoly Login fehlgeschlagen: Keine Session erhalten'); } - const verifyRes = await this._fetch(`${BASE_URL}/?op=my_account`); + const verifyRes = await this._fetch(`${BASE_URL}/my`); const verifyBody = await verifyRes.text(); - // A logged-out page shows the login form (name="login" + name="password"); - // a logged-in page shows account info ("Logout", "My Account", "My Files"). - const looksLoggedIn = /(?:logout|my[_ ]?account|my[_ ]?files)/i.test(verifyBody) - && !/]*>\s*[\s\S]{0,500}?name=["']password["']/i.test(verifyBody); - if (!looksLoggedIn) { + const hasPasswordForm = /]*>[\s\S]{0,800}?name=["']password["']/i.test(verifyBody); + const hasDashboardMarker = /(?:Dashboard|Video[- ]Manager|Logout|dashboard|my[_ -]?(account|files))/i.test(verifyBody); + if (hasPasswordForm || !hasDashboardMarker) { throw new Error('Vidmoly Login fehlgeschlagen: Session konnte nicht verifiziert werden'); } } /** - * Get upload form parameters from the upload page + * Fetch the upload session config from Vidmoly's new SPA API. + * Replaces the old HTML-form scrape at /?op=upload which the redesign + * removed. Returns an XFS-style session token + a transit-server URL. */ async getUploadParams() { - const res = await this._fetch(`${BASE_URL}/?op=upload`); - const html = await res.text(); - - // Parse hidden form fields from XFS upload form - const params = {}; - - const inputRegex = /]*type=["']hidden["'][^>]*>/gi; - let match; - while ((match = inputRegex.exec(html)) !== null) { - const tag = match[0]; - const nameMatch = tag.match(/name=["']([^"']+)["']/); - const valueMatch = tag.match(/value=["']([^"']*?)["']/); - if (nameMatch) { - params[nameMatch[1]] = valueMatch ? valueMatch[1] : ''; - } + const res = await this._fetch(`${BASE_URL}/api/upload/config`); + const body = await res.text(); + let payload = null; + try { payload = JSON.parse(body); } catch { + throw new Error('Vidmoly: /api/upload/config lieferte kein JSON — evtl. nicht eingeloggt?'); } - - // Extract form action - const formMatch = html.match(/]*id=["']?file_upload["']?[^>]*action=["']([^"']+)["']/i) - || html.match(/]*enctype=["']multipart\/form-data["'][^>]*action=["']([^"']+)["']/i) - || html.match(/]*action=["']([^"']+)["'][^>]*enctype=["']multipart\/form-data["']/i); - - let uploadUrl = null; - if (formMatch) { - uploadUrl = formMatch[1]; - } else if (params.srv_tmp_url) { - uploadUrl = params.srv_tmp_url; + if (!payload || !payload.sess_id || !payload.upload_url) { + throw new Error('Vidmoly: /api/upload/config unvollständig (sess_id/upload_url fehlt)'); } - - if (!uploadUrl) { - const cgiMatch = html.match(/(https?:\/\/[^"'\s]+\/cgi-bin\/upload\.cgi[^"'\s]*)/i) - || html.match(/(https?:\/\/[^"'\s]+\/upload\/\d+)/i); - if (cgiMatch) uploadUrl = cgiMatch[1]; - } - - if (!uploadUrl) { - throw new Error('Vidmoly Upload-URL nicht gefunden. Bist du eingeloggt?'); - } - - let fileFieldName = 'file'; - const fileInputMatch = html.match(/]*type=["']file["'][^>]*name=["']([^"']+)["']/i) - || html.match(/]*name=["']([^"']+)["'][^>]*type=["']file["']/i); - if (fileInputMatch && fileInputMatch[1]) { - fileFieldName = fileInputMatch[1].trim(); - } - - return { uploadUrl, params, fileFieldName }; + return { + uploadUrl: payload.upload_url, + params: { sess_id: payload.sess_id, utype: 'reg' }, + fileFieldName: 'file_0' + }; } /**