mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2025-12-30 03:49:44 -06:00
FF-1775: Updated track sorter to use String Operations
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -213,7 +213,9 @@ public class FfmpegBuilderTrackSorter : FfmpegBuilderNode
|
||||
sorterLength = 2;
|
||||
}
|
||||
|
||||
var sortValue = Math.Round(SortValue(args, stream, Sorters[i], sorterLength)).ToString(CultureInfo.InvariantCulture);
|
||||
var sortValue = Math.Round(SortValue(args, stream, Sorters[i], sorterLength))
|
||||
.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
// Trim the sort value to sorter Length characters
|
||||
string trimmedValue = sortValue[..Math.Min(sortValue.Length, sorterLength)];
|
||||
|
||||
@@ -226,30 +228,6 @@ public class FfmpegBuilderTrackSorter : FfmpegBuilderNode
|
||||
|
||||
return sortKey.TrimEnd('|');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if two lists are the same
|
||||
/// </summary>
|
||||
/// <param name="original">the original list</param>
|
||||
/// <param name="reordered">the reordered list</param>
|
||||
/// <typeparam name="T">the type of items</typeparam>
|
||||
/// <returns>true if the lists are the same, otherwise false</returns>
|
||||
public bool AreSame<T>(List<T> original, List<T> reordered) where T : FfmpegStream
|
||||
{
|
||||
for (int i = 0; i < reordered.Count; i++)
|
||||
{
|
||||
if (reordered[i] != original[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the sort value for a stream property based on the specified sorter.
|
||||
@@ -284,17 +262,10 @@ public class FfmpegBuilderTrackSorter : FfmpegBuilderNode
|
||||
|
||||
if (property == nameof(stream.Language))
|
||||
{
|
||||
object? oOriginalLanguage = null;
|
||||
args?.Variables?.TryGetValue("OriginalLanguage", out oOriginalLanguage);
|
||||
var originalLanguage = LanguageHelper.GetIso2Code(oOriginalLanguage?.ToString() ?? string.Empty);
|
||||
comparison = string.Join("|",
|
||||
comparison.Split('|', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x =>
|
||||
{
|
||||
if (x?.ToLowerInvariant()?.StartsWith("orig") == true)
|
||||
return originalLanguage;
|
||||
return LanguageHelper.GetIso2Code(x);
|
||||
}).Where(x => string.IsNullOrWhiteSpace(x) == false).ToArray());
|
||||
bool matches = LanguageHelper.Matches(args, comparison, stream.Language);
|
||||
if (invert)
|
||||
return matches ? 1 : 0;
|
||||
return matches ? 0 : 1;
|
||||
}
|
||||
|
||||
var value = property switch
|
||||
@@ -320,129 +291,16 @@ public class FfmpegBuilderTrackSorter : FfmpegBuilderNode
|
||||
result = dblValue;
|
||||
}
|
||||
}
|
||||
else if (IsMathOperation(comparison))
|
||||
result = ApplyMathOperation(value.ToString(), comparison) ? 0 : 1;
|
||||
else if (GeneralHelper.IsRegex(comparison))
|
||||
result = Regex.IsMatch(value.ToString(), comparison, RegexOptions.IgnoreCase) ? 0 : 1;
|
||||
else if (args.MathHelper.IsMathOperation(comparison))
|
||||
result = args.MathHelper.IsTrue(comparison, value.ToString()) ? 0 : 1;
|
||||
else if (value != null && double.TryParse(value.ToString(), out double dbl))
|
||||
result = dbl;
|
||||
else if (property == nameof(FfmpegStream.Title) && string.IsNullOrWhiteSpace(comparison) == false && string.IsNullOrWhiteSpace(value?.ToString()) == false)
|
||||
result = value?.ToString()?.ToLowerInvariant()?.Contains(comparison.ToLowerInvariant()) == true ? 0 : 1;
|
||||
else
|
||||
result = string.Equals(value?.ToString() ?? string.Empty, comparison ?? string.Empty, StringComparison.OrdinalIgnoreCase) ? 0 : 1;
|
||||
result = args.StringHelper.Matches(comparison, value) ? 0 : 1;
|
||||
|
||||
return invert ? InvertBits(result, sorterLength) : result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adjusts the comparison string by handling common mistakes in units and converting them into full numbers.
|
||||
/// </summary>
|
||||
/// <param name="comparisonValue">The original comparison string to be adjusted.</param>
|
||||
/// <returns>The adjusted comparison string with corrected units or the original comparison if no adjustments are made.</returns>
|
||||
private static string AdjustComparisonValue(string comparisonValue)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(comparisonValue))
|
||||
return string.Empty;
|
||||
|
||||
string adjustedComparison = comparisonValue.ToLower().Trim();
|
||||
|
||||
// Handle common mistakes in units
|
||||
if (adjustedComparison.EndsWith("mbps"))
|
||||
{
|
||||
// Make an educated guess for Mbps to kbps conversion
|
||||
return adjustedComparison[..^4] switch
|
||||
{
|
||||
{ } value when double.TryParse(value, out var numericValue) => (numericValue * 1_000_000)
|
||||
.ToString(CultureInfo.InvariantCulture),
|
||||
_ => comparisonValue
|
||||
};
|
||||
}
|
||||
if (adjustedComparison.EndsWith("kbps"))
|
||||
{
|
||||
// Make an educated guess for kbps to bps conversion
|
||||
return adjustedComparison[..^4] switch
|
||||
{
|
||||
{ } value when double.TryParse(value, out var numericValue) => (numericValue * 1_000)
|
||||
.ToString(CultureInfo.InvariantCulture),
|
||||
_ => comparisonValue
|
||||
};
|
||||
}
|
||||
if (adjustedComparison.EndsWith("kb"))
|
||||
{
|
||||
return adjustedComparison[..^2] switch
|
||||
{
|
||||
{ } value when double.TryParse(value, out var numericValue) => (numericValue * 1_000 )
|
||||
.ToString(CultureInfo.InvariantCulture),
|
||||
_ => comparisonValue
|
||||
};
|
||||
}
|
||||
if (adjustedComparison.EndsWith("mb"))
|
||||
{
|
||||
return adjustedComparison[..^2] switch
|
||||
{
|
||||
{ } value when double.TryParse(value, out var numericValue) => (numericValue * 1_000_000 )
|
||||
.ToString(CultureInfo.InvariantCulture),
|
||||
_ => comparisonValue
|
||||
};
|
||||
}
|
||||
if (adjustedComparison.EndsWith("gb"))
|
||||
{
|
||||
return adjustedComparison[..^2] switch
|
||||
{
|
||||
{ } value when double.TryParse(value, out var numericValue) => (numericValue * 1_000_000_000 )
|
||||
.ToString(CultureInfo.InvariantCulture),
|
||||
_ => comparisonValue
|
||||
};
|
||||
}
|
||||
if (adjustedComparison.EndsWith("tb"))
|
||||
{
|
||||
return adjustedComparison[..^2] switch
|
||||
{
|
||||
{ } value when double.TryParse(value, out var numericValue) => (numericValue * 1_000_000_000_000)
|
||||
.ToString(CultureInfo.InvariantCulture),
|
||||
_ => comparisonValue
|
||||
};
|
||||
}
|
||||
|
||||
if (adjustedComparison.EndsWith("kib"))
|
||||
{
|
||||
return adjustedComparison[..^3] switch
|
||||
{
|
||||
{ } value when double.TryParse(value, out var numericValue) => (numericValue * 1_024 )
|
||||
.ToString(CultureInfo.InvariantCulture),
|
||||
_ => comparisonValue
|
||||
};
|
||||
}
|
||||
if (adjustedComparison.EndsWith("mib"))
|
||||
{
|
||||
return adjustedComparison[..^3] switch
|
||||
{
|
||||
{ } value when double.TryParse(value, out var numericValue) => (numericValue * 1_048_576 )
|
||||
.ToString(CultureInfo.InvariantCulture),
|
||||
_ => comparisonValue
|
||||
};
|
||||
}
|
||||
if (adjustedComparison.EndsWith("gib"))
|
||||
{
|
||||
return adjustedComparison[..^3] switch
|
||||
{
|
||||
{ } value when double.TryParse(value, out var numericValue) => (numericValue * 1_099_511_627_776 )
|
||||
.ToString(CultureInfo.InvariantCulture),
|
||||
_ => comparisonValue
|
||||
};
|
||||
}
|
||||
if (adjustedComparison.EndsWith("tib"))
|
||||
{
|
||||
return adjustedComparison[..^3] switch
|
||||
{
|
||||
{ } value when double.TryParse(value, out var numericValue) => (numericValue * 1_000_000_000_000)
|
||||
.ToString(CultureInfo.InvariantCulture),
|
||||
_ => comparisonValue
|
||||
};
|
||||
}
|
||||
return comparisonValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inverts the bits of a double value.
|
||||
/// </summary>
|
||||
@@ -474,49 +332,4 @@ public class FfmpegBuilderTrackSorter : FfmpegBuilderNode
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the comparison string represents a mathematical operation.
|
||||
/// </summary>
|
||||
/// <param name="comparison">The comparison string to check.</param>
|
||||
/// <returns>True if the comparison is a mathematical operation, otherwise false.</returns>
|
||||
private static bool IsMathOperation(string comparison)
|
||||
{
|
||||
// Check if the comparison string starts with <=, <, >, >=, ==, or =
|
||||
return new[] { "<=", "<", ">", ">=", "==", "=" }.Any(comparison.StartsWith);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a mathematical operation to the value based on the specified operation string.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to apply the operation to.</param>
|
||||
/// <param name="operation">The operation string representing the mathematical operation.</param>
|
||||
/// <returns>True if the mathematical operation is successful, otherwise false.</returns>
|
||||
private static bool ApplyMathOperation(string value, string operation)
|
||||
{
|
||||
// This is a basic example; you may need to handle different operators
|
||||
switch (operation.Substring(0, 2))
|
||||
{
|
||||
case "<=":
|
||||
return Convert.ToDouble(value) <= Convert.ToDouble(AdjustComparisonValue(operation[2..].Trim()));
|
||||
case ">=":
|
||||
return Convert.ToDouble(value) >= Convert.ToDouble(AdjustComparisonValue(operation[2..].Trim()));
|
||||
case "==":
|
||||
return Math.Abs(Convert.ToDouble(value) - Convert.ToDouble(AdjustComparisonValue(operation[2..].Trim()))) < 0.05f;
|
||||
case "!=":
|
||||
case "<>":
|
||||
return Math.Abs(Convert.ToDouble(value) - Convert.ToDouble(AdjustComparisonValue(operation[2..].Trim()))) > 0.05f;
|
||||
}
|
||||
|
||||
switch (operation.Substring(0, 1))
|
||||
{
|
||||
case "<":
|
||||
return Convert.ToDouble(value) < Convert.ToDouble(AdjustComparisonValue(operation[1..].Trim()));
|
||||
case ">":
|
||||
return Convert.ToDouble(value) > Convert.ToDouble(AdjustComparisonValue(operation[1..].Trim()));
|
||||
case "=":
|
||||
return Math.Abs(Convert.ToDouble(value) - Convert.ToDouble(AdjustComparisonValue(operation[1..].Trim()))) < 0.05f;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -250,7 +250,7 @@ public class VideoHasStream : VideoNode
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(lang) == false && LanguageMatches(args, lang, x.Language) == false)
|
||||
if (string.IsNullOrEmpty(lang) == false && LanguageHelper.Matches(args, lang, x.Language) == false)
|
||||
return false;
|
||||
|
||||
double xChannels = Math.Round(x.Channels, 1);
|
||||
@@ -295,7 +295,7 @@ public class VideoHasStream : VideoNode
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(lang) == false && LanguageMatches(args, lang, x.Language) == false)
|
||||
if (string.IsNullOrEmpty(lang) == false && LanguageHelper.Matches(args, lang, x.Language) == false)
|
||||
return false;
|
||||
|
||||
if (string.IsNullOrEmpty(Default) == false)
|
||||
@@ -330,45 +330,6 @@ public class VideoHasStream : VideoNode
|
||||
return found ? 1 : 2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if a language matches
|
||||
/// </summary>
|
||||
/// <param name="args">the node parameters</param>
|
||||
/// <param name="lang">the language string to test</param>
|
||||
/// <param name="streamLanguage">the language of the stream</param>
|
||||
/// <returns>the match result</returns>
|
||||
private bool LanguageMatches(NodeParameters args, string lang, string streamLanguage)
|
||||
{
|
||||
lang = args.ReplaceVariables(lang.Replace("{orig}", "{OriginalLanguage}"), stripMissing: false);
|
||||
if (args.Variables.TryGetValue("OriginalLanguage", out var oOrigLanguage) && oOrigLanguage is string origLanguage &&
|
||||
string.IsNullOrWhiteSpace(origLanguage) == false)
|
||||
{
|
||||
lang = lang.Replace("OriginalLanguage", origLanguage, StringComparison.InvariantCultureIgnoreCase);
|
||||
lang = lang.Replace("original", origLanguage);
|
||||
lang = lang.Replace("orig", origLanguage);
|
||||
}
|
||||
|
||||
string iso1 = LanguageHelper.GetIso1Code(streamLanguage);
|
||||
string iso2 = LanguageHelper.GetIso2Code(streamLanguage);
|
||||
string english = LanguageHelper.GetEnglishFor(streamLanguage);
|
||||
var iso1Matches = ValueMatch(lang, iso1) == MatchResult.Matched;
|
||||
var iso2Matches = ValueMatch(lang, iso2) == MatchResult.Matched;
|
||||
var engMatches = ValueMatch(lang, english) == MatchResult.Matched;
|
||||
|
||||
bool anyMatches = iso1Matches || iso2Matches || engMatches;
|
||||
if(anyMatches == false)
|
||||
{
|
||||
args.Logger.ILog("Language does not match: " + streamLanguage);
|
||||
return false;
|
||||
}
|
||||
if(iso1Matches)
|
||||
args.Logger?.ILog($"Language ISO-1 match found: '{iso1}' vs '{lang}'");
|
||||
if(iso2Matches)
|
||||
args.Logger?.ILog($"Language ISO-2 match found: '{iso2}' vs '{lang}'");
|
||||
if(engMatches)
|
||||
args.Logger?.ILog($"Language English match found: '{english}' vs '{lang}'");
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if a value matches the pattern
|
||||
|
||||
@@ -254,7 +254,7 @@ public class FfmpegBuilder_TrackSorterTests : VideoTestBase
|
||||
// Mock sorters by different properties
|
||||
trackSorter.Sorters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new ("Codec", "^ac3$"),
|
||||
new ("Codec", "/^ac3$/"),
|
||||
};
|
||||
|
||||
// Act
|
||||
@@ -271,6 +271,38 @@ public class FfmpegBuilder_TrackSorterTests : VideoTestBase
|
||||
Assert.AreEqual("2 / fr / eac3 / 5.1", streams[2].ToString());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessStreams_SortsStreamsBasedOnAc3()
|
||||
{
|
||||
// Arrange
|
||||
var trackSorter = new FfmpegBuilderTrackSorter();
|
||||
List<FfmpegAudioStream> streams = new List<FfmpegAudioStream>
|
||||
{
|
||||
new() { Index = 1, Channels = 2, Language = "en", Codec = "ac3" },
|
||||
new() { Index = 2, Channels = 5.1f, Language = "fr", Codec = "eac3" },
|
||||
new() { Index = 3, Channels = 7.1f, Language = "en", Codec = "ac3" },
|
||||
};
|
||||
|
||||
// Mock sorters by different properties
|
||||
trackSorter.Sorters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new ("Codec", "ac3"),
|
||||
};
|
||||
|
||||
// Act
|
||||
var result = trackSorter.ProcessStreams(args, streams);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, streams[0].Index);
|
||||
Assert.AreEqual(3, streams[1].Index);
|
||||
Assert.AreEqual(2, streams[2].Index);
|
||||
|
||||
// Additional assertions for logging
|
||||
Assert.AreEqual("1 / en / ac3 / 2.0", streams[0].ToString());
|
||||
Assert.AreEqual("3 / en / ac3 / 7.1", streams[1].ToString());
|
||||
Assert.AreEqual("2 / fr / eac3 / 5.1", streams[2].ToString());
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessStreams_SortsStreamsBasedOnMultipleSorters()
|
||||
{
|
||||
@@ -593,6 +625,54 @@ public class FfmpegBuilder_TrackSorterTests : VideoTestBase
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessStreams_SortsStreamsBasedOnLanguage_EndsWith()
|
||||
{
|
||||
// Arrange
|
||||
var trackSorter = new FfmpegBuilderTrackSorter();
|
||||
List<FfmpegAudioStream> streams = new List<FfmpegAudioStream>
|
||||
{
|
||||
new() { Index = 1, Channels = 2, Language = "eng", Codec = "aac" },
|
||||
new() { Index = 2, Channels = 2, Language = "fr", Codec = "aac" },
|
||||
new() { Index = 3, Channels = 5.1f, Language = "en", Codec = "eac3" },
|
||||
new() { Index = 4, Channels = 5.1f, Language = "ger", Codec = "ac3" },
|
||||
new() { Index = 5, Channels = 5.1f, Language = "German", Codec = "dts" },
|
||||
new() { Index = 6, Channels = 5.1f, Language = "English", Codec = "aac" },
|
||||
new() { Index = 7, Channels = 5.1f, Language = "eng", Codec = "ac3" },
|
||||
};
|
||||
|
||||
// Mock sorters by different properties
|
||||
trackSorter.Sorters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new("Language", "*lish")
|
||||
};
|
||||
|
||||
// Act
|
||||
var sorted = trackSorter.SortStreams(args, streams);
|
||||
|
||||
// Assert
|
||||
Assert.AreEqual(1, sorted[0].Index);
|
||||
Assert.AreEqual(3, sorted[1].Index);
|
||||
Assert.AreEqual(6, sorted[2].Index);
|
||||
Assert.AreEqual(7, sorted[3].Index);
|
||||
|
||||
// non english
|
||||
Assert.AreEqual(2, sorted[4].Index);
|
||||
Assert.AreEqual(4, sorted[5].Index);
|
||||
Assert.AreEqual(5, sorted[6].Index);
|
||||
|
||||
// Additional assertions for logging
|
||||
Assert.AreEqual("eng", sorted[0].Language);
|
||||
Assert.AreEqual("en", sorted[1].Language);
|
||||
Assert.AreEqual("English", sorted[2].Language);
|
||||
Assert.AreEqual("eng", sorted[3].Language);
|
||||
|
||||
Assert.AreEqual("fr", sorted[4].Language);
|
||||
Assert.AreEqual("ger", sorted[5].Language);
|
||||
Assert.AreEqual("German", sorted[6].Language);
|
||||
}
|
||||
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void ProcessStreams_SortsStreamsBasedOnLanguageRegex()
|
||||
@@ -613,7 +693,7 @@ public class FfmpegBuilder_TrackSorterTests : VideoTestBase
|
||||
// Mock sorters by different properties
|
||||
trackSorter.Sorters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new("Language", "en|deu")
|
||||
new("Language", "/en|deu/")
|
||||
};
|
||||
|
||||
// Act
|
||||
@@ -663,7 +743,7 @@ public class FfmpegBuilder_TrackSorterTests : VideoTestBase
|
||||
// Mock sorters by different properties
|
||||
trackSorter.Sorters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new("Language", "orig|deu")
|
||||
new("Language", "/orig|deu/")
|
||||
};
|
||||
|
||||
// Act
|
||||
@@ -795,7 +875,7 @@ public class FfmpegBuilder_TrackSorterTests : VideoTestBase
|
||||
// Mock sorters by different properties
|
||||
trackSorter.Sorters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new("TitleDesc", "Commentary"),
|
||||
new("TitleDesc", "*Commentary*"),
|
||||
new("Language", "English")
|
||||
};
|
||||
trackSorter.StreamType = "Audio";
|
||||
|
||||
Reference in New Issue
Block a user