Compare commits

...

2 Commits

Author SHA1 Message Date
Sucukdeluxe
99074464fb Release v1.7.21 2026-03-07 19:37:07 +01:00
Sucukdeluxe
927ff5c21a Auto-fix legacy (N) suffix filenames on startup
Detect items whose targetPath has a " (N)" suffix from the previous
duplicate filename bug and rename them back to the original filename.
This fixes extraction failures for RAR split archives that were
downloaded with (1) suffix before v1.7.19.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 19:36:30 +01:00
2 changed files with 51 additions and 1 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "real-debrid-downloader", "name": "real-debrid-downloader",
"version": "1.7.20", "version": "1.7.21",
"description": "Desktop downloader", "description": "Desktop downloader",
"main": "build/main/main/main.js", "main": "build/main/main/main.js",
"author": "Sucukdeluxe", "author": "Sucukdeluxe",

View File

@ -3988,6 +3988,56 @@ export class DownloadManager extends EventEmitter {
if (restored > 0) { if (restored > 0) {
logger.info(`restoreTargetPathReservations: ${restored} Pfade aus Session wiederhergestellt`); logger.info(`restoreTargetPathReservations: ${restored} Pfade aus Session wiederhergestellt`);
} }
// Fix legacy (N) suffix files: rename back to original if original path is free
this.fixDuplicateSuffixFiles();
}
/** Detect items whose targetPath has a " (N)" suffix from a previous bug and rename
* them back to the original filename if the original path is not claimed by another item. */
private fixDuplicateSuffixFiles(): void {
const SUFFIX_RE = /^(.+) \(\d+\)(\.[^.]+)$/;
let fixed = 0;
for (const item of Object.values(this.session.items)) {
const tp = String(item.targetPath || "").trim();
if (!tp) continue;
const parsed = path.parse(tp);
const fullName = parsed.name + parsed.ext; // e.g. "file.part3 (1).rar"
const match = SUFFIX_RE.exec(fullName);
if (!match) continue;
const originalName = match[1] + match[2]; // "file.part3.rar"
const originalPath = path.join(parsed.dir, originalName);
const originalKey = pathKey(originalPath);
const originalOwner = this.reservedTargetPaths.get(originalKey);
// Only rename if original path is not claimed by another item and doesn't exist on disk
if (originalOwner && originalOwner !== item.id) continue;
if (!originalOwner && fs.existsSync(originalPath)) continue;
if (!fs.existsSync(tp)) {
// File with (N) doesn't exist either — just fix the path reference
this.reservedTargetPaths.delete(pathKey(tp));
this.reservedTargetPaths.set(originalKey, item.id);
this.claimedTargetPathByItem.set(item.id, originalPath);
item.targetPath = originalPath;
item.fileName = originalName;
fixed += 1;
continue;
}
try {
fs.renameSync(tp, originalPath);
this.reservedTargetPaths.delete(pathKey(tp));
this.reservedTargetPaths.set(originalKey, item.id);
this.claimedTargetPathByItem.set(item.id, originalPath);
item.targetPath = originalPath;
item.fileName = originalName;
fixed += 1;
logger.info(`fixDuplicateSuffix: ${path.basename(tp)}${originalName}`);
} catch (err) {
logger.warn(`fixDuplicateSuffix: Umbenennung fehlgeschlagen ${tp}: ${compactErrorText(err)}`);
}
}
if (fixed > 0) {
logger.info(`fixDuplicateSuffixFiles: ${fixed} Dateien korrigiert`);
this.persistSoon();
}
} }
private assignItemTargetPath(item: DownloadItem, targetPath: string): string { private assignItemTargetPath(item: DownloadItem, targetPath: string): string {