From 981c4f145d2d51ae6bceae4ab5c24034ee51e98e Mon Sep 17 00:00:00 2001 From: Mark Pitman Date: Fri, 13 Feb 2026 23:44:19 -0800 Subject: [PATCH] Fix rip output summary and title suffix --- .../Services/DiscRipperTitleSuffixTests.cs | 147 ++++++++++++++++++ src/RipSharp/Core/Program.cs | 5 - src/RipSharp/Services/DiscRipper.cs | 10 +- 3 files changed, 153 insertions(+), 9 deletions(-) create mode 100644 src/RipSharp.Tests/Services/DiscRipperTitleSuffixTests.cs diff --git a/src/RipSharp.Tests/Services/DiscRipperTitleSuffixTests.cs b/src/RipSharp.Tests/Services/DiscRipperTitleSuffixTests.cs new file mode 100644 index 0000000..1390bb0 --- /dev/null +++ b/src/RipSharp.Tests/Services/DiscRipperTitleSuffixTests.cs @@ -0,0 +1,147 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; + +using AwesomeAssertions; + +using NSubstitute; + +using Xunit; + +namespace BugZapperLabs.RipSharp.Tests.Services; + +public class DiscRipperTitleSuffixTests +{ + [Fact] + public async Task BuildTitlePlansAsync_SingleMovieTitle_DoesNotAppendSuffix() + { + var encoder = Substitute.For(); + var ripper = CreateRipper(encoder); + var discInfo = new DiscInfo + { + Titles = new List + { + new() { Id = 0, Name = "Control" } + } + }; + var titleIds = new List { 0 }; + var metadata = new ContentMetadata { Title = "Control", Year = 2007, Type = "movie" }; + var options = new RipOptions { Output = "/tmp" }; + + var plans = await InvokeBuildTitlePlansAsync(ripper, discInfo, titleIds, metadata, options); + plans.Should().HaveCount(1); + + var plan = plans.Single(); + var finalFileName = GetStringProperty(plan, "FinalFileName"); + var versionSuffix = GetStringProperty(plan, "VersionSuffix"); + + finalFileName.Should().Be("Control (2007).mkv"); + versionSuffix.Should().BeNull(); + } + + [Fact] + public async Task EncodeAndRenameAsync_SingleMovieTitle_DoesNotAppendSuffix() + { + var outputRoot = Path.Combine(Path.GetTempPath(), $"ripsharp-tests-{Path.GetRandomFileName()}"); + Directory.CreateDirectory(outputRoot); + var sourceFile = Path.Combine(outputRoot, "source.mkv"); + File.WriteAllText(sourceFile, "data"); + + try + { + var encoder = Substitute.For(); + encoder.EncodeAsync( + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any(), + Arg.Any()) + .Returns(callInfo => + { + var outputPath = callInfo.ArgAt(1); + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)!); + File.WriteAllText(outputPath, "data"); + return Task.FromResult(true); + }); + + var ripper = CreateRipper(encoder); + var discInfo = new DiscInfo + { + Titles = new List + { + new() { Id = 0, Name = "Control" } + } + }; + var titleIds = new List { 0 }; + var rippedFilesMap = new Dictionary { { 0, sourceFile } }; + var metadata = new ContentMetadata { Title = "Control", Year = 2007, Type = "movie" }; + var options = new RipOptions { Output = outputRoot }; + + var finalFiles = await InvokeEncodeAndRenameAsync(ripper, discInfo, titleIds, rippedFilesMap, metadata, options); + + finalFiles.Should().HaveCount(1); + finalFiles[0].Should().Be(Path.Combine(outputRoot, "Control (2007).mkv")); + finalFiles[0].Should().NotContain("title01"); + } + finally + { + Directory.Delete(outputRoot, recursive: true); + } + } + + private static DiscRipper CreateRipper(IEncoderService encoder) + { + var scanner = Substitute.For(); + var metadataService = Substitute.For(); + var makeMkv = Substitute.For(); + var notifier = Substitute.For(); + var userPrompt = Substitute.For(); + var episodeTitles = Substitute.For(); + var progressDisplay = Substitute.For(); + + return new DiscRipper(scanner, encoder, metadataService, makeMkv, notifier, userPrompt, episodeTitles, progressDisplay); + } + + private static async Task> InvokeBuildTitlePlansAsync( + DiscRipper ripper, + DiscInfo discInfo, + List titleIds, + ContentMetadata metadata, + RipOptions options) + { + var method = typeof(DiscRipper).GetMethod("BuildTitlePlansAsync", BindingFlags.NonPublic | BindingFlags.Instance); + method.Should().NotBeNull(); + + var task = (Task)method!.Invoke(ripper, new object[] { discInfo, titleIds, metadata, options })!; + await task.ConfigureAwait(false); + + var result = task.GetType().GetProperty("Result")!.GetValue(task)!; + return ((IEnumerable)result).Cast().ToList(); + } + + private static async Task> InvokeEncodeAndRenameAsync( + DiscRipper ripper, + DiscInfo discInfo, + List titleIds, + Dictionary rippedFilesMap, + ContentMetadata metadata, + RipOptions options) + { + var method = typeof(DiscRipper).GetMethod("EncodeAndRenameAsync", BindingFlags.NonPublic | BindingFlags.Instance); + method.Should().NotBeNull(); + + var task = (Task)method!.Invoke(ripper, new object[] { discInfo, titleIds, rippedFilesMap, metadata, options })!; + await task.ConfigureAwait(false); + + return (List)task.GetType().GetProperty("Result")!.GetValue(task)!; + } + + private static string? GetStringProperty(object target, string propertyName) + { + return target.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance)?.GetValue(target) as string; + } +} diff --git a/src/RipSharp/Core/Program.cs b/src/RipSharp/Core/Program.cs index 3b85b35..429f53c 100644 --- a/src/RipSharp/Core/Program.cs +++ b/src/RipSharp/Core/Program.cs @@ -128,11 +128,6 @@ private static async Task RunAsync(string[] args, CursorManager cursorManag if (files.Count > 0) { - writer.Success("Success! Files created:"); - foreach (var f in files) - { - writer.Plain(f); - } return 0; } else diff --git a/src/RipSharp/Services/DiscRipper.cs b/src/RipSharp/Services/DiscRipper.cs index 200cf25..54214c6 100644 --- a/src/RipSharp/Services/DiscRipper.cs +++ b/src/RipSharp/Services/DiscRipper.cs @@ -138,8 +138,9 @@ private async Task> BuildTitlePlansAsync(DiscInfo discInfo, List else { var ordinal = idx + 1; - versionSuffix = $" - title{ordinal:D2}"; - var safeVersionSuffix = FileNaming.SanitizeFileName(versionSuffix); + var includeSuffix = titleIds.Count > 1; + versionSuffix = includeSuffix ? $" - title{ordinal:D2}" : null; + var safeVersionSuffix = string.IsNullOrWhiteSpace(versionSuffix) ? "" : FileNaming.SanitizeFileName(versionSuffix); var yearPart = metadata.Year.HasValue ? $" ({metadata.Year.Value})" : ""; var safeTitle = !string.IsNullOrWhiteSpace(titleName) ? FileNaming.SanitizeFileName(titleName!) : safeSeriesTitle; finalFileName = $"{safeTitle}{yearPart}{safeVersionSuffix}.mkv"; @@ -758,8 +759,9 @@ private async Task> EncodeAndRenameAsync(DiscInfo discInfo, List 1; + versionSuffix = includeSuffix ? $" - title{ordinal:D2}" : null; + var safeVersionSuffix = string.IsNullOrWhiteSpace(versionSuffix) ? "" : FileNaming.SanitizeFileName(versionSuffix); outputName = Path.Combine(options.Output, $"{safeTitle}{safeVersionSuffix}.mkv"); } if (File.Exists(outputName)) File.Delete(outputName);