diff --git a/src/CCVTAC.Console/Downloading/Downloader.cs b/src/CCVTAC.Console/Downloading/Downloader.cs index 784c6a9..19232fa 100644 --- a/src/CCVTAC.Console/Downloading/Downloader.cs +++ b/src/CCVTAC.Console/Downloading/Downloader.cs @@ -33,13 +33,13 @@ internal static Result WrapUrlInMediaType(string url) if (!mediaType.IsVideo && !mediaType.IsPlaylistVideo) { - printer.Info("Please wait for the multiple videos to be downloaded..."); + printer.Info("Please wait for multiple videos to be downloaded..."); } var rawUrls = FSharp.Downloading.ExtractDownloadUrls(mediaType); var urls = new Urls(rawUrls[0], rawUrls.Length == 2 ? rawUrls[1] : null); - Result downloadResult = new(); + var downloadResult = new Result<(int, string)> (); string? successfulFormat = null; foreach (string format in settings.AudioFormats) @@ -47,11 +47,22 @@ internal static Result WrapUrlInMediaType(string url) string args = GenerateDownloadArgs(format, settings, mediaType, urls.Primary); var downloadSettings = new ToolSettings(ExternalTool, args, settings.WorkingDirectory!); - downloadResult = Runner.Run(downloadSettings, printer); + downloadResult = Runner.Run(downloadSettings, otherSuccessExitCodes: [1], printer); if (downloadResult.IsSuccess) { successfulFormat = format; + + var (exitCode, warnings) = downloadResult.Value; + if (exitCode != 0) + { + printer.Warning($"Downloading completed with minor issues."); + if (warnings.HasText()) + { + printer.Warning(warnings); + } + } + break; } @@ -60,7 +71,16 @@ internal static Result WrapUrlInMediaType(string url) var errors = downloadResult.Errors.Select(e => e.Message).ToList(); - if (downloadResult.IsFailed) + int audioFileCount = IoUtilties.Directories.AudioFileCount(settings.WorkingDirectory); + if (audioFileCount == 0) + { + return Result.Fail(string.Join( + Environment.NewLine, + ["No audio files were downloaded.", ..errors]) + ); + } + + if (errors.Count != 0) { downloadResult.Errors.ForEach(e => printer.Error(e.Message)); printer.Info("Post-processing will still be attempted."); // For any partial downloads @@ -75,7 +95,11 @@ internal static Result WrapUrlInMediaType(string url) supplementaryArgs, settings.WorkingDirectory!); - var supplementaryDownloadResult = Runner.Run(supplementaryDownloadSettings, printer); + var supplementaryDownloadResult = + Runner.Run( + supplementaryDownloadSettings, + otherSuccessExitCodes: [1], + printer); if (supplementaryDownloadResult.IsSuccess) { diff --git a/src/CCVTAC.Console/ExtensionMethods.cs b/src/CCVTAC.Console/ExtensionMethods.cs index 3002661..1b3dacd 100644 --- a/src/CCVTAC.Console/ExtensionMethods.cs +++ b/src/CCVTAC.Console/ExtensionMethods.cs @@ -66,4 +66,8 @@ public static string ReplaceInvalidPathChars( ); } + public static string TrimTerminalLineBreak(this string text) => + text.HasText() + ? text.TrimEnd(Environment.NewLine.ToCharArray()) + : text; } diff --git a/src/CCVTAC.Console/ExternalTools/Runner.cs b/src/CCVTAC.Console/ExternalTools/Runner.cs index 9420810..ebc0f6f 100644 --- a/src/CCVTAC.Console/ExternalTools/Runner.cs +++ b/src/CCVTAC.Console/ExternalTools/Runner.cs @@ -4,7 +4,22 @@ namespace CCVTAC.Console.ExternalTools; internal static class Runner { - internal static Result Run(ToolSettings settings, Printer printer) + private const int AuthenticSuccessExitCode = 0; + + private static bool IsSuccessExitCode(HashSet otherSuccessExitCodes, int exitCode) => + otherSuccessExitCodes.Append(AuthenticSuccessExitCode).Contains(exitCode); + + /// + /// Calls an external application. + /// + /// + /// Additional exit codes, other than 0, that can be treated as non-failures. + /// + /// A `Result` containing the exit code, if successful, or else an error message. + internal static Result<(int SuccessExitCode, string Warnings)> Run( + ToolSettings settings, + HashSet otherSuccessExitCodes, + Printer printer) { Watch watch = new(); @@ -29,18 +44,13 @@ internal static Result Run(ToolSettings settings, Printer printer) return Result.Fail($"Could not locate {settings.Program.Name}. If it's not installed, please install from {settings.Program.Url}."); } - - string error = process.StandardError.ReadToEnd(); // Must precede `WaitForExit()`. + string errors = process.StandardError.ReadToEnd(); // Must precede `WaitForExit()` process.WaitForExit(); - printer.Info($"Completed {settings.Program.Purpose} in {watch.ElapsedFriendly}."); - int exitCode = process.ExitCode; - if (exitCode == 0) - { - return Result.Ok(); - } - - return Result.Fail($"[{settings.Program.Name}] {error.Replace(Environment.NewLine, string.Empty)}."); + var trimmedErrors = errors.TrimTerminalLineBreak(); + return IsSuccessExitCode(otherSuccessExitCodes ?? [], process.ExitCode) + ? Result.Ok((process.ExitCode, trimmedErrors)) // Errors will be considered warnings. + : Result.Fail($"[{settings.Program.Name}] Exit code {process.ExitCode}: {trimmedErrors}."); } } diff --git a/src/CCVTAC.Console/IoUtilties/Directories.cs b/src/CCVTAC.Console/IoUtilties/Directories.cs index 680ee87..ba7175b 100644 --- a/src/CCVTAC.Console/IoUtilties/Directories.cs +++ b/src/CCVTAC.Console/IoUtilties/Directories.cs @@ -1,5 +1,6 @@ using System.IO; using System.Text; +using CCVTAC.Console.PostProcessing; namespace CCVTAC.Console.IoUtilties; @@ -8,6 +9,13 @@ internal static class Directories private static readonly string AllFilesSearchPattern = "*"; private static readonly EnumerationOptions EnumerationOptions = new(); + internal static int AudioFileCount(string directory) + { + return new DirectoryInfo(directory) + .EnumerateFiles() + .Count(f => PostProcessor.AudioExtensions.CaseInsensitiveContains(f.Extension)); + } + internal static Result WarnIfAnyFiles(string directory, int showMax) { var fileNames = GetDirectoryFileNames(directory); diff --git a/src/CCVTAC.Console/PostProcessing/ImageProcessor.cs b/src/CCVTAC.Console/PostProcessing/ImageProcessor.cs index e02007c..726bbd1 100644 --- a/src/CCVTAC.Console/PostProcessing/ImageProcessor.cs +++ b/src/CCVTAC.Console/PostProcessing/ImageProcessor.cs @@ -18,6 +18,6 @@ internal static void Run(string workingDirectory, Printer printer) workingDirectory ); - Runner.Run(imageEditToolSettings, printer); + Runner.Run(imageEditToolSettings, [], printer); } }