diff --git a/Futonizer.csproj b/Futonizer.csproj index 33739f8..bd52497 100644 --- a/Futonizer.csproj +++ b/Futonizer.csproj @@ -9,8 +9,8 @@ enable Futonizer Futonizer - 1.0.4 - 1.0.4.0 + 1.0.5 + 1.0.5.0 Assets\app.ico diff --git a/Services/FileNameHelper.cs b/Services/FileNameHelper.cs index ab64a16..678afc4 100644 --- a/Services/FileNameHelper.cs +++ b/Services/FileNameHelper.cs @@ -24,10 +24,15 @@ public static class FileNameHelper private static readonly Regex PrefixTagRegex = new(@"^\[(.+?)\]", RegexOptions.Compiled); - // Episode-only filename: starts with S01E01, S1E1, etc. (no show name present) + // Episode-only filename (no tag prefix): starts with S01E01, S1E1, etc. private static readonly Regex EpisodeOnlyRegex = new(@"^S\d+E\d+", RegexOptions.IgnoreCase | RegexOptions.Compiled); + // Episode start after a tag prefix is stripped: plain number OR S01E01 style. + // e.g. "03 - Deus Vult ..." or "S01E01-Deep Blue" + private static readonly Regex EpisodeStartRegex = + new(@"^(\d+|S\d+E\d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled); + // Individual metadata-token patterns used to find where the show name ends // inside a folder name. private static readonly Regex[] MetadataPatterns = @@ -86,12 +91,35 @@ public static class FileNameHelper if (string.IsNullOrEmpty(tag) && !string.IsNullOrEmpty(folderName)) tag = ExtractReleaseTag(folderName); - // 3. Inject show name when only an episode code is present. - if (EpisodeOnlyRegex.IsMatch(stemNoExt) && !string.IsNullOrEmpty(folderName)) + // 3. Check for episode-only patterns and inject show name if needed. + if (!string.IsNullOrEmpty(folderName)) { - string showName = ExtractShowName(folderName); - if (!string.IsNullOrEmpty(showName)) - fileName = showName + " " + fileName; + // Pattern A: untagged stem starts with S01E01 (e.g. "S01E01-Deep Blue.mkv") + if (EpisodeOnlyRegex.IsMatch(stemNoExt)) + { + string showName = ExtractShowName(folderName); + if (!string.IsNullOrEmpty(showName)) + fileName = showName + " " + fileName; + } + // Pattern B: file already carries [TAG] but episode number follows directly. + // e.g. "[WBDP] 03 - Deus Vult ..." → insert show name after the tag. + else if (!string.IsNullOrEmpty(tag)) + { + string tagPfx = $"[{tag}] "; + if (stemNoExt.StartsWith(tagPfx, StringComparison.OrdinalIgnoreCase)) + { + string afterTag = stemNoExt[tagPfx.Length..]; + if (EpisodeStartRegex.IsMatch(afterTag)) + { + string showName = ExtractShowName(folderName); + if (!string.IsNullOrEmpty(showName)) + { + // Strip the tag, inject show name; tag is re-prepended in step 4. + fileName = showName + " " + fileName[tagPfx.Length..]; + } + } + } + } } // 4. Prepend release tag if not already present. @@ -123,8 +151,13 @@ public static class FileNameHelper /// /// Derives the show name from a folder name by stripping any release tag - /// (prefix or suffix) and then taking all words that precede the first - /// recognised metadata token (season, quality, source, codec, etc.). + /// (prefix or suffix) and then: + /// + /// If the remainder contains brackets (e.g. [BD][1080p-FLAC]), + /// returns the text that precedes the first bracket. + /// Otherwise splits on spaces and collects words up to the first + /// recognised metadata token (season, quality, source, codec, etc.). + /// /// public static string ExtractShowName(string folderName) { @@ -132,7 +165,15 @@ public static class FileNameHelper string name = FolderSuffixTagRegex.Replace(folderName, "").Trim(); name = PrefixTagRegex.Replace(name, "").Trim(); - // Collect words up to the first metadata token. + // Nothing left, or what remains immediately starts with a bracket — no show name. + if (string.IsNullOrEmpty(name) || name[0] == '[') return string.Empty; + + // Bracket-style metadata: "The Saga of Tanya the Evil [BD][1080p-FLAC][HEVC]" + int bracketIdx = name.IndexOf('['); + if (bracketIdx > 0) + return name[..bracketIdx].Trim(); + + // Space-separated metadata: "Grand Blue Dreaming S01 1080p BD Remux FLAC" var words = name.Split(' ', StringSplitOptions.RemoveEmptyEntries); var showWords = new List(); foreach (var word in words)