diff --git a/Futonizer.csproj b/Futonizer.csproj index 3263779..89413cc 100644 --- a/Futonizer.csproj +++ b/Futonizer.csproj @@ -9,8 +9,8 @@ enable Futonizer Futonizer - 1.0.8 - 1.0.8.0 + 1.0.9 + 1.0.9.0 Assets\app.ico diff --git a/Services/FileNameHelper.cs b/Services/FileNameHelper.cs index c963cb4..48edc75 100644 --- a/Services/FileNameHelper.cs +++ b/Services/FileNameHelper.cs @@ -14,11 +14,21 @@ public static class FileNameHelper private static readonly Regex FolderSuffixTagRegex = new(@"-([A-Z][A-Z0-9]{1,7})$", RegexOptions.Compiled); + // Folder suffix bracket release tag: "Show Name ... x264 [i_c]" → tag = "i_c" + // A bracketed tag at the very end of the folder name (as opposed to + // PrefixTagRegex, which matches one at the start). + private static readonly Regex FolderSuffixBracketTagRegex = + new(@"\[([^\[\]]+)\]$", RegexOptions.Compiled); + // File suffix release tag: "…HEVC-DemiHuman" → tag = "DemiHuman" // Mixed case, 3-21 chars (no dots/spaces), at end of filename stem. - // Min 3 chars avoids false-positives like "-v2" or "-HD". + // Min 3 chars avoids false-positives like "-v2" or "-HD". The word + // immediately preceding the dash must itself be recognisable quality/ + // source/codec metadata (checked by the caller via IsMetadataToken), so + // an ordinary hyphenated title word (e.g. "Scary-oke") is never mistaken + // for a "-GroupName" suffix. private static readonly Regex FileSuffixTagRegex = - new(@"-([A-Za-z][A-Za-z0-9]{2,20})$", RegexOptions.Compiled); + new(@"(?:^|[\s.])([A-Za-z0-9]+)-([A-Za-z][A-Za-z0-9]{2,20})$", RegexOptions.Compiled); // Trailing parenthesised metadata block ending in the release group as its // last word, e.g. "... (1080p AMZN WEB-DL x265 Celdra)" → group="Celdra". @@ -86,13 +96,18 @@ public static class FileNameHelper string folderName = string.IsNullOrEmpty(folder) ? "" : (Path.GetFileName(folder) ?? ""); // 1. Extract in-filename suffix tag and remove it from the stem. - // e.g. "...HEVC-DemiHuman" → tag="DemiHuman", stem="...HEVC" + // e.g. "...x264-DemiHuman" → tag="DemiHuman", stem="...x264" + // Only fires when the word right before the dash is itself a + // recognised metadata token (codec/source/etc.), so ordinary + // hyphenated title words are left alone. string? fileTag = null; var fileSuffixMatch = FileSuffixTagRegex.Match(stemNoExt); - if (fileSuffixMatch.Success) + if (fileSuffixMatch.Success + && IsMetadataToken(fileSuffixMatch.Groups[1].Value) + && !IsMetadataToken(fileSuffixMatch.Groups[2].Value)) { - fileTag = fileSuffixMatch.Groups[1].Value; - stemNoExt = stemNoExt[..fileSuffixMatch.Index]; + fileTag = fileSuffixMatch.Groups[2].Value; + stemNoExt = stemNoExt[..(fileSuffixMatch.Groups[2].Index - 1)]; fileName = stemNoExt + ext; } else @@ -169,17 +184,24 @@ public static class FileNameHelper } /// - /// Extracts the release tag string (without brackets) from a folder name. - /// Suffix pattern (-TAG) takes priority over prefix pattern - /// ([TAG]). Returns null when neither is present. + /// Extracts the release tag string (without brackets) from a folder name, + /// checking (in priority order): a dash suffix (-TAG), a bracketed + /// suffix ([tag] at the end), then a bracketed prefix ([tag] + /// at the start). Returns null when none are present. /// public static string? ExtractReleaseTag(string folderName) { var suffixMatch = FolderSuffixTagRegex.Match(folderName); - if (suffixMatch.Success) return suffixMatch.Groups[1].Value; + if (suffixMatch.Success && !IsMetadataToken(suffixMatch.Groups[1].Value)) + return suffixMatch.Groups[1].Value; + + var bracketSuffixMatch = FolderSuffixBracketTagRegex.Match(folderName); + if (bracketSuffixMatch.Success && !IsMetadataBracket(bracketSuffixMatch.Groups[1].Value)) + return bracketSuffixMatch.Groups[1].Value; var prefixMatch = PrefixTagRegex.Match(folderName); - if (prefixMatch.Success) return prefixMatch.Groups[1].Value; + if (prefixMatch.Success && !IsMetadataBracket(prefixMatch.Groups[1].Value)) + return prefixMatch.Groups[1].Value; return null; } @@ -198,6 +220,7 @@ public static class FileNameHelper { // Strip release tags first. string name = FolderSuffixTagRegex.Replace(folderName, "").Trim(); + name = FolderSuffixBracketTagRegex.Replace(name, "").Trim(); name = PrefixTagRegex.Replace(name, "").Trim(); // Nothing left, or what remains immediately starts with a bracket — no show name. @@ -226,4 +249,16 @@ public static class FileNameHelper if (pattern.IsMatch(token)) return true; return false; } + + /// + /// True when every word inside a bracketed block is recognisable quality/ + /// source/codec metadata (e.g. "[HEVC]", "[1080p-FLAC]"), meaning it's + /// just another metadata tag rather than an actual release group name + /// (e.g. "[i_c]"). + /// + private static bool IsMetadataBracket(string content) + { + var parts = content.Split(new[] { ' ', '-' }, StringSplitOptions.RemoveEmptyEntries); + return parts.Length > 0 && parts.All(IsMetadataToken); + } }