diff --git a/src/main/download-manager.ts b/src/main/download-manager.ts index 025c1d8..d57d253 100644 --- a/src/main/download-manager.ts +++ b/src/main/download-manager.ts @@ -2682,6 +2682,13 @@ export class DownloadManager extends EventEmitter { forceEpisodeForSeasonFolder: true }); if (!targetBaseName) { + if (pkg) { + this.logPackageForPackage(pkg, "WARN", "Auto-Rename übersprungen: kein Zielname", { + sourceName, + sourceBaseName, + folders: folderCandidates.join(", ") + }); + } logger.info(`Auto-Rename: kein Zielname für ${sourceName} (folders=${folderCandidates.join(", ")})`); continue; } @@ -2706,6 +2713,13 @@ export class DownloadManager extends EventEmitter { } } if (!targetPath) { + if (pkg) { + this.logPackageForPackage(pkg, "WARN", "Auto-Rename übersprungen: Zielpfad ungültig", { + sourceName, + sourceBaseName, + targetBaseName + }); + } logger.warn(`Auto-Rename übersprungen (Zielpfad zu lang/ungültig): ${sourcePath}`); continue; } @@ -2713,6 +2727,12 @@ export class DownloadManager extends EventEmitter { continue; } if (await this.existsAsync(targetPath)) { + if (pkg) { + this.logPackageForPackage(pkg, "WARN", "Auto-Rename übersprungen: Ziel existiert", { + sourceName, + targetPath + }); + } logger.warn(`Auto-Rename übersprungen (Ziel existiert): ${targetPath}`); continue; } @@ -2758,6 +2778,12 @@ export class DownloadManager extends EventEmitter { } } logger.warn(`Auto-Rename fehlgeschlagen (${sourceName}): ${compactErrorText(error)}`); + if (pkg) { + this.logPackageForPackage(pkg, "WARN", "Auto-Rename fehlgeschlagen", { + sourceName, + error: compactErrorText(error) + }); + } } } diff --git a/src/main/extractor.ts b/src/main/extractor.ts index 6853a45..315a35c 100644 --- a/src/main/extractor.ts +++ b/src/main/extractor.ts @@ -457,8 +457,14 @@ function effectiveConflictMode(conflictMode: ConflictMode): "overwrite" | "skip" return "skip"; } -function cleanErrorText(text: string): string { - return String(text || "").replace(/\s+/g, " ").trim().slice(0, 500); +export function cleanErrorText(text: string): string { + const normalized = String(text || "").replace(/\s+/g, " ").trim(); + if (normalized.length <= 500) { + return normalized; + } + const head = normalized.slice(0, 240).trimEnd(); + const tail = normalized.slice(-240).trimStart(); + return `${head} ... ${tail}`; } function appendLimited(base: string, chunk: string, maxLen = MAX_EXTRACT_OUTPUT_BUFFER): string { @@ -2342,7 +2348,7 @@ async function runExternalExtractInner( let bestPercent = 0; let passwordAttempt = 0; let usePerformanceFlags = externalExtractorSupportsPerfFlags && shouldUseExtractorPerformanceFlags(); - const summarizeResultError = (errorText: string): string => cleanErrorText(errorText).slice(0, 280); + const summarizeResultError = (errorText: string): string => cleanErrorText(errorText); let createErrorText = ""; let createErrorPassword = ""; diff --git a/tests/auto-rename.test.ts b/tests/auto-rename.test.ts index f6363ec..a0da6ab 100644 --- a/tests/auto-rename.test.ts +++ b/tests/auto-rename.test.ts @@ -744,4 +744,22 @@ describe("buildAutoRenameBaseNameFromFolders", () => { ); expect(result).toBe("A.Million.Little.Things.S03E10.GERMAN.DL.720p.WEB.H264-4SF"); }); + + it("renames abbreviated source jkl.web.7p-s01e13 via season folder", () => { + const result = buildAutoRenameBaseNameFromFoldersWithOptions( + ["9JKL.S01.GERMAN.720p.WEB.x264-WvF"], + "jkl.web.7p-s01e13", + { forceEpisodeForSeasonFolder: true } + ); + expect(result).toBe("9JKL.S01E13.GERMAN.720p.WEB.x264-WvF"); + }); + + it("renames abbreviated source jkl.web.7p-s01e14 via season folder", () => { + const result = buildAutoRenameBaseNameFromFoldersWithOptions( + ["9JKL.S01.GERMAN.720p.WEB.x264-WvF"], + "jkl.web.7p-s01e14", + { forceEpisodeForSeasonFolder: true } + ); + expect(result).toBe("9JKL.S01E14.GERMAN.720p.WEB.x264-WvF"); + }); }); diff --git a/tests/extractor.test.ts b/tests/extractor.test.ts index 2c29f49..fd82002 100644 --- a/tests/extractor.test.ts +++ b/tests/extractor.test.ts @@ -5,6 +5,7 @@ import AdmZip from "adm-zip"; import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { buildExternalExtractArgs, + cleanErrorText, collectArchiveCleanupTargets, extractPackageArchives, type ExtractArchiveFailureInfo, @@ -1038,6 +1039,13 @@ describe("extractor", () => { it("returns unknown for unrecognized errors", () => { expect(classifyExtractionError("something weird happened")).toBe("unknown"); }); + + it("keeps important tail markers when long extractor output is trimmed", () => { + const noisy = `Extracting from archive.rar ${"x".repeat(700)} Unexpected end of archive`; + const cleaned = cleanErrorText(noisy); + expect(cleaned).toContain("Unexpected end of archive"); + expect(classifyExtractionError(cleaned)).toBe("missing_parts"); + }); }); describe("password discovery", () => {