11using NLog ;
22using NzbDrone . Common . Instrumentation ;
33using System . Text . RegularExpressions ;
4+ using Tubifarry . Core . Model ;
45using Tubifarry . Core . Utilities ;
56
67namespace Tubifarry . Metadata . Converter
@@ -14,7 +15,12 @@ public class ConversionRule
1415 public int ? TargetBitrate { get ; set ; }
1516 public bool IsArtistRule { get ; set ; }
1617
17- public bool IsGlobalRule => SourceFormat . ToString ( ) . Equals ( RuleParser . GlobalRuleIdentifier , StringComparison . OrdinalIgnoreCase ) ;
18+ // Track the type of category rule
19+ public bool IsGlobalRule { get ; set ; }
20+ public bool IsLossyRule { get ; set ; }
21+ public bool IsLosslessRule { get ; set ; }
22+
23+ public bool IsCategoryRule => IsGlobalRule || IsLossyRule || IsLosslessRule ;
1824
1925 public bool MatchesBitrate ( int ? currentBitrate )
2026 {
@@ -26,6 +32,20 @@ public bool MatchesBitrate(int? currentBitrate)
2632 return EvaluateBitrateCondition ( currentBitrate . Value ) ;
2733 }
2834
35+ public bool MatchesFormat ( AudioFormat trackFormat )
36+ {
37+ if ( IsGlobalRule )
38+ return true ;
39+
40+ if ( IsLossyRule )
41+ return AudioFormatHelper . IsLossyFormat ( trackFormat ) ;
42+
43+ if ( IsLosslessRule )
44+ return ! AudioFormatHelper . IsLossyFormat ( trackFormat ) ;
45+
46+ return SourceFormat == trackFormat ;
47+ }
48+
2949 private bool HasBitrateConstraints ( ) => SourceBitrateOperator . HasValue && SourceBitrateValue . HasValue ;
3050
3151 private bool EvaluateBitrateCondition ( int currentBitrate )
@@ -51,7 +71,16 @@ private bool EvaluateBitrateCondition(int currentBitrate)
5171
5272 private string FormatSourcePart ( )
5373 {
54- string source = SourceFormat . ToString ( ) ;
74+ string source ;
75+ if ( IsGlobalRule )
76+ source = RuleParser . GlobalRuleIdentifier ;
77+ else if ( IsLossyRule )
78+ source = RuleParser . LossyRuleIdentifier ;
79+ else if ( IsLosslessRule )
80+ source = RuleParser . LosslessRuleIdentifier ;
81+ else
82+ source = SourceFormat . ToString ( ) ;
83+
5584 if ( HasBitrateConstraints ( ) )
5685 source += GetOperatorSymbol ( ) + SourceBitrateValue ! . Value ;
5786 return source ;
@@ -117,6 +146,8 @@ public enum ComparisonOperator
117146 public static class RuleParser
118147 {
119148 public const string GlobalRuleIdentifier = "all" ;
149+ public const string LossyRuleIdentifier = "lossy" ;
150+ public const string LosslessRuleIdentifier = "lossless" ;
120151 public const string NoConversionTag = "no-conversion" ;
121152 private static readonly Regex SourceFormatPattern = new ( @"^([a-zA-Z0-9]+)(?:([!<>=]{1,2})(\d+))?$" , RegexOptions . Compiled ) ;
122153 private static readonly Regex TargetFormatPattern = new ( @"^([a-zA-Z0-9]+)(?::(\d+)k?)?$" , RegexOptions . Compiled ) ;
@@ -193,6 +224,13 @@ private static bool ParseSourcePart(string sourceKey, ConversionRule rule)
193224
194225 if ( sourceMatch . Groups [ 2 ] . Success && sourceMatch . Groups [ 3 ] . Success )
195226 {
227+ // Category rules (all, lossy, lossless) cannot have bitrate constraints
228+ if ( rule . IsCategoryRule )
229+ {
230+ _logger . Warn ( "Invalid: Bitrate constraints not applicable to category rules (all, lossy, lossless)" ) ;
231+ return false ;
232+ }
233+
196234 if ( ! AudioFormatHelper . IsLossyFormat ( rule . SourceFormat ) )
197235 {
198236 _logger . Warn ( "Invalid: Bitrate constraints not applicable to lossless format" ) ;
@@ -211,6 +249,21 @@ private static bool ParseSourceFormat(string formatName, ConversionRule rule)
211249 if ( string . Equals ( formatName , GlobalRuleIdentifier , StringComparison . OrdinalIgnoreCase ) )
212250 {
213251 rule . SourceFormat = AudioFormat . Unknown ;
252+ rule . IsGlobalRule = true ;
253+ return true ;
254+ }
255+
256+ if ( string . Equals ( formatName , LossyRuleIdentifier , StringComparison . OrdinalIgnoreCase ) )
257+ {
258+ rule . SourceFormat = AudioFormat . Unknown ;
259+ rule . IsLossyRule = true ;
260+ return true ;
261+ }
262+
263+ if ( string . Equals ( formatName , LosslessRuleIdentifier , StringComparison . OrdinalIgnoreCase ) )
264+ {
265+ rule . SourceFormat = AudioFormat . Unknown ;
266+ rule . IsLosslessRule = true ;
214267 return true ;
215268 }
216269
@@ -264,6 +317,12 @@ private static bool ParseTargetFormat(string formatName, ConversionRule rule)
264317 return false ;
265318 }
266319
320+ if ( ! AudioMetadataHandler . IsTargetFormatSupportedForEncoding ( targetFormat ) )
321+ {
322+ _logger . Warn ( "Target format {0} is not supported for encoding by FFmpeg" , targetFormat ) ;
323+ return false ;
324+ }
325+
267326 rule . TargetFormat = targetFormat ;
268327 return true ;
269328 }
0 commit comments