mirror of https://github.com/lidarr/Lidarr
Added: Monkey Audio and WavPack support (#455)
* Added: Monkey Audio and WavPack support * fixup! Add test case, fix typo
This commit is contained in:
parent
894385747e
commit
499af45566
|
@ -144,6 +144,32 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
{
|
||||
ParseAndVerifyQuality(title, desc, bitrate, Quality.ALAC);
|
||||
}
|
||||
|
||||
[TestCase("Stevie Ray Vaughan Discography (1981-1987) [APE]", null, 0)]
|
||||
[TestCase("Brain Ape - Rig it [2014][ape]", null, 0)]
|
||||
[TestCase("", "Monkey's Audio", 0)]
|
||||
public void should_parse_ape_quality(string title, string desc, int bitrate)
|
||||
{
|
||||
ParseAndVerifyQuality(title, desc, bitrate, Quality.APE);
|
||||
}
|
||||
|
||||
[TestCase("Max Roach - Drums Unlimited (1966) [WavPack]", null, 0)]
|
||||
[TestCase("Roxette - Charm School(2011) (2CD) [WV]", null, 0)]
|
||||
[TestCase("", "WavPack", 0)]
|
||||
public void should_parse_wavpack_quality(string title, string desc, int bitrate)
|
||||
{
|
||||
ParseAndVerifyQuality(title, desc, bitrate, Quality.WAVPACK);
|
||||
}
|
||||
|
||||
[TestCase("Arctic Monkeys - AM {2013-Album}", null, 0)]
|
||||
[TestCase("Audio Adrinaline - Audio Adrinaline", null, 0)]
|
||||
[TestCase("Brain Ape - Rig it [2014][flac]", null, 0)]
|
||||
[TestCase("Coil - The Ape Of Naples(2005) (FLAC)", null, 0)]
|
||||
public void should_not_parse_ape_quality(string title, string desc, int bitrate)
|
||||
{
|
||||
var result = QualityParser.ParseQuality(title, desc, bitrate);
|
||||
result.Quality.Should().NotBe(Quality.APE);
|
||||
}
|
||||
|
||||
[TestCase("Milky Chance - Sadnecessary [256 Kbps] [M4A]", null, 0)]
|
||||
[TestCase("Little Mix - Salute [Deluxe Edition] [2013] [M4A-256]-V3nom [GLT", null, 0)]
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using FluentMigrator;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(19)]
|
||||
public class add_ape_quality_in_profiles : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Execute.WithConnection(ConvertProfile);
|
||||
}
|
||||
|
||||
private void ConvertProfile(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
var updater = new ProfileUpdater19(conn, tran);
|
||||
|
||||
updater.SplitQualityAppend(6, 35); // APE after Flac
|
||||
updater.SplitQualityAppend(6, 36); // WavPack after Flac
|
||||
|
||||
updater.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public class Profile19
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int Cutoff { get; set; }
|
||||
public List<ProfileItem19> Items { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileItem19
|
||||
{
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public int? Quality { get; set; }
|
||||
|
||||
public bool Allowed { get; set; }
|
||||
public List<ProfileItem19> Items { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileUpdater19
|
||||
{
|
||||
private readonly IDbConnection _connection;
|
||||
private readonly IDbTransaction _transaction;
|
||||
|
||||
private List<Profile19> _profiles;
|
||||
private HashSet<Profile19> _changedProfiles = new HashSet<Profile19>();
|
||||
|
||||
public ProfileUpdater19(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
_connection = conn;
|
||||
_transaction = tran;
|
||||
|
||||
_profiles = GetProfiles();
|
||||
}
|
||||
|
||||
public void Commit()
|
||||
{
|
||||
foreach (var profile in _changedProfiles)
|
||||
{
|
||||
using (var updateProfileCmd = _connection.CreateCommand())
|
||||
{
|
||||
updateProfileCmd.Transaction = _transaction;
|
||||
updateProfileCmd.CommandText = "UPDATE Profiles SET Name = ?, Cutoff = ?, Items = ? WHERE Id = ?";
|
||||
updateProfileCmd.AddParameter(profile.Name);
|
||||
updateProfileCmd.AddParameter(profile.Cutoff);
|
||||
updateProfileCmd.AddParameter(profile.Items.ToJson());
|
||||
updateProfileCmd.AddParameter(profile.Id);
|
||||
|
||||
updateProfileCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
_changedProfiles.Clear();
|
||||
}
|
||||
|
||||
public void SplitQualityAppend(int find, int quality)
|
||||
{
|
||||
foreach (var profile in _profiles)
|
||||
{
|
||||
if (profile.Items.Any(v => v.Quality == quality)) continue;
|
||||
|
||||
var findIndex = profile.Items.FindIndex(v =>
|
||||
{
|
||||
return v.Quality == find || (v.Items != null && v.Items.Any(b => b.Quality == find));
|
||||
});
|
||||
|
||||
profile.Items.Insert(findIndex + 1, new ProfileItem19
|
||||
{
|
||||
Quality = quality,
|
||||
Allowed = false
|
||||
});
|
||||
|
||||
_changedProfiles.Add(profile);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Profile19> GetProfiles()
|
||||
{
|
||||
var profiles = new List<Profile19>();
|
||||
|
||||
using (var getProfilesCmd = _connection.CreateCommand())
|
||||
{
|
||||
getProfilesCmd.Transaction = _transaction;
|
||||
getProfilesCmd.CommandText = @"SELECT Id, Name, Cutoff, Items FROM Profiles";
|
||||
|
||||
using (var profileReader = getProfilesCmd.ExecuteReader())
|
||||
{
|
||||
while (profileReader.Read())
|
||||
{
|
||||
profiles.Add(new Profile19
|
||||
{
|
||||
Id = profileReader.GetInt32(0),
|
||||
Name = profileReader.GetString(1),
|
||||
Cutoff = profileReader.GetInt32(2),
|
||||
Items = Json.Deserialize<List<ProfileItem19>>(profileReader.GetString(3))
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return profiles;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,9 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{ ".ogg", Quality.Unknown },
|
||||
{ ".wma", Quality.WMA },
|
||||
{ ".wav", Quality.WAV },
|
||||
{ ".flac", Quality.FLAC }
|
||||
{ ".wv" , Quality.WAVPACK },
|
||||
{ ".flac", Quality.FLAC },
|
||||
{ ".ape", Quality.APE }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -190,6 +190,7 @@
|
|||
<Compile Include="Datastore\Migration\016_update_artist_history_indexes.cs" />
|
||||
<Compile Include="Datastore\Migration\017_remove_nma.cs" />
|
||||
<Compile Include="Datastore\Migration\018_album_disambiguation.cs" />
|
||||
<Compile Include="Datastore\Migration\019_add_ape_quality_in_profiles.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationDbFactory.cs" />
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
private static readonly Regex SampleSizeRegex = new Regex(@"\b(?:(?<S24>24[ ]bit|24bit|[\[\(].*24bit.*[\]\)]))");
|
||||
|
||||
private static readonly Regex CodecRegex = new Regex(@"\b(?:(?<MP3VBR>MP3.*VBR|MPEG Version 1 Audio, Layer 3 vbr)|(?<MP3CBR>MP3|MPEG Version \d+ Audio, Layer 3)|(?<FLAC>flac)|(?<ALAC>alac)|(?<WMA>WMA\d?)|(?<WAV>WAV|PCM)|(?<AAC>M4A|AAC|mp4a)|(?<OGG>OGG|Vorbis))\b",
|
||||
private static readonly Regex CodecRegex = new Regex(@"\b(?:(?<MP3VBR>MP3.*VBR|MPEG Version 1 Audio, Layer 3 vbr)|(?<MP3CBR>MP3|MPEG Version \d+ Audio, Layer 3)|(?<FLAC>flac)|(?<WAVPACK>wavpack|wv)|(?<ALAC>alac)|(?<WMA>WMA\d?)|(?<WAV>WAV|PCM)|(?<AAC>M4A|AAC|mp4a)|(?<OGG>OGG|Vorbis))\b|(?<APE>monkey's audio|[\[|\(].*ape.*[\]|\)])",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static QualityModel ParseQuality(string name, string desc, int fileBitrate, int fileSampleSize = 0)
|
||||
|
@ -66,14 +66,14 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
if (desc.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var descCodec = ParseCodec(desc);
|
||||
var descCodec = ParseCodec(desc, "");
|
||||
|
||||
result.Quality = FindQuality(descCodec, fileBitrate, fileSampleSize);
|
||||
|
||||
if (result.Quality != Quality.Unknown) { return result; }
|
||||
}
|
||||
|
||||
var codec = ParseCodec(normalizedName);
|
||||
var codec = ParseCodec(normalizedName,name);
|
||||
var bitrate = ParseBitRate(normalizedName);
|
||||
var sampleSize = ParseSampleSize(normalizedName);
|
||||
|
||||
|
@ -100,6 +100,12 @@ namespace NzbDrone.Core.Parser
|
|||
case Codec.ALAC:
|
||||
result.Quality = Quality.ALAC;
|
||||
break;
|
||||
case Codec.WAVPACK:
|
||||
result.Quality = Quality.WAVPACK;
|
||||
break;
|
||||
case Codec.APE:
|
||||
result.Quality = Quality.APE;
|
||||
break;
|
||||
case Codec.WMA:
|
||||
result.Quality = Quality.WMA;
|
||||
break;
|
||||
|
@ -154,7 +160,7 @@ namespace NzbDrone.Core.Parser
|
|||
return result;
|
||||
}
|
||||
|
||||
private static Codec ParseCodec(string name)
|
||||
private static Codec ParseCodec(string name, string origName)
|
||||
{
|
||||
var match = CodecRegex.Match(name);
|
||||
|
||||
|
@ -167,6 +173,8 @@ namespace NzbDrone.Core.Parser
|
|||
if (match.Groups["OGG"].Success) { return Codec.OGG; }
|
||||
if (match.Groups["MP3VBR"].Success) { return Codec.MP3VBR; }
|
||||
if (match.Groups["MP3CBR"].Success) { return Codec.MP3CBR; }
|
||||
if (match.Groups["WAVPACK"].Success) { return Codec.WAVPACK; }
|
||||
if (match.Groups["APE"].Success) { return Codec.APE; }
|
||||
|
||||
return Codec.Unknown;
|
||||
}
|
||||
|
@ -232,6 +240,10 @@ namespace NzbDrone.Core.Parser
|
|||
return Quality.FLAC;
|
||||
case Codec.ALAC:
|
||||
return Quality.ALAC;
|
||||
case Codec.WAVPACK:
|
||||
return Quality.WAVPACK;
|
||||
case Codec.APE:
|
||||
return Quality.APE;
|
||||
case Codec.WMA:
|
||||
return Quality.WMA;
|
||||
case Codec.WAV:
|
||||
|
@ -289,12 +301,14 @@ namespace NzbDrone.Core.Parser
|
|||
MP3VBR,
|
||||
FLAC,
|
||||
ALAC,
|
||||
APE,
|
||||
WAVPACK,
|
||||
WMA,
|
||||
AAC,
|
||||
AACVBR,
|
||||
OGG,
|
||||
WAV,
|
||||
Unknown,
|
||||
Unknown
|
||||
}
|
||||
|
||||
public enum BitRate
|
||||
|
|
|
@ -90,6 +90,8 @@ namespace NzbDrone.Core.Qualities
|
|||
public static Quality MP3_008 => new Quality(32, "MP3-8"); // For Current Files Only
|
||||
public static Quality MP3_112 => new Quality(33, "MP3-112"); // For Current Files Only
|
||||
public static Quality MP3_224 => new Quality(34, "MP3-224"); // For Current Files Only
|
||||
public static Quality APE => new Quality(35, "APE");
|
||||
public static Quality WAVPACK => new Quality(36, "WavPack");
|
||||
|
||||
static Quality()
|
||||
{
|
||||
|
@ -128,6 +130,8 @@ namespace NzbDrone.Core.Qualities
|
|||
VORBIS_Q5,
|
||||
ALAC,
|
||||
FLAC,
|
||||
APE,
|
||||
WAVPACK,
|
||||
FLAC_24,
|
||||
WAV
|
||||
};
|
||||
|
@ -173,6 +177,8 @@ namespace NzbDrone.Core.Qualities
|
|||
new QualityDefinition(Quality.VORBIS_Q10) { Weight = 21, MinSize = 0, MaxSize = 550, GroupName = "High Quality Lossy", GroupWeight = 6 },
|
||||
new QualityDefinition(Quality.ALAC) { Weight = 22, MinSize = 0, MaxSize = null, GroupName = "Lossless", GroupWeight = 7 },
|
||||
new QualityDefinition(Quality.FLAC) { Weight = 22, MinSize = 0, MaxSize = null, GroupName = "Lossless", GroupWeight = 7 },
|
||||
new QualityDefinition(Quality.APE) { Weight = 22, MinSize = 0, MaxSize = null, GroupName = "Lossless", GroupWeight = 7 },
|
||||
new QualityDefinition(Quality.WAVPACK) { Weight = 22, MinSize = 0, MaxSize = null, GroupName = "Lossless", GroupWeight = 7 },
|
||||
new QualityDefinition(Quality.FLAC_24) { Weight = 23, MinSize = 0, MaxSize = null, GroupName = "Lossless", GroupWeight = 7 },
|
||||
new QualityDefinition(Quality.WAV) { Weight = 24, MinSize = 0, MaxSize = null, GroupWeight = 8}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue