diff --git a/src/NzbDrone.Common/Lidarr.Common.csproj b/src/NzbDrone.Common/Lidarr.Common.csproj
index 21a822ea8..fb2096362 100644
--- a/src/NzbDrone.Common/Lidarr.Common.csproj
+++ b/src/NzbDrone.Common/Lidarr.Common.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs
index 5d22174ab..4dab3a8aa 100644
--- a/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs
+++ b/src/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs
@@ -297,6 +297,7 @@ public void should_parse_quality_from_name(string title)
[TestCase("01. Kanye West - Ultralight Beam.mp3")]
[TestCase("01. Kanye West - Ultralight Beam.ogg")]
+ [TestCase("01. Kanye West - Ultralight Beam.mka")]
// These get detected by name as we are looking for the extensions as identifiers for release names
// [TestCase("01. Kanye West - Ultralight Beam.m4a")]
diff --git a/src/NzbDrone.Core/Lidarr.Core.csproj b/src/NzbDrone.Core/Lidarr.Core.csproj
index d5eed7f10..ad9cce669 100644
--- a/src/NzbDrone.Core/Lidarr.Core.csproj
+++ b/src/NzbDrone.Core/Lidarr.Core.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/src/NzbDrone.Core/MediaFiles/AudioTag.cs b/src/NzbDrone.Core/MediaFiles/AudioTag.cs
index 500a94bed..e8a0cac39 100644
--- a/src/NzbDrone.Core/MediaFiles/AudioTag.cs
+++ b/src/NzbDrone.Core/MediaFiles/AudioTag.cs
@@ -177,7 +177,7 @@ public void Read(string path)
Logger.Debug("Audio Properties: " + acodec.Description + ", Bitrate: " + bitrate + ", Sample Size: " +
file.Properties.BitsPerSample + ", SampleRate: " + acodec.AudioSampleRate + ", Channels: " + acodec.AudioChannels);
- Quality = QualityParser.ParseQuality(file.Name, acodec.Description, bitrate, file.Properties.BitsPerSample);
+ Quality = QualityParser.ParseQualityFromCodec(file.Name, acodec, bitrate, file.Properties.BitsPerSample);
Logger.Debug($"Quality parsed: {Quality}, Source: {Quality.QualityDetectionSource}");
MediaInfo = new MediaInfoModel
diff --git a/src/NzbDrone.Core/MediaFiles/MediaFileExtensions.cs b/src/NzbDrone.Core/MediaFiles/MediaFileExtensions.cs
index b87fcc619..eef0523de 100644
--- a/src/NzbDrone.Core/MediaFiles/MediaFileExtensions.cs
+++ b/src/NzbDrone.Core/MediaFiles/MediaFileExtensions.cs
@@ -17,6 +17,7 @@ static MediaFileExtensions()
{ ".m4a", Quality.Unknown },
{ ".m4b", Quality.Unknown },
{ ".m4p", Quality.Unknown },
+ { ".mka", Quality.Unknown },
{ ".ogg", Quality.Unknown },
{ ".oga", Quality.Unknown },
{ ".opus", Quality.Unknown },
diff --git a/src/NzbDrone.Core/Parser/QualityParser.cs b/src/NzbDrone.Core/Parser/QualityParser.cs
index 1bfca5fea..43fb4f8f6 100644
--- a/src/NzbDrone.Core/Parser/QualityParser.cs
+++ b/src/NzbDrone.Core/Parser/QualityParser.cs
@@ -1,10 +1,13 @@
using System;
+using System.Reflection;
using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Qualities;
+using TagLib;
+using TagLib.Matroska;
namespace NzbDrone.Core.Parser
{
@@ -38,12 +41,46 @@ public class QualityParser
private static readonly Regex SampleSizeRegex = new (@"\b(?:(?24[-._ ]?bit|flac24(?:[-._ ]?bit)?|tr24|24-(?:44|48|96|192)|[\[\(].*24bit.*[\]\)]))\b", RegexOptions.Compiled);
- private static readonly Regex CodecRegex = new (@"\b(?:(?MPEG Version \d(.5)? Audio, Layer 1|MP1)|(?MPEG Version \d(.5)? Audio, Layer 2|MP2)|(?MP3.*VBR|MPEG Version \d(.5)? Audio, Layer 3 vbr)|(?MP3|MPEG Version \d(.5)? Audio, Layer 3)|(?(web)?flac(?:24(?:[-._ ]?bit)?)?|TR24)|(?wavpack|wv)|(?alac)|(?WMA\d?)|(?WAV|PCM)|(?M4A|M4P|M4B|AAC|mp4a|MPEG-4 Audio(?!.*alac))|(?OGG|OGA|Vorbis))\b|(?monkey's audio|[\[|\(].*\bape\b.*[\]|\)])|(?Opus Version \d(.5)? Audio|[\[|\(].*\bopus\b.*[\]|\)])",
+ private static readonly Regex CodecRegex = new (@"\b(?:(?MPEG Version \d(.5)? Audio, Layer 1|MP1)|(?MPEG Version \d(.5)? Audio, Layer 2|MP2)|(?MP3.*VBR|MPEG Version \d(.5)? Audio, Layer 3 vbr)|(?MP3|MPEG Version \d(.5)? Audio, Layer 3)|(?(web)?flac(?:24(?:[-._ ]?bit)?)?|TR24)|(?wavpack|wv)|(?alac)|(?WMA\d?)|(?WAV|PCM)|(?M4A|M4P|M4B|AAC|mp4a|MPEG-4 Audio(?!.*alac))|(?MKA|OGG|OGA|Vorbis))\b|(?monkey's audio|[\[|\(].*\bape\b.*[\]|\)])|(?Opus Version \d(.5)? Audio|[\[|\(].*\bopus\b.*[\]|\)])",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex WebRegex = new (@"\b(?WEB)(?:\b|$|[ .])",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ public static QualityModel ParseQualityFromCodec(string name, IAudioCodec audioCodec, int fileBitrate, int fileSampleSize = 0)
+ {
+ var normalizedName = name.Replace('_', ' ').Trim().ToLower();
+ var result = ParseQualityModifiers(name, normalizedName);
+
+ var codec = Codec.Unknown;
+ var bitrate = ParseBitRate(normalizedName);
+ var sampleSize = ParseSampleSize(normalizedName);
+
+ if (audioCodec != null)
+ {
+ if (audioCodec is AudioTrack matroskaCodec)
+ {
+ codec = ParseCodec(StealCodecFromMatroskaTrack(matroskaCodec), string.Empty);
+ }
+
+ if (codec == Codec.Unknown && audioCodec!.Description.IsNotNullOrWhiteSpace())
+ {
+ var descCodec = ParseCodec(audioCodec.Description, string.Empty);
+ Logger.Trace($"Got codec {descCodec}");
+
+ result.Quality = FindQuality(descCodec, fileBitrate, fileSampleSize);
+
+ if (result.Quality != Quality.Unknown)
+ {
+ result.QualityDetectionSource = QualityDetectionSource.TagLib;
+ return result;
+ }
+ }
+ }
+
+ return ParseQuality(result, codec, name, normalizedName, bitrate, sampleSize);
+ }
+
public static QualityModel ParseQuality(string name, string desc, int fileBitrate, int fileSampleSize = 0)
{
Logger.Debug("Trying to parse quality for '{0}'", name);
@@ -74,6 +111,17 @@ public static QualityModel ParseQuality(string name, string desc, int fileBitrat
var bitrate = ParseBitRate(normalizedName);
var sampleSize = ParseSampleSize(normalizedName);
+ return ParseQuality(result, codec, name, normalizedName, bitrate, sampleSize);
+ }
+
+ public static QualityModel ParseQuality(
+ QualityModel result,
+ Codec codec,
+ string name,
+ string normalizedName,
+ BitRate bitrate,
+ SampleSize sampleSize)
+ {
switch (codec)
{
case Codec.MP1:
@@ -333,6 +381,20 @@ public static Codec ParseCodec(string name, string origName)
return Codec.Unknown;
}
+ private static string StealCodecFromMatroskaTrack(AudioTrack matroskaCodec)
+ {
+ var field = typeof(Track)
+ .GetField("track_codec_id", BindingFlags.NonPublic | BindingFlags.Instance);
+
+ if (field == null)
+ {
+ return null;
+ }
+
+ var val = ((string)field.GetValue(matroskaCodec) ?? string.Empty).Replace("A_", string.Empty);
+ return val;
+ }
+
private static BitRate ParseBitRate(string name)
{
// var nameWithNoSpaces = Regex.Replace(name, @"\s+", "");