fix(vidmoly): use new /api/upload/config endpoint

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.
This commit is contained in:
Administrator 2026-04-19 22:24:10 +02:00
parent 8e49733241
commit 0e7ae5ee7b

View File

@ -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 <form name="password">; 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)
&& !/<form[^>]*>\s*[\s\S]{0,500}?name=["']password["']/i.test(verifyBody);
if (!looksLoggedIn) {
const hasPasswordForm = /<form[^>]*>[\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 = /<input[^>]*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(/<form[^>]*id=["']?file_upload["']?[^>]*action=["']([^"']+)["']/i)
|| html.match(/<form[^>]*enctype=["']multipart\/form-data["'][^>]*action=["']([^"']+)["']/i)
|| html.match(/<form[^>]*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(/<input[^>]*type=["']file["'][^>]*name=["']([^"']+)["']/i)
|| html.match(/<input[^>]*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'
};
}
/**