diff --git a/VideoNodes/InputNodes/VideoFile.cs b/VideoNodes/InputNodes/VideoFile.cs
index c1d669e1..be1f0a0b 100644
--- a/VideoNodes/InputNodes/VideoFile.cs
+++ b/VideoNodes/InputNodes/VideoFile.cs
@@ -154,6 +154,8 @@ public class VideoFile : VideoNode
/// the node parameters
private void PrintFFmpegVersion(NodeParameters args)
{
+ if(string.IsNullOrEmpty(FFMPEG))
+ return;
string firstLine = string.Empty;
try
diff --git a/VideoNodes/Tests/SubtitleExtractorTests.cs b/VideoNodes/Tests/SubtitleExtractorTests.cs
index efdd1e28..2873e52b 100644
--- a/VideoNodes/Tests/SubtitleExtractorTests.cs
+++ b/VideoNodes/Tests/SubtitleExtractorTests.cs
@@ -45,9 +45,10 @@ namespace VideoNodes.Tests
var vi = new VideoInfoHelper(FfmpegPath, new TestLogger());
var vii = vi.Read(file);
- foreach (string ext in new[] { String.Empty, ".srt", ".sup" })
+ 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";
@@ -55,7 +56,9 @@ namespace VideoNodes.Tests
args.GetToolPathActual = (string tool) => FfmpegPath;
args.TempPath = TempPath;
- Assert.AreEqual(1, new VideoFile().Execute(args));
+ var vf = new VideoFile();
+ vf.PreExecute(args);
+ Assert.AreEqual(1, vf.Execute(args));
int output = node.Execute(args);
diff --git a/VideoNodes/VideoNodes.en.json b/VideoNodes/VideoNodes.en.json
index b3f96761..4968a8dc 100644
--- a/VideoNodes/VideoNodes.en.json
+++ b/VideoNodes/VideoNodes.en.json
@@ -498,7 +498,9 @@
"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."
+ "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.",
+ "ForcedOnly": "Forced Only",
+ "ForcedOnly-Help": "If only forced subtitles should be extracted."
}
},
"VideoHasStream": {
diff --git a/VideoNodes/VideoNodes/SubtitleExtractor.cs b/VideoNodes/VideoNodes/SubtitleExtractor.cs
index 7ebde434..ab6fe86f 100644
--- a/VideoNodes/VideoNodes/SubtitleExtractor.cs
+++ b/VideoNodes/VideoNodes/SubtitleExtractor.cs
@@ -1,145 +1,187 @@
-namespace FileFlows.VideoNodes
+using System.Net;
+
+namespace FileFlows.VideoNodes;
+
+///
+/// Element that extracts subtitles
+///
+public class SubtitleExtractor : EncodingNode
{
- using FileFlows.Plugin;
- using FileFlows.Plugin.Attributes;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
-
- public class SubtitleExtractor : EncodingNode
+ ///
+ /// Gets the number of outputs
+ ///
+ public override int Outputs => 2;
+ ///
+ /// Gets the icon for the element
+ ///
+ public override string Icon => "fas fa-comment-dots";
+ ///
+ /// Gets or sets the language to extract
+ ///
+ [Text(1)]
+ public string Language { get; set; }
+ ///
+ /// Gets or sets the destination output file
+ ///
+ [File(2)]
+ public string OutputFile { get; set; }
+ ///
+ /// Gets or sets if the new file should be set as the current working file
+ ///
+ [Boolean(3)]
+ public bool SetWorkingFile { get; set; }
+ ///
+ /// Gets or sets if only forced subtitles should be extracted
+ ///
+ [Boolean(4)]
+ public bool ForcedOnly { get; set; }
+
+
+ private Dictionary _Variables;
+ ///
+ /// Gets or sets the variables
+ ///
+ public override Dictionary Variables => _Variables;
+
+ ///
+ /// Creates an instance of the subtitle extractor
+ ///
+ public SubtitleExtractor()
{
- public override int Outputs => 2;
-
- public override string Icon => "fas fa-comment-dots";
-
- [Text(1)]
- public string Language { get; set; }
-
- [File(2)]
- public string OutputFile { get; set; }
-
- [Boolean(3)]
- public bool SetWorkingFile { get; set; }
- private Dictionary _Variables;
- public override Dictionary Variables => _Variables;
- public SubtitleExtractor()
+ _Variables = new Dictionary()
{
- _Variables = new Dictionary()
- {
- { "sub.FileName", "/path/to/subtitle.sub" }
- };
- }
+ { "sub.FileName", "/path/to/subtitle.sub" }
+ };
+ }
- public override int Execute(NodeParameters args)
+ ///
+ /// Executes the subtitle extractor
+ ///
+ /// the node parameters
+ /// the output to call next
+ public override int Execute(NodeParameters args)
+ {
+ try
{
- try
- {
- VideoInfo videoInfo = GetVideoInfo(args);
- if (videoInfo == null)
- return -1;
-
- // ffmpeg -i input.mkv -map "0:m:language:eng" -map "-0:v" -map "-0:a" output.srt
- var subTrack = videoInfo.SubtitleStreams?.Where(x => string.IsNullOrEmpty(Language) || x.Language?.ToLower() == Language.ToLower()).FirstOrDefault();
- if (subTrack == null)
- {
- args.Logger?.ILog("No subtitles found to extract");
- return 2;
- }
-
- if (string.IsNullOrEmpty(OutputFile) == false)
- {
- OutputFile = args.ReplaceVariables(OutputFile, true);
- }
- else
- {
- var file = new FileInfo(args.FileName);
-
-
- OutputFile = file.FullName.Substring(0, file.FullName.LastIndexOf(file.Extension));
- }
- OutputFile = args.MapPath(OutputFile);
-
- string extension = "srt";
- if (subTrack.Codec?.ToLower()?.Contains("pgs") == true)
- extension = "sup";
- if (OutputFile.ToLower().EndsWith(".srt") || OutputFile.ToLower().EndsWith(".sup"))
- OutputFile = OutputFile[0..^4];
-
- OutputFile += "." + extension;
- //bool textSubtitles = Regex.IsMatch(OutputFile, @"\.(sup)$") == false;
-
-
- var extracted = ExtractSubtitle(args, FFMPEG, "0:s:" + subTrack.TypeIndex, OutputFile);
- if(extracted)
- {
- args.UpdateVariables(new Dictionary
- {
- { "sub.FileName", OutputFile }
- });
- if (SetWorkingFile)
- args.SetWorkingFile(OutputFile, dontDelete: true);
-
- return 1;
- }
-
+ VideoInfo videoInfo = GetVideoInfo(args);
+ if (videoInfo == null)
return -1;
- }
- catch (Exception ex)
+
+ // ffmpeg -i input.mkv -map "0:m:language:eng" -map "-0:v" -map "-0:a" output.srt
+ var subTrack = videoInfo.SubtitleStreams?.Where(x =>
{
- args.Logger?.ELog("Failed processing VideoFile: " + ex.Message);
- return -1;
- }
- }
-
- internal bool ExtractSubtitle(NodeParameters args, string ffmpegExe, string subtitleStream, string output)
- {
- if (File.Exists(OutputFile))
- {
- args.Logger?.ILog("File already exists, deleting file: " + OutputFile);
- File.Delete(OutputFile);
- }
-
- bool textSubtitles = Regex.IsMatch(OutputFile.ToLower(), @"\.(sup)$") == false;
- // -y means it will overwrite a file if output already exists
- var result = args.Process.ExecuteShellCommand(new ExecuteArgs
- {
- Command = ffmpegExe,
- ArgumentList = textSubtitles ?
- new[] {
-
- "-i", args.WorkingFile,
- "-map", subtitleStream,
- output
- } :
- new[] {
-
- "-i", args.WorkingFile,
- "-map", subtitleStream,
- "-c:s", "copy",
- output
- }
- }).Result;
-
- var of = new FileInfo(OutputFile);
- if (result.ExitCode != 0)
- {
- args.Logger?.ELog("FFMPEG process failed to extract subtitles");
- args.Logger?.ILog("Unexpected exit code: " + result.ExitCode);
- args.Logger?.ILog(result.StandardOutput ?? String.Empty);
- args.Logger?.ILog(result.StandardError ?? String.Empty);
- if (of.Exists && of.Length == 0)
- {
- // delete the output file if it created an empty file
- try
- {
- of.Delete();
- }
- catch (Exception) { }
- }
+ if (ForcedOnly && x.Forced == false)
+ return false;
+ if(string.IsNullOrEmpty(Language))
+ return true;
+ if (x.Language?.ToLowerInvariant() == Language.ToLowerInvariant())
+ return true;
return false;
+ }).FirstOrDefault();
+ if (subTrack == null)
+ {
+ args.Logger?.ILog("No subtitles found to extract");
+ return 2;
}
- return of.Exists;
+
+ if (string.IsNullOrEmpty(OutputFile) == false)
+ {
+ OutputFile = args.ReplaceVariables(OutputFile, true);
+ }
+ else
+ {
+ var file = new FileInfo(args.FileName);
+
+
+ OutputFile = file.FullName.Substring(0, file.FullName.LastIndexOf(file.Extension));
+ }
+ OutputFile = args.MapPath(OutputFile);
+
+ string extension = "srt";
+ if (subTrack.Codec?.ToLower()?.Contains("pgs") == true)
+ extension = "sup";
+ if (OutputFile.ToLower().EndsWith(".srt") || OutputFile.ToLower().EndsWith(".sup"))
+ OutputFile = OutputFile[0..^4];
+
+ OutputFile += "." + extension;
+
+ var extracted = ExtractSubtitle(args, FFMPEG, "0:s:" + subTrack.TypeIndex, OutputFile);
+ if(extracted)
+ {
+ args.UpdateVariables(new Dictionary
+ {
+ { "sub.FileName", OutputFile }
+ });
+ if (SetWorkingFile)
+ args.SetWorkingFile(OutputFile, dontDelete: true);
+
+ return 1;
+ }
+
+ return -1;
+ }
+ catch (Exception ex)
+ {
+ args.Logger?.ELog("Failed processing VideoFile: " + ex.Message);
+ return -1;
}
}
+
+ ///
+ /// Extracts a subtitle
+ ///
+ /// the node parameters
+ /// the FFmpeg executable
+ /// the FFmpeg subtitle stream to extract
+ /// the destination file of the extracted subtitle
+ /// if it was successful or not
+ internal bool ExtractSubtitle(NodeParameters args, string ffmpegExe, string subtitleStream, string output)
+ {
+ if (File.Exists(OutputFile))
+ {
+ args.Logger?.ILog("File already exists, deleting file: " + OutputFile);
+ File.Delete(OutputFile);
+ }
+
+ bool textSubtitles = Regex.IsMatch(OutputFile.ToLower(), @"\.(sup)$") == false;
+ // -y means it will overwrite a file if output already exists
+ var result = args.Process.ExecuteShellCommand(new ExecuteArgs
+ {
+ Command = ffmpegExe,
+ ArgumentList = textSubtitles ?
+ new[] {
+
+ "-i", args.WorkingFile,
+ "-map", subtitleStream,
+ output
+ } :
+ new[] {
+
+ "-i", args.WorkingFile,
+ "-map", subtitleStream,
+ "-c:s", "copy",
+ output
+ }
+ }).Result;
+
+ var of = new FileInfo(OutputFile);
+ if (result.ExitCode != 0)
+ {
+ args.Logger?.ELog("FFMPEG process failed to extract subtitles");
+ args.Logger?.ILog("Unexpected exit code: " + result.ExitCode);
+ args.Logger?.ILog(result.StandardOutput ?? String.Empty);
+ args.Logger?.ILog(result.StandardError ?? String.Empty);
+ if (of.Exists && of.Length == 0)
+ {
+ // delete the output file if it created an empty file
+ try
+ {
+ of.Delete();
+ }
+ catch (Exception) { }
+ }
+ return false;
+ }
+ return of.Exists;
+ }
}