Compare commits
No commits in common. "9794efde466f59438c44dfac32688412323b1e4f" and "996fc5aa17daa1221c84acc4109e66b96226a5f1" have entirely different histories.
9794efde46
...
996fc5aa17
@ -10,29 +10,15 @@ const UPLOAD_TIMEOUT = 1800000; // 30 min
|
|||||||
// Cap doodstream's per-hoster debug log alongside the main log files so
|
// Cap doodstream's per-hoster debug log alongside the main log files so
|
||||||
// dev-mode sessions don't accumulate gigabytes of upload trace.
|
// dev-mode sessions don't accumulate gigabytes of upload trace.
|
||||||
const { maybeRotateLogFile } = require('./log-rotation');
|
const { maybeRotateLogFile } = require('./log-rotation');
|
||||||
|
const _DOODSTREAM_LOG_PATH = path.join(__dirname, '..', 'doodstream-debug.log');
|
||||||
const _DOODSTREAM_LOG_MAX_BYTES = 10 * 1024 * 1024;
|
const _DOODSTREAM_LOG_MAX_BYTES = 10 * 1024 * 1024;
|
||||||
const _DOODSTREAM_LOG_MAX_BACKUPS = 1;
|
const _DOODSTREAM_LOG_MAX_BACKUPS = 1;
|
||||||
|
|
||||||
// Resolve the log path at write-time. In a packaged build __dirname lives
|
|
||||||
// inside app.asar (read-only) — writing there fails silently and we lose every
|
|
||||||
// production trace. Prefer Electron's writable userData dir, fall back to the
|
|
||||||
// repo root only when running outside Electron (tests / plain node).
|
|
||||||
function _doodstreamLogPath() {
|
|
||||||
try {
|
|
||||||
const { app } = require('electron');
|
|
||||||
if (app && typeof app.getPath === 'function') {
|
|
||||||
return path.join(app.getPath('userData'), 'doodstream-debug.log');
|
|
||||||
}
|
|
||||||
} catch { /* not running under Electron */ }
|
|
||||||
return path.join(__dirname, '..', 'doodstream-debug.log');
|
|
||||||
}
|
|
||||||
|
|
||||||
function _debugLog(msg) {
|
function _debugLog(msg) {
|
||||||
try {
|
try {
|
||||||
const logPath = _doodstreamLogPath();
|
maybeRotateLogFile(_DOODSTREAM_LOG_PATH, _DOODSTREAM_LOG_MAX_BYTES, _DOODSTREAM_LOG_MAX_BACKUPS);
|
||||||
maybeRotateLogFile(logPath, _DOODSTREAM_LOG_MAX_BYTES, _DOODSTREAM_LOG_MAX_BACKUPS);
|
|
||||||
const ts = new Date().toISOString();
|
const ts = new Date().toISOString();
|
||||||
fs.appendFileSync(logPath, `[${ts}] ${msg}\n`);
|
fs.appendFileSync(_DOODSTREAM_LOG_PATH, `[${ts}] ${msg}\n`);
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,9 +210,6 @@ class DoodstreamUploader {
|
|||||||
|
|
||||||
// Get upload server
|
// Get upload server
|
||||||
const uploadUrl = await this._getUploadServer();
|
const uploadUrl = await this._getUploadServer();
|
||||||
// Remember which CDN node handled this upload so a later parse failure can
|
|
||||||
// report it — failures sometimes correlate with a specific node.
|
|
||||||
this._lastUploadUrl = uploadUrl;
|
|
||||||
|
|
||||||
// Build multipart form
|
// Build multipart form
|
||||||
const boundary = `----WebKitFormBoundary${crypto.randomBytes(16).toString('hex')}`;
|
const boundary = `----WebKitFormBoundary${crypto.randomBytes(16).toString('hex')}`;
|
||||||
@ -396,19 +379,7 @@ class DoodstreamUploader {
|
|||||||
return this._buildResult(dlMatch[1]);
|
return this._buildResult(dlMatch[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No filecode anywhere. Surface WHY: XFileSharing puts the real reason
|
throw new Error(`Doodstream Upload: upload_result Seite hat keinen filecode (${followText.slice(0, 150)})`);
|
||||||
// in the `st` field (anything other than "OK" means the backend refused
|
|
||||||
// the file — copyright/hash match, duplicate, size, quota, …). The
|
|
||||||
// download link being empty while the page structure is unchanged points
|
|
||||||
// at doodstream's backend, not at a parsing bug on our side.
|
|
||||||
const st = hiddenFields.st || '';
|
|
||||||
const fnInfo = fnCode ? `"${fnCode}"(len ${fnCode.length})` : 'fehlt/leer';
|
|
||||||
const node = this._lastUploadUrl || '?';
|
|
||||||
_debugLog(`No filecode. st=${st} fn=${fnInfo} node=${node} CDN-body=${(resText || '').slice(0, 400)}`);
|
|
||||||
if (st && st !== 'OK') {
|
|
||||||
throw new Error(`Doodstream lehnt Datei ab (Server-Status: ${st}). CDN=${node}`);
|
|
||||||
}
|
|
||||||
throw new Error(`Doodstream Upload: kein Filecode — Server gab leeren Link zurueck (st=${st || '?'}, fn=${fnInfo}, CDN=${node}). CDN-Antwort: ${(resText || '').slice(0, 200)}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Fallback: follow form action as-is (for non-XFS forms)
|
// 4. Fallback: follow form action as-is (for non-XFS forms)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "multi-hoster-uploader",
|
"name": "multi-hoster-uploader",
|
||||||
"version": "3.3.24",
|
"version": "3.3.23",
|
||||||
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
|
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -1,65 +0,0 @@
|
|||||||
const { test } = require('node:test');
|
|
||||||
const assert = require('node:assert');
|
|
||||||
const DoodstreamUploader = require('../lib/doodstream-upload');
|
|
||||||
|
|
||||||
// The CDN hands back an XFileSharing form. `fn` is the filecode, `st` is the
|
|
||||||
// status ("OK" on success, an error string when the backend refuses the file).
|
|
||||||
// These tests pin the parse/error behaviour of _parseUploadResponse without
|
|
||||||
// touching the network — _fetch is stubbed to return the upload_result page.
|
|
||||||
function cdnForm({ fn = '', st = 'OK' } = {}) {
|
|
||||||
return `<HTML><BODY><Form name='F1' action='https://cdn.example/' method='POST'>` +
|
|
||||||
`<textarea name="op">upload_result</textarea>` +
|
|
||||||
`<textarea name="fn">${fn}</textarea>` +
|
|
||||||
`<textarea name="st">${st}</textarea>` +
|
|
||||||
`</Form></BODY></HTML>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const EMPTY_RESULT = '<textarea id="copy_dl" readonly class="form-control" rows="5"></textarea>';
|
|
||||||
const LINK_RESULT = (code) => `<textarea id="copy_dl" readonly class="form-control" rows="5">https://myvidplay.com/d/${code}</textarea>`;
|
|
||||||
|
|
||||||
function uploaderWithResult(resultHtml) {
|
|
||||||
const up = new DoodstreamUploader();
|
|
||||||
up._lastUploadUrl = 'https://cdn.example/upload/01';
|
|
||||||
// Stub the second-step submit so no real request goes out.
|
|
||||||
up._fetch = async () => ({ text: async () => resultHtml });
|
|
||||||
return up;
|
|
||||||
}
|
|
||||||
|
|
||||||
test('rejected file: empty fn + non-OK st surfaces the real status', async () => {
|
|
||||||
const up = uploaderWithResult(EMPTY_RESULT);
|
|
||||||
await assert.rejects(
|
|
||||||
() => up._parseUploadResponse(cdnForm({ fn: '', st: 'Error: file already exists' })),
|
|
||||||
(err) => {
|
|
||||||
assert.match(err.message, /lehnt Datei ab/);
|
|
||||||
assert.match(err.message, /file already exists/);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('empty fn + st OK: generic error still reports st, fn-state and CDN node', async () => {
|
|
||||||
const up = uploaderWithResult(EMPTY_RESULT);
|
|
||||||
await assert.rejects(
|
|
||||||
() => up._parseUploadResponse(cdnForm({ fn: '', st: 'OK' })),
|
|
||||||
(err) => {
|
|
||||||
assert.match(err.message, /kein Filecode/);
|
|
||||||
assert.match(err.message, /st=OK/);
|
|
||||||
assert.match(err.message, /fehlt\/leer/);
|
|
||||||
assert.match(err.message, /cdn\.example/);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('valid fn but empty result page: still resolves via fn (no regression)', async () => {
|
|
||||||
const up = uploaderWithResult(EMPTY_RESULT);
|
|
||||||
const res = await up._parseUploadResponse(cdnForm({ fn: '7mnp8xna3123', st: 'OK' }));
|
|
||||||
assert.equal(res.file_code, '7mnp8xna3123');
|
|
||||||
assert.equal(res.download_url, 'https://doodstream.com/d/7mnp8xna3123');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('happy path: link in result page wins', async () => {
|
|
||||||
const up = uploaderWithResult(LINK_RESULT('jjsuhr931ds9'));
|
|
||||||
const res = await up._parseUploadResponse(cdnForm({ fn: 'jjsuhr931ds9', st: 'OK' }));
|
|
||||||
assert.equal(res.file_code, 'jjsuhr931ds9');
|
|
||||||
});
|
|
||||||
Loading…
Reference in New Issue
Block a user