diff --git a/SubRenamer.Core/Matcher.cs b/SubRenamer.Core/Matcher.cs index d4eeef6..5636759 100644 --- a/SubRenamer.Core/Matcher.cs +++ b/SubRenamer.Core/Matcher.cs @@ -27,14 +27,27 @@ public static List Execute(IReadOnlyList inputItems, Match subtitleFiles.Add(item.Subtitle); }); + // Return directly if only 1 video and 1 subtitle + if (videoFiles.Count == 1 && subtitleFiles.Count == 1) + return [new MatchItem("1", videoFiles[0], subtitleFiles[0])]; + // Get file keys var video2Keys = CalculateFileKeys(videoFiles, customRegex: options.VideoRegex); var subtitle2Keys = CalculateFileKeys(subtitleFiles, customRegex: options.SubtitleRegex); + // Merge items with same filename + result = MatcherHelper.MergeSameFilenameItems(result); + // Apply keys List keyedItems = []; foreach (var item in result) { + if (item.Key != "") + { + keyedItems.Add(item); + continue; + } + string? k = null; if (!string.IsNullOrEmpty(item.Video)) video2Keys.TryGetValue(item.Video, out k); @@ -77,7 +90,8 @@ private static Dictionary CalculateFileKeys(IReadOnlyList CalculateFileKeys(IReadOnlyList MergeSameKeysItems(IReadOnlyList items) return result; } + public static List MergeSameFilenameItems(IReadOnlyList items) + { + var groupBNotNullCNull = items + .Where(item => string.IsNullOrEmpty(item.Key) && !string.IsNullOrEmpty(item.Video) && string.IsNullOrEmpty(item.Subtitle)) + .ToList(); + + var groupBNullCNotNull = items + .Where(item => string.IsNullOrEmpty(item.Key) && string.IsNullOrEmpty(item.Video) && !string.IsNullOrEmpty(item.Subtitle)) + .ToList(); + + var result = new List(); + + var mergedItems = groupBNotNullCNull + .Join(groupBNullCNotNull, + item1 => Path.GetFileNameWithoutExtension(item1.Video), + item2 => Path.GetFileNameWithoutExtension(item2.Subtitle), + (item1, item2) => new MatchItem(Path.GetFileNameWithoutExtension(item1.Video), item1.Video, item2.Subtitle)) + .ToList(); + + result.AddRange(mergedItems); + + var mergedVideos = new HashSet(mergedItems.Select(x => x.Video)); + var mergedSubtitles = new HashSet(mergedItems.Select(x => x.Subtitle)); + + var itemsToRemove = items.Where(item => + { + if (item.Key != "") return false; + if (item.Video != "" && item.Subtitle != "") return false; + if (item.Video != "" && mergedVideos.Contains(item.Video)) return true; + if (item.Subtitle != "" && mergedSubtitles.Contains(item.Subtitle)) return true; + return false; + }); + result.AddRange(items.Where(item => !itemsToRemove.Contains(item))); + + return result; + } + public static List MoveEmptyKeyItemsToLast(IReadOnlyList items) { var keyedItems = items.Where(x => !string.IsNullOrEmpty(x.Key)); diff --git a/SubRenamer.Tests/MatcherTests/MergeSameFilenameItemsTest.cs b/SubRenamer.Tests/MatcherTests/MergeSameFilenameItemsTest.cs new file mode 100644 index 0000000..db2456c --- /dev/null +++ b/SubRenamer.Tests/MatcherTests/MergeSameFilenameItemsTest.cs @@ -0,0 +1,40 @@ +using SubRenamer.Core; +using static SubRenamer.Core.MatcherHelper; + +namespace SubRenamer.Tests.MatcherTests; + +[TestFixture] +public class MergeSameFilenameItemsTests +{ + [Test] + public void Basic() + { + var input = new List + { + new("", "a.mp4", ""), + new("", "", "b.srt"), + + new("", "", "a.srt"), + new("", "b.mp4", ""), + + + new("", "v1.mp4", ""), + new("", "", "s1.srt"), + new("2", "v2.mp4", ""), + new("2", "", "s2.srt"), + }; + var output = new List + { + new("a", "a.mp4", "a.srt"), + new("b", "b.mp4", "b.srt"), + + new("", "v1.mp4", ""), + new("", "", "s1.srt"), + new("2", "v2.mp4", ""), + new("2", "", "s2.srt"), + }; + + var result = MergeSameFilenameItems(input); + Assert.That(result, Is.EqualTo(output)); + } +} \ No newline at end of file