diff --git a/BasicNodes/Tools/Unpack.cs b/BasicNodes/Tools/Unpack.cs index 31dce5f2..80fb3ae1 100644 --- a/BasicNodes/Tools/Unpack.cs +++ b/BasicNodes/Tools/Unpack.cs @@ -18,65 +18,78 @@ public class Unpack: Node public override FlowElementType Type => FlowElementType.Process; /// public override string Icon => "fas fa-file-archive"; - /// - /// Gets the Help URL for this element - /// + /// public override string HelpUrl => "https://fileflows.com/docs/plugins/basic-nodes/unpack"; - private string _DestinationPath = string.Empty; - private string _file = string.Empty; /// /// Gets or sets the destination path /// [Folder(1)] - public string DestinationPath - { - get => _DestinationPath; - set { _DestinationPath = value ?? ""; } - } + public string DestinationPath { get; set; } /// /// Gets or sets the file to unpack /// [TextVariable(2)] - public string File - { - get => _file; - set => _file = value ?? string.Empty; - } + public string File { get; set; } /// public override int Execute(NodeParameters args) { try { - var filename = args.ReplaceVariables(File ?? string.Empty, stripMissing: true)?.EmptyAsNull() ?? args.WorkingFile; + var localFileResult = args.FileService.GetLocalPath( + args.ReplaceVariables(File ?? string.Empty, stripMissing: true)?.EmptyAsNull() ?? args.WorkingFile); + + if (localFileResult.Failed(out string error)) + { + args.FailureReason = "Failed to get local file: " + error; + args.Logger?.ELog(args.FailureReason); + return -1; + } + + var filename = localFileResult.Value; var fileInfo = new FileInfo(filename); if (fileInfo.Exists == false) { - args.Logger?.ELog("File does not exist: " + filename); + args.FailureReason = "File does not exist: " + filename; + args.Logger?.ELog(args.FailureReason); return -1; } - string destDir = args.ReplaceVariables(DestinationPath, stripMissing: true, cleanSpecialCharacters: true); + var destDir = args.ReplaceVariables(DestinationPath, stripMissing: true, cleanSpecialCharacters: true); destDir = args.MapPath(destDir); if (Directory.Exists(destDir) == false) - Directory.CreateDirectory(destDir); + { + if (args.FileService.DirectoryCreate(destDir).Failed(out error)) + { + args.FailureReason = "Failed to create destination directory: " + error; + args.Logger?.ELog(args.FailureReason); + return -1; + } + } - args.ArchiveHelper.Extract(filename, destDir, (percent) => + var result = args.ArchiveHelper.Extract(filename, destDir, (percent) => { args.PartPercentageUpdate(percent); }); + if (result.Failed(out error)) + { + args.FailureReason = error; + args.Logger?.ELog(error); + return -1; + } return 1; } catch (Exception ex) { - args.Logger?.ELog("Failed unzip: " + ex.Message + Environment.NewLine + ex.StackTrace); + args.FailureReason = "Failed to unpack: " + ex.Message; + args.Logger?.ELog(args.FailureReason); return -1; } } diff --git a/ComicNodes/Comics/ComicExtractor.cs b/ComicNodes/Comics/ComicExtractor.cs index e2e9d9c8..3c78fb30 100644 --- a/ComicNodes/Comics/ComicExtractor.cs +++ b/ComicNodes/Comics/ComicExtractor.cs @@ -49,7 +49,7 @@ public class ComicExtractor : Node var metadata = new Dictionary(); metadata.Add("Format", args.WorkingFile[(args.WorkingFile.LastIndexOf(".", StringComparison.Ordinal) + 1)..].ToUpper()); - var rgxImages = new Regex(@"\.(jpeg|jpg|jpe|png|bmp|tiff|webp|gif)$"); + var rgxImages = new Regex(@"\.(jpeg|jpg|jpe|jp2|png|bmp|tiff|webp|gif)$"); metadata.Add("Pages", Directory.GetFiles(dest, "*.*", SearchOption.AllDirectories).Count(x => rgxImages.IsMatch(x))); args.SetMetadata(metadata); diff --git a/FileFlows.Plugin.dll b/FileFlows.Plugin.dll index b6100107..00250f3a 100644 Binary files a/FileFlows.Plugin.dll and b/FileFlows.Plugin.dll differ diff --git a/FileFlows.Plugin.pdb b/FileFlows.Plugin.pdb index a7d812c0..cdcc544b 100644 Binary files a/FileFlows.Plugin.pdb and b/FileFlows.Plugin.pdb differ diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs index 4ed22d65..84c9b4d3 100644 --- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs +++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderExecutor.cs @@ -95,17 +95,20 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode var model = this.Model; if (model == null) { - args.Logger.ELog("FFMPEG Builder model is null"); + args.FailureReason = "FFMPEG Builder model is null"; + args.Logger.ELog(args.FailureReason); return -1; } - else if (model.VideoInfo == null) + if (model.VideoInfo == null) { - args.Logger.ELog("FFMPEG Builder VideoInfo is null"); + args.FailureReason = "FFMPEG Builder VideoInfo is null"; + args.Logger.ELog(args.FailureReason); return -1; } - else if (model.VideoInfo.FileName == null) + if (model.VideoInfo.FileName == null) { - args.Logger.ELog("FFMPEG Builder VideoInfo Filename is null"); + args.FailureReason = "FFMPEG Builder VideoInfo Filename is null"; + args.Logger.ELog(args.FailureReason); return -1; } List ffArgs = new List(); @@ -278,12 +281,14 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode GetHardwareDecodingArgs(args, localFile, FFMPEG, video?.Stream?.Codec, pxtFormat, encodingParameters: encodingParameters); if (decodingParameters.Any() == true) { - args.StatisticRecorderRunningTotals("DecoderParameters", string.Join(" ", decodingParameters)); + args.StatisticRecorderRunningTotals?.Invoke("DecoderParameters", string.Join(" ", decodingParameters)); startArgs.AddRange(decodingParameters); } } } + startArgs.AddRange(["-c:s", "webvtt"]); + foreach (var file in model.InputFiles) { startArgs.Add("-i"); @@ -467,7 +472,7 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode arguments = new VaapiAdjustments().Run(args.Logger, arguments); } - args.AdditionalInfoRecorder("Testing", string.Join(" ", hw), 1, new TimeSpan(0, 0, 10)); + args.AdditionalInfoRecorder?.Invoke("Testing", string.Join(" ", hw), 1, new TimeSpan(0, 0, 10)); try { @@ -515,7 +520,7 @@ public class FfmpegBuilderExecutor: FfmpegBuilderNode } finally { - args.AdditionalInfoRecorder("Testing", null, 1, new TimeSpan(0, 0, 10)); + args.AdditionalInfoRecorder?.Invoke("Testing", null, 1, new TimeSpan(0, 0, 10)); try { if (System.IO.File.Exists(testFile)) diff --git a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs index 61d49d3c..e6b5326f 100644 --- a/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs +++ b/VideoNodes/FfmpegBuilderNodes/FfmpegBuilderStart.cs @@ -52,7 +52,12 @@ public class FfmpegBuilderStart: FfmpegBuilderNode { VideoInfo videoInfo = GetVideoInfo(args); if (videoInfo == null) + { + args.FailureReason = "No VideoInformation found"; + args.Logger?.ELog(args.FailureReason); return -1; + } + this.Model = Models.FfmpegModel.CreateModel(videoInfo); args.Logger.ILog("FFMPEG Builder File: " + videoInfo.FileName); diff --git a/VideoNodes/FfmpegBuilderNodes/Models/FfmpegSubtitleStream.cs b/VideoNodes/FfmpegBuilderNodes/Models/FfmpegSubtitleStream.cs index f2dc7662..f8f978aa 100644 --- a/VideoNodes/FfmpegBuilderNodes/Models/FfmpegSubtitleStream.cs +++ b/VideoNodes/FfmpegBuilderNodes/Models/FfmpegSubtitleStream.cs @@ -52,8 +52,8 @@ public class FfmpegSubtitleStream : FfmpegStream } } - if (destCodec == "copy" && Stream.Codec == "webvtt") - destCodec = "webvtt"; // FF-1534: webvtt issue + // if (destCodec == "copy" && Stream.Codec == "webvtt") + // destCodec = "webvtt"; // FF-1534: webvtt issue List results= new List { "-map", Stream.InputFileIndex + ":s:{sourceTypeIndex}", "-c:s:{index}", destCodec }; diff --git a/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs index a4d680de..5598f29c 100644 --- a/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs +++ b/VideoNodes/Tests/FfmpegBuilderTests/FfmpegBuilder_VideoEncodeTests.cs @@ -4,6 +4,7 @@ using FileFlows.VideoNodes.FfmpegBuilderNodes; using Microsoft.VisualStudio.TestTools.UnitTesting; using VideoNodes.Tests; using System.IO; +using FileFlows.VideoNodes.Helpers; namespace FileFlows.VideoNodes.Tests.FfmpegBuilderTests; @@ -30,7 +31,7 @@ public class FfmpegBuilder_VideoEncode_VideoEncodeTests: TestBase Assert.AreEqual(1, ffStart.Execute(args)); FfmpegBuilderVideoEncode ffEncode = new(); - ffEncode.Encoder = "VAAPI"; + //ffEncode.Encoder = "VAAPI"; //ffEncode.Encoder = "NVIDIA"; // ffEncode.Encoder = "Intel QSV"; ffEncode.Codec = codec; @@ -256,6 +257,46 @@ public class FfmpegBuilder_VideoEncode_VideoEncodeTests: TestBase TestContext.WriteLine(log); Assert.AreEqual(1, result); } + + [TestMethod] + public void FfmpegBuilder_VideoEncode_WebVTT() + { + var logger = new TestLogger(); + string ffmpeg = FfmpegPath; + const string FILE = "/home/john/Videos/webvtt/webvtt.mkv"; + var vi = new VideoInfoHelper(ffmpeg, logger); + var vii = vi.Read(FILE); + var args = new NodeParameters(FILE, logger, false, string.Empty, new LocalFileService()); + args.GetToolPathActual = (string tool) => ffmpeg; + args.TempPath = TempPath; + args.Parameters.Add("VideoInfo", vii.Value); + + FfmpegBuilderStart ffStart = new(); + ffStart.PreExecute(args); + Assert.AreEqual(1, ffStart.Execute(args)); + + FfmpegBuilderVideoEncode ffEncode = new(); + ffEncode.Quality = 28; + ffEncode.Speed = "fast"; + ffEncode.Encoder = "CPU"; + ffEncode.Codec = "h265"; + ffEncode.PreExecute(args); + ffEncode.Execute(args); + + FFmpegBuilderDurationStart ds = new(); + ds.Start = new TimeSpan(0, 0, 0); + ds.Duration = new TimeSpan(0, 1, 0); + ds.PreExecute(args); + ds.Execute(args); + + FfmpegBuilderExecutor ffExecutor = new(); + ffExecutor.Strictness = "experimental"; + ffExecutor.PreExecute(args); + int result = ffExecutor.Execute(args); + string log = logger.ToString(); + TestContext.WriteLine(log); + Assert.AreEqual(1, result); + } } #endif \ No newline at end of file diff --git a/VideoNodes/Tests/SubtitleExtractorTests.cs b/VideoNodes/Tests/SubtitleExtractorTests.cs index 5cb7180b..8af928b0 100644 --- a/VideoNodes/Tests/SubtitleExtractorTests.cs +++ b/VideoNodes/Tests/SubtitleExtractorTests.cs @@ -1,69 +1,92 @@ #if(DEBUG) -namespace VideoNodes.Tests +using FileFlows.VideoNodes; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.IO; +using VideoFile = FileFlows.VideoNodes.VideoFile; + +namespace VideoNodes.Tests; + +[TestClass] +public class SubtitleExtractorTests: TestBase { - using FileFlows.VideoNodes; - using Microsoft.VisualStudio.TestTools.UnitTesting; - using System; - using System.IO; - - [TestClass] - public class SubtitleExtractorTests: TestBase + [TestMethod] + public void SubtitleExtractor_Extension_Test() { - [TestMethod] - public void SubtitleExtractor_Extension_Test() + string file = TestFile_BasicMkv; + var vi = new VideoInfoHelper(FfmpegPath, new TestLogger()); + var vii = vi.Read(file); + + foreach (string ext in new[] { String.Empty, ".srt", ".sup" }) { - string file = TestFile_BasicMkv; - var vi = new VideoInfoHelper(FfmpegPath, new TestLogger()); - var vii = vi.Read(file); + SubtitleExtractor node = new(); + node.OutputFile = Path.Combine(TempPath, "subtitle.en" + ext); + node.Language = "eng"; - foreach (string ext in new[] { String.Empty, ".srt", ".sup" }) - { - SubtitleExtractor node = new(); - node.OutputFile = Path.Combine(TempPath, "subtitle.en" + ext); - node.Language = "eng"; + var args = new NodeParameters(file, new TestLogger(), false, string.Empty, null);; + args.GetToolPathActual = (string tool) => FfmpegPath; + args.TempPath = TempPath; - var args = new NodeParameters(file, new TestLogger(), false, string.Empty, null);; - args.GetToolPathActual = (string tool) => FfmpegPath; - args.TempPath = TempPath; + Assert.AreEqual(1, new VideoFile().Execute(args)); - Assert.AreEqual(1, new VideoFile().Execute(args)); + int output = node.Execute(args); - int output = node.Execute(args); - - Assert.AreEqual(1, output); - } + Assert.AreEqual(1, output); } + } - [TestMethod] - public void SubtitleExtractor_Pgs_Test() + [TestMethod] + public void SubtitleExtractor_Pgs_Test() + { + string file = TestFile_Pgs; + var vi = new VideoInfoHelper(FfmpegPath, new TestLogger()); + var vii = vi.Read(file); + + foreach (string ext in new[] { string.Empty, ".srt", ".sup" }) { - string file = TestFile_Pgs; - var vi = new VideoInfoHelper(FfmpegPath, new TestLogger()); - var vii = vi.Read(file); + SubtitleExtractor node = new(); + node.ForcedOnly = true; + node.OutputFile = Path.Combine(TempPath, "subtitle.en" + ext); + node.Language = "eng"; - foreach (string ext in new[] { string.Empty, ".srt", ".sup" }) - { - SubtitleExtractor node = new(); - node.ForcedOnly = true; - node.OutputFile = Path.Combine(TempPath, "subtitle.en" + ext); - node.Language = "eng"; + var args = new NodeParameters(file, new TestLogger(), false, string.Empty, null);; + args.GetToolPathActual = (string tool) => FfmpegPath; + args.TempPath = TempPath; - var args = new NodeParameters(file, new TestLogger(), false, string.Empty, null);; - args.GetToolPathActual = (string tool) => FfmpegPath; - args.TempPath = TempPath; + var vf = new VideoFile(); + vf.PreExecute(args); + Assert.AreEqual(1, vf.Execute(args)); - var vf = new VideoFile(); - vf.PreExecute(args); - Assert.AreEqual(1, vf.Execute(args)); + int output = node.Execute(args); - int output = node.Execute(args); - - Assert.AreEqual(1, output); - } + Assert.AreEqual(1, output); } } + + + [TestMethod] + public void Webvtt_Extract() + { + string file = TestFile_Webvtt; + + var args = new NodeParameters(file, new TestLogger(), false, string.Empty, new LocalFileService());; + args.GetToolPathActual = (string tool) => FfmpegPath; + args.TempPath = TempPath; + + var vf = new VideoFile(); + vf.PreExecute(args); + Assert.AreEqual(1, vf.Execute(args)); + + SubtitleExtractor extractor = new(); + extractor.OutputFile = Path.Combine(TempPath, "subtitle.srt"); + extractor.ExtractAll = true; + extractor.PreExecute(args); + int output = extractor.Execute(args); + + Assert.AreEqual(1, output); + } } + #endif \ No newline at end of file diff --git a/VideoNodes/Tests/_TestBase.cs b/VideoNodes/Tests/_TestBase.cs index 94419307..c99ab28f 100644 --- a/VideoNodes/Tests/_TestBase.cs +++ b/VideoNodes/Tests/_TestBase.cs @@ -16,6 +16,8 @@ public abstract class TestBase /// private TestContext testContextInstance; + internal TestLogger Logger = new(); + /// /// Gets or sets the test context /// @@ -56,6 +58,12 @@ public abstract class TestBase Directory.CreateDirectory(this.TempPath); } + [TestCleanup] + public void CleanUp() + { + TestContext.WriteLine(Logger.ToString()); + } + private void LoadSettings(string filename) { try @@ -81,6 +89,7 @@ public abstract class TestBase protected string TestFile_MovText_Mp4 => Path.Combine(TestPath, "movtext.mp4"); protected string TestFile_BasicMkv => Path.Combine(TestPath, "basic.mkv"); + protected string TestFile_Webvtt => Path.Combine(TestPath, "webvtt.mkv"); protected string TestFile_Tag => Path.Combine(TestPath, "tag.mp4"); protected string TestFile_Sitcom => Path.Combine(TestPath, "sitcom.mkv"); protected string TestFile_Pgs => Path.Combine(TestPath, "pgs.mkv");