Fix duplicate VOE and Vidmoly recovery claims

Share account-scoped recovery claims with login uploader instances and serialize same-title recovery windows. Reserve direct and recovered file codes consistently, reject reused identities, and cover concurrent singleton recovery plus distinct-code and parallel-success cases.
This commit is contained in:
Sucukdeluxe
2026-08-13 22:30:27 +02:00
parent acb43d982e
commit c209abdbbc
5 changed files with 323 additions and 32 deletions
+18 -6
View File
@@ -1248,13 +1248,9 @@ class UploadManager extends EventEmitter {
async _executeUploadUnchecked(task, progressCb, signal, throttle, fileProbe) {
if (task.hoster === 'vidmoly.me' && task.username) {
const vidmoly = new VidmolyUploader();
await vidmoly.login(task.username, task.password);
return vidmoly.upload(task.file, progressCb, signal, throttle);
return this._executeRecoveryAwareLoginUpload(task, VidmolyUploader, progressCb, signal, throttle);
} else if (task.hoster === 'voe.sx' && task.username) {
const voe = new VoeUploader();
await voe.login(task.username, task.password);
return voe.upload(task.file, progressCb, signal, throttle);
return this._executeRecoveryAwareLoginUpload(task, VoeUploader, progressCb, signal, throttle);
} else if (task.hoster === 'doodstream.com' && task.username) {
// Login-path reliability fix: the web-form upload returns the filecode in
// an HTML form that comes back empty for large files (doodstream backend
@@ -1282,6 +1278,22 @@ class UploadManager extends EventEmitter {
}
}
async _executeRecoveryAwareLoginUpload(task, UploaderClass, progressCb, signal, throttle) {
const accountIdentity = task.accountId !== null && task.accountId !== undefined
? task.accountId
: String(task.username || '').trim().toLowerCase();
const recoveryClaim = this._recoveryClaims.forUpload(
task.hoster,
accountIdentity,
path.basename(task.file)
);
return recoveryClaim.runExclusive(async () => {
const uploader = new UploaderClass(recoveryClaim);
await uploader.login(task.username, task.password);
return uploader.upload(task.file, progressCb, signal, throttle);
}, signal);
}
async _executeRecoveryAwareApiUpload(hosterName, filePath, apiKey, progressCb, signal, throttle, fileProbe) {
const recoveryClaim = this._recoveryClaims.forUpload(hosterName, apiKey, path.basename(filePath));
return recoveryClaim.runExclusive(async () => {