diff --git a/Apprise/Apprise.csproj b/Apprise/Apprise.csproj index 850537e7..3b05cfba 100644 Binary files a/Apprise/Apprise.csproj and b/Apprise/Apprise.csproj differ diff --git a/BasicNodes/BasicNodes.csproj b/BasicNodes/BasicNodes.csproj index 18257423..e8f34834 100644 Binary files a/BasicNodes/BasicNodes.csproj and b/BasicNodes/BasicNodes.csproj differ diff --git a/ChecksumNodes/ChecksumNodes.csproj b/ChecksumNodes/ChecksumNodes.csproj index 761883c0..42307a3b 100644 Binary files a/ChecksumNodes/ChecksumNodes.csproj and b/ChecksumNodes/ChecksumNodes.csproj differ diff --git a/CollectionNodes/CollectionNodes.csproj b/CollectionNodes/CollectionNodes.csproj index 2785f805..6171b600 100644 Binary files a/CollectionNodes/CollectionNodes.csproj and b/CollectionNodes/CollectionNodes.csproj differ diff --git a/DiscordNodes/DiscordNodes.csproj b/DiscordNodes/DiscordNodes.csproj index 8866143c..9fd96615 100644 Binary files a/DiscordNodes/DiscordNodes.csproj and b/DiscordNodes/DiscordNodes.csproj differ diff --git a/EmailNodes/EmailNodes.csproj b/EmailNodes/EmailNodes.csproj index 98d16328..d777e690 100644 Binary files a/EmailNodes/EmailNodes.csproj and b/EmailNodes/EmailNodes.csproj differ diff --git a/Emby/Emby.csproj b/Emby/Emby.csproj index 2ba1e556..976bf3b6 100644 Binary files a/Emby/Emby.csproj and b/Emby/Emby.csproj differ diff --git a/FileFlows.Plugin.dll b/FileFlows.Plugin.dll index de5e5245..ea43043c 100644 Binary files a/FileFlows.Plugin.dll and b/FileFlows.Plugin.dll differ diff --git a/FileFlows.Plugin.pdb b/FileFlows.Plugin.pdb index 26165175..9a831ec6 100644 Binary files a/FileFlows.Plugin.pdb and b/FileFlows.Plugin.pdb differ diff --git a/Gotify/Gotify.csproj b/Gotify/Gotify.csproj index 6ddb5ec0..aabeb41f 100644 Binary files a/Gotify/Gotify.csproj and b/Gotify/Gotify.csproj differ diff --git a/ImageNodes/ImageNodes.csproj b/ImageNodes/ImageNodes.csproj index 0b53f79a..5be7728d 100644 Binary files a/ImageNodes/ImageNodes.csproj and b/ImageNodes/ImageNodes.csproj differ diff --git a/MetaNodes/MetaNodes.csproj b/MetaNodes/MetaNodes.csproj index a84a28b2..1e74cf2c 100644 Binary files a/MetaNodes/MetaNodes.csproj and b/MetaNodes/MetaNodes.csproj differ diff --git a/MusicNodes/MusicNodes.csproj b/MusicNodes/MusicNodes.csproj index 592a2e10..7b86ba67 100644 Binary files a/MusicNodes/MusicNodes.csproj and b/MusicNodes/MusicNodes.csproj differ diff --git a/Plex/Plex.csproj b/Plex/Plex.csproj index 76d3489a..f952c008 100644 Binary files a/Plex/Plex.csproj and b/Plex/Plex.csproj differ diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs index e534f40d..ba21d410 100644 --- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs +++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderNode.cs @@ -19,8 +19,9 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes if (base.PreExecute(args) == false) return false; - if (Model == null) + if(this is FfmpegBuilderStart == false && Model == null) throw new Exception("FFMPEG Builder Model not set, use the \"FFMPEG Builder Start\" node to first"); + return true; } diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs index 6a31ecbf..a53a81a0 100644 --- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs +++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs @@ -9,6 +9,7 @@ namespace FileFlows.VideoNodes.FfmpegBuilderNodes public override string Icon => "far fa-file-video"; public override FlowElementType Type => FlowElementType.BuildStart; + public override int Execute(NodeParameters args) { VideoInfo videoInfo = GetVideoInfo(args); diff --git a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs index b7418f1a..7d5d4ae7 100644 --- a/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs +++ b/VideoNodes/FfmpegBuilderNodes/Video/FfmpegBuilderVideoEncode.cs @@ -9,12 +9,18 @@ public class FfmpegBuilderVideoEncode:FfmpegBuilderNode { public override int Outputs => 1; - private const string CODEC_H264 = "h264"; - private const string CODEC_H265 = "h265"; + internal const string CODEC_H264 = "h264"; + internal const string CODEC_H264_10BIT = "h264 10BIT"; + internal const string CODEC_H265 = "h265"; + internal const string CODEC_H265_10BIT = "h265 10BIT"; public override string HelpUrl => "https://github.com/revenz/FileFlows/wiki/FFMPEG-Builder:-Video-Encode"; [DefaultValue("h265")] + [ChangeValue(nameof(Quality), 23, CODEC_H264)] + [ChangeValue(nameof(Quality), 23, CODEC_H265_10BIT)] + [ChangeValue(nameof(Quality), 28, CODEC_H265)] + [ChangeValue(nameof(Quality), 28, CODEC_H265_10BIT)] [Select(nameof(CodecOptions), 1)] public string Codec { get; set; } @@ -27,8 +33,10 @@ public class FfmpegBuilderVideoEncode:FfmpegBuilderNode { _CodecOptions = new List { - new () { Label = "h264", Value = CODEC_H264 }, - new () { Label = "h265", Value = CODEC_H265 } + new () { Label = "H.264", Value = CODEC_H264 }, + new () { Label = "H.264 (10-Bit)", Value = CODEC_H264_10BIT }, + new () { Label = "H.265", Value = CODEC_H265 }, + new () { Label = "H.265 (10-Bit)", Value = CODEC_H265_10BIT }, }; } return _CodecOptions; @@ -39,42 +47,58 @@ public class FfmpegBuilderVideoEncode:FfmpegBuilderNode [Boolean(2)] public bool HardwareEncoding { get; set; } - [Slider(3)] + [Slider(3, inverse: true)] [Range(0, 51)] [DefaultValue(23)] public int Quality { get; set; } + private string bit10Filter = "yuv420p10le"; + public override int Execute(NodeParameters args) { var stream = Model.VideoStreams.Where(x => x.Deleted == false).First(); - if (Codec == CODEC_H264) - H264(stream); - else if (Codec == CODEC_H264) - H265(stream); + if (Codec == CODEC_H264 || Codec == CODEC_H264_10BIT) + H264(stream, Codec == CODEC_H264_10BIT); + else if (Codec == CODEC_H265 || Codec == CODEC_H265_10BIT) + H265(stream, Codec == CODEC_H265_10BIT); + else + return 2; + + stream.ForcedChange = true; bool encoding = false; return encoding ? 1 : 2; } - private void H264(FfmpegVideoStream stream) + private void H264(FfmpegVideoStream stream, bool tenBit) { if (HardwareEncoding == false) H26x_CPU(stream); else if (SupportsHardwareNvidia264()) - H264_Nvidia(stream); + H26x_Nvidia(stream, false); + else if (SupportsHardwareQsv264()) + H26x_Qsv(stream, false); else H26x_CPU(stream); + + if (tenBit) + stream.EncodingParameters.AddRange(new[] { "-pix_fmt:v:{index}", bit10Filter }); } - private void H265(FfmpegVideoStream stream) + private void H265(FfmpegVideoStream stream, bool tenBit) { // hevc_qsv -load_plugin hevc_hw -pix_fmt p010le -profile:v main10 -global_quality 21 -g 24 -look_ahead 1 -look_ahead_depth 60 if (HardwareEncoding == false) H26x_CPU(stream); else if (SupportsHardwareNvidia265()) - H265_Nvidia(stream); + H26x_Nvidia(stream, true); + else if (SupportsHardwareQsv265()) + H26x_Qsv(stream, true); else H26x_CPU(stream); + + if (tenBit) + stream.EncodingParameters.AddRange(new[] { "-pix_fmt:v:{index}", bit10Filter }); } @@ -89,23 +113,12 @@ public class FfmpegBuilderVideoEncode:FfmpegBuilderNode }); } - private void H264_Nvidia(FfmpegVideoStream stream) + private void H26x_Nvidia(FfmpegVideoStream stream, bool h265) { stream.EncodingParameters.Clear(); stream.EncodingParameters.AddRange(new [] { - "h264_nvenc", - "-rc", "vbr_hq", - // 0 == auto, so we set to 1 - "-cq", Quality <= 0 ? "1" : Quality.ToString(), - }); - } - private void H265_Nvidia(FfmpegVideoStream stream) - { - stream.EncodingParameters.Clear(); - stream.EncodingParameters.AddRange(new [] - { - "hevc_nvenc", + h265 ? "hevc_nvenc" : "h264_nvenc", "-rc", "constqp", "-qp", Quality.ToString(), //"-b:v", "0K", // this would do a two-pass... slower @@ -113,6 +126,36 @@ public class FfmpegBuilderVideoEncode:FfmpegBuilderNode // https://www.reddit.com/r/ffmpeg/comments/gg5szi/what_is_spatial_aq_and_temporal_aq_with_nvenc/ "-spatial-aq", "1" }); + + if (Codec == CODEC_H264_10BIT) + bit10Filter = "yuv420p"; + } + + private void H26x_Qsv(FfmpegVideoStream stream, bool h265) + { + //hevc_qsv -load_plugin hevc_hw -pix_fmt p010le -profile:v main10 -global_quality 21 -g 24 -look_ahead 1 -look_ahead_depth 60 + stream.EncodingParameters.Clear(); + if (h265) + { + stream.EncodingParameters.AddRange(new[] + { + "hevc_qsv", + "-load_plugin", "hevc_hw" + }); + } + else + { + stream.EncodingParameters.AddRange(new[] + { + "h264_qsv" + }); + + } + stream.EncodingParameters.AddRange(new[] + { + "-qp", Quality.ToString(), + "-preset", "p6", + }); } } diff --git a/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_BasicTests.cs b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_BasicTests.cs index 8bb2920d..53f23731 100644 --- a/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_BasicTests.cs +++ b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_BasicTests.cs @@ -4,967 +4,966 @@ using FileFlows.VideoNodes.FfmpegBuilderNodes; using Microsoft.VisualStudio.TestTools.UnitTesting; using VideoNodes.Tests; -namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests +namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests; + +[TestClass] +public class FfmpegBuilder_BasicTests { - [TestClass] - public class FfmpegBuilder_BasicTests + [TestMethod] + public void FfmpegBuilder_AddAc3Aac() { - [TestMethod] - public void FfmpegBuilder_AddAc3Aac() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); - FfmpegBuilderStart ffStart = new (); - Assert.AreEqual(1, ffStart.Execute(args)); + FfmpegBuilderStart ffStart = new (); + Assert.AreEqual(1, ffStart.Execute(args)); - FfmpegBuilderVideoCodec ffEncode = new (); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); + FfmpegBuilderVideoCodec ffEncode = new (); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); - FfmpegBuilderAudioAddTrack ffAddAudio = new (); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 0; - ffAddAudio.Execute(args); + FfmpegBuilderAudioAddTrack ffAddAudio = new (); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 0; + ffAddAudio.Execute(args); - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 1; - ffAddAudio2.Execute(args); + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 1; + ffAddAudio2.Execute(args); - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAudioTracks() - { - const string file = @"D:\videos\unprocessed\bigbuckbunny_480p_30s.mp4"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - var model = ffStart.GetModel(); - if (model.AudioStreams[0].Stream.Channels < 5.1f) - Assert.Fail(); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - int index = 0; - FfmpegBuilderAudioAddTrack ffAddAudioMono = new(); - ffAddAudioMono.Codec = "mp3"; - ffAddAudioMono.Index = index; - ffAddAudioMono.Channels = 1; - ffAddAudioMono.Execute(args); - model.AudioStreams[index].Title = "MP3 Mono"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioStereoAac = new(); - ffAddAudioStereoAac.Codec = "aac"; - ffAddAudioStereoAac.Index = index; - ffAddAudioStereoAac.Channels = 2; - ffAddAudioStereoAac.Execute(args); - model.AudioStreams[index].Title = "AAC Stereo"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioStereoMp3French = new(); - ffAddAudioStereoMp3French.Codec = "mp3"; - ffAddAudioStereoMp3French.Index = index; - ffAddAudioStereoMp3French.Channels = 2; - ffAddAudioStereoMp3French.Execute(args); - model.AudioStreams[index].Language = "fre"; - model.AudioStreams[index].Title = "MP3 Stereo"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioStereoMp3 = new(); - ffAddAudioStereoMp3.Codec = "mp3"; - ffAddAudioStereoMp3.Index = index; - ffAddAudioStereoMp3.Channels = 2; - ffAddAudioStereoMp3.Execute(args); - model.AudioStreams[index].Title = "MP3 Stereo"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioAc3German = new(); - ffAddAudioAc3German.Codec = "ac3"; - ffAddAudioAc3German.Index = index; - ffAddAudioAc3German.Execute(args); - model.AudioStreams[index].Title = "AC3 5.1"; - model.AudioStreams[index].Language = "deu"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioAc3 = new(); - ffAddAudioAc3.Codec = "ac3"; - ffAddAudioAc3.Index = index; - ffAddAudioAc3.Execute(args); - model.AudioStreams[index].Title = "AC3 5.1"; - ++index; - - FfmpegBuilderAudioAddTrack ffAddAudioAac = new(); - ffAddAudioAac.Codec = "aac"; - ffAddAudioAac.Index = index; - ffAddAudioAac.Execute(args); - model.AudioStreams[index].Title = "AAC 5.1"; - ++index; - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_Normalize() - { - const string file = @"D:\videos\unprocessed\dummy.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); - ffAudioRemover.RemoveAll = true; - ffAudioRemover.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderAudioNormalization ffAudioNormalize = new(); - ffAudioNormalize.TwoPass = false; - ffAudioNormalize.AllAudio = true; - ffAudioNormalize.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_AdjustVolume() - { - const string file = @"D:\videos\unprocessed\dummy.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); - ffAudioRemover.RemoveAll = true; - ffAudioRemover.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderAudioAdjustVolume ffAudioAdjust= new(); - ffAudioAdjust.VolumePercent = 1000; - ffAudioAdjust.Pattern = ">1"; - ffAudioAdjust.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars() - { - const string file = @"D:\videos\unprocessed\blackbars.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h265"; - ffEncode.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - FfmpegBuilderCropBlackBars ffCropBlackBars = new(); - ffCropBlackBars.CroppingThreshold = 10; - ffCropBlackBars.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled480p() - { - const string file = @"D:\videos\unprocessed\blackbars.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h265"; - ffEncode.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - FfmpegBuilderCropBlackBars ffCropBlackBars = new(); - ffCropBlackBars.CroppingThreshold = 10; - ffCropBlackBars.Execute(args); - - FfmpegBuilderScaler ffScaler = new(); - ffScaler.Resolution = "640:-2"; - ffScaler.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled4k() - { - const string file = @"D:\videos\unprocessed\blackbars.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h265"; - ffEncode.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - FfmpegBuilderCropBlackBars ffCropBlackBars = new(); - ffCropBlackBars.CroppingThreshold = 10; - ffCropBlackBars.Execute(args); - - FfmpegBuilderScaler ffScaler = new(); - ffScaler.Resolution = "3840:-2"; - ffScaler.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled480p2() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h265"; - ffEncode.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - FfmpegBuilderCropBlackBars ffCropBlackBars = new(); - ffCropBlackBars.CroppingThreshold = 10; - ffCropBlackBars.Execute(args); - - FfmpegBuilderScaler ffScaler = new(); - ffScaler.Resolution = "640:-2"; - ffScaler.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_AutoChapters() - { - const string file = @"D:\videos\unprocessed\sitcom.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderAutoChapters ffAutoChapters = new(); - ffAutoChapters.Percent = 45; - ffAutoChapters.MinimumLength = 60; - Assert.AreEqual(1, ffAutoChapters.Execute(args)); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_ComskipChapters() - { - const string file = @"D:\videos\recordings\Rescue My Renovation (2001).ts"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 1; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 2; - ffAddAudio2.Execute(args); - - FfmpegBuilderAudioSetLanguage ffSetLanguage = new(); - ffSetLanguage.Language = "deu"; - ffSetLanguage.Execute(args); - - FfmpegBuilderComskipChapters ffComskipChapters = new(); - Assert.AreEqual(1, ffComskipChapters.Execute(args)); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_AudioTrackReorder() - { - const string file = @"D:\videos\unprocessed\multi_audio.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderAudioTrackReorder ffAudioReorder= new(); - ffAudioReorder.Channels = new List { "1.0", "5.1", "2.0" }; - ffAudioReorder.Languages = new List { "fre", "deu" }; - ffAudioReorder.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Normalize_AutoChapters_Upscale4k() - { - const string file = @"D:\videos\unprocessed\blackbars.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - var model = ffStart.GetModel(); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h265"; - ffEncode.Execute(args); - - FfmpegBuilderScaler ffScaler = new(); - ffScaler.Resolution = "3840:-2"; - ffScaler.Execute(args); - - FfmpegBuilderRemuxToMP4 ffMp4 = new(); - ffMp4.Execute(args); - - FfmpegBuilderCropBlackBars ffCropBlackBars = new(); - ffCropBlackBars.CroppingThreshold = 10; - ffCropBlackBars.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); - ffSubRemover.RemoveAll = true; - ffSubRemover.Execute(args); - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 0; - ffAddAudio.Execute(args); - model.AudioStreams[0].Language = "mao"; - model.AudioStreams[0].Title = "AC3"; - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 1; - ffAddAudio2.Execute(args); - model.AudioStreams[1].Language = "fre"; - model.AudioStreams[1].Title = "AAC"; - - FfmpegBuilderAudioNormalization ffAudioNormalize = new(); - ffAudioNormalize.TwoPass = false; - ffAudioNormalize.AllAudio = true; - ffAudioNormalize.Execute(args); - - - FfmpegBuilderAutoChapters ffaAutoChapters = new(); - ffaAutoChapters.MinimumLength = 30; - ffaAutoChapters.Percent = 45; - ffaAutoChapters.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_SetLanguage() - { - const string file = @"D:\videos\unprocessed\sitcom.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderAudioSetLanguage ffSetLanguage = new(); - ffSetLanguage.Language = "deu"; - ffSetLanguage.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_HdrToSdr() - { - const string file = @"D:\videos\unprocessed\hdr.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderHdrToSdr ffHdrToSdr= new(); - Assert.AreEqual(1, ffHdrToSdr.Execute(args)); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_AudioMinusOne() - { - const string file = @"D:\videos\unprocessed\minus1.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - //FfmpegBuilderVideoCodec ffEncode = new(); - //ffEncode.VideoCodec = "h264"; - //ffEncode.Execute(args); - - FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); - ffAudioRemover.RemoveAll = true; - ffAudioRemover.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 0; - ffAddAudio.Execute(args); - - //FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - //ffAddAudio2.Codec = "aac"; - //ffAddAudio2.Index = 2; - //ffAddAudio2.Execute(args); - - //FfmpegBuilderAudioNormalization ffAudioNormalize = new(); - //ffAudioNormalize.TwoPass = false; - //ffAudioNormalize.AllAudio = true; - //ffAudioNormalize.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_HardwareDecoding() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Execute(args); - - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 0; - ffAddAudio.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - ffExecutor.HardwareDecoding = true; - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_VideoBitrate() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoBitrate ffBitrate = new(); - ffBitrate.Bitrate = 1_000; - ffBitrate.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - ffExecutor.HardwareDecoding = true; - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_VideoCodecAndBitrate() - { - const string file = @"D:\videos\unprocessed\basic.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderVideoCodec ffEncode = new(); - ffEncode.VideoCodec = "h264"; - ffEncode.Force = true; - ffEncode.Execute(args); - - FfmpegBuilderVideoBitrate ffBitrate = new(); - ffBitrate.Bitrate = 50; - ffBitrate.Percent = true; - ffBitrate.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - ffExecutor.HardwareDecoding = true; - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void FfmpegBuilder_FF43() - { - const string file = @"D:\videos\testfiles\ff-43.ts"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderAudioTrackRemover ffRemoveAudio = new(); - ffRemoveAudio.RemoveAll = true; - ffRemoveAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio = new(); - ffAddAudio.Codec = "ac3"; - ffAddAudio.Index = 0; - ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Index = 1; - ffAddAudio2.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void FfmpegBuilder_AddAc3Aac_AV1() - { - const string file = @"D:\videos\testfiles\av1.mkv"; - var logger = new TestLogger(); - const string ffmpeg = @"C:\utils\ffmpeg5\ffmpeg.exe"; - VideoInfoHelper.ProbeSize = 1000; - var vi = new VideoInfoHelper(ffmpeg, logger); - var vii = vi.Read(file); - var args = new NodeParameters(file, logger, false, string.Empty); - args.GetToolPathActual = (string tool) => ffmpeg; - args.TempPath = @"D:\videos\temp"; - args.Parameters.Add("VideoInfo", vii); - - - FfmpegBuilderStart ffStart = new(); - - Assert.AreEqual(1, ffStart.Execute(args)); - - FfmpegBuilderAudioTrackRemover ffAudioRemove = new(); - ffAudioRemove.RemoveAll = true; - ffAudioRemove.Execute(args); - - //FfmpegBuilderAudioAddTrack ffAddAudio = new(); - //ffAddAudio.Codec = "ac3"; - //ffAddAudio.Language = "eng"; - //ffAddAudio.Index = 0; - //ffAddAudio.Execute(args); - - FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); - ffAddAudio2.Codec = "aac"; - ffAddAudio2.Language = "deu"; - ffAddAudio2.Index = 1; - ffAddAudio2.Execute(args); - - FfmpegBuilderSubtitleFormatRemover ffSubtitle= new(); - ffSubtitle.RemoveAll = true; - ffSubtitle.Execute(args); - - FfmpegBuilderExecutor ffExecutor = new(); - - int result = ffExecutor.Execute(args); - - string log = logger.ToString(); - Assert.AreEqual(1, result); - } + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + string log = logger.ToString(); + Assert.AreEqual(1, result); } + + [TestMethod] + public void FfmpegBuilder_AddAudioTracks() + { + const string file = @"D:\videos\unprocessed\bigbuckbunny_480p_30s.mp4"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + var model = ffStart.GetModel(); + if (model.AudioStreams[0].Stream.Channels < 5.1f) + Assert.Fail(); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + int index = 0; + FfmpegBuilderAudioAddTrack ffAddAudioMono = new(); + ffAddAudioMono.Codec = "mp3"; + ffAddAudioMono.Index = index; + ffAddAudioMono.Channels = 1; + ffAddAudioMono.Execute(args); + model.AudioStreams[index].Title = "MP3 Mono"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioStereoAac = new(); + ffAddAudioStereoAac.Codec = "aac"; + ffAddAudioStereoAac.Index = index; + ffAddAudioStereoAac.Channels = 2; + ffAddAudioStereoAac.Execute(args); + model.AudioStreams[index].Title = "AAC Stereo"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioStereoMp3French = new(); + ffAddAudioStereoMp3French.Codec = "mp3"; + ffAddAudioStereoMp3French.Index = index; + ffAddAudioStereoMp3French.Channels = 2; + ffAddAudioStereoMp3French.Execute(args); + model.AudioStreams[index].Language = "fre"; + model.AudioStreams[index].Title = "MP3 Stereo"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioStereoMp3 = new(); + ffAddAudioStereoMp3.Codec = "mp3"; + ffAddAudioStereoMp3.Index = index; + ffAddAudioStereoMp3.Channels = 2; + ffAddAudioStereoMp3.Execute(args); + model.AudioStreams[index].Title = "MP3 Stereo"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioAc3German = new(); + ffAddAudioAc3German.Codec = "ac3"; + ffAddAudioAc3German.Index = index; + ffAddAudioAc3German.Execute(args); + model.AudioStreams[index].Title = "AC3 5.1"; + model.AudioStreams[index].Language = "deu"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioAc3 = new(); + ffAddAudioAc3.Codec = "ac3"; + ffAddAudioAc3.Index = index; + ffAddAudioAc3.Execute(args); + model.AudioStreams[index].Title = "AC3 5.1"; + ++index; + + FfmpegBuilderAudioAddTrack ffAddAudioAac = new(); + ffAddAudioAac.Codec = "aac"; + ffAddAudioAac.Index = index; + ffAddAudioAac.Execute(args); + model.AudioStreams[index].Title = "AAC 5.1"; + ++index; + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_Normalize() + { + const string file = @"D:\videos\unprocessed\dummy.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); + ffAudioRemover.RemoveAll = true; + ffAudioRemover.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderAudioNormalization ffAudioNormalize = new(); + ffAudioNormalize.TwoPass = false; + ffAudioNormalize.AllAudio = true; + ffAudioNormalize.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_AdjustVolume() + { + const string file = @"D:\videos\unprocessed\dummy.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); + ffAudioRemover.RemoveAll = true; + ffAudioRemover.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderAudioAdjustVolume ffAudioAdjust= new(); + ffAudioAdjust.VolumePercent = 1000; + ffAudioAdjust.Pattern = ">1"; + ffAudioAdjust.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs() + { + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars() + { + const string file = @"D:\videos\unprocessed\blackbars.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h265"; + ffEncode.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + FfmpegBuilderCropBlackBars ffCropBlackBars = new(); + ffCropBlackBars.CroppingThreshold = 10; + ffCropBlackBars.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled480p() + { + const string file = @"D:\videos\unprocessed\blackbars.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h265"; + ffEncode.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + FfmpegBuilderCropBlackBars ffCropBlackBars = new(); + ffCropBlackBars.CroppingThreshold = 10; + ffCropBlackBars.Execute(args); + + FfmpegBuilderScaler ffScaler = new(); + ffScaler.Resolution = "640:-2"; + ffScaler.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled4k() + { + const string file = @"D:\videos\unprocessed\blackbars.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h265"; + ffEncode.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + FfmpegBuilderCropBlackBars ffCropBlackBars = new(); + ffCropBlackBars.CroppingThreshold = 10; + ffCropBlackBars.Execute(args); + + FfmpegBuilderScaler ffScaler = new(); + ffScaler.Resolution = "3840:-2"; + ffScaler.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Scaled480p2() + { + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h265"; + ffEncode.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + FfmpegBuilderCropBlackBars ffCropBlackBars = new(); + ffCropBlackBars.CroppingThreshold = 10; + ffCropBlackBars.Execute(args); + + FfmpegBuilderScaler ffScaler = new(); + ffScaler.Resolution = "640:-2"; + ffScaler.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_AutoChapters() + { + const string file = @"D:\videos\unprocessed\sitcom.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderAutoChapters ffAutoChapters = new(); + ffAutoChapters.Percent = 45; + ffAutoChapters.MinimumLength = 60; + Assert.AreEqual(1, ffAutoChapters.Execute(args)); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_ComskipChapters() + { + const string file = @"D:\videos\recordings\Rescue My Renovation (2001).ts"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 1; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 2; + ffAddAudio2.Execute(args); + + FfmpegBuilderAudioSetLanguage ffSetLanguage = new(); + ffSetLanguage.Language = "deu"; + ffSetLanguage.Execute(args); + + FfmpegBuilderComskipChapters ffComskipChapters = new(); + Assert.AreEqual(1, ffComskipChapters.Execute(args)); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_AudioTrackReorder() + { + const string file = @"D:\videos\unprocessed\multi_audio.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderAudioTrackReorder ffAudioReorder= new(); + ffAudioReorder.Channels = new List { "1.0", "5.1", "2.0" }; + ffAudioReorder.Languages = new List { "fre", "deu" }; + ffAudioReorder.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_AddAc3AacMp4NoSubs_BlackBars_Normalize_AutoChapters_Upscale4k() + { + const string file = @"D:\videos\unprocessed\blackbars.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + var model = ffStart.GetModel(); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h265"; + ffEncode.Execute(args); + + FfmpegBuilderScaler ffScaler = new(); + ffScaler.Resolution = "3840:-2"; + ffScaler.Execute(args); + + FfmpegBuilderRemuxToMP4 ffMp4 = new(); + ffMp4.Execute(args); + + FfmpegBuilderCropBlackBars ffCropBlackBars = new(); + ffCropBlackBars.CroppingThreshold = 10; + ffCropBlackBars.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubRemover = new(); + ffSubRemover.RemoveAll = true; + ffSubRemover.Execute(args); + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 0; + ffAddAudio.Execute(args); + model.AudioStreams[0].Language = "mao"; + model.AudioStreams[0].Title = "AC3"; + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 1; + ffAddAudio2.Execute(args); + model.AudioStreams[1].Language = "fre"; + model.AudioStreams[1].Title = "AAC"; + + FfmpegBuilderAudioNormalization ffAudioNormalize = new(); + ffAudioNormalize.TwoPass = false; + ffAudioNormalize.AllAudio = true; + ffAudioNormalize.Execute(args); + + + FfmpegBuilderAutoChapters ffaAutoChapters = new(); + ffaAutoChapters.MinimumLength = 30; + ffaAutoChapters.Percent = 45; + ffaAutoChapters.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_SetLanguage() + { + const string file = @"D:\videos\unprocessed\sitcom.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderAudioSetLanguage ffSetLanguage = new(); + ffSetLanguage.Language = "deu"; + ffSetLanguage.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_HdrToSdr() + { + const string file = @"D:\videos\unprocessed\hdr.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderHdrToSdr ffHdrToSdr= new(); + Assert.AreEqual(1, ffHdrToSdr.Execute(args)); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_AudioMinusOne() + { + const string file = @"D:\videos\unprocessed\minus1.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + //FfmpegBuilderVideoCodec ffEncode = new(); + //ffEncode.VideoCodec = "h264"; + //ffEncode.Execute(args); + + FfmpegBuilderAudioTrackRemover ffAudioRemover = new(); + ffAudioRemover.RemoveAll = true; + ffAudioRemover.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 0; + ffAddAudio.Execute(args); + + //FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + //ffAddAudio2.Codec = "aac"; + //ffAddAudio2.Index = 2; + //ffAddAudio2.Execute(args); + + //FfmpegBuilderAudioNormalization ffAudioNormalize = new(); + //ffAudioNormalize.TwoPass = false; + //ffAudioNormalize.AllAudio = true; + //ffAudioNormalize.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_HardwareDecoding() + { + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Execute(args); + + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 0; + ffAddAudio.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + ffExecutor.HardwareDecoding = true; + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_VideoBitrate() + { + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoBitrate ffBitrate = new(); + ffBitrate.Bitrate = 1_000; + ffBitrate.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + ffExecutor.HardwareDecoding = true; + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_VideoCodecAndBitrate() + { + const string file = @"D:\videos\unprocessed\basic.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoCodec ffEncode = new(); + ffEncode.VideoCodec = "h264"; + ffEncode.Force = true; + ffEncode.Execute(args); + + FfmpegBuilderVideoBitrate ffBitrate = new(); + ffBitrate.Bitrate = 50; + ffBitrate.Percent = true; + ffBitrate.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + ffExecutor.HardwareDecoding = true; + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void FfmpegBuilder_FF43() + { + const string file = @"D:\videos\testfiles\ff-43.ts"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderAudioTrackRemover ffRemoveAudio = new(); + ffRemoveAudio.RemoveAll = true; + ffRemoveAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio = new(); + ffAddAudio.Codec = "ac3"; + ffAddAudio.Index = 0; + ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Index = 1; + ffAddAudio2.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + + + [TestMethod] + public void FfmpegBuilder_AddAc3Aac_AV1() + { + const string file = @"D:\videos\testfiles\av1.mkv"; + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg5\ffmpeg.exe"; + VideoInfoHelper.ProbeSize = 1000; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderAudioTrackRemover ffAudioRemove = new(); + ffAudioRemove.RemoveAll = true; + ffAudioRemove.Execute(args); + + //FfmpegBuilderAudioAddTrack ffAddAudio = new(); + //ffAddAudio.Codec = "ac3"; + //ffAddAudio.Language = "eng"; + //ffAddAudio.Index = 0; + //ffAddAudio.Execute(args); + + FfmpegBuilderAudioAddTrack ffAddAudio2 = new(); + ffAddAudio2.Codec = "aac"; + ffAddAudio2.Language = "deu"; + ffAddAudio2.Index = 1; + ffAddAudio2.Execute(args); + + FfmpegBuilderSubtitleFormatRemover ffSubtitle= new(); + ffSubtitle.RemoveAll = true; + ffSubtitle.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + + int result = ffExecutor.Execute(args); + + string log = logger.ToString(); + Assert.AreEqual(1, result); + } + } #endif \ No newline at end of file diff --git a/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs new file mode 100644 index 00000000..c27cd63e --- /dev/null +++ b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs @@ -0,0 +1,83 @@ +#if(DEBUG) + +using FileFlows.VideoNodes.FfmpegBuilderNodes; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using VideoNodes.Tests; + +namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests; + +[TestClass] +public class FfmpegBuilder_VideoEncode_VideoEncodeTests: TestBase +{ + private (int output, string log) Encode(string codec, int quality, bool hardwareEncoding, string file, string outfile) + { + if (File.Exists(file) == false) + throw new FileNotFoundException(file); + + var logger = new TestLogger(); + const string ffmpeg = @"C:\utils\ffmpeg\ffmpeg.exe"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(file); + var args = new NodeParameters(file, logger, false, string.Empty); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = @"D:\videos\temp"; + args.Parameters.Add("VideoInfo", vii); + + + FfmpegBuilderStart ffStart = new(); + ffStart.PreExecute(args); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoEncode ffEncode = new(); + ffEncode.Codec = codec; + ffEncode.Quality = quality; + ffEncode.HardwareEncoding = hardwareEncoding; + ffEncode.PreExecute(args); + ffEncode.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + ffExecutor.PreExecute(args); + int result = ffExecutor.Execute(args); + string log = logger.ToString(); + if(args.WorkingFile.StartsWith(args.TempPath)) + File.Move(args.WorkingFile, Path.Combine(args.TempPath, outfile), true); + Assert.AreEqual(1, result); + return (result, log); + } + + private void TestEncode(bool h265, bool bit10, bool hardware) + { + foreach (var quality in new int[] { 18, 20, 23, 28, 35, 50 }) + { + string codec = h265 && bit10 ? FfmpegBuilderVideoEncode.CODEC_H265_10BIT : + h265 ? FfmpegBuilderVideoEncode.CODEC_H265 : + bit10 ? FfmpegBuilderVideoEncode.CODEC_H264_10BIT : + FfmpegBuilderVideoEncode.CODEC_H264; + + var result = Encode(codec, quality, hardware, TestFile_120_mbps_4k_uhd_hevc_10bit, + $"{(hardware ? "nvidia" : "cpu")}_h26{(h265 ? "5" : "4")}{(bit10 ? "_10bit" : "")}_{quality}.mkv"); + } + + } + + [TestMethod] + public void FfmpegBuilder_VideoEncode_H265_10bit_Hardware() => TestEncode(true, true, true); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H265_Hardware() => TestEncode(true, false, true); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H265() => TestEncode(true, false, false); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H265_10bit() => TestEncode(true, false, true); + + + [TestMethod] + public void FfmpegBuilder_VideoEncode_H264_10bit_Hardware() => TestEncode(false, true, true); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H264_Hardware() => TestEncode(false, false, true); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H264() => TestEncode(false, false, false); + [TestMethod] + public void FfmpegBuilder_VideoEncode_H264_10bit() => TestEncode(false, false, true); +} + +#endif \ No newline at end of file diff --git a/VideoNodes/Tests/_TestBase.cs b/VideoNodes/Tests/_TestBase.cs index d0b2777f..f29f2200 100644 --- a/VideoNodes/Tests/_TestBase.cs +++ b/VideoNodes/Tests/_TestBase.cs @@ -52,6 +52,10 @@ public abstract class TestBase protected string TestFile_BasicMkv => Path.Combine(TestPath, "basic.mkv"); protected string TestFile_Pgs => Path.Combine(TestPath, "pgs.mkv"); protected string TestFile_TwoPassNegInifinity => Path.Combine(TestPath, "audio_normal_neg_infinity.mkv"); + protected string TestFile_4k_h264mov => Path.Combine(TestPath, "4k_h264.mov"); + + protected string TestFile_50_mbps_hd_h264 => Path.Combine(TestPath, "50-mbps-hd-h264.mkv"); + protected string TestFile_120_mbps_4k_uhd_hevc_10bit => Path.Combine(TestPath, "120-mbps-4k-uhd-hevc-10bit.mkv"); private class TestSettings { diff --git a/VideoNodes/VideoNodes.csproj b/VideoNodes/VideoNodes.csproj index 1b68acfd..5ae78006 100644 Binary files a/VideoNodes/VideoNodes.csproj and b/VideoNodes/VideoNodes.csproj differ diff --git a/VideoNodes/VideoNodes.en.json b/VideoNodes/VideoNodes.en.json index 289a0168..4e9c1251 100644 --- a/VideoNodes/VideoNodes.en.json +++ b/VideoNodes/VideoNodes.en.json @@ -1,591 +1,596 @@ { - "Flow":{ - "Parts": { - "AudioAddTrack": { - "Outputs": { - "1": "Audio track added and saved to temporary file" - }, - "Description": "Adds a new audio track to the video file, all other audio tracks will remain. This will use the first audio track of the file as the source audio track to convert.", - "Fields": { - "Index": "Index", - "Index-Help": "The index where to insert the new audio track. 0 based, so to insert the new audio track as the first track set this to 0.", - "Channels": "Channels", - "Channels-Help": "The number of channels to convert this audio track to.", - "Bitrate": "Bitrate", - "Bitrate-Help": "Bitrate of the new audio track" - } + "H": { + "264": "H.264", + "265": "H.265" + }, + "Flow": { + "Parts": { + "AudioAddTrack": { + "Outputs": { + "1": "Audio track added and saved to temporary file" + }, + "Description": "Adds a new audio track to the video file, all other audio tracks will remain. This will use the first audio track of the file as the source audio track to convert.", + "Fields": { + "Index": "Index", + "Index-Help": "The index where to insert the new audio track. 0 based, so to insert the new audio track as the first track set this to 0.", + "Channels": "Channels", + "Channels-Help": "The number of channels to convert this audio track to.", + "Bitrate": "Bitrate", + "Bitrate-Help": "Bitrate of the new audio track" + } + }, + "AudioAdjustVolume": { + "Outputs": { + "1": "Audio tracks volume was adjusted and saved to temporary file", + "2": "Audio tracks were not adjusted" }, - "AudioAdjustVolume": { - "Outputs": { - "1": "Audio tracks volume was adjusted and saved to temporary file", - "2": "Audio tracks were not adjusted" - }, - "Description": "Adjusts audio tracks volume in a video file using FFMPEG", - "Fields": { - "VolumePercent": "Volume Percent", - "VolumePercent-Help": "The percent of the adjusted volume.\n100 means no adjustment\n50 means half volume\n0 means muted" - } + "Description": "Adjusts audio tracks volume in a video file using FFMPEG", + "Fields": { + "VolumePercent": "Volume Percent", + "VolumePercent-Help": "The percent of the adjusted volume.\n100 means no adjustment\n50 means half volume\n0 means muted" + } + }, + "AudioNormalization": { + "Outputs": { + "1": "Audio tracks were normalized and saved to temporary file", + "2": "No audio tracks were found to be normalized" }, - "AudioNormalization": { - "Outputs": { - "1": "Audio tracks were normalized and saved to temporary file", - "2": "No audio tracks were found to be normalized" - }, - "Description": "Normalizes all audio tracks in a video file using FFMPEGs loudnorm filter", - "Fields": { - "AllAudio": "All Audio Tracks", - "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", - "TwoPass": "Two Pass", - "TwoPass-Help": "If the audio tracks should use two pass normalization. This improves the normalization but increases the processing time.", - "Pattern": "Pattern", - "Pattern-Help": "An optional regular expression to filter out audio tracks to normalize. Will match against the title, codec and language", - "NotMatching": "Not Matching", - "NotMatching-Help": "If the pattern should be used to exclude audio tracks from normalization, otherwise if the audio track matches they will be normalized." - } + "Description": "Normalizes all audio tracks in a video file using FFMPEGs loudnorm filter", + "Fields": { + "AllAudio": "All Audio Tracks", + "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", + "TwoPass": "Two Pass", + "TwoPass-Help": "If the audio tracks should use two pass normalization. This improves the normalization but increases the processing time.", + "Pattern": "Pattern", + "Pattern-Help": "An optional regular expression to filter out audio tracks to normalize. Will match against the title, codec and language", + "NotMatching": "Not Matching", + "NotMatching-Help": "If the pattern should be used to exclude audio tracks from normalization, otherwise if the audio track matches they will be normalized." + } + }, + "AudioTrackRemover": { + "Outputs": { + "1": "Audio tracks were removed", + "2": "Audio tracks were NOT removed" }, - "AudioTrackRemover": { - "Outputs": { - "1": "Audio tracks were removed", - "2": "Audio tracks were NOT removed" - }, - "Description": "Allows you to remove audio tracks based on either their title or their language codes.\n\nAny title (or language code if set to \"Use Language Code\") that is blank will NOT be removed regardless of the pattern.", - "Fields": { - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", - "UseLanguageCode": "Use Language Code", - "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" - } + "Description": "Allows you to remove audio tracks based on either their title or their language codes.\n\nAny title (or language code if set to \"Use Language Code\") that is blank will NOT be removed regardless of the pattern.", + "Fields": { + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", + "UseLanguageCode": "Use Language Code", + "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" + } + }, + "AudioTrackReorder": { + "Outputs": { + "1": "Audio tracks re-ordered in new temporary file", + "2": "Audio tracks NOT re-ordered" }, - "AudioTrackReorder": { - "Outputs": { - "1": "Audio tracks re-ordered in new temporary file", - "2": "Audio tracks NOT re-ordered" - }, - "Description": "Allows you to reorder audio tracks in the preferred order.\n\nEnter the languages/audio codecs/channels in the order you want. Any not listed will be ordered after the ones entered in their original order.\nIf there are multiple tracks with same language/codec/channels, they will be ordered first by the order you entered, then in their original order.\n\nOutput 1: Audio tracks were reordered\nOutput 2: Audio tracks did not need reordering", - "Fields": { - "OrderedTracks": "Ordered Audio Codecs", - "OrderedTracks-Help": "The order of audio codecs to the audio tracks by. This is done after the languages (if any)", - "Languages": "Languages", - "Languages-Help": "The order of languages to sort the audio tracks by. This sorting is done before the codec.", - "Channels": "Channels", - "Channels-Help": "The order of audio channels to sort the audio tracks by. This sorting is done before languages.\nFor example \"5.1\",\"7.1\",\"6.2\",\"2\"" - } + "Description": "Allows you to reorder audio tracks in the preferred order.\n\nEnter the languages/audio codecs/channels in the order you want. Any not listed will be ordered after the ones entered in their original order.\nIf there are multiple tracks with same language/codec/channels, they will be ordered first by the order you entered, then in their original order.\n\nOutput 1: Audio tracks were reordered\nOutput 2: Audio tracks did not need reordering", + "Fields": { + "OrderedTracks": "Ordered Audio Codecs", + "OrderedTracks-Help": "The order of audio codecs to the audio tracks by. This is done after the languages (if any)", + "Languages": "Languages", + "Languages-Help": "The order of languages to sort the audio tracks by. This sorting is done before the codec.", + "Channels": "Channels", + "Channels-Help": "The order of audio channels to sort the audio tracks by. This sorting is done before languages.\nFor example \"5.1\",\"7.1\",\"6.2\",\"2\"" + } + }, + "AudioTrackSetLanguage": { + "Label": "Audio Set Language", + "Outputs": { + "1": "Audio tracks updated to new temporary file", + "2": "Audio tracks NOT updated" }, - "AudioTrackSetLanguage": { - "Label": "Audio Set Language", - "Outputs": { - "1": "Audio tracks updated to new temporary file", - "2": "Audio tracks NOT updated" - }, - "Description": "Allows you to set the language for any audio tracks that have no language set. If the audio track does have a language set, it will be skipped.\n\nOutput 1: Audio Tracks were updated\nOutput 2: No audio tracks were needing to be updated", - "Fields": { - "Language": "Language", - "Language-Help": "The ISO 639-2 language code to use. \nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" - } + "Description": "Allows you to set the language for any audio tracks that have no language set. If the audio track does have a language set, it will be skipped.\n\nOutput 1: Audio Tracks were updated\nOutput 2: No audio tracks were needing to be updated", + "Fields": { + "Language": "Language", + "Language-Help": "The ISO 639-2 language code to use. \nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" + } + }, + "AutoChapters": { + "Description": "Automatically detect scene changes in the video to generate chapters.", + "Outputs": { + "1": "Chapters generated and saved to temporary file", + "2": "No chapters detected or video already had chapters" }, - "AutoChapters": { - "Description": "Automatically detect scene changes in the video to generate chapters.", - "Outputs": { - "1": "Chapters generated and saved to temporary file", - "2": "No chapters detected or video already had chapters" - }, - "Fields": { - "MinimumLength": "Minimum Length", - "MinimumLength-Suffix": "seconds", - "MinimumLength-Help": "The minimum length of a chapter in seconds", - "Percent": "Percent", - "Percent-Suffix": "%", - "Percent-Help": "The threshold percentage value to use for scene detection changes. A good value is 45%" - } + "Fields": { + "MinimumLength": "Minimum Length", + "MinimumLength-Suffix": "seconds", + "MinimumLength-Help": "The minimum length of a chapter in seconds", + "Percent": "Percent", + "Percent-Suffix": "%", + "Percent-Help": "The threshold percentage value to use for scene detection changes. A good value is 45%" + } + }, + "ComskipChapters": { + "Description": "Uses a comskip EDL file and will create chapters given that EDL comskip file.", + "Outputs": { + "1": "Commercials chapters created, saved to temporary file", + "2": "No commercials detected" + } + }, + "ComskipRemoveAds": { + "Description": "Uses a comskip EDL file and will remove commercials using that file.", + "Outputs": { + "1": "Commercials removed, saved to temporary file", + "2": "No commercials detected" + } + }, + "VideoFile": { + "Description": "An input video file that has had its VideoInformation read and can be processed", + "Outputs": { + "1": "Video file from library" }, - "ComskipChapters": { - "Description": "Uses a comskip EDL file and will create chapters given that EDL comskip file.", - "Outputs": { - "1": "Commercials chapters created, saved to temporary file", - "2": "No commercials detected" - } + "Fields": { + "ProbeSize": "Probe Size", + "ProbeSize-Suffix": "MB", + "ProbeSize-Help": "The probe size to use in FFMPEG when executing." + } + }, + "DetectBlackBars": { + "Description": "Processes a video file and scans for black bars in the video.\n\nIf found a parameter \"VideoCrop\" will be added.\n\nOutput 1: Black bars detected\nOutput 2: Not detected", + "Outputs": { + "1": "Black bars detected", + "2": "No black bars detected" }, - "ComskipRemoveAds": { - "Description": "Uses a comskip EDL file and will remove commercials using that file.", - "Outputs": { - "1": "Commercials removed, saved to temporary file", - "2": "No commercials detected" - } + "Fields": { + "CroppingThreshold": "Threshold", + "CroppingThreshold-Help": "The amount of pixels that must be greater than to crop. E.g. if there's only 5 pixels detected as black space, you may consider this too small to crop." + } + }, + "FFMPEG": { + "Description": "The node lets you run any FFMPEG command you like. Giving you full control over what it can do.\n\nFor more information refer to the FFMPEG documentation", + "Outputs": { + "1": "Video processed" }, - "VideoFile": { - "Description": "An input video file that has had its VideoInformation read and can be processed", - "Outputs": { - "1": "Video file from library" - }, - "Fields": { - "ProbeSize": "Probe Size", - "ProbeSize-Suffix": "MB", - "ProbeSize-Help": "The probe size to use in FFMPEG when executing." - } + "Fields": { + "Extension": "Extension", + "Extension-Help": "The file extension to use on the newly created file", + "CommandLine": "Command Line", + "CommandLine-Help": "The command line to run with FFMPEG.\n'{WorkingFile}': the working file of the flow\n'{Output}': The output file that will be passed as the last parameter to FFMPEG including the extension defined above." + } + }, + "FfmpegBuilderStart": { + "Label": "FFMPEG Builder: Start", + "Outputs": { + "1": "FFMPEG Builder created and ready to add FFMPEG Builder nodes to" }, - "DetectBlackBars": { - "Description": "Processes a video file and scans for black bars in the video.\n\nIf found a parameter \"VideoCrop\" will be added.\n\nOutput 1: Black bars detected\nOutput 2: Not detected", - "Outputs": { - "1": "Black bars detected", - "2": "No black bars detected" - }, - "Fields": { - "CroppingThreshold": "Threshold", - "CroppingThreshold-Help": "The amount of pixels that must be greater than to crop. E.g. if there's only 5 pixels detected as black space, you may consider this too small to crop." - } + "Description": "Creates an instance of the FFMPEG Builder which can build a FFMPEG argument to then execute with the FFMPEG Executor." + }, + "FfmpegBuilderExecutor": { + "Label": "FFMPEG Builder: Executor", + "Outputs": { + "1": "FFMPEG Builder ran successfully and created new temporary file", + "2": "No changes detected in FFMPEG Builder, file not created" }, - "FFMPEG": { - "Description": "The node lets you run any FFMPEG command you like. Giving you full control over what it can do.\n\nFor more information refer to the FFMPEG documentation", - "Outputs": { - "1": "Video processed" - }, - "Fields": { - "Extension": "Extension", - "Extension-Help": "The file extension to use on the newly created file", - "CommandLine": "Command Line", - "CommandLine-Help": "The command line to run with FFMPEG.\n'{WorkingFile}': the working file of the flow\n'{Output}': The output file that will be passed as the last parameter to FFMPEG including the extension defined above." - } + "Description": "Executes a FFMPEG Builder command created by other FFMPEG Builder nodes.", + "Fields": { + "HardwareDecoding": "Hardware Decoding", + "HardwareDecoding-Help": "If the executor should attempt to use hardware decoding. If not available the execution will proceed just without hardware decoding enabled." + } + }, + "FfmpegBuilderAddInputFile": { + "Label": "FFMPEG Builder: Add Input File", + "Outputs": { + "1": "File found and added", + "2": "No file found" }, - "FfmpegBuilderStart": { - "Label": "FFMPEG Builder: Start", - "Outputs": { - "1": "FFMPEG Builder created and ready to add FFMPEG Builder nodes to" - }, - "Description": "Creates an instance of the FFMPEG Builder which can build a FFMPEG argument to then execute with the FFMPEG Executor." + "Fields": { + "Pattern": "Pattern", + "Pattern-Help": "A regular expression used to search for input files", + "UseSourceDirectory": "Use Source Directory", + "UseSourceDirectory-Help": "If checked the original source directory will be searched, otherwise the working directory will be used." + } + }, + "FfmpegBuilderAudioAddTrack": { + "Label": "FFMPEG Builder: Audio Add Track", + "Outputs": { + "1": "Added audio track to FFMPEG Builder" }, - "FfmpegBuilderExecutor": { - "Label": "FFMPEG Builder: Executor", - "Outputs": { - "1": "FFMPEG Builder ran successfully and created new temporary file", - "2": "No changes detected in FFMPEG Builder, file not created" - }, - "Description": "Executes a FFMPEG Builder command created by other FFMPEG Builder nodes.", - "Fields": { - "HardwareDecoding": "Hardware Decoding", - "HardwareDecoding-Help": "If the executor should attempt to use hardware decoding. If not available the execution will proceed just without hardware decoding enabled." - } + "Description": "Adds a new audio track to FFMPEG Builder which will be added once the builder is executed.", + "Fields": { + "Index": "Index", + "Index-Help": "The index where to insert the new audio track. 0 based, so to insert the new audio track as the first track set this to 0.", + "Channels": "Channels", + "Channels-Help": "The number of channels this new audio track will be.\nIf you specify more channels than the source, FFMPEG will automatically upmix it.\nIf you specify fewer channels than the source, FFMPEG will automatically down mix it.", + "Bitrate": "Bitrate", + "Bitrate-Help": "Bitrate of the new audio track", + "Language": "Language", + "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" + } + }, + "FfmpegBuilderAudioAdjustVolume": { + "Label": "FFMPEG Builder: Audio Adjust Volume", + "Outputs": { + "1": "Audio tracks volume filter added to FFMPEG Builder", + "2": "Audio tracks were not adjusted" }, - "FfmpegBuilderAddInputFile": { - "Label": "FFMPEG Builder: Add Input File", - "Outputs": { - "1": "File found and added", - "2": "No file found" - }, - "Fields": { - "Pattern": "Pattern", - "Pattern-Help": "A regular expression used to search for input files", - "UseSourceDirectory": "Use Source Directory", - "UseSourceDirectory-Help": "If checked the original source directory will be searched, otherwise the working directory will be used." - } + "Description": "Adjusts audio tracks volume in a video file using FFMPEG", + "Fields": { + "AllAudio": "All Audio Tracks", + "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", + "VolumePercent": "Volume Percent", + "VolumePercent-Help": "The percent of the adjusted volume.\n100 means no adjustment\n50 means half volume\n0 means muted", + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", + "UseLanguageCode": "Use Language Code", + "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" + } + }, + "FfmpegBuilderAudioNormalization": { + "Label": "FFMPEG Builder: Audio Normalization", + "Outputs": { + "1": "Audio tracks were normalized and added to FFMPEG Builder", + "2": "No audio tracks were found to be normalized" }, - "FfmpegBuilderAudioAddTrack": { - "Label": "FFMPEG Builder: Audio Add Track", - "Outputs": { - "1": "Added audio track to FFMPEG Builder" - }, - "Description": "Adds a new audio track to FFMPEG Builder which will be added once the builder is executed.", - "Fields": { - "Index": "Index", - "Index-Help": "The index where to insert the new audio track. 0 based, so to insert the new audio track as the first track set this to 0.", - "Channels": "Channels", - "Channels-Help": "The number of channels this new audio track will be.\nIf you specify more channels than the source, FFMPEG will automatically upmix it.\nIf you specify fewer channels than the source, FFMPEG will automatically down mix it.", - "Bitrate": "Bitrate", - "Bitrate-Help": "Bitrate of the new audio track", - "Language": "Language", - "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" - } + "Description": "Normalizes all audio tracks in a video file using FFMPEGs loudnorm filter", + "Fields": { + "TwoPass": "Two Pass", + "TwoPass-Help": "If the audio tracks should use two pass normalization. This improves the normalization but increases the processing time.", + "AllAudio": "All Audio Tracks", + "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", + "UseLanguageCode": "Use Language Code", + "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" + } + }, + "FfmpegBuilderAudioTrackRemover": { + "Label": "FFMPEG Builder: Audio Track Remover", + "Outputs": { + "1": "Audio tracks set to remove", + "2": "Audio tracks NOT set to removed" }, - "FfmpegBuilderAudioAdjustVolume": { - "Label": "FFMPEG Builder: Audio Adjust Volume", - "Outputs": { - "1": "Audio tracks volume filter added to FFMPEG Builder", - "2": "Audio tracks were not adjusted" - }, - "Description": "Adjusts audio tracks volume in a video file using FFMPEG", - "Fields": { - "AllAudio": "All Audio Tracks", - "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", - "VolumePercent": "Volume Percent", - "VolumePercent-Help": "The percent of the adjusted volume.\n100 means no adjustment\n50 means half volume\n0 means muted", - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", - "UseLanguageCode": "Use Language Code", - "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" - } + "Description": "Allows you to remove audio tracks based on either their title or their language codes.\n\nAny title (or language code if set to \"Use Language Code\") that is blank will NOT be removed regardless of the pattern.", + "Fields": { + "RemoveAll": "Remove All", + "RemoveAll-Help": "Remove all current tracks from the output file. You can use Add Audio Track afterwards to add tracks of specific codecs", + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", + "UseLanguageCode": "Use Language Code", + "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title", + "RemoveIndex": "Remove Index", + "RemoveIndex-Help": "The start index where to remove the audio tracks from. This allows you to remove all, or all matching, audio streams after the starting index.\nSet to zero to remove all matching the parameters.\nSet to 1 to keep the first audio track and remove any after the first matching the parameters" + } + }, + "FfmpegBuilderAudioTrackReorder": { + "Label": "FFMPEG Builder: Audio Track Reorder", + "Outputs": { + "1": "Audio tracks re-ordered in FFMPEG Builder", + "2": "Audio tracks NOT re-ordered" }, - "FfmpegBuilderAudioNormalization": { - "Label": "FFMPEG Builder: Audio Normalization", - "Outputs": { - "1": "Audio tracks were normalized and added to FFMPEG Builder", - "2": "No audio tracks were found to be normalized" - }, - "Description": "Normalizes all audio tracks in a video file using FFMPEGs loudnorm filter", - "Fields": { - "TwoPass": "Two Pass", - "TwoPass-Help": "If the audio tracks should use two pass normalization. This improves the normalization but increases the processing time.", - "AllAudio": "All Audio Tracks", - "AllAudio-Help": "If all audio tracks should be normalized or if just the first track should be", - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", - "UseLanguageCode": "Use Language Code", - "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" - } + "Description": "Allows you to reorder audio tracks in the preferred order.\n\nEnter the languages/audio codecs/channels in the order you want. Any not listed will be ordered after the ones entered in their original order.\nIf there are multiple tracks with same language/codec/channels, they will be ordered first by the order you entered, then in their original order.\n\nOutput 1: Audio tracks were reordered\nOutput 2: Audio tracks did not need reordering", + "Fields": { + "OrderedTracks": "Ordered Audio Codecs", + "OrderedTracks-Help": "The order of audio codecs to the audio tracks by. This is done after the languages (if any)", + "Languages": "Languages", + "Languages-Help": "The order of languages to sort the audio tracks by. This sorting is done before the codec.", + "Channels": "Channels", + "Channels-Help": "The order of audio channels to sort the audio tracks by. This sorting is done before languages.\nFor example \"5.1\",\"7.1\",\"6.2\",\"2\"" + } + }, + "FfmpegBuilderAudioSetLanguage": { + "Label": "FFMPEG Builder: Audio Set Language", + "Outputs": { + "1": "Audio tracks updated in FFMPEG Builder", + "2": "Audio tracks NOT updated" }, - "FfmpegBuilderAudioTrackRemover": { - "Label": "FFMPEG Builder: Audio Track Remover", - "Outputs": { - "1": "Audio tracks set to remove", - "2": "Audio tracks NOT set to removed" - }, - "Description": "Allows you to remove audio tracks based on either their title or their language codes.\n\nAny title (or language code if set to \"Use Language Code\") that is blank will NOT be removed regardless of the pattern.", - "Fields": { - "RemoveAll": "Remove All", - "RemoveAll-Help": "Remove all current tracks from the output file. You can use Add Audio Track afterwards to add tracks of specific codecs", - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"commentary\" to remove commentary tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If audio tracks NOT matching the pattern should be removed", - "UseLanguageCode": "Use Language Code", - "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title", - "RemoveIndex": "Remove Index", - "RemoveIndex-Help": "The start index where to remove the audio tracks from. This allows you to remove all, or all matching, audio streams after the starting index.\nSet to zero to remove all matching the parameters.\nSet to 1 to keep the first audio track and remove any after the first matching the parameters" - } + "Description": "Allows you to set the language for any audio tracks that have no language set. If the audio track does have a language set, it will be skipped.\n\nOutput 1: Audio Tracks were updated\nOutput 2: No audio tracks were needing to be updated", + "Fields": { + "Language": "Language", + "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" + } + }, + "FfmpegBuilderAutoChapters": { + "Label": "FFMPEG Builder: Auto Chapters", + "Description": "Automatically detect scene changes in the video to generate chapters.", + "Outputs": { + "1": "Chapters generated and added to FFMPEG Builder", + "2": "No chapters detected or video already had chapters" }, - "FfmpegBuilderAudioTrackReorder": { - "Label": "FFMPEG Builder: Audio Track Reorder", - "Outputs": { - "1": "Audio tracks re-ordered in FFMPEG Builder", - "2": "Audio tracks NOT re-ordered" - }, - "Description": "Allows you to reorder audio tracks in the preferred order.\n\nEnter the languages/audio codecs/channels in the order you want. Any not listed will be ordered after the ones entered in their original order.\nIf there are multiple tracks with same language/codec/channels, they will be ordered first by the order you entered, then in their original order.\n\nOutput 1: Audio tracks were reordered\nOutput 2: Audio tracks did not need reordering", - "Fields": { - "OrderedTracks": "Ordered Audio Codecs", - "OrderedTracks-Help": "The order of audio codecs to the audio tracks by. This is done after the languages (if any)", - "Languages": "Languages", - "Languages-Help": "The order of languages to sort the audio tracks by. This sorting is done before the codec.", - "Channels": "Channels", - "Channels-Help": "The order of audio channels to sort the audio tracks by. This sorting is done before languages.\nFor example \"5.1\",\"7.1\",\"6.2\",\"2\"" - } + "Fields": { + "MinimumLength": "Minimum Length", + "MinimumLength-Suffix": "seconds", + "MinimumLength-Help": "The minimum length of a chapter in seconds", + "Percent": "Percent", + "Percent-Suffix": "%", + "Percent-Help": "The threshold percentage value to use for scene detection changes. A good value is 45%" + } + }, + "FfmpegBuilderComskipChapters": { + "Label": "FFMPEG Builder: Comskip Chapters", + "Description": "Uses a comskip EDL file and will create chapters given that EDL comskip file.", + "Outputs": { + "1": "Commercials chapters created, added to FFMPEG Builder", + "2": "No commercials detected" + } + }, + "FfmpegBuilderHdrToSdr": { + "Label": "FFMPEG Builder: HDR to SDR", + "Description": "Checks if a video stream is HDR and if it is updates the FFMPEG Builder to convert it to SDR", + "Outputs": { + "1": "HDR stream detected and updated FFMPEG Builder to convert", + "2": "No HDR stream found" + } + }, + "FfmpegBuilderSubtitleFormatRemover": { + "Label": "FFMPEG Builder: Subtitle Format Remover", + "Description": "Removes subtitles from a video file if found.", + "Outputs": { + "1": "Subtitles marked for removal in FFMPEG Builder", + "2": "No subtitles to remove" }, - "FfmpegBuilderAudioSetLanguage": { - "Label": "FFMPEG Builder: Audio Set Language", - "Outputs": { - "1": "Audio tracks updated in FFMPEG Builder", - "2": "Audio tracks NOT updated" - }, - "Description": "Allows you to set the language for any audio tracks that have no language set. If the audio track does have a language set, it will be skipped.\n\nOutput 1: Audio Tracks were updated\nOutput 2: No audio tracks were needing to be updated", - "Fields": { - "Language": "Language", - "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" - } + "Fields": { + "SubtitlesToRemove": "Subtitles To Remove", + "RemoveAll": "Remove All", + "RemoveAll-Help": "When checked, all subtitles will be removed from the file, otherwise only those selected below will be" + } + }, + "FfmpegBuilderSubtitleTrackRemover": { + "Label": "FFMPEG Builder: Subtitle Track Remover", + "Outputs": { + "1": "Subtitles marked for removal in FFMPEG Builder", + "2": "No subtitles to remove" }, - "FfmpegBuilderAutoChapters": { - "Label": "FFMPEG Builder: Auto Chapters", - "Description": "Automatically detect scene changes in the video to generate chapters.", - "Outputs": { - "1": "Chapters generated and added to FFMPEG Builder", - "2": "No chapters detected or video already had chapters" - }, - "Fields": { - "MinimumLength": "Minimum Length", - "MinimumLength-Suffix": "seconds", - "MinimumLength-Help": "The minimum length of a chapter in seconds", - "Percent": "Percent", - "Percent-Suffix": "%", - "Percent-Help": "The threshold percentage value to use for scene detection changes. A good value is 45%" - } + "Description": "Allows you to remove subtitles based on either their title or their language codes.\n\nAny language (or title if set to \"Use Title\") that is blank will NOT be removed regardless of the pattern.", + "Fields": { + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"eng\" to remove English tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If subtitles NOT matching the pattern should be removed", + "UseLanguageCode": "Use Language Code", + "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" + } + }, + "FfmpegBuilderSubtitleTrackMerge": { + "Label": "FFMPEG Builder: Subtitle Track Merge", + "Outputs": { + "1": "Subtitles found and added", + "2": "No subtitles found" }, - "FfmpegBuilderComskipChapters": { - "Label": "FFMPEG Builder: Comskip Chapters", - "Description": "Uses a comskip EDL file and will create chapters given that EDL comskip file.", - "Outputs": { - "1": "Commercials chapters created, added to FFMPEG Builder", - "2": "No commercials detected" - } + "Fields": { + "Subtitles": "Subtitles", + "Subtitles-Help": "Select which subtitles to search for to add", + "UseSourceDirectory": "Use Source Directory", + "UseSourceDirectory-Help": "If checked the original source directory will be searched, otherwise the working directory will be used." + } + }, + "FfmpegBuilderCropBlackBars": { + "Label": "FFMPEG Builder: Crop Black Bars", + "Description": "Updated FFMPEG Builder to crop black bars if detected", + "Outputs": { + "1": "FFMPEG Builder updated to crop black bars", + "2": "No black bars detected, not cropping" }, - "FfmpegBuilderHdrToSdr": { - "Label": "FFMPEG Builder: HDR to SDR", - "Description": "Checks if a video stream is HDR and if it is updates the FFMPEG Builder to convert it to SDR", - "Outputs": { - "1": "HDR stream detected and updated FFMPEG Builder to convert", - "2": "No HDR stream found" - } + "Fields": { + "CroppingThreshold": "Threshold", + "CroppingThreshold-Help": "The amount of pixels that must be greater than to crop. E.g. if there's only 5 pixels detected as black space, you may consider this too small to crop." + } + }, + "FfmpegBuilderRemuxToMkv": { + "Label": "FFMPEG Builder: Remux to MKV", + "Descritption": "Remuxes a video file into a MKV container.", + "Outputs": { + "1": "FFMPEG Builder set to remux to MKV" + } + }, + "FfmpegBuilderRemuxToMP4": { + "Label": "FFMPEG Builder: Remux to MP4", + "Descritption": "Remuxes a video file into a MP4 container.", + "Outputs": { + "1": "FFMPEG Builder set to remux to MP4" + } + }, + "FfmpegBuilderScaler": { + "Label": "FFMPEG Builder: Video Scaler", + "Description": "This allows you to scale a video to the specified dimensions. It will retain the aspect ratio of the video so if the video was 1920x1000 it would scale to 1280x668 if you select 720P.", + "Outputs": { + "1": "FFMPEG Builder scale filter added", + "2": "Video was already in/near the scaled resolution" }, - "FfmpegBuilderSubtitleFormatRemover": { - "Label": "FFMPEG Builder: Subtitle Format Remover", - "Description": "Removes subtitles from a video file if found.", - "Outputs": { - "1": "Subtitles marked for removal in FFMPEG Builder", - "2": "No subtitles to remove" - }, - "Fields": { - "SubtitlesToRemove": "Subtitles To Remove", - "RemoveAll": "Remove All", - "RemoveAll-Help": "When checked, all subtitles will be removed from the file, otherwise only those selected below will be" - } + "Fields": { + "Force": "Force", + "Force-Help": "When checked the video will be force scaled even if the working file is already in this resolution (or near this resolution).", + "Resolution": "Resolution" + } + }, + "FfmpegBuilderVideo10Bit": { + "Label": "FFMPEG Builder: Video 10 Bit", + "Description": "Sets FFMPEG Builder to encode the video streams in 10 Bit", + "Outputs": { + "1": "FFMPEG Builder video streams set to encode in 10 Bit" + } + }, + "FfmpegBuilderVideoBitrate": { + "Label": "FFMPEG Builder: Video Bitrate", + "Description": "Sets FFMPEG Builder to encode the video given the bitrate", + "Outputs": { + "1": "FFMPEG Builder video streams updated" }, - "FfmpegBuilderSubtitleTrackRemover": { - "Label": "FFMPEG Builder: Subtitle Track Remover", - "Outputs": { - "1": "Subtitles marked for removal in FFMPEG Builder", - "2": "No subtitles to remove" - }, - "Description": "Allows you to remove subtitles based on either their title or their language codes.\n\nAny language (or title if set to \"Use Title\") that is blank will NOT be removed regardless of the pattern.", - "Fields": { - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"eng\" to remove English tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If subtitles NOT matching the pattern should be removed", - "UseLanguageCode": "Use Language Code", - "UseLanguageCode-Help": "If the language code of the audio track should be used instead of the title" - } + "Fields": { + "Bitrate": "Bitrate", + "Bitrate-Suffix": "KB / %", + "Bitrate-Help": "The target bitrate of the video in kilobytes", + "Percent": "Percent", + "Percent-Help": "When selected the bitrate will be calculated as a percentage of the current bitrate." + } + }, + "FfmpegBuilderVideoCodec": { + "Label": "FFMPEG Builder: Video Codec", + "Description": "Sets FFMPEG Builder to encode the video streams in the specified codec", + "Outputs": { + "1": "FFMPEG Builder video streams set to encode", + "2": "Video already in target codec, will not re-encode" }, - "FfmpegBuilderSubtitleTrackMerge": { - "Label": "FFMPEG Builder: Subtitle Track Merge", - "Outputs": { - "1": "Subtitles found and added", - "2": "No subtitles found" - }, - "Fields": { - "Subtitles": "Subtitles", - "Subtitles-Help": "Select which subtitles to search for to add", - "UseSourceDirectory": "Use Source Directory", - "UseSourceDirectory-Help": "If checked the original source directory will be searched, otherwise the working directory will be used." - } + "Fields": { + "VideoCodec": "Video Codec", + "VideoCodec-Help": "The video codec the video should be in, for example hevc, h264.\nIf left empty all original video tracks will be copied.", + "VideoCodecParameters": "Video Codec Parameters", + "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration.", + "Force": "Force Encode", + "Force-Help": "Will force a encode of the video even if it is already in the target Video Codec", + "DisableOtherVideoStreams": "Only First", + "DisableOtherVideoStreams-Help": "When checked if there are multiple video streams in the file, this will remove all but the first video stream from the file once executed." + } + }, + "FfmpegBuilderVideoEncode": { + "Label": "FFMPEG Builder: Video Encode", + "Description": "Sets the FFMPEG Builder to encode the video with simple to use presets", + "Outputs": { + "1": "FFMPEG Builder video streams set to encode" }, - "FfmpegBuilderCropBlackBars": { - "Label": "FFMPEG Builder: Crop Black Bars", - "Description": "Updated FFMPEG Builder to crop black bars if detected", - "Outputs": { - "1": "FFMPEG Builder updated to crop black bars", - "2": "No black bars detected, not cropping" - }, - "Fields": { - "CroppingThreshold": "Threshold", - "CroppingThreshold-Help": "The amount of pixels that must be greater than to crop. E.g. if there's only 5 pixels detected as black space, you may consider this too small to crop." - } + "Fields": { + "Codec": "Codec", + "HardwareEncoding": "Hardware Encode", + "HardwareEncoding-Help": "When checked, will test to see if hardware encoders are found on the Processing Node, and if found will use hardware encoding, otherwise will fallback to CPU encoding.", + "Quality": "Quality", + "Quality-Help": "A logarithmic quality scale, so small changes in the this slider cause large changes in file size/quality.\nThe lower the number the higher the quality.\nSee Help for more information", + "Quality-Suffix": "(Higher Quality, larger file)" + } + }, + "RemuxToMKV": { + "Descritption": "Remuxes a video file into a MKV container. All streams will be copied to the new container", + "Outputs": { + "1": "File remuxed to temporary file", + "2": "File was already in a MKV container" }, - "FfmpegBuilderRemuxToMkv": { - "Label": "FFMPEG Builder: Remux to MKV", - "Descritption": "Remuxes a video file into a MKV container.", - "Outputs": { - "1": "FFMPEG Builder set to remux to MKV" - } + "Fields": { + "Force": "Force", + "Force-Help": "If the file should be always remuxed into a MKV container even when it already is in a MKV container.\ni.e. a new temporary file will always be created." + } + }, + "ReadVideoInfo": { + "Descritption": "Reads the video information from the current working file and updates the vi variables.", + "Outputs": { + "1": "File was a video file and information read into flow", + "2": "File was not a video file or failed to be read" + } + }, + "RemuxToMP4": { + "Descritption": "Remuxes a video file into a MP4 container. All streams will be copied to the new container", + "Outputs": { + "1": "File remuxed to temporary file", + "2": "File was already in a MP4 container" }, - "FfmpegBuilderRemuxToMP4": { - "Label": "FFMPEG Builder: Remux to MP4", - "Descritption": "Remuxes a video file into a MP4 container.", - "Outputs": { - "1": "FFMPEG Builder set to remux to MP4" - } + "Fields": { + "Force": "Force", + "Force-Help": "If the file should be always remuxed into a MP4 container even when it already is in a MP4 container.\ni.e. a new temporary file will always be created." + } + }, + "SubtitleRemover": { + "Description": "Removes subtitles from a video file if found.\n\nOutput 1: Subtitles were removed\nOutput 2: No subtitles found that needed to be removed", + "Outputs": { + "1": "Subtitles removed in new temporary file", + "2": "No subtitles to remove" }, - "FfmpegBuilderScaler": { - "Label": "FFMPEG Builder: Video Scaler", - "Description": "This allows you to scale a video to the specified dimensions. It will retain the aspect ratio of the video so if the video was 1920x1000 it would scale to 1280x668 if you select 720P.", - "Outputs": { - "1": "FFMPEG Builder scale filter added", - "2": "Video was already in/near the scaled resolution" - }, - "Fields": { - "Force": "Force", - "Force-Help": "When checked the video will be force scaled even if the working file is already in this resolution (or near this resolution).", - "Resolution": "Resolution" - } + "Fields": { + "SubtitlesToRemove": "Subtitles To Remove", + "RemoveAll": "Remove All", + "RemoveAll-Help": "When checked, all subtitles will be removed from the file, otherwise only those selected below will be" + } + }, + "SubtitleExtractor": { + "Description": "Extract a single subtitle tracks and saves it to the destination. Can extract srt, ass, and ssa format.\nThis will NOT update the working file, and will keep the working file the same as the input file.\n\nOutput 1: Subtitles were extracted\nOutput 2: No subtitles found to extract", + "Outputs": { + "1": "Subtitles extracted", + "2": "No subtitles extracted" }, - "FfmpegBuilderVideo10Bit": { - "Label": "FFMPEG Builder: Video 10 Bit", - "Description": "Sets FFMPEG Builder to encode the video streams in 10 Bit", - "Outputs": { - "1": "FFMPEG Builder video streams set to encode in 10 Bit" - } + "Fields": { + "Language": "Language", + "Language-Help": "The ISO 639-2 language code to use. \nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes", + "OutputFile": "Output File", + "OutputFile-Help": "Where to save the the output file to, e.g. \"'{folder.Orig.FullName}\\{file.Orig.FileName}.srt'\" to save it with the original file as a srt output.\nIf left blank an srt subtitle will be created in the same folder as the original input file.", + "SetWorkingFile": "Set as Working File", + "SetWorkingFile-Help": "When this is checked, if a subtitle is extracted, the working file will be changed to this extracted subtitle. The original working file will NOT be deleted." + } + }, + "SubtitleLanguageRemover": { + "Outputs": { + "1": "Subtitles were removed", + "2": "Subtitles were NOT removed" }, - "FfmpegBuilderVideoBitrate": { - "Label": "FFMPEG Builder: Video Bitrate", - "Description": "Sets FFMPEG Builder to encode the video given the bitrate", - "Outputs": { - "1": "FFMPEG Builder video streams updated" - }, - "Fields": { - "Bitrate": "Bitrate", - "Bitrate-Suffix": "KB / %", - "Bitrate-Help": "The target bitrate of the video in kilobytes", - "Percent": "Percent", - "Percent-Help": "When selected the bitrate will be calculated as a percentage of the current bitrate." - } + "Description": "Allows you to remove subtitles based on either their title or their language codes.\n\nAny language (or title if set to \"Use Title\") that is blank will NOT be removed regardless of the pattern.", + "Fields": { + "Pattern": "Pattern", + "Pattern-Help": "A regular expression to match against, eg \"eng\" to remove English tracks", + "NotMatching": "Not Matching", + "NotMatching-Help": "If subtitles NOT matching the pattern should be removed", + "UseTitle": "Use Title", + "UseTitle-Help": "If the title of the subtitle should be used for matching instead of the language" + } + }, + "VideoCodec": { + "Description": "This node will check the codecs in the input file, and trigger when matched.\n\nOutput 1: Matches\nOutput 2: Does not match", + "Fields": { + "Codecs": "Codecs", + "Codecs-Help": "Enter a list of case insensitive video or audio codecs.\nEg hevc, h265, mpeg4, ac3" + } + }, + "VideoEncode": { + "Description": "A generic video encoding node, this lets you customize how to encode a video file using ffmpeg.\n\nOutput 1: Video was processed\nOutput 2: No processing required", + "Outputs": { + "1": "Video re-encoded to temporary file", + "2": "Video not re-encoded" }, - "FfmpegBuilderVideoCodec": { - "Label": "FFMPEG Builder: Video Codec", - "Description": "Sets FFMPEG Builder to encode the video streams in the specified codec", - "Outputs": { - "1": "FFMPEG Builder video streams set to encode", - "2": "Video already in target codec, will not re-encode" - }, - "Fields": { - "VideoCodec": "Video Codec", - "VideoCodec-Help": "The video codec the video should be in, for example hevc, h264.\nIf left empty all original video tracks will be copied.", - "VideoCodecParameters": "Video Codec Parameters", - "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration.", - "Force": "Force Encode", - "Force-Help": "Will force a encode of the video even if it is already in the target Video Codec", - "DisableOtherVideoStreams": "Only First", - "DisableOtherVideoStreams-Help": "When checked if there are multiple video streams in the file, this will remove all but the first video stream from the file once executed." - } + "Fields": { + "Extension": "Extension", + "Extension-Help": "The file extension to use on the newly created file.", + "VideoCodec": "Video Codec", + "VideoCodec-Help": "The video codec the video should be in, for example hevc, h264.\nIf left empty all original video tracks will be copied.", + "VideoCodecParameters": "Video Codec Parameters", + "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration.", + "AudioCodec": "Audio Codec", + "AudioCodec-Help": "The audio codec to encode the video with.\nIf left empty all original audio tracks will be copied.", + "Language": "Language", + "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" + } + }, + "VideoHasStream": { + "Description": "Tests if a video file contains a stream", + "Outputs": { + "1": "Contains the matching stream", + "2": "Does not contain the matching stream" }, - "FfmpegBuilderVideoEncode": { - "Label": "FFMPEG Builder: Video Encode", - "Description": "Sets the FFMPEG Builder to encode the video with simple to use presets", - "Outputs": { - "1": "FFMPEG Builder video streams set to encode" - }, - "Fields": { - "Codec": "Codec", - "HardwareEncoding": "Hardware Encode", - "HardwareEncoding-Help": "When checked, will test to see if hardware encoders are found on the Processing Node, and if found will use hardware encoding, otherwise will fallback to CPU encoding.", - "Quality": "Quality", - "Quality-Help": "Sets the quality of the video" - } + "Fields": { + "Stream": "Type", + "Stream-Help": "The type of stream to look for", + "Title": "Title", + "Title-Help": "A regular expression used to test the stream title", + "Codec": "Codec", + "Codec-Help": "A regular expression used to test the stream codec", + "Language": "Language", + "Language-Help": "A regular expression used to test the stream language", + "Channels": "Channels", + "Channels-Help": "The number of channels to test for. Set to 0 to ignore this check" + } + }, + "VideoScaler": { + "Description": "This allows you to scale a video to the specified dimensions. It will retain the aspect ratio of the video so if the video was 1920x1000 it would scale to 1280x668 if you select 720P.", + "Outputs": { + "1": "Video rescaled to temporary file", + "2": "Video was already in/near the scaled resolution" }, - "RemuxToMKV": { - "Descritption": "Remuxes a video file into a MKV container. All streams will be copied to the new container", - "Outputs": { - "1": "File remuxed to temporary file", - "2": "File was already in a MKV container" - }, - "Fields": { - "Force": "Force", - "Force-Help": "If the file should be always remuxed into a MKV container even when it already is in a MKV container.\ni.e. a new temporary file will always be created." - } - }, - "ReadVideoInfo": { - "Descritption": "Reads the video information from the current working file and updates the vi variables.", - "Outputs": { - "1": "File was a video file and information read into flow", - "2": "File was not a video file or failed to be read" - } - }, - "RemuxToMP4": { - "Descritption": "Remuxes a video file into a MP4 container. All streams will be copied to the new container", - "Outputs": { - "1": "File remuxed to temporary file", - "2": "File was already in a MP4 container" - }, - "Fields": { - "Force": "Force", - "Force-Help": "If the file should be always remuxed into a MP4 container even when it already is in a MP4 container.\ni.e. a new temporary file will always be created." - } - }, - "SubtitleRemover": { - "Description": "Removes subtitles from a video file if found.\n\nOutput 1: Subtitles were removed\nOutput 2: No subtitles found that needed to be removed", - "Outputs": { - "1": "Subtitles removed in new temporary file", - "2": "No subtitles to remove" - }, - "Fields": { - "SubtitlesToRemove": "Subtitles To Remove", - "RemoveAll": "Remove All", - "RemoveAll-Help": "When checked, all subtitles will be removed from the file, otherwise only those selected below will be" - } - }, - "SubtitleExtractor": { - "Description": "Extract a single subtitle tracks and saves it to the destination. Can extract srt, ass, and ssa format.\nThis will NOT update the working file, and will keep the working file the same as the input file.\n\nOutput 1: Subtitles were extracted\nOutput 2: No subtitles found to extract", - "Outputs": { - "1": "Subtitles extracted", - "2": "No subtitles extracted" - }, - "Fields": { - "Language": "Language", - "Language-Help": "The ISO 639-2 language code to use. \nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes", - "OutputFile": "Output File", - "OutputFile-Help": "Where to save the the output file to, e.g. \"'{folder.Orig.FullName}\\{file.Orig.FileName}.srt'\" to save it with the original file as a srt output.\nIf left blank an srt subtitle will be created in the same folder as the original input file.", - "SetWorkingFile": "Set as Working File", - "SetWorkingFile-Help": "When this is checked, if a subtitle is extracted, the working file will be changed to this extracted subtitle. The original working file will NOT be deleted." - } - }, - "SubtitleLanguageRemover": { - "Outputs": { - "1": "Subtitles were removed", - "2": "Subtitles were NOT removed" - }, - "Description": "Allows you to remove subtitles based on either their title or their language codes.\n\nAny language (or title if set to \"Use Title\") that is blank will NOT be removed regardless of the pattern.", - "Fields": { - "Pattern": "Pattern", - "Pattern-Help": "A regular expression to match against, eg \"eng\" to remove English tracks", - "NotMatching": "Not Matching", - "NotMatching-Help": "If subtitles NOT matching the pattern should be removed", - "UseTitle": "Use Title", - "UseTitle-Help": "If the title of the subtitle should be used for matching instead of the language" - } - }, - "VideoCodec": { - "Description": "This node will check the codecs in the input file, and trigger when matched.\n\nOutput 1: Matches\nOutput 2: Does not match", - "Fields": { - "Codecs": "Codecs", - "Codecs-Help": "Enter a list of case insensitive video or audio codecs.\nEg hevc, h265, mpeg4, ac3" - } - }, - "VideoEncode": { - "Description": "A generic video encoding node, this lets you customize how to encode a video file using ffmpeg.\n\nOutput 1: Video was processed\nOutput 2: No processing required", - "Outputs": { - "1": "Video re-encoded to temporary file", - "2": "Video not re-encoded" - }, - "Fields": { - "Extension": "Extension", - "Extension-Help": "The file extension to use on the newly created file.", - "VideoCodec": "Video Codec", - "VideoCodec-Help": "The video codec the video should be in, for example hevc, h264.\nIf left empty all original video tracks will be copied.", - "VideoCodecParameters": "Video Codec Parameters", - "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration.", - "AudioCodec": "Audio Codec", - "AudioCodec-Help": "The audio codec to encode the video with.\nIf left empty all original audio tracks will be copied.", - "Language": "Language", - "Language-Help": "Optional ISO 639-2 language code to use. Will attempt to find an audio track with this language code if not the best audio track will be used.\nhttps://en.wikipedia.org/wiki/List_of_ISO_639-2_codes" - } - }, - "VideoHasStream": { - "Description": "Tests if a video file contains a stream", - "Outputs": { - "1": "Contains the matching stream", - "2": "Does not contain the matching stream" - }, - "Fields": { - "Stream": "Type", - "Stream-Help": "The type of stream to look for", - "Title": "Title", - "Title-Help": "A regular expression used to test the stream title", - "Codec": "Codec", - "Codec-Help": "A regular expression used to test the stream codec", - "Language": "Language", - "Language-Help": "A regular expression used to test the stream language", - "Channels": "Channels", - "Channels-Help": "The number of channels to test for. Set to 0 to ignore this check" - } - }, - "VideoScaler": { - "Description": "This allows you to scale a video to the specified dimensions. It will retain the aspect ratio of the video so if the video was 1920x1000 it would scale to 1280x668 if you select 720P.", - "Outputs": { - "1": "Video rescaled to temporary file", - "2": "Video was already in/near the scaled resolution" - }, - "Fields": { - "VideoCodec": "Video Codec", - "Language-Help": "The video codec to encode the scaled video in", - "Extension": "Extension", - "Extension-Help": "The file extension to use on the newly created file", - "Force": "Force", - "Force-Help": "When checked the video will be force scaled even if the working file is already in this resolution (or near this resolution).", - "Resolution": "Resolution", - "VideoCodecParameters": "Video Codec Parameters", - "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration." - } + "Fields": { + "VideoCodec": "Video Codec", + "Language-Help": "The video codec to encode the scaled video in", + "Extension": "Extension", + "Extension-Help": "The file extension to use on the newly created file", + "Force": "Force", + "Force-Help": "When checked the video will be force scaled even if the working file is already in this resolution (or near this resolution).", + "Resolution": "Resolution", + "VideoCodecParameters": "Video Codec Parameters", + "VideoCodecParameters-Help": "The parameters to use to encode the video, eg. \"hevc_nvenc -preset hq -crf 23\" to encode into hevc using the HQ preset a constant rate factor of 23 and using NVIDIA hardware acceleration." } } } + } } \ No newline at end of file diff --git a/build/utils/PluginInfoGenerator/FileFlows.Plugin.dll b/build/utils/PluginInfoGenerator/FileFlows.Plugin.dll index e9f45cc2..5d71cabf 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.Plugin.dll and b/build/utils/PluginInfoGenerator/FileFlows.Plugin.dll differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.Plugin.pdb b/build/utils/PluginInfoGenerator/FileFlows.Plugin.pdb index 628ccef2..61fead5c 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.Plugin.pdb and b/build/utils/PluginInfoGenerator/FileFlows.Plugin.pdb differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.ServerShared.dll b/build/utils/PluginInfoGenerator/FileFlows.ServerShared.dll index 7c182e3c..b378903a 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.ServerShared.dll and b/build/utils/PluginInfoGenerator/FileFlows.ServerShared.dll differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.ServerShared.pdb b/build/utils/PluginInfoGenerator/FileFlows.ServerShared.pdb index dccab33e..fdfc54c9 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.ServerShared.pdb and b/build/utils/PluginInfoGenerator/FileFlows.ServerShared.pdb differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.Shared.dll b/build/utils/PluginInfoGenerator/FileFlows.Shared.dll index 48914891..c494fa1d 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.Shared.dll and b/build/utils/PluginInfoGenerator/FileFlows.Shared.dll differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.Shared.pdb b/build/utils/PluginInfoGenerator/FileFlows.Shared.pdb index cd822efc..c40049a3 100644 Binary files a/build/utils/PluginInfoGenerator/FileFlows.Shared.pdb and b/build/utils/PluginInfoGenerator/FileFlows.Shared.pdb differ diff --git a/build/utils/PluginInfoGenerator/FileFlows.Shared.xml b/build/utils/PluginInfoGenerator/FileFlows.Shared.xml index 95040533..8a19a934 100644 --- a/build/utils/PluginInfoGenerator/FileFlows.Shared.xml +++ b/build/utils/PluginInfoGenerator/FileFlows.Shared.xml @@ -75,6 +75,26 @@ A special flow that is executed when a flow fails during execution + + + The available processing libraries options + + + + + Only process the libraries specified + + + + + Process all libraries + + + + + Process all libraries except those specified + + Extension methods used by FileFlows @@ -503,6 +523,11 @@ Gets or sets the parameters of the field + + + Gets a list of change values for this field + + Gets or sets the validators for the field @@ -651,6 +676,62 @@ the value to test the condition against true if the condition is matches + + + Changes a value when the conditions are met + + + + + Get or sets the Field this condition is attached to + + + + + Gets or sets the property to change + + + + + Gets or sets the value to set in the property + + + + + Gets or sets when to change the value, when this value equals a value + + + + + Gets or sets if the value should be set when this value does not equal the WhenValue + + + + + Gets or sets the owner who owns this condition + + + + + Constructs a condition + + + + + Constructs a change value + + the property to change + the value to set in the property + when to change the value, when this value equals a value + the value should be set when this value does not equal the WhenValue + + + + Test if the change value condition matches the given object value + + the value of the field + true if the condition is matches + An item in the file browser @@ -1324,6 +1405,12 @@ When the library was last scanned + + + Gets or sets if recreated files (files with a different creation time) should be automatically reprocessed + This is helpful if you download the same file multiple times and want to reprocess it again + + The timespan of when this was last scanned @@ -1466,6 +1553,16 @@ Gets the total processing time of the library file + + + Gets or sets when the file was created + + + + + Gets or sets when the file was written to + + Possible status of library files @@ -1863,11 +1960,6 @@ Gets or sets if telemetry should be disabled - - - Gets or sets if the library file logs should be saved in a compressed format to reduce file size - - Gets or sets a list of available URLs to additional plugin repositories diff --git a/build/utils/PluginInfoGenerator/PluginInfoGenerator.dll b/build/utils/PluginInfoGenerator/PluginInfoGenerator.dll index 366a8df4..2b1d69bd 100644 Binary files a/build/utils/PluginInfoGenerator/PluginInfoGenerator.dll and b/build/utils/PluginInfoGenerator/PluginInfoGenerator.dll differ diff --git a/build/utils/PluginInfoGenerator/PluginInfoGenerator.pdb b/build/utils/PluginInfoGenerator/PluginInfoGenerator.pdb index f2cddec8..cad67c5c 100644 Binary files a/build/utils/PluginInfoGenerator/PluginInfoGenerator.pdb and b/build/utils/PluginInfoGenerator/PluginInfoGenerator.pdb differ