mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-02-06 10:48:45 -06:00
fixed issue with Video Has Stream not working
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,3 +17,4 @@ Emby/settings.invalid.json
|
||||
Emby/settings.json
|
||||
VideoNodes/test.settings.dev.json
|
||||
Apprise/settings.json
|
||||
build/utils/PluginInfoGenerator/
|
||||
|
||||
@@ -1,120 +1,133 @@
|
||||
namespace FileFlows.VideoNodes
|
||||
namespace FileFlows.VideoNodes;
|
||||
|
||||
using System.Linq;
|
||||
using System.ComponentModel;
|
||||
using FileFlows.Plugin;
|
||||
using FileFlows.Plugin.Attributes;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
public class VideoHasStream : VideoNode
|
||||
{
|
||||
using System.Linq;
|
||||
using System.ComponentModel;
|
||||
using FileFlows.Plugin;
|
||||
using FileFlows.Plugin.Attributes;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
public override int Inputs => 1;
|
||||
public override int Outputs => 2;
|
||||
public override FlowElementType Type => FlowElementType.Logic;
|
||||
|
||||
public class VideoHasStream : VideoNode
|
||||
[Select(nameof(StreamTypeOptions), 1)]
|
||||
public string Stream { get; set; }
|
||||
|
||||
private static List<ListOption> _StreamTypeOptions;
|
||||
public static List<ListOption> StreamTypeOptions
|
||||
{
|
||||
public override int Inputs => 1;
|
||||
public override int Outputs => 2;
|
||||
public override FlowElementType Type => FlowElementType.Logic;
|
||||
|
||||
[Select(nameof(StreamTypeOptions), 1)]
|
||||
public string Stream { get; set; }
|
||||
|
||||
private static List<ListOption> _StreamTypeOptions;
|
||||
public static List<ListOption> StreamTypeOptions
|
||||
get
|
||||
{
|
||||
get
|
||||
if (_StreamTypeOptions == null)
|
||||
{
|
||||
if (_StreamTypeOptions == null)
|
||||
_StreamTypeOptions = new List<ListOption>
|
||||
{
|
||||
_StreamTypeOptions = new List<ListOption>
|
||||
{
|
||||
new ListOption { Label = "Video", Value = "Video" },
|
||||
new ListOption { Label = "Audio", Value = "Audio" },
|
||||
new ListOption { Label = "Subtitle", Value = "Subtitle" }
|
||||
};
|
||||
}
|
||||
return _StreamTypeOptions;
|
||||
}
|
||||
}
|
||||
|
||||
[TextVariable(2)]
|
||||
public string Title { get; set; }
|
||||
|
||||
[TextVariable(3)]
|
||||
public string Codec { get; set; }
|
||||
|
||||
[ConditionEquals(nameof(Stream), "Video", inverse: true)]
|
||||
[TextVariable(4)]
|
||||
public string Language { get; set; }
|
||||
|
||||
[ConditionEquals(nameof(Stream), "Audio")]
|
||||
[NumberInt(5)]
|
||||
public float Channels { get; set; }
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
var videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
bool found = false;
|
||||
if (this.Stream == "Video")
|
||||
{
|
||||
found = videoInfo.VideoStreams.Where(x =>
|
||||
{
|
||||
if (TitleMatches(x.Title))
|
||||
return false;
|
||||
if (CodecMatches(x.Codec))
|
||||
return false;
|
||||
return true;
|
||||
}).Any();
|
||||
}
|
||||
else if (this.Stream == "Audio")
|
||||
{
|
||||
found = videoInfo.AudioStreams.Where(x =>
|
||||
{
|
||||
if (TitleMatches(x.Title))
|
||||
return false;
|
||||
if (CodecMatches(x.Codec))
|
||||
return false;
|
||||
if (LanguageMatches(x.Codec))
|
||||
return false;
|
||||
if (this.Channels > 0 && Math.Abs(x.Channels - this.Channels) > 0.05f)
|
||||
return false;
|
||||
return true;
|
||||
}).Any();
|
||||
}
|
||||
else if (this.Stream == "Subtitle")
|
||||
{
|
||||
found = videoInfo.SubtitleStreams.Where(x =>
|
||||
{
|
||||
if (TitleMatches(x.Title))
|
||||
return false;
|
||||
if (CodecMatches(x.Codec))
|
||||
return false;
|
||||
if (LanguageMatches(x.Codec))
|
||||
return false;
|
||||
return true;
|
||||
}).Any();
|
||||
}
|
||||
|
||||
return found ? 1 : 2;
|
||||
}
|
||||
|
||||
private bool TitleMatches(string value) => ValueMatch(this.Title, value);
|
||||
private bool CodecMatches(string value) => ValueMatch(this.Codec, value);
|
||||
private bool LanguageMatches(string value) => ValueMatch(this.Language, value);
|
||||
private bool ValueMatch(string pattern, string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pattern))
|
||||
return true; // no test, it matches
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return false;
|
||||
var rgx = new Regex(pattern, RegexOptions.IgnoreCase);
|
||||
return rgx.IsMatch(value);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
new ListOption { Label = "Video", Value = "Video" },
|
||||
new ListOption { Label = "Audio", Value = "Audio" },
|
||||
new ListOption { Label = "Subtitle", Value = "Subtitle" }
|
||||
};
|
||||
}
|
||||
return _StreamTypeOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TextVariable(2)]
|
||||
public string Title { get; set; }
|
||||
|
||||
[TextVariable(3)]
|
||||
public string Codec { get; set; }
|
||||
|
||||
[ConditionEquals(nameof(Stream), "Video", inverse: true)]
|
||||
[TextVariable(4)]
|
||||
public string Language { get; set; }
|
||||
|
||||
[ConditionEquals(nameof(Stream), "Audio")]
|
||||
[NumberInt(5)]
|
||||
public float Channels { get; set; }
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
var videoInfo = GetVideoInfo(args);
|
||||
if (videoInfo == null)
|
||||
return -1;
|
||||
|
||||
bool found = false;
|
||||
if (this.Stream == "Video")
|
||||
{
|
||||
found = videoInfo.VideoStreams.Where(x =>
|
||||
{
|
||||
if (TitleMatches(x.Title) == MatchResult.NoMatch)
|
||||
return false;
|
||||
if (CodecMatches(x.Codec) == MatchResult.NoMatch)
|
||||
return false;
|
||||
return true;
|
||||
}).Any();
|
||||
}
|
||||
else if (this.Stream == "Audio")
|
||||
{
|
||||
found = videoInfo.AudioStreams.Where(x =>
|
||||
{
|
||||
if (TitleMatches(x.Title) == MatchResult.NoMatch)
|
||||
return false;
|
||||
if (CodecMatches(x.Codec) == MatchResult.NoMatch)
|
||||
return false;
|
||||
if (LanguageMatches(x.Codec) == MatchResult.NoMatch)
|
||||
return false;
|
||||
if (this.Channels > 0 && Math.Abs(x.Channels - this.Channels) > 0.05f)
|
||||
return false;
|
||||
return true;
|
||||
}).Any();
|
||||
}
|
||||
else if (this.Stream == "Subtitle")
|
||||
{
|
||||
found = videoInfo.SubtitleStreams.Where(x =>
|
||||
{
|
||||
if (TitleMatches(x.Title) == MatchResult.NoMatch)
|
||||
return false;
|
||||
if (CodecMatches(x.Codec) == MatchResult.NoMatch)
|
||||
return false;
|
||||
if (LanguageMatches(x.Codec) == MatchResult.NoMatch)
|
||||
return false;
|
||||
return true;
|
||||
}).Any();
|
||||
}
|
||||
|
||||
return found ? 1 : 2;
|
||||
}
|
||||
|
||||
private MatchResult TitleMatches(string value) => ValueMatch(this.Title, value);
|
||||
private MatchResult CodecMatches(string value) => ValueMatch(this.Codec, value);
|
||||
private MatchResult LanguageMatches(string value) => ValueMatch(this.Language, value);
|
||||
private MatchResult ValueMatch(string pattern, string value)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(pattern))
|
||||
return MatchResult.Skipped;
|
||||
try
|
||||
{
|
||||
|
||||
if (string.IsNullOrEmpty(value))
|
||||
return MatchResult.NoMatch;
|
||||
var rgx = new Regex(pattern, RegexOptions.IgnoreCase);
|
||||
if(rgx.IsMatch(value))
|
||||
return MatchResult.Matched;
|
||||
|
||||
if (value.ToLower() == "hevc" && pattern.ToLower() == "h265")
|
||||
return MatchResult.Matched; // special case
|
||||
|
||||
return MatchResult.NoMatch;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return MatchResult.NoMatch;
|
||||
}
|
||||
}
|
||||
|
||||
private enum MatchResult
|
||||
{
|
||||
NoMatch = 0,
|
||||
Matched = 1,
|
||||
Skipped = 2
|
||||
}
|
||||
}
|
||||
|
||||
166
VideoNodes/Tests/VideoHasStreamTests.cs
Normal file
166
VideoNodes/Tests/VideoHasStreamTests.cs
Normal file
@@ -0,0 +1,166 @@
|
||||
#if(DEBUG)
|
||||
|
||||
namespace VideoNodes.Tests;
|
||||
|
||||
using FileFlows.VideoNodes;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[TestClass]
|
||||
public class VideoHasStreamTests : TestBase
|
||||
{
|
||||
[TestMethod]
|
||||
public void VideoHasStream_Video_H264()
|
||||
{
|
||||
string file = TestFile_BasicMkv;
|
||||
var vi = new VideoInfoHelper(FfmpegPath, new TestLogger());
|
||||
var vii = vi.Read(file);
|
||||
|
||||
VideoHasStream node = new();
|
||||
node.Codec = "h264";
|
||||
node.Stream = "Video";
|
||||
|
||||
var args = new NodeParameters(file, new TestLogger(), false, string.Empty);
|
||||
args.GetToolPathActual = (string tool) => FfmpegPath;
|
||||
args.TempPath = TempPath;
|
||||
|
||||
var vf = new VideoFile();
|
||||
vf.PreExecute(args);
|
||||
Assert.AreEqual(1, vf.Execute(args));
|
||||
|
||||
int output = node.Execute(args);
|
||||
|
||||
Assert.AreEqual(1, output);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void VideoHasStream_Video_H265()
|
||||
{
|
||||
string file = TestFile_120_mbps_4k_uhd_hevc_10bit;
|
||||
var vi = new VideoInfoHelper(FfmpegPath, new TestLogger());
|
||||
var vii = vi.Read(file);
|
||||
|
||||
VideoHasStream node = new();
|
||||
node.Codec = "h265";
|
||||
node.Stream = "Video";
|
||||
|
||||
var args = new NodeParameters(file, new TestLogger(), false, string.Empty);
|
||||
args.GetToolPathActual = (string tool) => FfmpegPath;
|
||||
args.TempPath = TempPath;
|
||||
|
||||
var vf = new VideoFile();
|
||||
vf.PreExecute(args);
|
||||
Assert.AreEqual(1, vf.Execute(args));
|
||||
|
||||
int output = node.Execute(args);
|
||||
|
||||
Assert.AreEqual(1, output);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void VideoHasStream_Video_Hevc()
|
||||
{
|
||||
string file = TestFile_120_mbps_4k_uhd_hevc_10bit;
|
||||
var vi = new VideoInfoHelper(FfmpegPath, new TestLogger());
|
||||
var vii = vi.Read(file);
|
||||
|
||||
VideoHasStream node = new();
|
||||
node.Codec = "h265";
|
||||
node.Stream = "Video";
|
||||
|
||||
var args = new NodeParameters(file, new TestLogger(), false, string.Empty);
|
||||
args.GetToolPathActual = (string tool) => FfmpegPath;
|
||||
args.TempPath = TempPath;
|
||||
|
||||
var vf = new VideoFile();
|
||||
vf.PreExecute(args);
|
||||
Assert.AreEqual(1, vf.Execute(args));
|
||||
|
||||
int output = node.Execute(args);
|
||||
|
||||
Assert.AreEqual(1, output);
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void VideoHasStream_Audio_Vorbis()
|
||||
{
|
||||
string file = TestFile_BasicMkv;
|
||||
var vi = new VideoInfoHelper(FfmpegPath, new TestLogger());
|
||||
var vii = vi.Read(file);
|
||||
|
||||
VideoHasStream node = new();
|
||||
node.Codec = "vorbis";
|
||||
node.Stream = "Audio";
|
||||
|
||||
var args = new NodeParameters(file, new TestLogger(), false, string.Empty);
|
||||
args.GetToolPathActual = (string tool) => FfmpegPath;
|
||||
args.TempPath = TempPath;
|
||||
|
||||
var vf = new VideoFile();
|
||||
vf.PreExecute(args);
|
||||
Assert.AreEqual(1, vf.Execute(args));
|
||||
|
||||
int output = node.Execute(args);
|
||||
|
||||
Assert.AreEqual(1, output);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void VideoHasStream_Audio_Channels_Pass()
|
||||
{
|
||||
string file = TestFile_BasicMkv;
|
||||
var vi = new VideoInfoHelper(FfmpegPath, new TestLogger());
|
||||
var vii = vi.Read(file);
|
||||
|
||||
VideoHasStream node = new();
|
||||
node.Channels = 5.1f;
|
||||
node.Stream = "Audio";
|
||||
|
||||
var args = new NodeParameters(file, new TestLogger(), false, string.Empty);
|
||||
args.GetToolPathActual = (string tool) => FfmpegPath;
|
||||
args.TempPath = TempPath;
|
||||
|
||||
var vf = new VideoFile();
|
||||
vf.PreExecute(args);
|
||||
Assert.AreEqual(1, vf.Execute(args));
|
||||
|
||||
int output = node.Execute(args);
|
||||
|
||||
Assert.AreEqual(1, output);
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void VideoHasStream_Audio_Channels_Fail()
|
||||
{
|
||||
string file = TestFile_BasicMkv;
|
||||
var vi = new VideoInfoHelper(FfmpegPath, new TestLogger());
|
||||
var vii = vi.Read(file);
|
||||
|
||||
VideoHasStream node = new();
|
||||
node.Channels = 2;
|
||||
node.Stream = "Audio";
|
||||
|
||||
var args = new NodeParameters(file, new TestLogger(), false, string.Empty);
|
||||
args.GetToolPathActual = (string tool) => FfmpegPath;
|
||||
args.TempPath = TempPath;
|
||||
|
||||
var vf = new VideoFile();
|
||||
vf.PreExecute(args);
|
||||
Assert.AreEqual(1, vf.Execute(args));
|
||||
|
||||
int output = node.Execute(args);
|
||||
|
||||
Assert.AreEqual(2, output);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user