Compare commits
2 Commits
7d09479b44
...
afef8dae6f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afef8dae6f | ||
|
|
e80948df54 |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "real-debrid-downloader",
|
"name": "real-debrid-downloader",
|
||||||
"version": "1.7.22",
|
"version": "1.7.23",
|
||||||
"description": "Desktop downloader",
|
"description": "Desktop downloader",
|
||||||
"main": "build/main/main/main.js",
|
"main": "build/main/main/main.js",
|
||||||
"author": "Sucukdeluxe",
|
"author": "Sucukdeluxe",
|
||||||
|
|||||||
@ -6926,33 +6926,38 @@ export class DownloadManager extends EventEmitter {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disk-fallback: if all parts exist on disk but some items lack "completed" status,
|
// Disk-fallback: if all parts exist on disk at their full expected size but some
|
||||||
// allow extraction if none of those parts are actively downloading/validating.
|
// items lack "completed" status, allow extraction. This handles items that finished
|
||||||
// This handles items that finished downloading but whose status was not updated.
|
// downloading but whose status was not updated (crash between write and persist).
|
||||||
const missingParts = partsOnDisk.filter((part) => !completedPaths.has(pathKey(part)));
|
const missingParts = partsOnDisk.filter((part) => !completedPaths.has(pathKey(part)));
|
||||||
let allMissingExistOnDisk = true;
|
let allMissingFullOnDisk = true;
|
||||||
for (const part of missingParts) {
|
for (const part of missingParts) {
|
||||||
try {
|
try {
|
||||||
const stat = await fs.promises.stat(part);
|
const stat = await fs.promises.stat(part);
|
||||||
if (stat.size < 10240) {
|
// Find the item that owns this file to get its expected totalBytes
|
||||||
allMissingExistOnDisk = false;
|
const ownerItem = this.findItemByDiskPath(pkg, part);
|
||||||
|
const minBytes = ownerItem?.totalBytes && ownerItem.totalBytes > 0
|
||||||
|
? ownerItem.totalBytes - ALLOCATION_UNIT_SIZE
|
||||||
|
: 10240;
|
||||||
|
if (stat.size < minBytes) {
|
||||||
|
allMissingFullOnDisk = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
allMissingExistOnDisk = false;
|
allMissingFullOnDisk = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!allMissingExistOnDisk) {
|
if (!allMissingFullOnDisk) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Any non-completed item blocks extraction — cancelled/stopped items may
|
// Any non-completed item blocks extraction — failed/cancelled/stopped items may
|
||||||
// have partial files on disk that would corrupt the extraction.
|
// have partial files on disk that would corrupt the extraction.
|
||||||
const anyActivelyProcessing = missingParts.some((part) => {
|
const anyNonCompletedItem = missingParts.some((part) => {
|
||||||
const status = pendingItemStatus.get(pathKey(part));
|
const status = pendingItemStatus.get(pathKey(part));
|
||||||
return status !== undefined && status !== "failed";
|
return status !== undefined;
|
||||||
});
|
});
|
||||||
if (anyActivelyProcessing) {
|
if (anyNonCompletedItem) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Safety: if any pending item in the package has neither targetPath nor fileName,
|
// Safety: if any pending item in the package has neither targetPath nor fileName,
|
||||||
@ -6975,6 +6980,17 @@ export class DownloadManager extends EventEmitter {
|
|||||||
return ready;
|
return ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private findItemByDiskPath(pkg: PackageEntry, diskPath: string): DownloadItem | undefined {
|
||||||
|
const key = pathKey(diskPath);
|
||||||
|
for (const itemId of pkg.itemIds) {
|
||||||
|
const item = this.session.items[itemId];
|
||||||
|
if (!item) continue;
|
||||||
|
if (item.targetPath && pathKey(item.targetPath) === key) return item;
|
||||||
|
if (item.fileName && pkg.outputDir && pathKey(path.join(pkg.outputDir, item.fileName)) === key) return item;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
private looksLikeArchivePart(fileName: string, entryPointName: string): boolean {
|
private looksLikeArchivePart(fileName: string, entryPointName: string): boolean {
|
||||||
const multipartMatch = entryPointName.match(/^(.*)\.part0*1\.rar$/i);
|
const multipartMatch = entryPointName.match(/^(.*)\.part0*1\.rar$/i);
|
||||||
if (multipartMatch) {
|
if (multipartMatch) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user