From 475b632a20f889f862e601c08fddbf927a9a7676 Mon Sep 17 00:00:00 2001 From: ToaHartor <41634031+ToaHartor@users.noreply.github.com> Date: Tue, 23 Jul 2024 08:02:54 +0900 Subject: [PATCH] feat(api): add --key parameter for demuxing --- README.md | 2 ++ src/Commands/DemuxCommand.cs | 9 +++++++++ src/Demuxer.cs | 4 ++-- src/Parameters.cs | 4 ++++ src/Utils/CliOptions.cs | 26 ++++++++++++++++++++++++++ 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 38db2e9..9c908a0 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,8 @@ Several options are available for most of the commands : - `--audio-format` and `--video-format` can be used to select codecs. If at least one option is chosen, **the merging engine is automatically changed to FFMPEG**. - `--audio-lang` allow to specify audio track language in the output, allowed values are `[chi,eng,jpn,kor]` +For demuxing, a key can be supplied to decrypt the USM file using either the parameter `--key ` or `-b <4 lower bytes of key> -a <4 higher bytes of key>`. + Maintenance commands and options: - `update` retrieves the latest `versions.json` file from the repository and checks if a new version has to be downloaded. It can take several optional parameters as follows : diff --git a/src/Commands/DemuxCommand.cs b/src/Commands/DemuxCommand.cs index 7e23a5e..2b8290a 100644 --- a/src/Commands/DemuxCommand.cs +++ b/src/Commands/DemuxCommand.cs @@ -22,6 +22,7 @@ public DemuxCommand() CliOptions.Output.AddAlias("-o"); AddOption(CliOptions.Output); + AddOption(CliOptions.HexKey); AddOption(CliOptions.Key1); AddOption(CliOptions.Key2); CliOptions.Subs.AddAlias("--subtitles"); @@ -43,6 +44,7 @@ public DemuxCommand() DemuxArgsOptionsBinder demuxArgsOptions = new DemuxArgsOptionsBinder( demuxInputArg, CliOptions.Output, + CliOptions.HexKey, CliOptions.Key1, CliOptions.Key2, CliOptions.MkvEngine, @@ -65,6 +67,7 @@ private static void Execute(DemuxArgsOptions demuxArgsOptions) // Check given arguments and options if (!input.Exists) throw new ArgumentNullException($"Input path does not exist: {input.FullName}"); + DirectoryInfo output = demuxArgsOptions.output; if (!output.Exists) output.Create(); @@ -72,6 +75,12 @@ private static void Execute(DemuxArgsOptions demuxArgsOptions) byte[] key1 = demuxArgsOptions.key1 ?? Array.Empty(); byte[] key2 = demuxArgsOptions.key2 ?? Array.Empty(); + if (demuxArgsOptions.hexKey != null) + { + key1 = demuxArgsOptions.hexKey[..4]; + key2 = demuxArgsOptions.hexKey[4..]; + } + bool merge = demuxArgsOptions.merge; bool includeSubs = demuxArgsOptions.subs; bool noCleanup = demuxArgsOptions.noCleanup; diff --git a/src/Demuxer.cs b/src/Demuxer.cs index f4faa19..2946776 100644 --- a/src/Demuxer.cs +++ b/src/Demuxer.cs @@ -167,9 +167,9 @@ DirectoryInfo output Dictionary> filePaths = usmFile.Demux(true, true, output.FullName); // TODO: Return file list for easier parsing if (!filePaths.TryGetValue("hca", out List hcaPaths)) - throw new Exception("No HCA files could be demuxed..."); + Console.WriteLine("No HCA files have been demuxed..."); - Task[] decodingTasks = new Task[hcaPaths.Count]; + Task[] decodingTasks = new Task[(hcaPaths?.Count) ?? 0]; for (int i = 0; i < decodingTasks.Length; i++) { int j = i; diff --git a/src/Parameters.cs b/src/Parameters.cs index fea49e1..d4477b9 100644 --- a/src/Parameters.cs +++ b/src/Parameters.cs @@ -7,6 +7,7 @@ internal sealed class DemuxArgsOptions { public required FileSystemInfo input; public required DirectoryInfo output; + public byte[]? hexKey; public byte[]? key1; public byte[]? key2; public bool merge; @@ -21,6 +22,7 @@ internal sealed class DemuxArgsOptions internal sealed class DemuxArgsOptionsBinder( Argument inputArg, Option outputOption, + Option hexKeyOption, Option key1Option, Option key2Option, Option mkvEngineOption, @@ -34,6 +36,7 @@ Option audioLangOption { private Argument InputArg { get; } = inputArg; private Option OutputOption { get; } = outputOption; + private Option HexKeyOption { get; } = hexKeyOption; private Option Key1Option { get; } = key1Option; private Option Key2Option { get; } = key2Option; private Option MkvEngineOption { get; } = mkvEngineOption; @@ -51,6 +54,7 @@ protected override DemuxArgsOptions GetBoundValue(BindingContext bindingContext) output = bindingContext.ParseResult.GetValueForOption(OutputOption) ?? new DirectoryInfo("./output"), + hexKey = bindingContext.ParseResult.GetValueForOption(HexKeyOption), key1 = bindingContext.ParseResult.GetValueForOption(Key1Option), key2 = bindingContext.ParseResult.GetValueForOption(Key2Option), subs = bindingContext.ParseResult.GetValueForOption(SubsOption), diff --git a/src/Utils/CliOptions.cs b/src/Utils/CliOptions.cs index c723467..68a31da 100644 --- a/src/Utils/CliOptions.cs +++ b/src/Utils/CliOptions.cs @@ -1,3 +1,4 @@ +using System.Buffers.Binary; using System.CommandLine; namespace GICutscenes; @@ -10,6 +11,31 @@ public static class CliOptions getDefaultValue: () => new DirectoryInfo("./output") ); + public static Option HexKey = new Option( + name: "--key", + description: "USM encryption key (hexadecimal and number format are supported). Overrides options '-a' and '-b'", + parseArgument: result => + { + string strKey = result.Tokens.Single().Value; + // If number only || If hex (0x before or letters A-F) + if ( + ulong.TryParse(strKey, out ulong numKey) + || ulong.TryParse( + strKey.StartsWith("0x") ? strKey.Substring(2) : strKey, + System.Globalization.NumberStyles.HexNumber, + null, + out numKey + ) + ) + { + byte[] byteKey = new byte[8]; + BitConverter.GetBytes(numKey).CopyTo(byteKey, 0); + return byteKey; + } + throw new ArgumentException("Argument --key does not have the right format"); + } + ); + public static Option Key1 = new Option( name: "-a", description: "4 lower bytes of the key (hex format)",