Auto-Rename Folder-Override: nur bei OBFUSKIERTEM Source-Filename
Regression in v1.7.147: der Folder-Override (parentEpisodeToken ueberschreibt sourceEpisodeToken bei Mismatch) ist zu aggressiv. Bei sauberen Scene-Releases die zufaellig im falschen Folder liegen wuerde das den Episodennamen FALSCH umschreiben. Beispiel aus Production-Log: Folder: The.Royals.S01E08.Der.Grosse.stuerzt.German.DL.720p.BluRay.x264-J4F File: the.royals.2015.s01e09.german.dl.720p.bluray.x264-j4f.mkv Beide haben sauberes Scene-Format. Datei sagt klar S01E09 — Folder ist falsch beschriftet (Hoster-Fehler). Die Datei zu S01E08 umbenennen waere Daten-Korruption. Fix: neue Helper-Funktion looksLikeObfuscatedSceneFileName() prueft ob ein Filename Scene-Marker hat (720p/1080p, german/english, bluray/web/ hdtv, x264/x265, ac3/aac/dts) ODER 5+ Punkte als Scene-Struktur. Wenn 2+ Marker oder 5+ Punkte → KEIN Override (Source ist authoritativ). Wenn weniger → Source ist obfuskiert, Folder gewinnt. Beispiele aus Production: - "awa-diethundermans02e16hd.mkv" (0 Marker, 0 Punkte) → obfuskiert, Folder Die.Thundermans.S02E01... gewinnt → korrekt umbenannt - "the.royals.2015.s01e09.german.dl.720p.bluray.x264-j4f.mkv" (5 Marker) → sauber, Source bleibt → Skip statt Falsch-Rename - "Desperate.Housewives.S01E01.German.Synced.DL.720p.WEB-DL.AC3.h264.mkv" (5+ Marker) → sauber, kein Override 4 neue Unit-Tests fuer looksLikeObfuscatedSceneFileName, 581/581 gruen.
This commit is contained in:
parent
b1291d2e3c
commit
834da04b45
@ -866,6 +866,46 @@ export function hasMeaningfulSeriesPrefix(name: string): boolean {
|
||||
const alphaChars = (prefix.match(/[A-Za-z]/g) || []).length;
|
||||
return alphaChars >= 3;
|
||||
}
|
||||
|
||||
/** Heuristic: returns true if the file name LOOKS LIKE an obfuscated /
|
||||
* scrambled hoster name (e.g. "awa-diethundermans02e16hd.mkv") rather than
|
||||
* a clean scene release ("the.royals.2015.s01e09.german.dl.720p.bluray.x264-j4f.mkv").
|
||||
*
|
||||
* Used as a guard before we override a source-derived episode token with
|
||||
* a folder-derived one. A clean scene file's embedded SxxExx is
|
||||
* authoritative — overriding it would mislabel the episode. Only files
|
||||
* that lack the usual scene markers (quality, language, codec, source/
|
||||
* format) are treated as obfuscated and let the folder win.
|
||||
*
|
||||
* Threshold: < 2 scene markers AND no proper dot-separated scene
|
||||
* structure → considered obfuscated. */
|
||||
export function looksLikeObfuscatedSceneFileName(name: string): boolean {
|
||||
const text = String(name || "").toLowerCase();
|
||||
if (!text) {
|
||||
return true;
|
||||
}
|
||||
let markers = 0;
|
||||
if (/(?:^|[._\-\s])(?:480|540|576|720|1080|1440|2160|4320)p(?:[._\-\s]|$)/.test(text)) markers += 1;
|
||||
if (/(?:^|[._\-\s])(?:german|english|french|italian|spanish|dutch|nordic|multi|ger|eng|ita|fre|spa)(?:[._\-\s]|$)/.test(text)) markers += 1;
|
||||
if (/(?:^|[._\-\s])(?:bluray|brrip|bdrip|webrip|web-?dl|web|hdtv|dvdrip|amazonhd|amzn|nflx|nf|hulu|dsnp)(?:[._\-\s]|$)/.test(text)) markers += 1;
|
||||
if (/(?:^|[._\-\s])(?:x264|x265|h264|h265|hevc|xvid|divx|avc)(?:[._\-\s]|$)/.test(text)) markers += 1;
|
||||
if (/(?:^|[._\-\s])(?:ac3|aac|dd5\.?1|dd51|dts|eac3|atmos|truehd|flac)(?:[._\-\s]|$)/.test(text)) markers += 1;
|
||||
// 2+ scene markers → definitely a clean scene file, not obfuscated
|
||||
if (markers >= 2) {
|
||||
return false;
|
||||
}
|
||||
// No markers AND looks like glued/short hoster code → obfuscated
|
||||
// Check for typical hoster pattern: short prefix + glued lowercase + episode digits
|
||||
// e.g. "awa-diethundermans02e16hd", "scn-dthund7-S02E06"
|
||||
const dotCount = (text.match(/\./g) || []).length;
|
||||
// A clean scene file usually has 6+ dot-separated tokens (excluding extension)
|
||||
// An obfuscated file usually has 0-2 dots (mostly using - or no separators).
|
||||
if (dotCount >= 5) {
|
||||
// Many dots usually means scene-style structure even with few markers
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const SCENE_SEASON_CAPTURE_RE = /(?:^|[._\-\s])s(\d{1,2})(?=[._\-\s]|$)/i;
|
||||
const SCENE_EPISODE_ONLY_RE = /(?:^|[._\-\s])e(?:p(?:isode)?)?\s*0*(\d{1,3})(?:[._\-\s]|$)/i;
|
||||
const SCENE_PART_TOKEN_RE = /(?:^|[._\-\s])(?:teil|part)\s*0*(\d{1,3})(?=[._\-\s]|$)/i;
|
||||
@ -3787,10 +3827,20 @@ export class DownloadManager extends EventEmitter {
|
||||
// misleading source token.
|
||||
const parentFolderName = path.basename(path.dirname(sourcePath));
|
||||
const parentEpisodeToken = extractEpisodeToken(parentFolderName);
|
||||
// GUARD: only let the folder override the source token when the
|
||||
// source filename actually LOOKS obfuscated (no scene markers like
|
||||
// 720p / german / x264 / bluray, no dot-separated structure).
|
||||
// A clean scene release filename — e.g. "the.royals.2015.s01e09.
|
||||
// german.dl.720p.bluray.x264-j4f.mkv" — must NEVER be overridden,
|
||||
// because a one-off folder/file mismatch with a clean source means
|
||||
// the FOLDER is wrong, not the file. Renaming a real S01E09 to
|
||||
// S01E08 because the folder happens to say E08 would corrupt data.
|
||||
const sourceLooksObfuscated = looksLikeObfuscatedSceneFileName(sourceName);
|
||||
const folderIsAuthoritative = Boolean(
|
||||
parentEpisodeToken
|
||||
&& parentEpisodeToken === targetEpisodeToken
|
||||
&& parentFolderName.toLowerCase() !== path.basename(extractDir).toLowerCase()
|
||||
&& sourceLooksObfuscated
|
||||
);
|
||||
if (folderIsAuthoritative) {
|
||||
logger.info(`Auto-Rename: source-Token ${sourceEpisodeToken} ignoriert, Folder-Token ${targetEpisodeToken} ist authoritativ (vermutlich obfuskierter Dateiname in ${parentFolderName})`);
|
||||
|
||||
@ -7,7 +7,8 @@ import {
|
||||
buildAutoRenameBaseName,
|
||||
buildAutoRenameBaseNameFromFolders,
|
||||
buildAutoRenameBaseNameFromFoldersWithOptions,
|
||||
hasMeaningfulSeriesPrefix
|
||||
hasMeaningfulSeriesPrefix,
|
||||
looksLikeObfuscatedSceneFileName
|
||||
} from "../src/main/download-manager";
|
||||
|
||||
describe("hasMeaningfulSeriesPrefix", () => {
|
||||
@ -31,6 +32,32 @@ describe("hasMeaningfulSeriesPrefix", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("looksLikeObfuscatedSceneFileName", () => {
|
||||
it("flags hoster-obfuscated names with no scene markers as obfuscated", () => {
|
||||
// No 720p / german / x264 / bluray, no dot-separated structure
|
||||
expect(looksLikeObfuscatedSceneFileName("awa-diethundermans02e16hd.mkv")).toBe(true);
|
||||
expect(looksLikeObfuscatedSceneFileName("scn-dthund7-S02E06.mkv")).toBe(true);
|
||||
expect(looksLikeObfuscatedSceneFileName("4sj-blue-bloods-s08e21-720p.mkv")).toBe(true);
|
||||
});
|
||||
|
||||
it("treats clean scene releases with multiple markers as NOT obfuscated", () => {
|
||||
// Has 720p + german + bluray + x264 — clearly a clean scene file
|
||||
expect(looksLikeObfuscatedSceneFileName("the.royals.2015.s01e09.german.dl.720p.bluray.x264-j4f.mkv")).toBe(false);
|
||||
expect(looksLikeObfuscatedSceneFileName("Die.Thundermans.S02E06.Tickets.und.Shreddy.GERMAN.WS.720p.HDTV.x264-aWake.mkv")).toBe(false);
|
||||
expect(looksLikeObfuscatedSceneFileName("Desperate.Housewives.S01E01.German.Synced.DL.720p.WEB-DL.AC3.h264.mkv")).toBe(false);
|
||||
});
|
||||
|
||||
it("handles edge cases (empty, very short)", () => {
|
||||
expect(looksLikeObfuscatedSceneFileName("")).toBe(true);
|
||||
expect(looksLikeObfuscatedSceneFileName("a.mkv")).toBe(true);
|
||||
});
|
||||
|
||||
it("treats long dotted names as scene-style even with few markers", () => {
|
||||
// 6+ dots → looks like scene structure even without quality/codec markers
|
||||
expect(looksLikeObfuscatedSceneFileName("Some.Show.With.Many.Tokens.S01E01.mkv")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractEpisodeToken", () => {
|
||||
it("extracts S01E01 from standard scene format", () => {
|
||||
expect(extractEpisodeToken("show.name.s01e01.720p")).toBe("S01E01");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user