diff --git a/UsmToolkit/Commands.cs b/UsmToolkit/Commands.cs new file mode 100644 index 0000000..da0dc64 --- /dev/null +++ b/UsmToolkit/Commands.cs @@ -0,0 +1,174 @@ +using McMaster.Extensions.CommandLineUtils; +using Newtonsoft.Json; +using System; +using System.ComponentModel.DataAnnotations; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net; +using VGMToolbox.format; + +namespace UsmToolkit +{ + [Command(Description = "Extract audio and video")] + public class ExtractCommand + { + [Required] + [FileOrDirectoryExists] + [Argument(0, Description = "File or folder containing usm files")] + public string InputPath { get; set; } + + protected int OnExecute(CommandLineApplication app) + { + FileAttributes attr = File.GetAttributes(InputPath); + if (attr.HasFlag(FileAttributes.Directory)) + { + foreach (var file in Directory.GetFiles(InputPath, "*.usm")) + Process(file); + } + else + Process(InputPath); + + return 0; + } + + private void Process(string fileName) + { + Console.WriteLine($"File: {fileName}"); + var usmStream = new CriUsmStream(fileName); + + Console.WriteLine("Demuxing..."); + usmStream.DemultiplexStreams(new MpegStream.DemuxOptionsStruct() + { + AddHeader = false, + AddPlaybackHacks = false, + ExtractAudio = true, + ExtractVideo = true, + SplitAudioStreams = false + }); + } + } + + [Command(Description = "Convert according to the parameters in config.json")] + public class ConvertCommand + { + [Required] + [FileOrDirectoryExists] + [Argument(0, Description = "File or folder containing usm files")] + public string InputPath { get; set; } + + [Option(CommandOptionType.SingleValue, Description = "Specify output directory", ShortName = "o", LongName = "output-dir")] + public string OutputDir { get; set; } + + [Option(CommandOptionType.NoValue, Description = "Remove temporary m2v and audio after converting", ShortName = "c", LongName = "clean")] + public bool CleanTempFiles { get; set; } + + protected int OnExecute(CommandLineApplication app) + { + FileAttributes attr = File.GetAttributes(InputPath); + if (attr.HasFlag(FileAttributes.Directory)) + { + foreach (var file in Directory.GetFiles(InputPath, "*.usm")) + Process(file); + } + else + Process(InputPath); + + return 0; + } + + private void Process(string fileName) + { + Console.WriteLine($"File: {fileName}"); + var usmStream = new CriUsmStream(fileName); + + Console.WriteLine("Demuxing..."); + usmStream.DemultiplexStreams(new MpegStream.DemuxOptionsStruct() + { + AddHeader = false, + AddPlaybackHacks = false, + ExtractAudio = true, + ExtractVideo = true, + SplitAudioStreams = false + }); + + if (!string.IsNullOrEmpty(OutputDir) && !Directory.Exists(OutputDir)) + Directory.CreateDirectory(OutputDir); + + JoinOutputFile(usmStream); + } + + private void JoinOutputFile(CriUsmStream usmStream) + { + if (!File.Exists("config.json")) + { + Console.WriteLine("ERROR: config.json not found!"); + return; + } + + var audioFormat = usmStream.FinalAudioExtension; + var pureFileName = Path.GetFileNameWithoutExtension(usmStream.FilePath); + + if (audioFormat == ".adx") + { + //ffmpeg can not handle .adx from 0.2 for whatever reason + //need vgmstream to format that to wav + if (!Directory.Exists("vgmstream")) + { + Console.WriteLine("ERROR: vgmstream folder not found!"); + return; + } + + Console.WriteLine("adx audio detected, convert to wav..."); + Helpers.ExecuteProcess("vgmstream/test.exe", $"\"{Path.ChangeExtension(usmStream.FilePath, usmStream.FinalAudioExtension)}\" -o \"{Path.ChangeExtension(usmStream.FilePath, "wav")}\""); + + usmStream.FinalAudioExtension = ".wav"; + } + + Helpers.ExecuteProcess("ffmpeg", Helpers.CreateFFmpegParameters(usmStream, pureFileName, OutputDir)); + + if (CleanTempFiles) + { + Console.WriteLine($"Cleaning up temporary files from {pureFileName}"); + + File.Delete(Path.ChangeExtension(usmStream.FilePath, "wav")); + File.Delete(Path.ChangeExtension(usmStream.FilePath, "adx")); + File.Delete(Path.ChangeExtension(usmStream.FilePath, "hca")); + File.Delete(Path.ChangeExtension(usmStream.FilePath, "m2v")); + } + } + } + + [Command(Description = "Setup ffmpeg and vgmstream needed for conversion")] + public class GetDependenciesCommand + { + protected int OnExecute(CommandLineApplication app) + { + DepsConfig conf = JsonConvert.DeserializeObject(File.ReadAllText("deps.json")); + WebClient client = new WebClient(); + + Console.WriteLine($"Downloading ffmpeg from {conf.FFmpeg}"); + client.DownloadFile(conf.FFmpeg, "ffmpeg.zip"); + + Console.WriteLine($"Extracting ffmpeg..."); + using (ZipArchive archive = ZipFile.OpenRead("ffmpeg.zip")) + { + var ent = archive.Entries.FirstOrDefault(x => x.Name == "ffmpeg.exe"); + if (ent != null) + { + ent.ExtractToFile("ffmpeg.exe", true); + } + } + File.Delete("ffmpeg.zip"); + + Console.WriteLine($"Downloading vgmstream from {conf.Vgmstream}"); + client.DownloadFile(conf.Vgmstream, "vgmstream.zip"); + + Console.WriteLine("Extracting vgmstream..."); + ZipFile.ExtractToDirectory("vgmstream.zip", "vgmstream", true); + File.Delete("vgmstream.zip"); + + return 0; + } + } +} diff --git a/UsmToolkit/Configs.cs b/UsmToolkit/Configs.cs new file mode 100644 index 0000000..c77acb8 --- /dev/null +++ b/UsmToolkit/Configs.cs @@ -0,0 +1,15 @@ +namespace UsmToolkit +{ + public class JoinConfig + { + public string VideoParameter { get; set; } + public string AudioParameter { get; set; } + public string OutputFormat { get; set; } + } + + public class DepsConfig + { + public string Vgmstream { get; set; } + public string FFmpeg { get; set; } + } +} diff --git a/UsmToolkit/Helpers.cs b/UsmToolkit/Helpers.cs index f40fbf4..62d5d58 100644 --- a/UsmToolkit/Helpers.cs +++ b/UsmToolkit/Helpers.cs @@ -1,4 +1,8 @@ -using System.Diagnostics; +using Newtonsoft.Json; +using System.Diagnostics; +using System.IO; +using System.Text; +using VGMToolbox.format; namespace UsmToolkit { @@ -14,11 +18,33 @@ namespace UsmToolkit UseShellExecute = false, }; - Process process = new Process(); - process.StartInfo = startInfo; + Process process = new Process + { + StartInfo = startInfo + }; process.Start(); process.WaitForExit(); } + + public static string CreateFFmpegParameters(CriUsmStream usmStream, string pureFileName, string outputDir) + { + JoinConfig conf = JsonConvert.DeserializeObject(File.ReadAllText("config.json")); + + StringBuilder sb = new StringBuilder(); + sb.Append($"-i \"{Path.ChangeExtension(usmStream.FilePath, usmStream.FileExtensionVideo)}\" "); + + if (usmStream.HasAudio) + sb.Append($"-i \"{Path.ChangeExtension(usmStream.FilePath, usmStream.FinalAudioExtension)}\" "); + + sb.Append($"{conf.VideoParameter} "); + + if (usmStream.HasAudio) + sb.Append($"{conf.AudioParameter} "); + + sb.Append($"\"{Path.Combine(outputDir ?? string.Empty, $"{pureFileName}.{conf.OutputFormat}")}\""); + + return sb.ToString(); + } } } diff --git a/UsmToolkit/Program.cs b/UsmToolkit/Program.cs index e02d05f..c39f49e 100644 --- a/UsmToolkit/Program.cs +++ b/UsmToolkit/Program.cs @@ -1,23 +1,15 @@ using McMaster.Extensions.CommandLineUtils; -using Newtonsoft.Json; using System; -using System.ComponentModel.DataAnnotations; using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net; using System.Reflection; -using System.Text; -using VGMToolbox.format; namespace UsmToolkit { [Command("UsmToolkit")] [VersionOptionFromMember("--version", MemberName = nameof(GetVersion))] - [Subcommand(typeof(ExtractCommand), typeof(GetDependenciesCommand))] + [Subcommand(typeof(ExtractCommand), typeof(ConvertCommand), typeof(GetDependenciesCommand))] class Program { - static int Main(string[] args) { try @@ -44,168 +36,5 @@ namespace UsmToolkit private static string GetVersion() => typeof(Program).Assembly.GetCustomAttribute().InformationalVersion; - - private class ExtractCommand - { - private class JoinConfig - { - public string VideoParameter { get; set; } - public string AudioParameter { get; set; } - public string OutputFormat { get; set; } - } - - [Required] - [FileOrDirectoryExists] - [Argument(0, Description = "File or folder containing usm files")] - public string InputPath { get; set; } - - [Option(CommandOptionType.NoValue, Description = "Join files after extraction.", ShortName = "j", LongName = "join")] - public bool Join { get; set; } - - [Option(CommandOptionType.SingleValue, Description = "Specify output directory.", ShortName = "o", LongName = "output-dir")] - public string OutputDir { get; set; } - - [Option(CommandOptionType.NoValue, Description = "Remove temporary m2v and audio after joining.", ShortName = "c", LongName = "clean")] - public bool CleanTempFiles { get; set; } - - protected int OnExecute(CommandLineApplication app) - { - FileAttributes attr = File.GetAttributes(InputPath); - if (attr.HasFlag(FileAttributes.Directory)) - { - foreach (var file in Directory.GetFiles(InputPath, "*.usm")) - { - Convert(file); - } - } - else - Convert(InputPath); - - return 0; - } - - private void Convert(string fileName) - { - Console.WriteLine($"File: {fileName}"); - var usmStream = new CriUsmStream(fileName); - - Console.WriteLine("Demuxing..."); - usmStream.DemultiplexStreams(new MpegStream.DemuxOptionsStruct() - { - AddHeader = false, - AddPlaybackHacks = false, - ExtractAudio = true, - ExtractVideo = true, - SplitAudioStreams = false - }); - - if (Join) - { - if (!string.IsNullOrEmpty(OutputDir) && !Directory.Exists(OutputDir)) - Directory.CreateDirectory(OutputDir); - - JoinOutputFile(usmStream); - } - } - - private void JoinOutputFile(CriUsmStream usmStream) - { - if (!File.Exists("config.json")) - { - Console.WriteLine("ERROR: config.json not found!"); - return; - } - - var audioFormat = usmStream.FinalAudioExtension; - var pureFileName = Path.GetFileNameWithoutExtension(usmStream.FilePath); - - if (audioFormat == ".adx") - { - //ffmpeg can not handle .adx from 0.2 for whatever reason - //need vgmstream to format that to wav - if (!Directory.Exists("vgmstream")) - { - Console.WriteLine("ERROR: vgmstream folder not found!"); - return; - } - - Console.WriteLine("adx audio detected, convert to wav..."); - Helpers.ExecuteProcess("vgmstream/test.exe", $"\"{Path.ChangeExtension(usmStream.FilePath, usmStream.FinalAudioExtension)}\" -o \"{Path.ChangeExtension(usmStream.FilePath, "wav")}\""); - - usmStream.FinalAudioExtension = ".wav"; - } - - - Helpers.ExecuteProcess("ffmpeg", CreateFFmpegParameters(usmStream, pureFileName)); - - if (CleanTempFiles) - { - Console.WriteLine($"Cleaning up temporary files from {pureFileName}"); - - File.Delete(Path.ChangeExtension(usmStream.FilePath, "wav")); - File.Delete(Path.ChangeExtension(usmStream.FilePath, "adx")); - File.Delete(Path.ChangeExtension(usmStream.FilePath, "hca")); - File.Delete(Path.ChangeExtension(usmStream.FilePath, "m2v")); - } - } - - private string CreateFFmpegParameters(CriUsmStream usmStream, string pureFileName) - { - JoinConfig conf = JsonConvert.DeserializeObject(File.ReadAllText("config.json")); - - StringBuilder sb = new StringBuilder(); - sb.Append($"-i \"{Path.ChangeExtension(usmStream.FilePath, usmStream.FileExtensionVideo)}\" "); - - if (usmStream.HasAudio) - sb.Append($"-i \"{Path.ChangeExtension(usmStream.FilePath, usmStream.FinalAudioExtension)}\" "); - - sb.Append($"{conf.VideoParameter} "); - - if (usmStream.HasAudio) - sb.Append($"{conf.AudioParameter} "); - - sb.Append($"\"{Path.Combine(OutputDir ?? string.Empty, $"{pureFileName}.{conf.OutputFormat}")}\""); - - return sb.ToString(); - } - } - - private class GetDependenciesCommand - { - private class DepsConfig - { - public string Vgmstream { get; set; } - public string FFmpeg { get; set; } - } - - protected int OnExecute(CommandLineApplication app) - { - DepsConfig conf = JsonConvert.DeserializeObject(File.ReadAllText("deps.json")); - WebClient client = new WebClient(); - - Console.WriteLine($"Downloading ffmpeg from {conf.FFmpeg}"); - client.DownloadFile(conf.FFmpeg, "ffmpeg.zip"); - - Console.WriteLine($"Extracting ffmpeg..."); - using (ZipArchive archive = ZipFile.OpenRead("ffmpeg.zip")) - { - var ent = archive.Entries.FirstOrDefault(x => x.Name == "ffmpeg.exe"); - if (ent != null) - { - ent.ExtractToFile("ffmpeg.exe", true); - } - } - File.Delete("ffmpeg.zip"); - - Console.WriteLine($"Downloading vgmstream from {conf.Vgmstream}"); - client.DownloadFile(conf.Vgmstream, "vgmstream.zip"); - - Console.WriteLine("Extracting vgmstream..."); - ZipFile.ExtractToDirectory("vgmstream.zip", "vgmstream", true); - File.Delete("vgmstream.zip"); - - return 0; - } - } } }