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:
+27
-7
@@ -15,8 +15,9 @@ const RESULT_POLL_DELAY_MS = 2000;
|
||||
* Fallback when API-based upload fails or is unavailable.
|
||||
*/
|
||||
class VoeUploader {
|
||||
constructor() {
|
||||
constructor(recoveryClaim = null) {
|
||||
this.cookies = new Map();
|
||||
this.recoveryClaim = recoveryClaim;
|
||||
}
|
||||
|
||||
_cookieHeader() {
|
||||
@@ -449,15 +450,22 @@ class VoeUploader {
|
||||
|
||||
const withCode = files.filter(f => f && (f.file_code || f.slug));
|
||||
const newFiles = withCode.filter(f => !baselineCodes.has(String(f.file_code || f.slug || '').trim()));
|
||||
const matches = newFiles.filter(file => {
|
||||
const title = this._normalizeTitle(file.title || file.name || '');
|
||||
return expectedTitle && title === expectedTitle;
|
||||
});
|
||||
const matches = newFiles
|
||||
.filter(file => {
|
||||
const title = this._normalizeTitle(file.title || file.name || '');
|
||||
return expectedTitle && title === expectedTitle;
|
||||
})
|
||||
.filter(file => {
|
||||
const code = String(file.file_code || file.slug || '').trim();
|
||||
return !this.recoveryClaim
|
||||
|| typeof this.recoveryClaim.has !== 'function'
|
||||
|| !this.recoveryClaim.has(code);
|
||||
});
|
||||
|
||||
if (matches.length > 1) return null;
|
||||
if (matches.length === 1) {
|
||||
const code = matches[0].file_code || matches[0].slug;
|
||||
return this._buildUrls(code);
|
||||
return this._buildUrls(code, 'recovery-poll');
|
||||
}
|
||||
|
||||
if (attempt < RESULT_POLL_ATTEMPTS - 1) {
|
||||
@@ -477,9 +485,21 @@ class VoeUploader {
|
||||
.replace(/[^a-z0-9]+/g, '');
|
||||
}
|
||||
|
||||
_buildUrls(fileCode) {
|
||||
_buildUrls(fileCode, phase = 'upload-result') {
|
||||
const code = String(fileCode || '').trim();
|
||||
if (!code) return null;
|
||||
if (this.recoveryClaim
|
||||
&& typeof this.recoveryClaim.reserve === 'function'
|
||||
&& !this.recoveryClaim.reserve(code)) {
|
||||
const error = createTransportError('VOE Upload-Ergebnis ist bereits einem anderen Upload zugeordnet', {
|
||||
phase,
|
||||
endpoint: BASE_URL,
|
||||
retryable: true,
|
||||
hosterTransient: true
|
||||
});
|
||||
error.remoteIdentityClaimed = true;
|
||||
throw error;
|
||||
}
|
||||
return {
|
||||
download_url: `${BASE_URL}/${code}`,
|
||||
embed_url: `${BASE_URL}/e/${code}`,
|
||||
|
||||
Reference in New Issue
Block a user