mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-02-22 11:08:25 -06:00
FF-1332 - added new flow element audio bitrate matches
This commit is contained in:
@@ -56,19 +56,23 @@ public class CreateAudioBook: AudioNode
|
||||
/// <returns>the output to call next, -1 to abort flow, 0 to end flow</returns>
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
var ffmpeg = GetFFmpeg(args);
|
||||
if (string.IsNullOrEmpty(ffmpeg))
|
||||
var ffmpegExeResult = GetFFmpeg(args);
|
||||
if (ffmpegExeResult.Failed(out string ffmpegError))
|
||||
{
|
||||
args.FailureReason = "FFmpeg not found";
|
||||
args.FailureReason = ffmpegError;
|
||||
args.Logger?.ELog(ffmpegError);
|
||||
return -1;
|
||||
}
|
||||
string ffmpeg = ffmpegExeResult.Value;
|
||||
|
||||
var ffprobe = GetFFprobe(args);
|
||||
if (string.IsNullOrEmpty(ffprobe))
|
||||
var ffprobeResult = GetFFprobe(args);
|
||||
if (ffmpegExeResult.Failed(out string ffprobeError))
|
||||
{
|
||||
args.FailureReason = "FFprobe not found";
|
||||
args.FailureReason = ffprobeError;
|
||||
args.Logger?.ELog(ffprobeError);
|
||||
return -1;
|
||||
}
|
||||
string ffprobe = ffprobeResult.Value;
|
||||
|
||||
var dir = args.IsDirectory ? args.WorkingFile : FileHelper.GetDirectory(args.WorkingFile);
|
||||
|
||||
|
||||
@@ -7,6 +7,20 @@
|
||||
"1": "Audio file from library"
|
||||
}
|
||||
},
|
||||
"AudioBitrateMatches": {
|
||||
"Label": "Audio Bitrate Matches",
|
||||
"Description": "Check if an audio bitrate matches the constraints.",
|
||||
"Fields": {
|
||||
"Match": "Match",
|
||||
"BitrateKilobytes": "Bitrate",
|
||||
"BitrateKilobytes-Suffix": "Kilobytes",
|
||||
"BitrateKilobytes-Help": "The bitrate in kilobytes to run the match against."
|
||||
},
|
||||
"Outputs": {
|
||||
"1": "Does match",
|
||||
"2": "Does not match"
|
||||
}
|
||||
},
|
||||
"AudioFileNormalization": {
|
||||
"Description": "Normalizes an audio file using two passes of FFMPEGs loudnorm filter",
|
||||
"Outputs": {
|
||||
|
||||
@@ -39,19 +39,23 @@ namespace FileFlows.AudioNodes
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
string ffmpegExe = GetFFmpeg(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
var ffmpegExeResult = GetFFmpeg(args);
|
||||
if (ffmpegExeResult.Failed(out string ffmpegError))
|
||||
{
|
||||
args.FailureReason = "FFmpeg not found";
|
||||
args.FailureReason = ffmpegError;
|
||||
args.Logger?.ELog(ffmpegError);
|
||||
return -1;
|
||||
}
|
||||
|
||||
string ffprobe = GetFFprobe(args);
|
||||
if (string.IsNullOrEmpty(ffprobe))
|
||||
string ffmpegExe = ffmpegExeResult.Value;
|
||||
|
||||
var ffprobeResult = GetFFprobe(args);
|
||||
if (ffmpegExeResult.Failed(out string ffprobeError))
|
||||
{
|
||||
args.FailureReason = "FFprobe not found";
|
||||
args.FailureReason = ffprobeError;
|
||||
args.Logger?.ELog(ffprobeError);
|
||||
return -1;
|
||||
}
|
||||
string ffprobe = ffprobeResult.Value;
|
||||
|
||||
|
||||
if (args.FileService.FileCreationTimeUtc(args.WorkingFile).Success(out DateTime createTime))
|
||||
@@ -66,9 +70,15 @@ namespace FileFlows.AudioNodes
|
||||
return 1;
|
||||
|
||||
var AudioInfo = GetAudioInfo(args);
|
||||
if (AudioInfo.Failed(out string error))
|
||||
{
|
||||
args.FailureReason = error;
|
||||
args.Logger?.ELog(error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(AudioInfo.Codec) == false)
|
||||
args.RecordStatistic("CODEC", AudioInfo.Codec);
|
||||
if (string.IsNullOrEmpty(AudioInfo.Value.Codec) == false)
|
||||
args.RecordStatistic("CODEC", AudioInfo.Value.Codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
123
AudioNodes/Nodes/AudioBitrateMatches.cs
Normal file
123
AudioNodes/Nodes/AudioBitrateMatches.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
namespace FileFlows.AudioNodes;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a audio files bitrate matches the condition
|
||||
/// </summary>
|
||||
public class AudioBitrateMatches : AudioNode
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override int Inputs => 1;
|
||||
/// <inheritdoc />
|
||||
public override int Outputs => 2;
|
||||
/// <inheritdoc />
|
||||
public override string HelpUrl => "https://fileflows.com/docs/plugins/audio-nodes/audio-bitrate-matches";
|
||||
/// <inheritdoc />
|
||||
public override FlowElementType Type => FlowElementType.Logic;
|
||||
/// <inheritdoc />
|
||||
public override string Icon => "fas fa-question";
|
||||
|
||||
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 = "<=";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the method to match
|
||||
/// </summary>
|
||||
[Select(nameof(MatchOptions), 1)]
|
||||
public string Match { get; set; }
|
||||
|
||||
private static List<ListOption> _MatchOptions;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the match options
|
||||
/// </summary>
|
||||
public static List<ListOption> MatchOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_MatchOptions == null)
|
||||
{
|
||||
_MatchOptions = new List<ListOption>
|
||||
{
|
||||
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},
|
||||
};
|
||||
}
|
||||
|
||||
return _MatchOptions;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the bitrate value to check
|
||||
/// </summary>
|
||||
[NumberInt(2)]
|
||||
public int BitrateKilobytes { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
var audioInfoResult = GetAudioInfo(args);
|
||||
if (audioInfoResult.Failed(out string error))
|
||||
{
|
||||
args.Logger?.ELog(error);
|
||||
args.FailureReason = error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
var audioInfo = audioInfoResult.Value;
|
||||
|
||||
var bitrate = audioInfo.Bitrate;
|
||||
long expected = BitrateKilobytes * 1000;
|
||||
|
||||
return DoMatch(args.Logger, Match, bitrate, expected) ? 1 : 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the match check
|
||||
/// </summary>
|
||||
/// <param name="logger">the logger</param>
|
||||
/// <param name="match">the match to test</param>
|
||||
/// <param name="bitrate">the actual bitrate</param>
|
||||
/// <param name="expected">the expected bitrate</param>
|
||||
/// <returns>true if matches, otherwise false</returns>
|
||||
internal static bool DoMatch(ILogger logger, string match, long bitrate, long expected)
|
||||
{
|
||||
bool matches = false;
|
||||
switch (match)
|
||||
{
|
||||
case MATCH_EQUALS:
|
||||
matches = bitrate == expected;
|
||||
break;
|
||||
case MATCH_NOT_EQUALS:
|
||||
matches = bitrate != expected;
|
||||
break;
|
||||
case MATCH_LESS_THAN:
|
||||
matches = bitrate < expected;
|
||||
break;
|
||||
case MATCH_LESS_THAN_OR_EQUAL:
|
||||
matches = bitrate <= expected;
|
||||
break;
|
||||
case MATCH_GREATER_THAN:
|
||||
matches = bitrate > expected;
|
||||
break;
|
||||
case MATCH_GREATER_THAN_OR_EQUAL:
|
||||
matches = bitrate >= expected;
|
||||
break;
|
||||
}
|
||||
|
||||
if(matches)
|
||||
logger?.ILog($"Bitrate matches expected: {bitrate} {match} {expected}");
|
||||
else
|
||||
logger?.ILog($"Bitrate does not match expected: {bitrate} {match} {expected}");
|
||||
|
||||
return matches;
|
||||
}
|
||||
}
|
||||
@@ -20,13 +20,24 @@ public class AudioFileNormalization : AudioNode
|
||||
{
|
||||
try
|
||||
{
|
||||
string ffmpegExe = GetFFmpeg(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
var ffmpegExeResult = GetFFmpeg(args);
|
||||
if (ffmpegExeResult.Failed(out string ffmpegError))
|
||||
{
|
||||
args.FailureReason = ffmpegError;
|
||||
args.Logger?.ELog(ffmpegError);
|
||||
return -1;
|
||||
}
|
||||
string ffmpegExe = ffmpegExeResult.Value;
|
||||
|
||||
AudioInfo AudioInfo = GetAudioInfo(args);
|
||||
if (AudioInfo == null)
|
||||
var audioInfoResult = GetAudioInfo(args);
|
||||
if (audioInfoResult.Failed(out string error))
|
||||
{
|
||||
args.Logger?.ELog(error);
|
||||
args.FailureReason = error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
AudioInfo AudioInfo = audioInfoResult.Value;
|
||||
|
||||
List<string> ffArgs = new List<string>();
|
||||
|
||||
|
||||
@@ -21,36 +21,36 @@ namespace FileFlows.AudioNodes
|
||||
return true;
|
||||
}
|
||||
|
||||
protected string GetFFmpeg(NodeParameters args)
|
||||
/// <summary>
|
||||
/// Gets the FFmpeg location
|
||||
/// </summary>
|
||||
/// <param name="args">the node parameters</param>
|
||||
/// <returns>the FFmpeg location</returns>
|
||||
protected Result<string> GetFFmpeg(NodeParameters args)
|
||||
{
|
||||
string ffmpeg = args.GetToolPath("FFMpeg");
|
||||
if (string.IsNullOrEmpty(ffmpeg))
|
||||
{
|
||||
args.Logger.ELog("FFmpeg tool not found.");
|
||||
return "";
|
||||
}
|
||||
return Result<string>.Fail("FFmpeg tool not found.");
|
||||
var fileInfo = new System.IO.FileInfo(ffmpeg);
|
||||
if (fileInfo.Exists == false)
|
||||
{
|
||||
args.Logger.ELog("FFmpeg tool configured by ffmpeg file does not exist.");
|
||||
return "";
|
||||
}
|
||||
Result<string>.Fail("FFmpeg tool configured by ffmpeg file does not exist.");
|
||||
return fileInfo.FullName;
|
||||
}
|
||||
protected string GetFFprobe(NodeParameters args)
|
||||
|
||||
/// <summary>
|
||||
/// Gets the FFprobe location
|
||||
/// </summary>
|
||||
/// <param name="args">the node parameters</param>
|
||||
/// <returns>the FFprobe location</returns>
|
||||
protected Result<string> GetFFprobe(NodeParameters args)
|
||||
{
|
||||
string ffmpeg = args.GetToolPath("FFprobe");
|
||||
if (string.IsNullOrEmpty(ffmpeg))
|
||||
{
|
||||
args.Logger.ELog("FFprobe tool not found.");
|
||||
return "";
|
||||
}
|
||||
return Result<string>.Fail("FFprobe tool not found.");
|
||||
|
||||
var fileInfo = new System.IO.FileInfo(ffmpeg);
|
||||
if (fileInfo.Exists == false)
|
||||
{
|
||||
args.Logger.ELog("FFprobe tool configured by ffmpeg file does not exist.");
|
||||
return "";
|
||||
}
|
||||
return Result<string>.Fail("FFprobe tool configured by ffmpeg file does not exist.");
|
||||
return fileInfo.FullName;
|
||||
}
|
||||
|
||||
@@ -122,20 +122,18 @@ namespace FileFlows.AudioNodes
|
||||
return;
|
||||
dict.Add(name, value);
|
||||
}
|
||||
|
||||
protected AudioInfo GetAudioInfo(NodeParameters args)
|
||||
|
||||
/// <summary>
|
||||
/// Gets the audio information previously read into the flow
|
||||
/// </summary>
|
||||
/// <param name="args">the node parameters</param>
|
||||
/// <returns>the audio information</returns>
|
||||
protected Result<AudioInfo> GetAudioInfo(NodeParameters args)
|
||||
{
|
||||
if (args.Parameters.ContainsKey(Audio_INFO) == false)
|
||||
{
|
||||
args.Logger.WLog("No codec information loaded, use a 'Audio File' node first");
|
||||
return null;
|
||||
}
|
||||
var result = args.Parameters[Audio_INFO] as AudioInfo;
|
||||
if (result == null)
|
||||
{
|
||||
args.Logger.WLog("AudioInfo not found for file");
|
||||
return null;
|
||||
}
|
||||
return Result<AudioInfo>.Fail("No codec information loaded, use a 'Audio File' node first");
|
||||
if (args.Parameters[Audio_INFO] is AudioInfo result == false)
|
||||
return Result<AudioInfo>.Fail("AudioInfo not found for file");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using FileFlows.AudioNodes.Helpers;
|
||||
using FileFlows.Plugin;
|
||||
using FileFlows.Plugin.Attributes;
|
||||
|
||||
namespace FileFlows.AudioNodes
|
||||
{
|
||||
@@ -99,9 +97,15 @@ namespace FileFlows.AudioNodes
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
AudioInfo AudioInfo = GetAudioInfo(args);
|
||||
if (AudioInfo == null)
|
||||
var audioInfoResult = GetAudioInfo(args);
|
||||
if (audioInfoResult.Failed(out string error))
|
||||
{
|
||||
args.Logger?.ELog(error);
|
||||
args.FailureReason = error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
AudioInfo AudioInfo = audioInfoResult.Value;
|
||||
|
||||
string ffmpegExe = GetFFmpeg(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
@@ -122,7 +126,7 @@ namespace FileFlows.AudioNodes
|
||||
|
||||
protected long GetSourceBitrate(NodeParameters args)
|
||||
{
|
||||
var info = GetAudioInfo(args);
|
||||
var info = GetAudioInfo(args).Value;
|
||||
return info.Bitrate;
|
||||
}
|
||||
|
||||
@@ -307,13 +311,23 @@ namespace FileFlows.AudioNodes
|
||||
if (AudioInfo == null)
|
||||
return -1;
|
||||
|
||||
string ffmpegExe = GetFFmpeg(args);
|
||||
if (string.IsNullOrEmpty(ffmpegExe))
|
||||
var ffmpegExeResult = GetFFmpeg(args);
|
||||
if (ffmpegExeResult.Failed(out string ffmpegError))
|
||||
{
|
||||
args.FailureReason = ffmpegError;
|
||||
args.Logger?.ELog(ffmpegError);
|
||||
return -1;
|
||||
}
|
||||
string ffmpegExe = ffmpegExeResult.Value;
|
||||
|
||||
string ffprobe = GetFFprobe(args);
|
||||
if (string.IsNullOrEmpty(ffprobe))
|
||||
var ffprobeResult = GetFFprobe(args);
|
||||
if (ffmpegExeResult.Failed(out string ffprobeError))
|
||||
{
|
||||
args.FailureReason = ffprobeError;
|
||||
args.Logger?.ELog(ffprobeError);
|
||||
return -1;
|
||||
}
|
||||
string ffprobe = ffprobeResult.Value;
|
||||
|
||||
if(Normalize == false && AudioInfo.Codec?.ToLower() == Extension?.ToLower())
|
||||
{
|
||||
|
||||
44
AudioNodes/Tests/AudioBitrateMatchesTests.cs
Normal file
44
AudioNodes/Tests/AudioBitrateMatchesTests.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
#if(DEBUG)
|
||||
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace FileFlows.AudioNodes.Tests;
|
||||
[TestClass]
|
||||
public class AudioBitrateMatchesTests
|
||||
{
|
||||
const string file = @"/home/john/Music/test/test.mp3";
|
||||
readonly string ffmpegExe = (OperatingSystem.IsLinux() ? "/usr/bin/ffmpeg" : @"C:\utils\ffmpeg\ffmpeg.exe");
|
||||
readonly string ffprobe = (OperatingSystem.IsLinux() ? "/usr/bin/ffprobe" : @"C:\utils\ffmpeg\ffprobe.exe");
|
||||
|
||||
[TestMethod]
|
||||
public void AudioInfo_SplitTrack()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
Assert.IsFalse(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_GREATER_THAN, 90, 100));
|
||||
Assert.IsFalse(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_GREATER_THAN, 100, 100));
|
||||
Assert.IsFalse(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_GREATER_THAN_OR_EQUAL, 90, 100));
|
||||
Assert.IsFalse(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_GREATER_THAN_OR_EQUAL, 99, 100));
|
||||
Assert.IsFalse(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_LESS_THAN, 110, 100));
|
||||
Assert.IsFalse(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_LESS_THAN, 100, 100));
|
||||
Assert.IsFalse(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_LESS_THAN_OR_EQUAL, 110, 100));
|
||||
Assert.IsFalse(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_LESS_THAN_OR_EQUAL, 101, 100));
|
||||
Assert.IsFalse(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_NOT_EQUALS, 100, 100));
|
||||
Assert.IsFalse(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_EQUALS, 90, 100));
|
||||
|
||||
Assert.IsTrue(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_GREATER_THAN, 110, 100));
|
||||
Assert.IsTrue(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_GREATER_THAN, 101, 100));
|
||||
Assert.IsTrue(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_GREATER_THAN_OR_EQUAL, 110, 100));
|
||||
Assert.IsTrue(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_GREATER_THAN_OR_EQUAL, 100, 100));
|
||||
Assert.IsTrue(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_LESS_THAN, 90, 100));
|
||||
Assert.IsTrue(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_LESS_THAN, 99, 100));
|
||||
Assert.IsTrue(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_LESS_THAN_OR_EQUAL, 90, 100));
|
||||
Assert.IsTrue(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_LESS_THAN_OR_EQUAL, 100, 100));
|
||||
Assert.IsTrue(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_NOT_EQUALS, 99, 100));
|
||||
Assert.IsTrue(AudioBitrateMatches.DoMatch(logger, AudioBitrateMatches.MATCH_EQUALS, 100, 100));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user