fixed issue with Video Has Stream not working

This commit is contained in:
John Andrews
2022-06-03 13:06:55 +12:00
parent c50277fd7b
commit b316625219
3 changed files with 291 additions and 111 deletions

1
.gitignore vendored
View File

@@ -17,3 +17,4 @@ Emby/settings.invalid.json
Emby/settings.json
VideoNodes/test.settings.dev.json
Apprise/settings.json
build/utils/PluginInfoGenerator/

View File

@@ -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
}
}

View 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