diff --git a/VideoNodes/LogicalNodes/VideoDuration.cs b/VideoNodes/LogicalNodes/VideoDuration.cs
new file mode 100644
index 00000000..819008c5
--- /dev/null
+++ b/VideoNodes/LogicalNodes/VideoDuration.cs
@@ -0,0 +1,138 @@
+using FileFlows.VideoNodes.FfmpegBuilderNodes;
+using FileFlows.VideoNodes.FfmpegBuilderNodes.Models;
+using FileFlows.VideoNodes.Helpers;
+
+namespace FileFlows.VideoNodes;
+
+///
+/// Flow element to test if a video duration matches the parameters
+///
+public class VideoDuration : VideoNode
+{
+ ///
+ /// Gets the number of inputs
+ ///
+ public override int Inputs => 1;
+ ///
+ /// Gets the number of outputs
+ ///
+ public override int Outputs => 2;
+ ///
+ /// Gets the type of flow element
+ ///
+ public override FlowElementType Type => FlowElementType.Logic;
+ ///
+ /// Gets the help URL
+ ///
+ public override string HelpUrl => "https://fileflows.com/docs/plugins/video-nodes/logical-nodes/video-duration";
+
+
+ internal const string MATCH_GREATER_THAN = ">";
+ internal const string MATCH_LESS_THAN = "<";
+ internal const string MATCH_EQUALS = "=";
+ internal const string MATCH_NOT_EQUALS = "!=";
+ internal const string MATCH_GREATER_THAN_OR_EQUAL = ">=";
+ internal const string MATCH_LESS_THAN_OR_EQUAL = "<=";
+ internal const string MATCH_BETWEEN = "||";
+ internal const string MATCH_NOT_BETWEEN = "^|";
+ ///
+ /// Gets or sets the method to match
+ ///
+ [Select(nameof(MatchOptions), 1)]
+ [DefaultValue(MATCH_LESS_THAN)]
+ public string Match { get; set; }
+
+ private static List _MatchOptions;
+
+ ///
+ /// Gets the match options
+ ///
+ public static List MatchOptions
+ {
+ get
+ {
+ if (_MatchOptions == null)
+ {
+ _MatchOptions = new List
+ {
+ new () { Label = "Equals", Value = MATCH_EQUALS},
+ new () { Label = "Not Equals", Value = MATCH_NOT_EQUALS},
+ new () { Label = "Less Than", Value = MATCH_LESS_THAN},
+ new () { Label = "Less Than Or Equal", Value = MATCH_LESS_THAN_OR_EQUAL},
+ new () { Label = "Greater Than", Value = MATCH_GREATER_THAN},
+ new () { Label = "Greater Than Or Equal", Value = MATCH_GREATER_THAN_OR_EQUAL},
+ new () { Label = "Between", Value = MATCH_BETWEEN},
+ new () { Label = "Not Between", Value = MATCH_NOT_BETWEEN},
+ };
+ }
+
+ return _MatchOptions;
+ }
+ }
+
+ ///
+ /// Gets or sets the first value to match against
+ ///
+ [Time(2)]
+ public TimeSpan ValueLow { get; set; }
+ ///
+ /// Gets or sets the second value to match against
+ ///
+ [Time(3)]
+ [ConditionEquals(nameof(Match), @"/\|/")]
+ public TimeSpan ValueHigh { get; set; }
+
+ ///
+ /// Executes the flow element
+ ///
+ /// the arguments
+ /// the output to call next
+ public override int Execute(NodeParameters args)
+ {
+ var video = GetVideoInfo(args)?.VideoStreams?.FirstOrDefault();
+ if (video == null)
+ {
+ args.FailureReason = "Failed to retrieve video info";
+ args.Logger?.ELog(args.FailureReason);
+ return -1;
+ }
+
+ int seconds = (int)Math.Round(video.Duration.TotalSeconds);
+ args.Logger?.ILog("Total Seconds: " + seconds);
+ args.Logger?.ILog("Match Method: " + Match);
+ int val1 = (int)ValueLow.TotalSeconds;
+ int val2 = (int)ValueHigh.TotalSeconds;
+
+ switch (Match)
+ {
+ case MATCH_EQUALS:
+ args.Logger?.ILog("Match Value: " + val1);
+ return seconds == val1 ? 1 : 2;
+ case MATCH_NOT_EQUALS:
+ args.Logger?.ILog("Match Value: " + val1);
+ return seconds != val1 ? 1 : 2;
+ case MATCH_LESS_THAN:
+ args.Logger?.ILog("Match Value: " + val1);
+ return seconds < val1 ? 1 : 2;
+ case MATCH_LESS_THAN_OR_EQUAL:
+ args.Logger?.ILog("Match Value: " + val1);
+ return seconds <= val1 ? 1 : 2;
+ case MATCH_GREATER_THAN:
+ args.Logger?.ILog("Match Value: " + val1);
+ return seconds > val1 ? 1 : 2;
+ case MATCH_GREATER_THAN_OR_EQUAL:
+ args.Logger?.ILog("Match Value: " + val1);
+ return seconds >= val1 ? 1 : 2;
+ case MATCH_BETWEEN:
+ args.Logger?.ILog("Between: " + val1);
+ args.Logger?.ILog("And: " + val2);
+ return seconds >= val1 && seconds <= val2 ? 1 : 2;
+ case MATCH_NOT_BETWEEN:
+ args.Logger?.ILog("Not Between: " + val1);
+ args.Logger?.ILog("And: " + val2);
+ return seconds >= val1 && seconds <= val2 ? 2 : 1;
+ }
+ args.Logger?.ELog("Invalid match");
+ return 2;
+ }
+}
diff --git a/VideoNodes/i18n/en.json b/VideoNodes/i18n/en.json
index b06887fa..a1640db8 100644
--- a/VideoNodes/i18n/en.json
+++ b/VideoNodes/i18n/en.json
@@ -87,6 +87,18 @@
"ProbeSize-Help": "The probe size to use in FFMPEG when executing."
}
},
+ "VideoDuration": {
+ "Description": "Tests whether or not the duration of the video matches the given parameters.",
+ "Outputs": {
+ "1": "Video duration matches",
+ "2": "Video duration does not match"
+ },
+ "Fields": {
+ "Match": "Match",
+ "ValueLow": "Duration",
+ "ValueHigh": " "
+ }
+ },
"FfmpegBuilderStart": {
"Label": "FFMPEG Builder: Start",
"Outputs": {