Mka Support

add mka support
This commit is contained in:
sharinganthief 2026-04-14 10:56:34 -04:00
parent fd6f97640c
commit 6898ead35d
6 changed files with 68 additions and 4 deletions

View file

@ -18,7 +18,7 @@
<PackageReference Include="SourceGear.sqlite3" Version="3.50.4.2" />
<PackageReference Include="System.Data.SQLite" Version="2.0.2" />
<PackageReference Include="System.IO.Abstractions" Version="17.0.24" />
<PackageReference Include="System.Text.Json" Version="8.0.6" />
<PackageReference Include="System.Text.Json" Version="10.0.5" />
<PackageReference Include="System.ValueTuple" Version="4.6.1" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.1" />

View file

@ -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")]

View file

@ -8,7 +8,7 @@
<PackageReference Include="Equ" Version="2.3.0" />
<PackageReference Include="MailKit" Version="4.15.1" />
<PackageReference Include="Polly" Version="8.6.4" />
<PackageReference Include="System.Text.Json" Version="8.0.6" />
<PackageReference Include="System.Text.Json" Version="10.0.5" />
<PackageReference Include="System.Memory" Version="4.6.3" />
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.20" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.1" />

View file

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

View file

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

View file

@ -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(?:(?<S24>24[-._ ]?bit|flac24(?:[-._ ]?bit)?|tr24|24-(?:44|48|96|192)|[\[\(].*24bit.*[\]\)]))\b", RegexOptions.Compiled);
private static readonly Regex CodecRegex = new (@"\b(?:(?<MP1>MPEG Version \d(.5)? Audio, Layer 1|MP1)|(?<MP2>MPEG Version \d(.5)? Audio, Layer 2|MP2)|(?<MP3VBR>MP3.*VBR|MPEG Version \d(.5)? Audio, Layer 3 vbr)|(?<MP3CBR>MP3|MPEG Version \d(.5)? Audio, Layer 3)|(?<FLAC>(web)?flac(?:24(?:[-._ ]?bit)?)?|TR24)|(?<WAVPACK>wavpack|wv)|(?<ALAC>alac)|(?<WMA>WMA\d?)|(?<WAV>WAV|PCM)|(?<AAC>M4A|M4P|M4B|AAC|mp4a|MPEG-4 Audio(?!.*alac))|(?<OGG>OGG|OGA|Vorbis))\b|(?<APE>monkey's audio|[\[|\(].*\bape\b.*[\]|\)])|(?<OPUS>Opus Version \d(.5)? Audio|[\[|\(].*\bopus\b.*[\]|\)])",
private static readonly Regex CodecRegex = new (@"\b(?:(?<MP1>MPEG Version \d(.5)? Audio, Layer 1|MP1)|(?<MP2>MPEG Version \d(.5)? Audio, Layer 2|MP2)|(?<MP3VBR>MP3.*VBR|MPEG Version \d(.5)? Audio, Layer 3 vbr)|(?<MP3CBR>MP3|MPEG Version \d(.5)? Audio, Layer 3)|(?<FLAC>(web)?flac(?:24(?:[-._ ]?bit)?)?|TR24)|(?<WAVPACK>wavpack|wv)|(?<ALAC>alac)|(?<WMA>WMA\d?)|(?<WAV>WAV|PCM)|(?<AAC>M4A|M4P|M4B|AAC|mp4a|MPEG-4 Audio(?!.*alac))|(?<OGG>MKA|OGG|OGA|Vorbis))\b|(?<APE>monkey's audio|[\[|\(].*\bape\b.*[\]|\)])|(?<OPUS>Opus Version \d(.5)? Audio|[\[|\(].*\bopus\b.*[\]|\)])",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex WebRegex = new (@"\b(?<web>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+", "");