Add Account Manager + fix Hybrid-Extract premature extraction
- Account Manager: table UI with add/remove/check for all 4 providers (Real-Debrid, Mega-Debrid, BestDebrid, AllDebrid) - Backend: checkRealDebridAccount, checkAllDebridAccount, checkBestDebridAccount - Hybrid-Extract fix: check item.fileName for queued items without targetPath, disable disk-fallback for multi-part archives, extend disk-fallback to catch active downloads by fileName match (prevents CRC errors on incomplete files) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
e6ec1ed755
commit
0b7c658c8f
@@ -4992,12 +4992,25 @@ export class DownloadManager extends EventEmitter {
|
||||
const partsOnDisk = collectArchiveCleanupTargets(candidate, dirFiles);
|
||||
const allPartsCompleted = partsOnDisk.every((part) => completedPaths.has(pathKey(part)));
|
||||
if (allPartsCompleted) {
|
||||
const candidateBase = path.basename(candidate).toLowerCase();
|
||||
const hasUnstartedParts = [...pendingPaths].some((pendingPath) => {
|
||||
const pendingName = path.basename(pendingPath).toLowerCase();
|
||||
const candidateStem = path.basename(candidate).toLowerCase();
|
||||
return this.looksLikeArchivePart(pendingName, candidateStem);
|
||||
return this.looksLikeArchivePart(pendingName, candidateBase);
|
||||
});
|
||||
if (hasUnstartedParts) {
|
||||
// Also check items without targetPath (queued items that only have fileName)
|
||||
const hasMatchingPendingItems = pkg.itemIds.some((itemId) => {
|
||||
const item = this.session.items[itemId];
|
||||
if (!item || item.status === "completed" || item.status === "failed" || item.status === "cancelled") {
|
||||
return false;
|
||||
}
|
||||
if (item.fileName && !item.targetPath) {
|
||||
if (this.looksLikeArchivePart(item.fileName.toLowerCase(), candidateBase)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (hasUnstartedParts || hasMatchingPendingItems) {
|
||||
continue;
|
||||
}
|
||||
ready.add(pathKey(candidate));
|
||||
@@ -5007,6 +5020,11 @@ export class DownloadManager extends EventEmitter {
|
||||
// Disk-fallback: if all parts exist on disk but some items lack "completed" status,
|
||||
// allow extraction if none of those parts are actively downloading/validating.
|
||||
// This handles items that finished downloading but whose status was not updated.
|
||||
// Skip disk-fallback entirely for multi-part archives — only allPartsCompleted should handle those.
|
||||
const isMultiPart = /\.part0*1\.rar$/i.test(path.basename(candidate));
|
||||
if (isMultiPart) {
|
||||
continue;
|
||||
}
|
||||
const missingParts = partsOnDisk.filter((part) => !completedPaths.has(pathKey(part)));
|
||||
let allMissingExistOnDisk = true;
|
||||
for (const part of missingParts) {
|
||||
@@ -5031,6 +5049,22 @@ export class DownloadManager extends EventEmitter {
|
||||
if (anyActivelyProcessing) {
|
||||
continue;
|
||||
}
|
||||
// Also check fileName for items without targetPath (queued/downloading items)
|
||||
const candidateBaseFb = path.basename(candidate).toLowerCase();
|
||||
const hasMatchingPendingFb = pkg.itemIds.some((itemId) => {
|
||||
const item = this.session.items[itemId];
|
||||
if (!item || item.status === "completed" || item.status === "failed" || item.status === "cancelled") {
|
||||
return false;
|
||||
}
|
||||
const nameToCheck = item.fileName?.toLowerCase() || (item.targetPath ? path.basename(item.targetPath).toLowerCase() : "");
|
||||
if (!nameToCheck) {
|
||||
return false;
|
||||
}
|
||||
return nameToCheck === candidateBaseFb || this.looksLikeArchivePart(nameToCheck, candidateBaseFb);
|
||||
});
|
||||
if (hasMatchingPendingFb) {
|
||||
continue;
|
||||
}
|
||||
logger.info(`Hybrid-Extract Disk-Fallback: ${path.basename(candidate)} (${missingParts.length} Part(s) auf Disk ohne completed-Status)`);
|
||||
ready.add(pathKey(candidate));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user