Fixed: Quality Parser and Augmenter Picks Wrong Quality

pull/3861/head
Qstick 5 years ago
parent 5c3fda48f7
commit bbadf3c7e6

@ -12,11 +12,11 @@ namespace NzbDrone.Core.Test.CustomFormat
[TestFixture]
public class QualityTagFixture : CoreTest
{
[TestCase("R_1080", TagType.Resolution, Resolution.R1080P)]
[TestCase("R_720", TagType.Resolution, Resolution.R720P)]
[TestCase("R_576", TagType.Resolution, Resolution.R576P)]
[TestCase("R_480", TagType.Resolution, Resolution.R480P)]
[TestCase("R_2160", TagType.Resolution, Resolution.R2160P)]
[TestCase("R_1080", TagType.Resolution, Resolution.R1080p)]
[TestCase("R_720", TagType.Resolution, Resolution.R720p)]
[TestCase("R_576", TagType.Resolution, Resolution.R576p)]
[TestCase("R_480", TagType.Resolution, Resolution.R480p)]
[TestCase("R_2160", TagType.Resolution, Resolution.R2160p)]
[TestCase("S_BLURAY", TagType.Source, Source.BLURAY)]
[TestCase("s_tv", TagType.Source, Source.TV)]
[TestCase("s_workPRINT", TagType.Source, Source.WORKPRINT)]
@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.CustomFormat
[TestCase("G_10<>20", TagType.Size, new[] { 10737418240L, 21474836480L})]
[TestCase("G_15.55<>20", TagType.Size, new[] { 16696685363L, 21474836480L})]
[TestCase("G_15.55<>25.1908754", TagType.Size, new[] { 16696685363L, 27048496500L})]
[TestCase("R__1080", TagType.Resolution, Resolution.R1080P)]
[TestCase("R__1080", TagType.Resolution, Resolution.R1080p)]
public void should_parse_tag_from_string(string raw, TagType type, object value, params TagModifier[] modifiers)
{
var parsed = new FormatTag(raw);

@ -0,0 +1,123 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Datastore.Migration;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Datastore.Migration
{
[TestFixture]
public class add_webrip_qualitesFixture : MigrationTest<add_webrip_qualites>
{
private string GenerateQualityJson(int quality, bool allowed)
{
return $"{{ \"quality\": {quality}, \"allowed\": {allowed.ToString().ToLowerInvariant()} }}";
}
private string GenerateQualityGroupJson(int quality, bool allowed, string groupname, int group)
{
return $"{{\"id\": {group}, \"name\": \"{groupname}\", \"items\": [ {{ \"quality\": {quality}, \"allowed\": {allowed.ToString().ToLowerInvariant()} }} ] }}";
}
[Test]
public void should_add_webrip_qualities_and_group_with_webdl()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Profiles").Row(new
{
Id = 0,
Name = "SDTV",
Cutoff = 1,
Items = $"[{GenerateQualityJson(1, true)}, {GenerateQualityJson((int)Quality.WEBRip480p, false)}, {GenerateQualityJson((int)Quality.WEBRip720p, false)}, {GenerateQualityJson((int)Quality.WEBRip1080p, false)}, {GenerateQualityJson((int)Quality.WEBRip2160p, false)}]"
});
});
var profiles = db.Query<Profile159>("SELECT Items FROM Profiles LIMIT 1");
var items = profiles.First().Items;
items.Should().HaveCount(5);
items.Select(v => v.Quality).Should().BeEquivalentTo(1, null, null, null, null);
items.Select(v => v.Items.Count).Should().BeEquivalentTo(0, 2, 2, 2, 2);
items.Select(v => v.Allowed).Should().BeEquivalentTo(true, false, false, false, false);
}
[Test]
public void should_add_webrip_and_webdl_if_webdl_is_missing()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Profiles").Row(new
{
Id = 0,
Name = "SDTV",
Cutoff = 1,
Items = $"[{GenerateQualityJson(1, true)}, {GenerateQualityJson((int)Quality.WEBRip480p, false)}, {GenerateQualityJson((int)Quality.WEBRip720p, false)}, {GenerateQualityJson((int)Quality.WEBRip1080p, false)}]"
});
});
var profiles = db.Query<Profile159>("SELECT Items FROM Profiles LIMIT 1");
var items = profiles.First().Items;
items.Should().HaveCount(5);
items.Select(v => v.Quality).Should().BeEquivalentTo(1, null, null, null, null);
items.Select(v => v.Items.Count).Should().BeEquivalentTo(0, 2, 2, 2, 2);
items.Select(v => v.Allowed).Should().BeEquivalentTo(true, false, false, false, false);
}
[Test]
public void should_add_webrip_beside_webdl_is_grouped()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Profiles").Row(new
{
Id = 0,
Name = "SDTV",
Cutoff = 1,
Items = $"[{GenerateQualityJson(1, true)}, {GenerateQualityGroupJson(5, true, "smegrup", 1001)}]"
});
});
var profiles = db.Query<Profile159>("SELECT Items FROM Profiles LIMIT 1");
var items = profiles.First().Items;
items.Count(c => c.Id == 1001).Should().Be(1);
items.Should().HaveCount(5);
items.Select(v => v.Quality).Should().BeEquivalentTo(1, null, null, null, null);
items.Select(v => v.Items.Count).Should().BeEquivalentTo(0, 2, 2, 2, 2);
items.Select(v => v.Allowed).Should().BeEquivalentTo(true, false, false, false, false);
}
[Test]
public void should_group_webrip_and_webdl_with_the_same_resolution()
{
var db = WithMigrationTestDb(c =>
{
c.Insert.IntoTable("Profiles").Row(new
{
Id = 0,
Name = "SDTV",
Cutoff = 1,
Items = $"[{GenerateQualityJson(1, true)}, {GenerateQualityJson((int)Quality.WEBRip480p, false)}, {GenerateQualityJson((int)Quality.WEBRip720p, false)}, {GenerateQualityJson((int)Quality.WEBRip1080p, false)}, {GenerateQualityJson((int)Quality.WEBRip2160p, false)}]"
});
});
var profiles = db.Query<Profile159>("SELECT Items FROM Profiles LIMIT 1");
var items = profiles.First().Items;
items[1].Items.First().Quality.Should().Be((int)Quality.WEBRip480p);
items[1].Items.Last().Quality.Should().Be((int)Quality.WEBDL480p);
items[2].Items.First().Quality.Should().Be((int)Quality.WEBRip720p);
items[2].Items.Last().Quality.Should().Be((int)Quality.WEBDL720p);
items[3].Items.First().Quality.Should().Be((int)Quality.WEBRip1080p);
items[3].Items.Last().Quality.Should().Be((int)Quality.WEBDL1080p);
items[4].Items.First().Quality.Should().Be((int)Quality.WEBRip2160p);
items[4].Items.Last().Quality.Should().Be((int)Quality.WEBDL2160p);
}
}
}

@ -6,6 +6,7 @@ using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators;
using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
@ -27,13 +28,13 @@ namespace NzbDrone.Core.Test.MediaFiles.MovieImport.Aggregation.Aggregators
_nameAugmenter = new Mock<IAugmentQuality>();
_mediaInfoAugmenter.Setup(s => s.AugmentQuality(It.IsAny<LocalMovie>()))
.Returns(AugmentQualityResult.ResolutionOnly(Resolution.R1080P, Confidence.MediaInfo));
.Returns(AugmentQualityResult.ResolutionOnly((int)Resolution.R1080p, Confidence.MediaInfo));
_fileExtensionAugmenter.Setup(s => s.AugmentQuality(It.IsAny<LocalMovie>()))
.Returns(new AugmentQualityResult(Source.TV, Confidence.Fallback, Resolution.R720P, Confidence.Fallback, Modifier.NONE, Confidence.Fallback, new Revision()));
.Returns(new AugmentQualityResult(Source.TV, Confidence.Fallback, (int)Resolution.R720p, Confidence.Fallback, Modifier.NONE, Confidence.Fallback, new Revision(), new List<CustomFormats.CustomFormat>()));
_nameAugmenter.Setup(s => s.AugmentQuality(It.IsAny<LocalMovie>()))
.Returns(new AugmentQualityResult(Source.TV, Confidence.Default, Resolution.R480P, Confidence.Default, Modifier.NONE, Confidence.Default, new Revision()));
.Returns(new AugmentQualityResult(Source.TV, Confidence.Default, (int)Resolution.R480p, Confidence.Default, Modifier.NONE, Confidence.Default, new Revision(), new List<CustomFormats.CustomFormat>()));
}
private void GivenAugmenters(params Mock<IAugmentQuality>[] mocks)

@ -6,6 +6,7 @@ using NzbDrone.Core.MediaFiles.MediaInfo;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Test.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality
{
@ -36,20 +37,20 @@ namespace NzbDrone.Core.Test.MediaFiles.MovieImport.Aggregation.Aggregators.Augm
Subject.AugmentQuality(localMovie).Should().Be(null);
}
[TestCase(4096, Resolution.R2160P)] // True 4K
[TestCase(4000, Resolution.R2160P)]
[TestCase(3840, Resolution.R2160P)] // 4K UHD
[TestCase(3200, Resolution.R2160P)]
[TestCase(2000, Resolution.R1080P)]
[TestCase(1920, Resolution.R1080P)] // Full HD
[TestCase(1800, Resolution.R1080P)]
[TestCase(1490, Resolution.R720P)]
[TestCase(1280, Resolution.R720P)] // HD
[TestCase(1200, Resolution.R720P)]
[TestCase(800, Resolution.R480P)]
[TestCase(720, Resolution.R480P)] // SDTV
[TestCase(600, Resolution.R480P)]
[TestCase(100, Resolution.R480P)]
[TestCase(4096, Resolution.R2160p)] // True 4K
[TestCase(4000, Resolution.R2160p)]
[TestCase(3840, Resolution.R2160p)] // 4K UHD
[TestCase(3200, Resolution.R2160p)]
[TestCase(2000, Resolution.R1080p)]
[TestCase(1920, Resolution.R1080p)] // Full HD
[TestCase(1800, Resolution.R1080p)]
[TestCase(1490, Resolution.R720p)]
[TestCase(1280, Resolution.R720p)] // HD
[TestCase(1200, Resolution.R720p)]
[TestCase(800, Resolution.R480p)]
[TestCase(720, Resolution.R480p)] // SDTV
[TestCase(600, Resolution.R480p)]
[TestCase(100, Resolution.R480p)]
public void should_return_closest_resolution(int mediaInfoWidth, Resolution expectedResolution)
{
var mediaInfo = Builder<MediaInfoModel>.CreateNew()
@ -63,7 +64,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MovieImport.Aggregation.Aggregators.Augm
var result = Subject.AugmentQuality(localMovie);
result.Should().NotBe(null);
result.Resolution.Should().Be(expectedResolution);
result.Resolution.Should().Be((int)expectedResolution);
}
}
}

@ -65,7 +65,7 @@ namespace NzbDrone.Core.Test.ParserTests
public void should_parse_ultrahd_from_title(string title, int version)
{
var parsed = QualityParser.ParseQuality(title);
parsed.Resolution.Should().Be(Resolution.R2160P);
parsed.Quality.Resolution.Should().Be((int)Resolution.R2160p);
}
}
}

@ -113,24 +113,13 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("My.Movie.GERMAN.Extended.Cut.2016", "Extended Cut")]
[TestCase("My.Movie.GERMAN.Extended.Cut", "Extended Cut")]
[TestCase("Mission Impossible: Rogue Nation 2012 Bluray", "")]
[TestCase("Loving.Pablo.2018.TS.FRENCH.MD.x264-DROGUERiE","")]
[TestCase("Loving.Pablo.2018.TS.FRENCH.MD.x264-DROGUERiE", "")]
public void should_parse_edition(string postTitle, string edition)
{
var parsed = Parser.Parser.ParseMovieTitle(postTitle, true);
if (parsed.Edition.IsNullOrWhiteSpace())
{
parsed.Edition = Parser.Parser.ParseEdition(parsed.SimpleReleaseTitle);
}
parsed.Edition.Should().Be(edition);
}
[TestCase("The Lord of the Rings The Fellowship of the Ring (Extended Edition) 1080p BD25", "The Lord Of The Rings The Fellowship Of The Ring", "Extended Edition")]
[TestCase("The.Lord.of.the.Rings.The.Fellowship.of.the.Ring.(Extended.Edition).1080p.BD25", "The Lord Of The Rings The Fellowship Of The Ring", "Extended Edition")]
public void should_parse_edition_lenient_mapping(string postTitle, string foundTitle, string edition)
{
Parser.Parser.ParseMinimalMovieTitle(postTitle, foundTitle, 1290).Edition.Should().Be(edition);
}
[TestCase("123", "tt0000123")]
[TestCase("1234567", "tt1234567")]
[TestCase("tt1234567", "tt1234567")]

@ -1,89 +1,90 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.MediaFiles.MediaInfo;
using NzbDrone.Core.Parser.Augmenters;
using NzbDrone.Core.Qualities;
//using FluentAssertions;
//using NUnit.Framework;
//using NzbDrone.Core.CustomFormats;
//using NzbDrone.Core.MediaFiles.MediaInfo;
//using NzbDrone.Core.Parser;
//using NzbDrone.Core.Parser.Augmenters;
//using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests.AugmentersTests
{
[TestFixture]
public class AugmentWithMediaInfoFixture : AugmentMovieInfoFixture<AugmentWithMediaInfo>
{
[TestCase(Resolution.R720P, Source.BLURAY, Resolution.R1080P)]
[TestCase(Resolution.R1080P, Source.TV, Resolution.R720P)]
public void should_correct_resolution(Resolution resolution, Source source, Resolution realResolution)
{
var quality = new QualityModel
{
Source = source,
Resolution = resolution,
};
MovieInfo.Quality = quality;
//namespace NzbDrone.Core.Test.ParserTests.ParsingServiceTests.AugmentersTests
//{
// [TestFixture]
// public class AugmentWithMediaInfoFixture : AugmentMovieInfoFixture<AugmentWithMediaInfo>
// {
// [TestCase(Resolution.R720p, Source.BLURAY, Resolution.R1080p)]
// [TestCase(Resolution.R1080p, Source.TV, Resolution.R720p)]
// public void should_correct_resolution(Resolution resolution, Source source, Resolution realResolution)
// {
// var quality = new QualityModel
// {
// Source = source,
// Resolution = resolution,
// };
// MovieInfo.Quality = quality;
var realWidth = 480;
switch (realResolution)
{
case Resolution.R720P:
realWidth = 1280;
break;
case Resolution.R1080P:
realWidth = 1920;
break;
case Resolution.R2160P:
realWidth = 2160;
break;
// var realWidth = 480;
// switch (realResolution)
// {
// case Resolution.R720p:
// realWidth = 1280;
// break;
// case Resolution.R1080p:
// realWidth = 1920;
// break;
// case Resolution.R2160p:
// realWidth = 2160;
// break;
}
// }
var mediaInfo = new MediaInfoModel
{
Width = realWidth
};
// var mediaInfo = new MediaInfoModel
// {
// Width = realWidth
// };
var movieInfo = Subject.AugmentMovieInfo(MovieInfo, mediaInfo);
movieInfo.Quality.Resolution.Should().BeEquivalentTo(realResolution);
movieInfo.Quality.QualityDetectionSource.Should().BeEquivalentTo(QualityDetectionSource.MediaInfo);
}
// var movieInfo = Subject.AugmentMovieInfo(MovieInfo, mediaInfo);
// movieInfo.Quality.Resolution.Should().BeEquivalentTo(realResolution);
// movieInfo.Quality.QualityDetectionSource.Should().BeEquivalentTo(QualityDetectionSource.MediaInfo);
// }
[TestCase(Resolution.R720P, Source.BLURAY, Resolution.R1080P, Modifier.BRDISK)]
[TestCase(Resolution.R1080P, Source.BLURAY, Resolution.R720P, Modifier.REMUX)]
[TestCase(Resolution.R480P, Source.BLURAY, Resolution.R720P)]
[TestCase(Resolution.R720P, Source.DVD, Resolution.R480P)]
public void should_not_correct_resolution(Resolution resolution, Source source, Resolution realResolution, Modifier modifier = Modifier.NONE)
{
var quality = new QualityModel
{
Source = source,
Resolution = resolution,
Modifier = modifier,
};
// [TestCase(Resolution.R720P, Source.BLURAY, Resolution.R1080P, Modifier.BRDISK)]
// [TestCase(Resolution.R1080P, Source.BLURAY, Resolution.R720P, Modifier.REMUX)]
// [TestCase(Resolution.R480P, Source.BLURAY, Resolution.R720P)]
// [TestCase(Resolution.R720P, Source.DVD, Resolution.R480P)]
// public void should_not_correct_resolution(Resolution resolution, Source source, Resolution realResolution, Modifier modifier = Modifier.NONE)
// {
// var quality = new QualityModel
// {
// Source = source,
// Resolution = resolution,
// Modifier = modifier,
// };
MovieInfo.Quality = quality;
// MovieInfo.Quality = quality;
var realWidth = 480;
switch (realResolution)
{
case Resolution.R720P:
realWidth = 1280;
break;
case Resolution.R1080P:
realWidth = 1920;
break;
case Resolution.R2160P:
realWidth = 2160;
break;
// var realWidth = 480;
// switch (realResolution)
// {
// case Resolution.R720P:
// realWidth = 1280;
// break;
// case Resolution.R1080P:
// realWidth = 1920;
// break;
// case Resolution.R2160P:
// realWidth = 2160;
// break;
}
// }
var mediaInfo = new MediaInfoModel
{
Width = realWidth
};
// var mediaInfo = new MediaInfoModel
// {
// Width = realWidth
// };
var movieInfo = Subject.AugmentMovieInfo(MovieInfo, mediaInfo);
movieInfo.Quality.Resolution.Should().BeEquivalentTo(resolution);
movieInfo.Quality.QualityDetectionSource.Should().BeEquivalentTo(QualityDetectionSource.Name);
}
}
}
// var movieInfo = Subject.AugmentMovieInfo(MovieInfo, mediaInfo);
// movieInfo.Quality.Resolution.Should().BeEquivalentTo(resolution);
// movieInfo.Quality.QualityDetectionSource.Should().BeEquivalentTo(QualityDetectionSource.Name);
// }
// }
//}

@ -24,27 +24,26 @@ namespace NzbDrone.Core.Test.ParserTests
public static object[] OtherSourceQualityParserCases =
{
new object[] { "SD TV", Source.TV, Resolution.R480P, Modifier.NONE },
new object[] { "SD DVD", Source.DVD, Resolution.R480P, Modifier.NONE },
new object[] { "480p WEB-DL", Source.WEBDL, Resolution.R480P, Modifier.NONE },
new object[] { "HD TV", Source.TV, Resolution.R720P, Modifier.NONE },
new object[] { "1080p HD TV", Source.TV, Resolution.R1080P, Modifier.NONE },
new object[] { "2160p HD TV", Source.TV, Resolution.R2160P, Modifier.NONE },
new object[] { "720p WEB-DL", Source.WEBDL, Resolution.R720P, Modifier.NONE },
new object[] { "1080p WEB-DL", Source.WEBDL, Resolution.R1080P, Modifier.NONE },
new object[] { "2160p WEB-DL", Source.WEBDL, Resolution.R2160P, Modifier.NONE },
new object[] { "720p BluRay", Source.BLURAY, Resolution.R720P, Modifier.NONE },
new object[] { "1080p BluRay", Source.BLURAY, Resolution.R1080P, Modifier.NONE },
new object[] { "2160p BluRay", Source.BLURAY, Resolution.R2160P, Modifier.NONE },
new object[] { "1080p Remux", Source.BLURAY, Resolution.R1080P, Modifier.REMUX },
new object[] { "2160p Remux", Source.BLURAY, Resolution.R2160P, Modifier.REMUX },
new object[] { "SD TV", Source.TV, Resolution.R480p, Modifier.NONE },
new object[] { "SD DVD", Source.DVD, Resolution.R480p, Modifier.NONE },
new object[] { "480p WEB-DL", Source.WEBDL, Resolution.R480p, Modifier.NONE },
new object[] { "HD TV", Source.TV, Resolution.R720p, Modifier.NONE },
new object[] { "1080p HD TV", Source.TV, Resolution.R1080p, Modifier.NONE },
new object[] { "2160p HD TV", Source.TV, Resolution.R2160p, Modifier.NONE },
new object[] { "720p WEB-DL", Source.WEBDL, Resolution.R720p, Modifier.NONE },
new object[] { "1080p WEB-DL", Source.WEBDL, Resolution.R1080p, Modifier.NONE },
new object[] { "2160p WEB-DL", Source.WEBDL, Resolution.R2160p, Modifier.NONE },
new object[] { "720p BluRay", Source.BLURAY, Resolution.R720p, Modifier.NONE },
new object[] { "1080p BluRay", Source.BLURAY, Resolution.R1080p, Modifier.NONE },
new object[] { "2160p BluRay", Source.BLURAY, Resolution.R2160p, Modifier.NONE },
new object[] { "1080p Remux", Source.BLURAY, Resolution.R1080p, Modifier.REMUX },
new object[] { "2160p Remux", Source.BLURAY, Resolution.R2160p, Modifier.REMUX },
};
[TestCase("Despicable.Me.3.2017.720p.TSRip.x264.AAC-Ozlem", false)]
[TestCase("IT.2017.HDTSRip.x264.AAC-Ozlem[ETRG]", false)]
public void should_parse_ts(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.TELESYNC, proper, Resolution.R720P);
ParseAndVerifyQuality(title, Source.TELESYNC, proper, Resolution.R720p);
}
[TestCase("S07E23 .avi ", false)]
@ -65,38 +64,32 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Muppet.Babies.S03.TVRip.XviD-NOGRP", false)]
public void should_parse_sdtv_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.TV, proper, Resolution.R480P);
ParseAndVerifyQuality(title, Source.TV, proper, Resolution.R480p);
}
[TestCase("WEEDS.S03E01-06.DUAL.XviD.Bluray.AC3-REPACK.-HELLYWOOD.avi", true)]
[TestCase("The.Shield.S01E13.NTSC.x264-CtrlSD", false)]
[TestCase("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", false)]
[TestCase("WEEDS.S03E01-06.DUAL.BDRip.X-viD.AC3.-HELLYWOOD", false)]
[TestCase("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD.avi", false)]
[TestCase("WEEDS.S03E01-06.DUAL.XviD.Bluray.AC3.-HELLYWOOD.avi", false)]
[TestCase("The.Girls.Next.Door.S03E06.DVDRip.XviD-WiDE", false)]
[TestCase("The.Girls.Next.Door.S03E06.DVD.Rip.XviD-WiDE", false)]
[TestCase("the.shield.1x13.circles.ws.xvidvd-tns", false)]
[TestCase("the_x-files.9x18.sunshine_days.ac3.ws_dvdrip_xvid-fov.avi", false)]
[TestCase("[FroZen] Miyuki - 23 [DVD][7F6170E6]", false)]
[TestCase("[Doki] Clannad - 02 (848x480 XviD BD MP3) [95360783]", false)]
[TestCase("The.Shield.S01E13.x264-CtrlSD", false)]
[TestCase("[HorribleSubs] Yowamushi Pedal - 32 [480p]", false)]
[TestCase("[CR] Sailor Moon - 004 [480p][48CE2D0F]", false)]
[TestCase("[Hatsuyuki] Naruto Shippuuden - 363 [848x480][ADE35E38]", false)]
public void should_parse_dvd_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.DVD, proper, Resolution.R480P);
ParseAndVerifyQuality(title, Source.DVD, proper, Resolution.R480p);
}
[TestCase("Elementary.S01E10.The.Leviathan.480p.WEB-DL.x264-mSD", false)]
[TestCase("Glee.S04E10.Glee.Actually.480p.WEB-DL.x264-mSD", false)]
[TestCase("The.Big.Bang.Theory.S06E11.The.Santa.Simulation.480p.WEB-DL.x264-mSD", false)]
[TestCase("Da.Vincis.Demons.S02E04.480p.WEB.DL.nSD.x264-NhaNc3", false)]
[TestCase("Series.Title.1x04.ITA.WEBMux.x264-NovaRip", false)]
public void should_parse_webdl480p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.WEBDL, proper, Resolution.R480P);
ParseAndVerifyQuality(title, Source.WEBDL, proper, Resolution.R480p);
}
[TestCase("Series.Title.1x04.ITA.WEBMux.x264-NovaRip", false)]
public void should_parse_webrip480p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.WEBRIP, proper, Resolution.R480p);
}
[TestCase("Heidi Girl of the Alps (BD)(640x480(RAW) (BATCH 1) (1-13)", false)]
@ -104,7 +97,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("WEEDS.S03E01-06.DUAL.BDRip.AC3.-HELLYWOOD", false)]
public void should_parse_bluray480p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.BLURAY, proper, Resolution.R480P);
ParseAndVerifyQuality(title, Source.BLURAY, proper, Resolution.R480p);
}
[TestCase("Dexter - S01E01 - Title [HDTV]", false)]
@ -119,7 +112,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Survivorman.The.Lost.Pilots.Summer.HR.WS.PDTV.x264-DHD", false)]
public void should_parse_hdtv720p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.TV, proper, Resolution.R720P);
ParseAndVerifyQuality(title, Source.TV, proper, Resolution.R720p);
}
@ -129,10 +122,9 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Dexter - S01E01 - Title [HDTV-1080p]", false)]
public void should_parse_hdtv1080p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.TV, proper, Resolution.R1080P);
ParseAndVerifyQuality(title, Source.TV, proper, Resolution.R1080p);
}
[TestCase("Arrested.Development.S04E01.720p.WEBRip.AAC2.0.x264-NFRiP", false)]
[TestCase("Vanguard S01E04 Mexicos Death Train 720p WEB DL", false)]
[TestCase("Hawaii Five 0 S02E21 720p WEB DL DD5 1 H 264", false)]
[TestCase("Castle S04E22 720p WEB DL DD5 1 H 264 NFHD", false)]
@ -146,24 +138,19 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Castle.S06E23.720p.WebHD.h264-euHD", false)]
[TestCase("The.Nightly.Show.2016.03.14.720p.WEB.x264-spamTV", false)]
[TestCase("The.Nightly.Show.2016.03.14.720p.WEB.h264-spamTV", false)]
[TestCase("Sonny.With.a.Chance.S02E15.720p", false)]
[TestCase("S07E23.mkv ", false)]
[TestCase("Sonny.With.a.Chance.S02E15.mkv", false)]
[TestCase("[Underwater-FFF] No Game No Life - 01 (720p) [27AAA0A0]", false)]
[TestCase("[Doki] Mahouka Koukou no Rettousei - 07 (1280x720 Hi10P AAC) [80AF7DDE]", false)]
[TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].[C65D4B1F].mkv", false)]
[TestCase("[HorribleSubs]_Fairy_Tail_-_145_[720p]", false)]
[TestCase("[Eveyuu] No Game No Life - 10 [Hi10P 1280x720 H264][10B23BD8]", false)]
[TestCase("Movie.Title.ITA.720p.WEBMux.x264-NovaRip", false)]
[TestCase("BrainDead.S01E01.The.Insanity.Principle.720p.WEB-DL.DD5.1.H.264-BD", false)]
public void should_parse_webdl720p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.WEBDL, proper, Resolution.R720P);
ParseAndVerifyQuality(title, Source.WEBDL, proper, Resolution.R720p);
}
[TestCase("Movie.Title.ITA.720p.WEBMux.x264-NovaRip", false)]
[TestCase("Arrested.Development.S04E01.720p.WEBRip.AAC2.0.x264-NFRiP", false)]
public void should_parse_webrip720p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.WEBRIP, proper, Resolution.R720p);
}
[TestCase("[HorribleSubs] Yowamushi Pedal - 32 [1080p]", false)]
[TestCase("Under the Dome S01E10 Let the Games Begin 1080p", false)]
[TestCase("Arrested.Development.S04E01.iNTERNAL.1080p.WEBRip.x264-QRUS", false)]
[TestCase("CSI NY S09E03 1080p WEB DL DD5 1 H264 NFHD", false)]
[TestCase("Two and a Half Men S10E03 1080p WEB DL DD5 1 H 264 NFHD", false)]
[TestCase("Criminal.Minds.S08E01.1080p.WEB-DL.DD5.1.H264-NFHD", false)]
@ -180,23 +167,34 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Series Title S06E08 No One PROPER 1080p WEB H 264-EXCLUSIVE", true)]
[TestCase("The.Simpsons.S25E21.Pay.Pal.1080p.WEB-DL.DD5.1.H.264-NTb", false)]
[TestCase("The.Simpsons.2017.1080p.WEB-DL.DD5.1.H.264.Remux.-NTb", false)]
[TestCase("Series.Title.1x04.ITA.1080p.WEBMux.x264-NovaRip", false)]
[TestCase("Fast.and.Furious.Presents.Hobbs.and.Shaw.2019.1080p.AMZN.WEB-DL.DDP5.1.H.264-NTG", false)]
public void should_parse_webdl1080p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.WEBDL, proper, Resolution.R1080P);
ParseAndVerifyQuality(title, Source.WEBDL, proper, Resolution.R1080p);
}
[TestCase("Arrested.Development.S04E01.iNTERNAL.1080p.WEBRip.x264-QRUS", false)]
[TestCase("Series.Title.1x04.ITA.1080p.WEBMux.x264-NovaRip", false)]
public void should_parse_webrip1080p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.WEBRIP, proper, Resolution.R1080p);
}
[TestCase("CASANOVA S01E01.2160P AMZN WEBRIP DD2.0 HI10P X264-TROLLUHD", false)]
[TestCase("JUST ADD MAGIC S01E01.2160P AMZN WEBRIP DD2.0 X264-TROLLUHD", false)]
[TestCase("The.Man.In.The.High.Castle.S01E01.2160p.AMZN.WEBRip.DD2.0.Hi10p.X264-TrollUHD", false)]
[TestCase("The Man In the High Castle S01E01 2160p AMZN WEBRip DD2.0 Hi10P x264-TrollUHD", false)]
[TestCase("The.Nightly.Show.2016.03.14.2160p.WEB.x264-spamTV", false)]
[TestCase("The.Nightly.Show.2016.03.14.2160p.WEB.h264-spamTV", false)]
[TestCase("The.Nightly.Show.2016.03.14.2160p.WEB.PROPER.h264-spamTV", true)]
public void should_parse_webdl2160p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.WEBDL, proper, Resolution.R2160P);
ParseAndVerifyQuality(title, Source.WEBDL, proper, Resolution.R2160p);
}
[TestCase("CASANOVA S01E01.2160P AMZN WEBRIP DD2.0 HI10P X264-TROLLUHD", false)]
[TestCase("JUST ADD MAGIC S01E01.2160P AMZN WEBRIP DD2.0 X264-TROLLUHD", false)]
[TestCase("The.Man.In.The.High.Castle.S01E01.2160p.AMZN.WEBRip.DD2.0.Hi10p.X264-TrollUHD", false)]
[TestCase("The Man In the High Castle S01E01 2160p AMZN WEBRip DD2.0 Hi10P x264-TrollUHD", false)]
public void should_parse_webrip2160p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.WEBRIP, proper, Resolution.R2160p);
}
[TestCase("WEEDS.S03E01-06.DUAL.Bluray.AC3.-HELLYWOOD.avi", false)]
@ -217,7 +215,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Opeth.Garden.Of.The.Titans.Live.At.Red.Rocks.Amphitheatre.2017.720p.MBluRay.x264-TREBLE.mkv", false)]
public void should_parse_bluray720p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.BLURAY, proper, Resolution.R720P);
ParseAndVerifyQuality(title, Source.BLURAY, proper, Resolution.R720p);
}
[TestCase("Chuck - S01E03 - Come Fly With Me - 1080p BluRay.mkv", false)]
@ -234,14 +232,14 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Opeth.Garden.Of.The.Titans.Live.At.Red.Rocks.Amphitheatre.2017.1080p.MBluRay.x264-TREBLE.mkv", false)]
public void should_parse_bluray1080p_quality(string title, bool proper)
{
ParseAndVerifyQuality(title, Source.BLURAY, proper, Resolution.R1080P);
ParseAndVerifyQuality(title, Source.BLURAY, proper, Resolution.R1080p);
}
[TestCase("Movie.Name.2004.576p.BDRip.x264-HANDJOB")]
[TestCase("Hannibal.S01E05.576p.BluRay.DD5.1.x264-HiSD")]
public void should_parse_bluray576p_quality(string title)
{
ParseAndVerifyQuality(title, Source.BLURAY, false, Resolution.R576P);
ParseAndVerifyQuality(title, Source.BLURAY, false, Resolution.R576p);
}
[TestCase("Contract.to.Kill.2016.REMUX.1080p.BluRay.AVC.DTS-HD.MA.5.1-iFT")]
@ -251,7 +249,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Wildling.2018.1080p.BluRay.REMUX.MPEG-2.DTS-HD.MA.5.1-EPSiLON")]
public void should_parse_remux1080p_quality(string title)
{
ParseAndVerifyQuality(title, Source.BLURAY, false, Resolution.R1080P, Modifier.REMUX);
ParseAndVerifyQuality(title, Source.BLURAY, false, Resolution.R1080p, Modifier.REMUX);
}
[TestCase("Contract.to.Kill.2016.REMUX.2160p.BluRay.AVC.DTS-HD.MA.5.1-iFT")]
@ -259,7 +257,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("The.Shining.1980.2160p.UHD.BluRay.Remux.HDR.HEVC.DTS-HD.MA.5.1-PmP.mkv")]
public void should_parse_remux2160p_quality(string title)
{
ParseAndVerifyQuality(title, Source.BLURAY, false, Resolution.R2160P, Modifier.REMUX);
ParseAndVerifyQuality(title, Source.BLURAY, false, Resolution.R2160p, Modifier.REMUX);
}
[TestCase("G.I.Joe.Retaliation.2013.BDISO")]
@ -270,13 +268,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Daylight.1996.Bluray.ISO")]
public void should_parse_brdisk_1080p_quality(string title)
{
ParseAndVerifyQuality(title, Source.BLURAY, false, Resolution.R1080P, Modifier.BRDISK);
}
[TestCase("Stripes (1981) 1080i HDTV DD5.1 MPEG2-TrollHD")]
public void should_parse_rawhd_quality(string title)
{
ParseAndVerifyQuality(title, Source.TV, false, Resolution.Unknown, Modifier.RAWHD);
ParseAndVerifyQuality(title, Source.BLURAY, false, Resolution.R1080p, Modifier.BRDISK);
}
//[TestCase("POI S02E11 1080i HDTV DD5.1 MPEG2-TrollHD", false)]
@ -371,12 +363,12 @@ namespace NzbDrone.Core.Test.ParserTests
var result = QualityParser.ParseQuality(title);
if (resolution != Resolution.Unknown)
{
result.Resolution.Should().Be(resolution);
result.Quality.Resolution.Should().Be((int)resolution);
}
result.Source.Should().Be(source);
result.Quality.Source.Should().Be(source);
if (modifier != Modifier.NONE)
{
result.Modifier.Should().Be(modifier);
result.Quality.Modifier.Should().Be(modifier);
}
var version = proper ? 2 : 1;

@ -1,6 +1,7 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Test.Qualities
@ -11,52 +12,52 @@ namespace NzbDrone.Core.Test.Qualities
[TestCase(Source.CAM, 480, Modifier.NONE)]
[TestCase(Source.CAM, 1080, Modifier.NONE)]
[TestCase(Source.CAM, 0, Modifier.NONE)]
public void should_return_CAM(Source source, Resolution resolution, Modifier modifier)
public void should_return_CAM(Source source, int resolution, Modifier modifier)
{
QualityFinder.FindBySourceAndResolution(source, resolution, modifier).Should().Be(Quality.CAM);
}
[TestCase(Source.CAM, 1080, Modifier.SCREENER)]
[TestCase(Source.CAM, 0, Modifier.SCREENER)]
public void should_return_Unknown(Source source, Resolution resolution, Modifier modifier)
public void should_return_Unknown(Source source, int resolution, Modifier modifier)
{
QualityFinder.FindBySourceAndResolution(source, resolution, modifier).Should().Be(Quality.Unknown);
}
[TestCase(Source.DVD, 480, Modifier.REMUX)]
public void should_return_DVD_Remux(Source source, Resolution resolution, Modifier modifier)
public void should_return_DVD_Remux(Source source, int resolution, Modifier modifier)
{
QualityFinder.FindBySourceAndResolution(source, resolution, modifier).Should().Be(Quality.DVDR);
}
[TestCase(Source.DVD, 480, Modifier.NONE)]
public void should_return_DVD(Source source, Resolution resolution, Modifier modifier)
public void should_return_DVD(Source source, int resolution, Modifier modifier)
{
QualityFinder.FindBySourceAndResolution(source, resolution, modifier).Should().Be(Quality.DVD);
}
[TestCase(Source.TV, 480, Modifier.NONE)]
public void should_return_SDTV(Source source, Resolution resolution, Modifier modifier)
public void should_return_SDTV(Source source, int resolution, Modifier modifier)
{
QualityFinder.FindBySourceAndResolution(source, resolution, modifier).Should().Be(Quality.SDTV);
}
[TestCase(Source.TV, 720, Modifier.NONE)]
[TestCase(Source.UNKNOWN, 720, Modifier.NONE)]
public void should_return_HDTV_720p(Source source, Resolution resolution, Modifier modifier)
public void should_return_HDTV_720p(Source source, int resolution, Modifier modifier)
{
QualityFinder.FindBySourceAndResolution(source, resolution, modifier).Should().Be(Quality.HDTV720p);
}
[TestCase(Source.TV, 1080, Modifier.NONE)]
[TestCase(Source.UNKNOWN, 1080, Modifier.NONE)]
public void should_return_HDTV_1080p(Source source, Resolution resolution, Modifier modifier)
public void should_return_HDTV_1080p(Source source, int resolution, Modifier modifier)
{
QualityFinder.FindBySourceAndResolution(source, resolution, modifier).Should().Be(Quality.HDTV1080p);
}
[TestCase(Source.BLURAY, 720, Modifier.NONE)]
public void should_return_Bluray720p(Source source, Resolution resolution, Modifier modifier)
public void should_return_Bluray720p(Source source, int resolution, Modifier modifier)
{
QualityFinder.FindBySourceAndResolution(source, resolution, modifier).Should().Be(Quality.Bluray720p);
}

@ -5,6 +5,7 @@ using System.Linq;
using System.Text.RegularExpressions;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Languages;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.CustomFormats
@ -74,11 +75,11 @@ namespace NzbDrone.Core.CustomFormats
case TagType.Language:
return movieInfo.Languages.Contains((Language)Value);
case TagType.Resolution:
return movieInfo.Quality.Resolution == (Resolution) Value;
return movieInfo.Quality.Quality.Resolution == (int)(Resolution) Value;
case TagType.Modifier:
return movieInfo.Quality.Modifier == (Modifier) Value;
return movieInfo.Quality.Quality.Modifier == (Modifier) Value;
case TagType.Source:
return movieInfo.Quality.Source == (Source) Value;
return movieInfo.Quality.Quality.Source == (Source) Value;
case TagType.Size:
var size = (movieInfo.ExtraInfo.GetValueOrDefault("Size", 0.0) as long?) ?? 0;
var tuple = Value as (long, long)? ?? (0, 0);
@ -108,19 +109,19 @@ namespace NzbDrone.Core.CustomFormats
switch (value)
{
case "2160":
Value = Resolution.R2160P;
Value = Resolution.R2160p;
break;
case "1080":
Value = Resolution.R1080P;
Value = Resolution.R1080p;
break;
case "720":
Value = Resolution.R720P;
Value = Resolution.R720p;
break;
case "576":
Value = Resolution.R576P;
Value = Resolution.R576p;
break;
case "480":
Value = Resolution.R480P;
Value = Resolution.R480p;
break;
}
break;
@ -248,16 +249,6 @@ namespace NzbDrone.Core.CustomFormats
AbsolutelyRequired = 4
}
public enum Resolution
{
Unknown = 0,
R480P = 480,
R576P = 576,
R720P = 720,
R1080P = 1080,
R2160P = 2160
}
public enum Source
{
UNKNOWN = 0,
@ -268,6 +259,7 @@ namespace NzbDrone.Core.CustomFormats
DVD,
TV,
WEBDL,
WEBRIP,
BLURAY
}

@ -0,0 +1,245 @@
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(159)]
public class add_webrip_qualites : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(ConvertProfile);
}
private void ConvertProfile(IDbConnection conn, IDbTransaction tran)
{
var updater = new ProfileUpdater159(conn, tran);
// updater.SplitQualityAppend(8, 12); // APE after Flac
// updater.SplitQualityAppend(5, 14); // APE after Flac
// updater.SplitQualityAppend(3, 15); // APE after Flacupdater.SplitQualityAppend(8, 12); // APE after Flac
// updater.SplitQualityAppend(18, 17); // APE after Flac
updater.CreateGroupAt(8, "WEB 480p", new int[]{12}); // Group WEBRip480p with WEBDL480p
updater.CreateGroupAt(5, "WEB 720p", new int[]{14}); // Group WEBRip720p with WEBDL720p
updater.CreateGroupAt(3, "WEB 1080p", new int[]{15}); // Group WEBRip1080p with WEBDL1080p
updater.CreateGroupAt(18, "WEB 2160p", new int[]{17}); // Group WEBRip2160p with WEBDL2160p
updater.Commit();
}
}
public class Profile159
{
public int Id { get; set; }
public string Name { get; set; }
public int Cutoff { get; set; }
public List<ProfileItem159> Items { get; set; }
}
public class ProfileItem159
{
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public int Id { get; set; }
public string Name { get; set; }
public int? Quality { get; set; }
public List<ProfileItem159> Items { get; set; }
public bool Allowed { get; set; }
public ProfileItem159()
{
Items = new List<ProfileItem159>();
}
}
public class ProfileUpdater159
{
private readonly IDbConnection _connection;
private readonly IDbTransaction _transaction;
private List<Profile159> _profiles;
private HashSet<Profile159> _changedProfiles = new HashSet<Profile159>();
public ProfileUpdater159(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 CreateGroupAt(int find, string name, int[] newQualities)
{
foreach (var profile in _profiles)
{
var nextGroup = 1000;
while (true)
{
if (profile.Items.FindIndex(v => v.Id == nextGroup) > -1)
{
nextGroup++;
}
else
{
break;
}
}
var findIndex = profile.Items.FindIndex(v =>
{
return v.Quality == find || (v.Items != null && v.Items.Any(b => b.Quality == find));
});
var isGrouped = !profile.Items.Any(p => p.Quality == find);
if (findIndex > -1 && !isGrouped)
{
var findQuality = profile.Items[findIndex];
var groupItems = new List<ProfileItem159>();
foreach (var newQuality in newQualities)
{
groupItems.Add(new ProfileItem159
{
Quality = newQuality,
Allowed = findQuality.Allowed
});
}
groupItems.Add(new ProfileItem159
{
Quality = find,
Allowed = findQuality.Allowed
});
profile.Items.Insert(findIndex, new ProfileItem159
{
Id = nextGroup,
Name = name,
Quality = null,
Items = groupItems,
Allowed = findQuality.Allowed
});
}
else if (findIndex > -1 && isGrouped)
{
var findQuality = profile.Items[findIndex];
foreach (var newQuality in newQualities)
{
profile.Items[findIndex].Items.Insert(findIndex, new ProfileItem159
{
Quality = newQuality,
Allowed = findQuality.Allowed
});
}
}
else
{
// If the ID isn't found for some reason (mangled migration 71?)
var groupItems = new List<ProfileItem159>();
foreach (var newQuality in newQualities)
{
groupItems.Add(new ProfileItem159
{
Quality = newQuality,
Allowed = false
});
}
groupItems.Add(new ProfileItem159
{
Quality = find,
Allowed = false
});
profile.Items.Add(new ProfileItem159
{
Id = nextGroup,
Name = name,
Quality = null,
Items = groupItems,
Allowed = false
});
}
foreach (var quality in newQualities)
{
var index = profile.Items.FindIndex(v => v.Quality == quality);
if (index > -1)
{
profile.Items.RemoveAt(index);
}
if (profile.Cutoff == quality)
{
profile.Cutoff = nextGroup;
}
}
_changedProfiles.Add(profile);
}
}
private List<Profile159> GetProfiles()
{
var profiles = new List<Profile159>();
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 Profile159
{
Id = profileReader.GetInt32(0),
Name = profileReader.GetString(1),
Cutoff = profileReader.GetInt32(2),
Items = Json.Deserialize<List<ProfileItem159>>(profileReader.GetString(3))
});
}
}
}
return profiles;
}
}
}

@ -42,15 +42,15 @@ namespace NzbDrone.Core.DecisionEngine
public List<DownloadDecision> GetRssDecision(List<ReleaseInfo> reports)
{
return GetMovieDecisions(reports).ToList();
return GetDecisions(reports).ToList();
}
public List<DownloadDecision> GetSearchDecision(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteriaBase)
{
return GetMovieDecisions(reports, searchCriteriaBase).ToList();
return GetDecisions(reports, searchCriteriaBase).ToList();
}
private IEnumerable<DownloadDecision> GetMovieDecisions(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
private IEnumerable<DownloadDecision> GetDecisions(List<ReleaseInfo> reports, SearchCriteriaBase searchCriteria = null)
{
if (reports.Any())
{
@ -98,12 +98,6 @@ namespace NzbDrone.Core.DecisionEngine
result.Movie = null; //To ensure we have a remote movie, else null exception on next line!
result.RemoteMovie.ParsedMovieInfo = parsedMovieInfo;
}
else
{
//Enhance Parsed Movie Info!
result.RemoteMovie.ParsedMovieInfo = Parser.Parser.ParseMinimalMovieTitle(parsedMovieInfo.MovieTitle,
result.RemoteMovie.Movie.Title, parsedMovieInfo.Year);
}
}
else
@ -148,7 +142,8 @@ namespace NzbDrone.Core.DecisionEngine
}
else
{
remoteMovie.DownloadAllowed = true;
// _aggregationService.Augment(remoteMovie);
remoteMovie.DownloadAllowed = remoteMovie.Movie != null;
decision = GetDecisionForReport(remoteMovie, searchCriteria);
}

@ -75,24 +75,12 @@ namespace NzbDrone.Core.Download.TrackedDownloads
public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, DownloadClientItem downloadItem)
{
if (downloadItem.DownloadId.IsNullOrWhiteSpace())
{
_logger.Warn("The following download client item ({0}) has no download hash (id), so it cannot be tracked: {1}",
downloadClient.Name, downloadItem.Title);
return null;
}
if (downloadItem.Title.IsNullOrWhiteSpace())
{
_logger.Warn("The following download client item ({0}) has no title so it cannot be tracked: {1}",
downloadClient.Name, downloadItem.Title);
return null;
}
var existingItem = Find(downloadItem.DownloadId);
if (existingItem != null && existingItem.State != TrackedDownloadStage.Downloading)
{
LogItemChange(existingItem, existingItem.DownloadItem, downloadItem);
existingItem.DownloadItem = downloadItem;
existingItem.IsTrackable = true;
@ -141,9 +129,10 @@ namespace NzbDrone.Core.Download.TrackedDownloads
}
}
// Track it so it can be displayed in the queue even though we can't determine which movie it is for
if (trackedDownload.RemoteMovie == null)
{
return null;
_logger.Trace("No Movie found for download '{0}'", trackedDownload.DownloadItem.Title);
}
}
catch (Exception e)
@ -152,6 +141,8 @@ namespace NzbDrone.Core.Download.TrackedDownloads
return null;
}
LogItemChange(trackedDownload, existingItem?.DownloadItem, trackedDownload.DownloadItem);
_cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload);
return trackedDownload;
}

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Qualities;
@ -9,115 +7,82 @@ namespace NzbDrone.Core.MediaFiles
{
public static class MediaFileExtensions
{
private static Dictionary<string, Source> _fileExtensions;
private static Dictionary<string, Resolution> _resolutionExt;
private static Dictionary<string, Quality> _fileExtensions;
static MediaFileExtensions()
{
_fileExtensions = new Dictionary<string, Source>
_fileExtensions = new Dictionary<string, Quality>
{
//Unknown
{ ".webm", Source.UNKNOWN },
{ ".webm", Quality.Unknown },
//SDTV
{ ".m4v", Source.TV },
{ ".3gp", Source.TV },
{ ".nsv", Source.TV },
{ ".ty", Source.TV },
{ ".strm", Source.TV },
{ ".rm", Source.TV },
{ ".rmvb", Source.TV },
{ ".m3u", Source.TV },
{ ".ifo", Source.TV },
{ ".mov", Source.TV },
{ ".qt", Source.TV },
{ ".divx", Source.TV },
{ ".xvid", Source.TV },
{ ".bivx", Source.TV },
{ ".nrg", Source.TV },
{ ".pva", Source.TV },
{ ".wmv", Source.TV },
{ ".asf", Source.TV },
{ ".asx", Source.TV },
{ ".ogm", Source.TV },
{ ".ogv", Source.TV },
{ ".m2v", Source.TV },
{ ".avi", Source.TV },
{ ".bin", Source.TV },
{ ".dat", Source.TV },
{ ".dvr-ms", Source.TV },
{ ".mpg", Source.TV },
{ ".mpeg", Source.TV },
{ ".mp4", Source.TV },
{ ".avc", Source.TV },
{ ".vp3", Source.TV },
{ ".svq3", Source.TV },
{ ".nuv", Source.TV },
{ ".viv", Source.TV },
{ ".dv", Source.TV },
{ ".fli", Source.TV },
{ ".flv", Source.TV },
{ ".wpl", Source.TV },
{ ".m4v", Quality.SDTV },
{ ".3gp", Quality.SDTV },
{ ".nsv", Quality.SDTV },
{ ".ty", Quality.SDTV },
{ ".strm", Quality.SDTV },
{ ".rm", Quality.SDTV },
{ ".rmvb", Quality.SDTV },
{ ".m3u", Quality.SDTV },
{ ".ifo", Quality.SDTV },
{ ".mov", Quality.SDTV },
{ ".qt", Quality.SDTV },
{ ".divx", Quality.SDTV },
{ ".xvid", Quality.SDTV },
{ ".bivx", Quality.SDTV },
{ ".nrg", Quality.SDTV },
{ ".pva", Quality.SDTV },
{ ".wmv", Quality.SDTV },
{ ".asf", Quality.SDTV },
{ ".asx", Quality.SDTV },
{ ".ogm", Quality.SDTV },
{ ".ogv", Quality.SDTV },
{ ".m2v", Quality.SDTV },
{ ".avi", Quality.SDTV },
{ ".bin", Quality.SDTV },
{ ".dat", Quality.SDTV },
{ ".dvr-ms", Quality.SDTV },
{ ".mpg", Quality.SDTV },
{ ".mpeg", Quality.SDTV },
{ ".mp4", Quality.SDTV },
{ ".avc", Quality.SDTV },
{ ".vp3", Quality.SDTV },
{ ".svq3", Quality.SDTV },
{ ".nuv", Quality.SDTV },
{ ".viv", Quality.SDTV },
{ ".dv", Quality.SDTV },
{ ".fli", Quality.SDTV },
{ ".flv", Quality.SDTV },
{ ".wpl", Quality.SDTV },
//DVD
{ ".img", Source.DVD },
{ ".iso", Source.DVD },
{ ".vob", Source.DVD },
{ ".img", Quality.DVD },
{ ".iso", Quality.DVD },
{ ".vob", Quality.DVD },
//HD
{ ".mkv", Source.WEBDL },
{ ".mk3d", Source.WEBDL},
{ ".ts", Source.TV },
{ ".wtv", Source.TV },
{ ".mkv", Quality.WEBDL720p },
{ ".mk3d", Quality.WEBDL720p},
{ ".ts", Quality.SDTV },
{ ".wtv", Quality.SDTV },
//Bluray
{ ".m2ts", Source.BLURAY }
};
_resolutionExt = new Dictionary<string, Resolution>
{
//HD
{ ".mkv", Resolution.R720P },
{ ".mk3d", Resolution.R720P },
{ ".ts", Resolution.R720P },
{ ".wtv", Resolution.R720P },
//Bluray
{ ".m2ts", Resolution.R720P }
{ ".m2ts", Quality.Bluray720p}
};
}
public static HashSet<string> Extensions => new HashSet<string>(_fileExtensions.Keys, StringComparer.OrdinalIgnoreCase);
public static Source GetSourceForExtension(string extension)
public static Quality GetQualityForExtension(string extension)
{
if (_fileExtensions.ContainsKey(extension))
{
return _fileExtensions[extension];
}
return Source.UNKNOWN;
return Quality.Unknown;
}
public static Resolution GetResolutionForExtension(string extension)
{
if (_resolutionExt.ContainsKey(extension))
{
return _resolutionExt[extension];
}
var source = Source.UNKNOWN;
if (_fileExtensions.ContainsKey(extension))
{
source = _fileExtensions[extension];
}
if (source == Source.DVD || source == Source.TV)
{
return Resolution.R480P;
}
return Resolution.Unknown;
}
}
}

@ -3,6 +3,7 @@ using System.Linq;
using NLog;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
@ -28,11 +29,12 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators
var source = Source.UNKNOWN;
var sourceConfidence = Confidence.Default;
var resolution = Resolution.Unknown;
var resolution = 0;
var resolutionConfidence = Confidence.Default;
var modifier = Modifier.NONE;
var modifierConfidence = Confidence.Default;
var revison = new Revision();
var customFormats = new List<CustomFormat>();
foreach (var augmentedQuality in augmentedQualities)
{
@ -61,11 +63,18 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators
{
revison = augmentedQuality.Revision;
}
if (augmentedQuality.CustomFormats != null)
{
var newFormats = augmentedQuality.CustomFormats.Where(c => !customFormats.Any(p => p.Id == c.Id));
customFormats.AddRange(newFormats);
}
}
_logger.Trace("Finding quality. Source: {0}. Resolution: {1}. Modifier {2}", source, resolution, modifier);
var quality = new QualityModel(QualityFinder.FindBySourceAndResolution(source, resolution, modifier), revison);
var quality = new QualityModel(QualityFinder.FindBySourceAndResolution(source, resolution, modifier), revison, customFormats);
if (resolutionConfidence == Confidence.MediaInfo)
{

@ -19,7 +19,8 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter
Confidence.Tag,
quality.Quality.Modifier,
Confidence.Tag,
quality.Revision);
quality.Revision,
quality.CustomFormats);
}
}
}

@ -24,7 +24,8 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter
confidence,
quality.Quality.Modifier,
confidence,
quality.Revision);
quality.Revision,
quality.CustomFormats);
}
}
}

@ -19,7 +19,8 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter
Confidence.Tag,
quality.Quality.Modifier,
Confidence.Tag,
quality.Revision);
quality.Revision,
quality.CustomFormats);
}
}
}

@ -1,4 +1,4 @@
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality
@ -16,22 +16,22 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter
if (width >= 3200)
{
return AugmentQualityResult.ResolutionOnly(Resolution.R2160P, Confidence.MediaInfo);
return AugmentQualityResult.ResolutionOnly((int)Resolution.R2160p, Confidence.MediaInfo);
}
if (width >= 1800)
{
return AugmentQualityResult.ResolutionOnly(Resolution.R1080P, Confidence.MediaInfo);
return AugmentQualityResult.ResolutionOnly((int)Resolution.R1080p, Confidence.MediaInfo);
}
if (width >= 1200)
{
return AugmentQualityResult.ResolutionOnly(Resolution.R720P, Confidence.MediaInfo);
return AugmentQualityResult.ResolutionOnly((int)Resolution.R720p, Confidence.MediaInfo);
}
if (width > 0)
{
return AugmentQualityResult.ResolutionOnly(Resolution.R480P, Confidence.MediaInfo);
return AugmentQualityResult.ResolutionOnly((int)Resolution.R480p, Confidence.MediaInfo);
}
return null;

@ -1,5 +1,7 @@
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Qualities;
using System.Collections.Generic;
namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenters.Quality
{
@ -7,19 +9,22 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter
{
public Source Source { get; set; }
public Confidence SourceConfidence { get; set; }
public Resolution Resolution { get; set; }
public int Resolution { get; set; }
public Confidence ResolutionConfidence { get; set; }
public Modifier Modifier { get; set; }
public Confidence ModifierConfidence { get; set; }
public Revision Revision { get; set; }
public List<CustomFormat> CustomFormats { get; set; }
public AugmentQualityResult(Source source,
Confidence sourceConfidence,
Resolution resolution,
int resolution,
Confidence resolutionConfidence,
Modifier modifier,
Confidence modifierConfidence,
Revision revision)
Revision revision,
List<CustomFormat> customFormats)
{
Source = source;
SourceConfidence = sourceConfidence;
@ -28,21 +33,22 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Aggregation.Aggregators.Augmenter
Modifier = modifier;
ModifierConfidence = modifierConfidence;
Revision = revision;
CustomFormats = customFormats;
}
public static AugmentQualityResult SourceOnly(Source source, Confidence sourceConfidence)
{
return new AugmentQualityResult(source, sourceConfidence, 0, Confidence.Default, Modifier.NONE, Confidence.Default, null);
return new AugmentQualityResult(source, sourceConfidence, 0, Confidence.Default, Modifier.NONE, Confidence.Default, null, null);
}
public static AugmentQualityResult ResolutionOnly(Resolution resolution, Confidence resolutionConfidence)
public static AugmentQualityResult ResolutionOnly(int resolution, Confidence resolutionConfidence)
{
return new AugmentQualityResult(Source.UNKNOWN, Confidence.Default, resolution, resolutionConfidence, Modifier.NONE, Confidence.Default, null);
return new AugmentQualityResult(Source.UNKNOWN, Confidence.Default, resolution, resolutionConfidence, Modifier.NONE, Confidence.Default, null, null);
}
public static AugmentQualityResult ModifierOnly(Modifier modifier, Confidence modifierConfidence)
{
return new AugmentQualityResult(Source.UNKNOWN, Confidence.Default, 0, Confidence.Default, modifier, modifierConfidence, null);
return new AugmentQualityResult(Source.UNKNOWN, Confidence.Default, 0, Confidence.Default, modifier, modifierConfidence, null, null);
}
}
}

@ -36,6 +36,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
private readonly IQualityDefinitionService _qualitiesService;
private readonly IConfigService _config;
private readonly IHistoryService _historyService;
private readonly IParsingService _parsingService;
private readonly ICached<string> _warnedFiles;
private readonly Logger _logger;
@ -47,6 +48,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
IQualityDefinitionService qualitiesService,
IConfigService config,
IHistoryService historyService,
IParsingService parsingService,
ICacheManager cacheManager,
Logger logger)
{
@ -58,6 +60,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
_qualitiesService = qualitiesService;
_config = config;
_historyService = historyService;
_parsingService = parsingService;
_warnedFiles = cacheManager.GetCache<string>(this.GetType());
_logger = logger;
}
@ -78,6 +81,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
if (downloadClientItem != null)
{
downloadClientItemInfo = Parser.Parser.ParseMovieTitle(downloadClientItem.Title, false);
downloadClientItemInfo = _parsingService.EnhanceMovieInfo(downloadClientItemInfo);
}
var nonSampleVideoFileCount = GetNonSampleVideoFileCount(newFiles, movie, downloadClientItemInfo, folderInfo);
@ -107,6 +111,11 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
var fileMovieInfo = Parser.Parser.ParseMoviePath(localMovie.Path, false);
if (fileMovieInfo != null)
{
fileMovieInfo = _parsingService.EnhanceMovieInfo(fileMovieInfo);
}
localMovie.FileMovieInfo = fileMovieInfo;
localMovie.Size = _diskProvider.GetFileSize(localMovie.Path);

@ -24,30 +24,30 @@ namespace NzbDrone.Core.Parser.Augmenters
if (helper is MediaInfoModel mediaInfo)
{
var quality = movieInfo.Quality;
if (!(quality.Modifier == Modifier.BRDISK || quality.Modifier == Modifier.REMUX) &&
(quality.Source == Source.BLURAY || quality.Source == Source.TV ||
quality.Source == Source.WEBDL) &&
!(quality.Resolution == Resolution.R480P || quality.Resolution == Resolution.R576P))
if (!(quality.Quality.Modifier == Modifier.BRDISK || quality.Quality.Modifier == Modifier.REMUX) &&
(quality.Quality.Source == Source.BLURAY || quality.Quality.Source == Source.TV ||
quality.Quality.Source == Source.WEBDL) &&
!(quality.Quality.Resolution == (int)Resolution.R480p || quality.Quality.Resolution == (int)Resolution.R576p))
{
var width = mediaInfo.Width;
var existing = quality.Resolution;
var existing = quality.Quality.Resolution;
if (width > 854)
{
quality.Resolution = Resolution.R720P;
quality.Quality.Resolution = (int)Resolution.R720p;
}
if (width > 1280)
{
quality.Resolution = Resolution.R1080P;
quality.Quality.Resolution = (int)Resolution.R1080p;
}
if (width > 1920)
{
quality.Resolution = Resolution.R2160P;
quality.Quality.Resolution = (int)Resolution.R2160p;
}
if (existing != quality.Resolution)
if (existing != quality.Quality.Resolution)
{
//_logger.Debug("Overwriting resolution info {0} with info from media info {1}", existing, quality.Resolution);
quality.QualityDetectionSource = QualityDetectionSource.MediaInfo;

@ -99,24 +99,25 @@ namespace NzbDrone.Core.Parser
private static readonly Regex ReportImdbId = new Regex(@"(?<imdbid>tt\d{7})", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex SimpleTitleRegex = new Regex(@"\s*(?:480[ip]|576[ip]|720[ip]|1080[ip]|2160[ip]|[xh][\W_]?26[45]|DD\W?5\W1|[<>?*:|]|848x480|1280x720|1920x1080|(8|10)b(it)?)",
private static readonly RegexReplace SimpleTitleRegex = new RegexReplace(@"\s*(?:480[ip]|576[ip]|720[ip]|1080[ip]|2160[ip]|[xh][\W_]?26[45]|DD\W?5\W1|[<>?*:|]|848x480|1280x720|1920x1080|(8|10)b(it)?)",
string.Empty,
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex SimpleReleaseTitleRegex = new Regex(@"\s*(?:[<>?*:|])", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex WebsitePrefixRegex = new Regex(@"^\[\s*[a-z]+(\.[a-z]+)+\s*\][- ]*|^www\.[a-z]+\.(?:com|net)[ -]*",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex AirDateRegex = new Regex(@"^(.*?)(?<!\d)((?<airyear>\d{4})[_.-](?<airmonth>[0-1][0-9])[_.-](?<airday>[0-3][0-9])|(?<airmonth>[0-1][0-9])[_.-](?<airday>[0-3][0-9])[_.-](?<airyear>\d{4}))(?!\d)",
private static readonly RegexReplace WebsitePrefixRegex = new RegexReplace(@"^\[\s*[a-z]+(\.[a-z]+)+\s*\][- ]*|^www\.[a-z]+\.(?:com|net)[ -]*",
string.Empty,
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex SixDigitAirDateRegex = new Regex(@"(?<=[_.-])(?<airdate>(?<!\d)(?<airyear>[1-9]\d{1})(?<airmonth>[0-1][0-9])(?<airday>[0-3][0-9]))(?=[_.-])",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly RegexReplace CleanReleaseGroupRegex = new RegexReplace(@"^(.*?[-._ ](S\d+E\d+)[-._ ])|(-(RP|1|NZBGeek|Obfuscated|Scrambled|sample|Pre|postbot|xpost|Rakuv[a-z0-9]*|WhiteRev|BUYMORE|AsRequested|AlternativeToRequested|GEROV|Z0iDS3N|Chamele0n|4P|4Planet))+$",
string.Empty,
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex CleanReleaseGroupRegex = new Regex(@"^(.*?[-._ ](S\d+E\d+)[-._ ])|(-(RP|1|NZBGeek|Obfuscated|sample|Pre|postbot|xpost|Rakuv[a-z0-9]*|WhiteRev|BUYMORE|AsRequested|AlternativeToRequested|GEROV|Z0iDS3N|Chamele0n))+$",
private static readonly RegexReplace CleanTorrentSuffixRegex = new RegexReplace(@"\[(?:ettv|rartv|rarbg|cttv)\]$",
string.Empty,
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex CleanTorrentSuffixRegex = new Regex(@"\[(?:ettv|rartv|rarbg|cttv)\]$",
private static readonly Regex CleanQualityBracketsRegex = new Regex(@"\[[a-z0-9 ._-]+\]$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex ReleaseGroupRegex = new Regex(@"-(?<releasegroup>[a-z0-9]+(?!.+?(?:480p|720p|1080p|2160p)))(?<!.*?WEB-DL|480p|720p|1080p|2160p)(?:\b|[-._ ]|$)|[-._ ]\[(?<releasegroup>[a-z0-9]+)\]$",
@ -173,8 +174,6 @@ namespace NzbDrone.Core.Parser
public static ParsedMovieInfo ParseMovieTitle(string title, bool isLenient, bool isDir = false)
{
ParsedMovieInfo realResult = null;
try
{
if (!ValidateBeforeParsing(title)) return null;
@ -191,17 +190,26 @@ namespace NzbDrone.Core.Parser
Logger.Debug("Reversed name detected. Converted to '{0}'", title);
}
var simpleTitle = SimpleTitleRegex.Replace(title, string.Empty);
var releaseTitle = RemoveFileExtension(title);
simpleTitle = RemoveFileExtension(simpleTitle);
releaseTitle = releaseTitle.Replace("【", "[").Replace("】", "]");
var simpleReleaseTitle = SimpleReleaseTitleRegex.Replace(title, string.Empty);
simpleReleaseTitle = RemoveFileExtension(simpleReleaseTitle);
var simpleTitle = SimpleTitleRegex.Replace(releaseTitle);
// TODO: Quick fix stripping [url] - prefixes.
simpleTitle = WebsitePrefixRegex.Replace(simpleTitle, string.Empty);
simpleTitle = WebsitePrefixRegex.Replace(simpleTitle);
simpleTitle = CleanTorrentSuffixRegex.Replace(simpleTitle, string.Empty);
simpleTitle = CleanTorrentSuffixRegex.Replace(simpleTitle);
simpleTitle = CleanQualityBracketsRegex.Replace(simpleTitle, m =>
{
if (QualityParser.ParseQualityName(m.Value).Quality != Qualities.Quality.Unknown)
{
return string.Empty;
}
return m.Value;
});
var allRegexes = ReportMovieTitleRegex.ToList();
@ -231,14 +239,44 @@ namespace NzbDrone.Core.Parser
if (result != null)
{
//TODO: Add tests for this!
var simpleReleaseTitle = SimpleReleaseTitleRegex.Replace(title, string.Empty);
if (result.MovieTitle.IsNotNullOrWhiteSpace())
{
simpleReleaseTitle = simpleReleaseTitle.Replace(result.MovieTitle, result.MovieTitle.Contains(".") ? "A.Movie" : "A Movie");
}
result.Languages = LanguageParser.EnhanceLanguages(simpleReleaseTitle, LanguageParser.ParseLanguages(releaseTitle));
Logger.Debug("Languages parsed: {0}", result.Languages);
result.Quality = QualityParser.ParseQuality(title);
Logger.Debug("Quality parsed: {0}", result.Quality);
if (result.Edition.IsNullOrWhiteSpace())
{
result.Edition = ParseEdition(simpleReleaseTitle);
}
result.ReleaseGroup = ParseReleaseGroup(releaseTitle);
var subGroup = GetSubGroup(match);
if (!subGroup.IsNullOrWhiteSpace())
{
result.ReleaseGroup = subGroup;
}
Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup);
result.ReleaseHash = GetReleaseHash(match);
if (!result.ReleaseHash.IsNullOrWhiteSpace())
{
Logger.Debug("Release Hash parsed: {0}", result.ReleaseHash);
}
result.SimpleReleaseTitle = simpleReleaseTitle;
realResult = result;
result.ImdbId = ParseImdbId(simpleReleaseTitle);
return result;
}
@ -254,58 +292,11 @@ namespace NzbDrone.Core.Parser
catch (Exception e)
{
if (!title.ToLower().Contains("password") && !title.ToLower().Contains("yenc"))
Logger.Error(e, "An error has occurred while trying to parse " + title);
Logger.Error(e, "An error has occurred while trying to parse {0}", title);
}
Logger.Debug("Unable to parse {0}", title);
return realResult;
}
public static ParsedMovieInfo ParseMinimalMovieTitle(string title, string foundTitle, int foundYear)
{
var result = new ParsedMovieInfo {MovieTitle = foundTitle};
var languageTitle = Regex.Replace(title.Replace(".", " "), foundTitle, "A Movie", RegexOptions.IgnoreCase);
result.Languages = LanguageParser.ParseLanguages(title);
Logger.Debug("Language parsed: {0}", result.Languages.ToExtendedString());
result.Quality = QualityParser.ParseQuality(title);
Logger.Debug("Quality parsed: {0}", result.Quality);
if (result.Edition.IsNullOrWhiteSpace())
{
result.Edition = ParseEdition(languageTitle);
}
result.ReleaseGroup = ParseReleaseGroup(title);
result.ImdbId = ParseImdbId(title);
Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup);
if (foundYear > 1800)
{
result.Year = foundYear;
}
else
{
var match = ReportYearRegex.Match(title);
if (match.Success && match.Groups["year"].Value != null)
{
int year = 1290;
if (int.TryParse(match.Groups["year"].Value, out year))
{
result.Year = year;
}
else
{
result.Year = year;
}
}
}
return result;
return null;
}
public static string ParseImdbId(string title)
@ -421,7 +412,7 @@ namespace NzbDrone.Core.Parser
{
title = title.Trim();
title = RemoveFileExtension(title);
title = WebsitePrefixRegex.Replace(title, "");
title = WebsitePrefixRegex.Replace(title);
var animeMatch = AnimeReleaseGroupRegex.Match(title);
@ -430,7 +421,7 @@ namespace NzbDrone.Core.Parser
return animeMatch.Groups["subgroup"].Value;
}
title = CleanReleaseGroupRegex.Replace(title, "");
title = CleanReleaseGroupRegex.Replace(title);
var matches = ReleaseGroupRegex.Matches(title);

@ -25,9 +25,9 @@ namespace NzbDrone.Core.Parser
Movie GetMovie(string title);
MappingResult Map(ParsedMovieInfo parsedMovieInfo, string imdbId, SearchCriteriaBase searchCriteria = null);
ParsedMovieInfo ParseMovieInfo(string title, List<object> helpers);
ParsedMovieInfo EnhanceMovieInfo(ParsedMovieInfo parsedMovieInfo, List<object> helpers = null);
ParsedMovieInfo ParseMinimalMovieInfo(string path, bool isDir = false);
ParsedMovieInfo ParseMinimalPathMovieInfo(string path);
List<CustomFormat> ParseCustomFormat(ParsedMovieInfo movieInfo);
List<FormatTagMatchResult> MatchFormatTags(ParsedMovieInfo movieInfo);
}
@ -65,40 +65,26 @@ namespace NzbDrone.Core.Parser
public ParsedMovieInfo ParseMovieInfo(string title, List<object> helpers)
{
var result = Parser.ParseMovieTitle(title, _config.ParsingLeniency > 0);
if (result == null)
{
return null;
}
result = EnhanceMinimalInfo(result, helpers);
result = EnhanceMovieInfo(result, helpers);
return result;
}
private ParsedMovieInfo EnhanceMinimalInfo(ParsedMovieInfo minimalInfo, List<object> helpers)
public ParsedMovieInfo EnhanceMovieInfo(ParsedMovieInfo minimalInfo, List<object> helpers = null)
{
minimalInfo.Languages = LanguageParser.ParseLanguages(minimalInfo.SimpleReleaseTitle);
_logger.Debug("Language(s) parsed: {0}", string.Join(", ", minimalInfo.Languages.ToExtendedString()));
minimalInfo.Quality = QualityParser.ParseQuality(minimalInfo.SimpleReleaseTitle);
if (minimalInfo.Edition.IsNullOrWhiteSpace())
if (helpers != null)
{
minimalInfo.Edition = Parser.ParseEdition(minimalInfo.SimpleReleaseTitle);
minimalInfo = AugmentMovieInfo(minimalInfo, helpers);
}
minimalInfo.ReleaseGroup = Parser.ParseReleaseGroup(minimalInfo.SimpleReleaseTitle);
minimalInfo.ImdbId = Parser.ParseImdbId(minimalInfo.SimpleReleaseTitle);
minimalInfo = AugmentMovieInfo(minimalInfo, helpers);
// After the augmenters have done their job on languages we can do our static method as well.
minimalInfo.Languages =
LanguageParser.EnhanceLanguages(minimalInfo.SimpleReleaseTitle, minimalInfo.Languages);
minimalInfo.Quality.Quality = QualityFinder.FindBySourceAndResolution(minimalInfo.Quality.Source, minimalInfo.Quality.Resolution,
minimalInfo.Quality.Modifier);
// minimalInfo.Quality.Quality = QualityFinder.FindBySourceAndResolution(minimalInfo.Quality.Quality.Source, minimalInfo.Quality.Quality.Resolution,
// minimalInfo.Quality.Quality.Modifier);
minimalInfo.Quality.CustomFormats = ParseCustomFormat(minimalInfo);
@ -120,7 +106,7 @@ namespace NzbDrone.Core.Parser
return minimalInfo;
}
public List<CustomFormat> ParseCustomFormat(ParsedMovieInfo movieInfo)
private List<CustomFormat> ParseCustomFormat(ParsedMovieInfo movieInfo)
{
var matches = MatchFormatTags(movieInfo);
var goodMatches = matches.Where(m => m.GoodMatch);

@ -17,9 +17,11 @@ namespace NzbDrone.Core.Parser
private static readonly Regex SourceRegex = new Regex(@"\b(?:
(?<bluray>M?BluRay|Blu-Ray|HDDVD|BD(?!$)|BDISO|BD25|BD50|BR.?DISK)|
(?<webdl>WEB[-_. ]DL|HDRIP|WEBDL|WebRip|Web-Rip|iTunesHD|MaxdomeHD|NetflixU?HD|WebHD|WEBMux|[. ]WEB[. ](?:[xh]26[45]|DDP?5[. ]1)|\d+0p[-. ]WEB[-. ]|WEB-DLMux|\b\s\/\sWEB\s\/\s\b)|
(?<webdl>WEB[-_. ]DL|WEBDL|AmazonHD|iTunesHD|MaxdomeHD|NetflixU?HD|WebHD|[. ]WEB[. ](?:[xh]26[45]|DDP?5[. ]1)|\d+0p[-. ]WEB[-. ]|WEB-DLMux|\b\s\/\sWEB\s\/\s\b)|
(?<webrip>WebRip|Web-Rip|WEBMux)|
(?<hdtv>HDTV)|
(?<bdrip>BDRip)|(?<brrip>BRRip)|
(?<bdrip>BDRip)|
(?<brrip>BRRip)|
(?<dvdr>DVD-R|DVDR)|
(?<dvd>DVD|DVDRip|NTSC|PAL|xvidvd)|
(?<dsr>WS[-_. ]DSR|DSR)|
@ -35,13 +37,11 @@ namespace NzbDrone.Core.Parser
)\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static readonly Regex HardcodedSubsRegex = new Regex(@"\b(?<hcsub>(\w+SUBS?)\b)|(?<hc>(HC|SUBBED))\b", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
private static readonly Regex RemuxRegex = new Regex(@"\b(?<remux>(BD)?[-_. ]?Remux)\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex RawHDRegex = new Regex(@"\b(?<rawhd>RawHD|1080i[-_. ]HDTV|Raw[-_. ]HD|MPEG[-_. ]?2)\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex BRDISKRegex = new Regex(@"\b(COMPLETE|ISO|BDISO|BD25|BD50|BR.?DISK)\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex ProperRegex = new Regex(@"\b(?<proper>proper)\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
@ -55,7 +55,7 @@ namespace NzbDrone.Core.Parser
private static readonly Regex RealRegex = new Regex(@"\b(?<real>REAL)\b",
RegexOptions.Compiled);
private static readonly Regex ResolutionRegex = new Regex(@"\b(?:(?<R480p>480(i|p)|640x480|848x480)|(?<R576p>576(i|p))|(?<R720p>720(i|p)|1280x720)|(?<R1080p>1080p|1920x1080|1440p|FHD|1080i)|(?<R2160p>2160p|4k[-_. ](?:UHD|HEVC|BD)|(?:UHD|HEVC|BD)[-_. ]4k))\b",
private static readonly Regex ResolutionRegex = new Regex(@"\b(?:(?<R480p>480p|640x480|848x480)|(?<R576p>576p)|(?<R720p>720p|1280x720)|(?<R1080p>1080p|1920x1080|1440p|FHD|1080i)|(?<R2160p>2160p|4k[-_. ](?:UHD|HEVC|BD)|(?:UHD|HEVC|BD)[-_. ]4k))\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex CodecRegex = new Regex(@"\b(?:(?<x264>x264)|(?<h264>h264)|(?<xvidhd>XvidHD)|(?<xvid>X-?vid)|(?<divx>divx))\b",
@ -67,16 +67,41 @@ namespace NzbDrone.Core.Parser
private static readonly Regex HighDefPdtvRegex = new Regex(@"hr[-_. ]ws", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex RemuxRegex = new Regex(@"\b(?<remux>(BD)?[-_. ]?Remux)\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex HDShitQualityRegex = new Regex(@"(HD-TS|HDTS|HDTSRip|HD-TC|HDTC|HDCAM|HD-CAM)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex RawHDRegex = new Regex(@"\b(?<rawhd>RawHD|1080i[-_. ]HDTV|Raw[-_. ]HD|MPEG[-_. ]?2)\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex HardcodedSubsRegex = new Regex(@"\b(?<hcsub>(\w+SUBS?)\b)|(?<hc>(HC|SUBBED))\b",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
public static QualityModel ParseQuality(string name)
{
Logger.Debug("Trying to parse quality for {0}", name);
name = name.Trim();
var result = ParseQualityName(name);
// Based on extension
if (result.Quality == Quality.Unknown && !name.ContainsInvalidPathChars())
{
try
{
result.Quality = MediaFileExtensions.GetQualityForExtension(Path.GetExtension(name));
result.QualityDetectionSource = QualityDetectionSource.Extension;
}
catch (ArgumentException)
{
// Swallow exception for cases where string contains illegal
// path characters.
}
}
return result;
}
public static QualityModel ParseQualityName(string name)
{
var normalizedName = name.Replace('_', ' ').Trim().ToLower();
var result = ParseQualityModifiers(name, normalizedName);
var subMatch = HardcodedSubsRegex.Matches(normalizedName).OfType<Match>().LastOrDefault();
@ -93,139 +118,210 @@ namespace NzbDrone.Core.Parser
}
}
var test = SourceRegex.Matches(normalizedName);
var sourceMatch = SourceRegex.Matches(normalizedName).OfType<Match>().LastOrDefault();
var resolution = ParseResolution(normalizedName);
var codecRegex = CodecRegex.Match(normalizedName);
result.Resolution = resolution;
if (BRDISKRegex.IsMatch(normalizedName) && sourceMatch?.Groups["bluray"].Success == true)
{
result.Modifier = Modifier.BRDISK;
result.Source = Source.BLURAY;
}
if (RemuxRegex.IsMatch(normalizedName) && sourceMatch?.Groups["webdl"].Success != true && sourceMatch?.Groups["hdtv"].Success != true)
{
result.Modifier = Modifier.REMUX;
result.Source = Source.BLURAY;
return result; //We found remux!
}
if (RawHDRegex.IsMatch(normalizedName) && result.Modifier != Modifier.BRDISK)
{
result.Modifier = Modifier.RAWHD;
result.Source = Source.TV;
return result;
}
var remuxMatch = RemuxRegex.IsMatch(normalizedName);
var brDiskMatch = BRDISKRegex.IsMatch(normalizedName);
if (sourceMatch != null && sourceMatch.Success)
{
if (sourceMatch.Groups["bluray"].Success)
{
result.Source = Source.BLURAY;
if (brDiskMatch)
{
result.Quality = Quality.BRDISK;
return result;
}
if (codecRegex.Groups["xvid"].Success || codecRegex.Groups["divx"].Success)
{
result.Resolution = Resolution.R480P;
result.Source = Source.DVD;
result.Quality = Quality.Bluray480p;
return result;
}
if (resolution == Resolution.Unknown) result.Resolution = Resolution.R720P; //Blurays are always at least 720p
if (resolution == Resolution.Unknown && result.Modifier == Modifier.BRDISK) result.Resolution = Resolution.R1080P; // BRDISKS are 1080p
if (resolution == Resolution.R2160p)
{
result.Quality = remuxMatch ? Quality.Remux2160p : Quality.Bluray2160p;
return result;
}
if (resolution == Resolution.R1080p)
{
result.Quality = remuxMatch ? Quality.Remux1080p : Quality.Bluray1080p;
return result;
}
if (resolution == Resolution.R576p)
{
result.Quality = Quality.Bluray576p;
return result;
}
if (resolution == Resolution.R480p)
{
result.Quality = Quality.Bluray480p;
return result;
}
// Treat a remux without a source as 1080p, not 720p.
if (remuxMatch)
{
result.Quality = Quality.Remux1080p;
return result;
}
result.Quality = Quality.Bluray720p;
return result;
}
if (sourceMatch.Groups["webdl"].Success)
{
result.Source = Source.WEBDL;
if (resolution == Resolution.Unknown) result.Resolution = Resolution.R480P;
if (resolution == Resolution.Unknown && name.Contains("[WEBDL]")) result.Resolution = Resolution.R720P;
return result;
}
if (resolution == Resolution.R2160p)
{
result.Quality = Quality.WEBDL2160p;
return result;
}
if (sourceMatch.Groups["hdtv"].Success)
{
result.Source = Source.TV;
if (resolution == Resolution.Unknown) result.Resolution = Resolution.R480P; //hdtvs are always at least 480p (they might have been downscaled
if (resolution == Resolution.Unknown && name.Contains("[HDTV]")) result.Resolution = Resolution.R720P;
if (resolution == Resolution.R1080p)
{
result.Quality = Quality.WEBDL1080p;
return result;
}
if (resolution == Resolution.R720p)
{
result.Quality = Quality.WEBDL720p;
return result;
}
if (name.Contains("[WEBDL]"))
{
result.Quality = Quality.WEBDL720p;
return result;
}
result.Quality = Quality.WEBDL480p;
return result;
}
if (sourceMatch.Groups["bdrip"].Success ||
sourceMatch.Groups["brrip"].Success)
if (sourceMatch.Groups["webrip"].Success)
{
if (codecRegex.Groups["xvid"].Success || codecRegex.Groups["divx"].Success)
if (resolution == Resolution.R2160p)
{
result.Quality = Quality.WEBRip2160p;
return result;
}
if (resolution == Resolution.R1080p)
{
result.Quality = Quality.WEBRip1080p;
return result;
}
if (resolution == Resolution.R720p)
{
// Since it's a dvd, res is 480p
result.Resolution = Resolution.R480P;
result.Source = Source.DVD;
result.Quality = Quality.WEBRip720p;
return result;
}
if (resolution == Resolution.Unknown) result.Resolution = Resolution.R480P; //BDRip are always 480p or more.
result.Quality = Quality.WEBRip480p;
return result;
}
result.Source = Source.BLURAY;
if (sourceMatch.Groups["scr"].Success)
{
result.Quality = Quality.DVDSCR;
return result;
}
if (sourceMatch.Groups["wp"].Success)
if (sourceMatch.Groups["cam"].Success)
{
result.Source = Source.WORKPRINT;
result.Quality = Quality.CAM;
return result;
}
if (sourceMatch.Groups["dvd"].Success)
if (sourceMatch.Groups["ts"].Success)
{
result.Resolution = Resolution.R480P;
result.Source = Source.DVD;
result.Quality = Quality.TELESYNC;
result.Quality.Resolution = (int)resolution;
return result;
}
if (sourceMatch.Groups["dvdr"].Success)
if (sourceMatch.Groups["tc"].Success)
{
result.Resolution = Resolution.R480P;
result.Source = Source.DVD;
//result.Modifier = Modifier.REGIONAL;
result.Quality = Quality.TELECINE;
return result;
}
if (sourceMatch.Groups["scr"].Success)
if (sourceMatch.Groups["wp"].Success)
{
result.Resolution = Resolution.R480P;
result.Source = Source.DVD;
result.Modifier = Modifier.SCREENER;
result.Quality = Quality.WORKPRINT;
return result;
}
if (sourceMatch.Groups["regional"].Success)
{
result.Resolution = Resolution.R480P;
result.Source = Source.DVD;
result.Modifier = Modifier.REGIONAL;
result.Quality = Quality.REGIONAL;
return result;
}
// they're shit, but at least 720p
if (HDShitQualityRegex.IsMatch(normalizedName)) result.Resolution = Resolution.R720P;
if (sourceMatch.Groups["cam"].Success)
if (sourceMatch.Groups["hdtv"].Success)
{
result.Source = Source.CAM;
if (resolution == Resolution.R2160p)
{
result.Quality = Quality.HDTV2160p;
return result;
}
if (resolution == Resolution.R1080p)
{
result.Quality = Quality.HDTV1080p;
return result;
}
if (resolution == Resolution.R720p)
{
result.Quality = Quality.HDTV720p;
return result;
}
if (name.Contains("[HDTV]"))
{
result.Quality = Quality.HDTV720p;
return result;
}
result.Quality = Quality.SDTV;
return result;
}
if (sourceMatch.Groups["ts"].Success)
if (sourceMatch.Groups["bdrip"].Success ||
sourceMatch.Groups["brrip"].Success)
{
result.Source = Source.TELESYNC;
return result;
switch (resolution)
{
case Resolution.R720p:
result.Quality = Quality.Bluray720p;
return result;
case Resolution.R1080p:
result.Quality = Quality.Bluray1080p;
return result;
case Resolution.R576p:
result.Quality = Quality.Bluray576p;
return result;
default:
result.Quality = Quality.Bluray480p;
return result;
}
}
if (sourceMatch.Groups["tc"].Success)
if (sourceMatch.Groups["dvd"].Success)
{
result.Source = Source.TELECINE;
result.Quality = Quality.DVD;
return result;
}
@ -234,128 +330,142 @@ namespace NzbDrone.Core.Parser
sourceMatch.Groups["dsr"].Success ||
sourceMatch.Groups["tvrip"].Success)
{
result.Source = Source.TV;
if (resolution == Resolution.R1080p || normalizedName.Contains("1080p"))
{
result.Quality = Quality.HDTV1080p;
return result;
}
if (resolution == Resolution.R720p || normalizedName.Contains("720p"))
{
result.Quality = Quality.HDTV720p;
return result;
}
if (HighDefPdtvRegex.IsMatch(normalizedName))
{
result.Resolution = Resolution.R720P;
result.Quality = Quality.HDTV720p;
return result;
}
result.Resolution = Resolution.R480P;
result.Quality = Quality.SDTV;
return result;
}
}
//Anime Bluray matching
// Anime Bluray matching
if (AnimeBlurayRegex.Match(normalizedName).Success)
{
if (resolution == Resolution.R480P || resolution == Resolution.R576P || normalizedName.Contains("480p"))
if (resolution == Resolution.R480p || resolution == Resolution.R576p || normalizedName.Contains("480p"))
{
result.Resolution = Resolution.R480P;
result.Source = Source.DVD;
result.Quality = Quality.DVD;
return result;
}
if (resolution == Resolution.R1080P || normalizedName.Contains("1080p"))
if (resolution == Resolution.R1080p || normalizedName.Contains("1080p"))
{
result.Resolution = Resolution.R1080P;
result.Source = Source.BLURAY;
result.Quality = remuxMatch ? Quality.Remux1080p : Quality.Bluray1080p;
return result;
}
result.Resolution = Resolution.R720P;
result.Source = Source.BLURAY;
if (resolution == Resolution.R2160p || normalizedName.Contains("2160p"))
{
result.Quality = remuxMatch ? Quality.Remux2160p : Quality.Bluray2160p;
return result;
}
// Treat a remux without a source as 1080p, not 720p.
if (remuxMatch)
{
result.Quality = Quality.Bluray1080p;
return result;
}
result.Quality = Quality.Bluray720p;
return result;
}
var otherSourceMatch = OtherSourceMatch(normalizedName);
if (resolution == Resolution.R2160p)
{
result.Quality = remuxMatch ? Quality.Remux2160p : Quality.HDTV2160p;
return result;
}
if (otherSourceMatch.Source != Source.UNKNOWN)
if (resolution == Resolution.R1080p)
{
result.Source = otherSourceMatch.Source;
result.Resolution = resolution == Resolution.Unknown ? otherSourceMatch.Resolution : resolution;
result.Quality = remuxMatch ? Quality.Remux1080p : Quality.HDTV1080p;
return result;
}
if (resolution == Resolution.R2160P || resolution == Resolution.R1080P || resolution == Resolution.R720P)
if (resolution == Resolution.R720p)
{
result.Source = Source.WEBDL;
result.Quality = Quality.HDTV720p;
return result;
}
if (resolution == Resolution.R480P)
if (resolution == Resolution.R480p)
{
result.Source = Source.DVD;
result.Quality = Quality.SDTV;
return result;
}
if (codecRegex.Groups["x264"].Success)
{
result.Source = Source.DVD;
result.Resolution = Resolution.R480P;
result.Quality = Quality.SDTV;
return result;
}
if (normalizedName.Contains("848x480"))
{
if (normalizedName.Contains("dvd"))
{
result.Quality = Quality.DVD;
}
result.Source = Source.DVD;
result.Resolution = Resolution.R480P;
return result;
result.Quality = Quality.SDTV;
}
if (normalizedName.Contains("1280x720"))
{
result.Resolution = Resolution.R720P;
result.Source = Source.WEBDL;
if (normalizedName.Contains("bluray"))
{
result.Source = Source.BLURAY;
result.Quality = Quality.Bluray720p;
}
return result;
result.Quality = Quality.HDTV720p;
}
if (normalizedName.Contains("1920x1080"))
{
result.Resolution = Resolution.R1080P;
result.Source = Source.WEBDL;
if (normalizedName.Contains("bluray"))
{
result.Source = Source.BLURAY;
result.Quality = Quality.Bluray1080p;
}
return result;
result.Quality = Quality.HDTV1080p;
}
if (normalizedName.Contains("bluray720p"))
{
result.Resolution = Resolution.R720P;
result.Source = Source.BLURAY;
return result;
result.Quality = Quality.Bluray720p;
}
if (normalizedName.Contains("bluray1080p"))
{
result.Resolution = Resolution.R1080P;
result.Source = Source.BLURAY;
return result;
result.Quality = Quality.Bluray1080p;
}
//Based on extension
if (result.Source == Source.UNKNOWN && !name.ContainsInvalidPathChars())
if (normalizedName.Contains("bluray2160p"))
{
try
{
result.Source = MediaFileExtensions.GetSourceForExtension(Path.GetExtension(name));
result.Resolution = MediaFileExtensions.GetResolutionForExtension(Path.GetExtension(name));
result.Quality = Quality.Bluray2160p;
}
result.QualityDetectionSource = QualityDetectionSource.Extension;
}
catch (ArgumentException)
{
//Swallow exception for cases where string contains illegal
//path characters.
}
var otherSourceMatch = OtherSourceMatch(normalizedName);
if (otherSourceMatch != Quality.Unknown)
{
result.Quality = otherSourceMatch;
}
return result;
@ -366,29 +476,29 @@ namespace NzbDrone.Core.Parser
var match = ResolutionRegex.Match(name);
if (!match.Success) return Resolution.Unknown;
if (match.Groups["R480p"].Success) return Resolution.R480P;
if (match.Groups["R576p"].Success) return Resolution.R576P;
if (match.Groups["R720p"].Success) return Resolution.R720P;
if (match.Groups["R1080p"].Success) return Resolution.R1080P;
if (match.Groups["R2160p"].Success) return Resolution.R2160P;
if (match.Groups["R480p"].Success) return Resolution.R480p;
if (match.Groups["R576p"].Success) return Resolution.R576p;
if (match.Groups["R720p"].Success) return Resolution.R720p;
if (match.Groups["R1080p"].Success) return Resolution.R1080p;
if (match.Groups["R2160p"].Success) return Resolution.R2160p;
return Resolution.Unknown;
}
private static QualityModel OtherSourceMatch(string name)
private static Quality OtherSourceMatch(string name)
{
var match = OtherSourceRegex.Match(name);
if (!match.Success) return new QualityModel();
if (match.Groups["sdtv"].Success) return new QualityModel {Source = Source.TV, Resolution = Resolution.R480P};
if (match.Groups["hdtv"].Success) return new QualityModel {Source = Source.TV, Resolution = Resolution.R720P};
if (!match.Success) return Quality.Unknown;
if (match.Groups["sdtv"].Success) return Quality.SDTV;
if (match.Groups["hdtv"].Success) return Quality.HDTV720p;
return new QualityModel();
return Quality.Unknown;
}
private static QualityModel ParseQualityModifiers(string name, string normalizedName)
{
var result = new QualityModel();
var result = new QualityModel { Quality = Quality.Unknown };
if (ProperRegex.IsMatch(normalizedName))
{
@ -408,8 +518,8 @@ namespace NzbDrone.Core.Parser
result.Revision.Version = Convert.ToInt32(versionRegexResult.Groups["version"].Value);
}
//TODO: re-enable this when we have a reliable way to determine real
//TODO: Only treat it as a real if it comes AFTER the season/epsiode number
// TODO: re-enable this when we have a reliable way to determine real
// TODO: Only treat it as a real if it comes AFTER the season/episode number
var realRegexResult = RealRegex.Matches(name);
if (realRegexResult.Count > 0)
@ -420,4 +530,14 @@ namespace NzbDrone.Core.Parser
return result;
}
}
public enum Resolution
{
Unknown,
R480p = 480,
R576p = 576,
R720p = 720,
R1080p = 1080,
R2160p = 2160
}
}

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace NzbDrone.Core.Parser
{
public class RegexReplace
{
private readonly Regex _regex;
private readonly string _replacementFormat;
private readonly MatchEvaluator _replacementFunc;
public RegexReplace(string pattern, string replacement, RegexOptions regexOptions)
{
_regex = new Regex(pattern, regexOptions);
_replacementFormat = replacement;
}
public RegexReplace(string pattern, MatchEvaluator replacement, RegexOptions regexOptions)
{
_regex = new Regex(pattern, regexOptions);
_replacementFunc = replacement;
}
public string Replace(string input)
{
if (_replacementFunc != null)
return _regex.Replace(input, _replacementFunc);
else
return _regex.Replace(input, _replacementFormat);
}
public bool TryReplace(ref string input)
{
var result = _regex.IsMatch(input);
if (_replacementFunc != null)
input = _regex.Replace(input, _replacementFunc);
else
input = _regex.Replace(input, _replacementFormat);
return result;
}
}
}

@ -130,9 +130,13 @@ namespace NzbDrone.Core.Profiles
Quality.HDTV1080p,
Quality.HDTV2160p,
Quality.WEBDL480p,
Quality.WEBRip480p,
Quality.WEBDL720p,
Quality.WEBRip720p,
Quality.WEBDL1080p,
Quality.WEBRip1080p,
Quality.WEBDL2160p,
Quality.WEBRip2160p,
Quality.Bluray480p,
Quality.Bluray576p,
Quality.Bluray720p,
@ -152,23 +156,27 @@ namespace NzbDrone.Core.Profiles
Quality.SDTV,
Quality.DVD,
Quality.WEBDL480p,
Quality.WEBRip480p,
Quality.Bluray480p,
Quality.Bluray576p);
AddDefaultProfile("HD-720p", Quality.Bluray720p,
Quality.HDTV720p,
Quality.WEBDL720p,
Quality.WEBRip720p,
Quality.Bluray720p);
AddDefaultProfile("HD-1080p", Quality.Bluray1080p,
Quality.HDTV1080p,
Quality.WEBDL1080p,
Quality.WEBRip1080p,
Quality.Bluray1080p,
Quality.Remux1080p);
AddDefaultProfile("Ultra-HD", Quality.Remux2160p,
Quality.HDTV2160p,
Quality.WEBDL2160p,
Quality.WEBRip2160p,
Quality.Bluray2160p,
Quality.Remux2160p);
@ -176,7 +184,9 @@ namespace NzbDrone.Core.Profiles
Quality.HDTV720p,
Quality.HDTV1080p,
Quality.WEBDL720p,
Quality.WEBRip720p,
Quality.WEBDL1080p,
Quality.WEBRip1080p,
Quality.Bluray720p,
Quality.Bluray1080p,
Quality.Remux1080p,

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Qualities
@ -11,14 +12,14 @@ namespace NzbDrone.Core.Qualities
public int Id { get; set; }
public string Name { get; set; }
public Source Source { get; set; }
public Resolution Resolution { get; set; }
public int Resolution { get; set; }
public Modifier Modifier { get; set; }
public Quality()
{
}
private Quality(int id, string name, Source source, Resolution resolution, Modifier modifier = Modifier.NONE)
private Quality(int id, string name, Source source, int resolution, Modifier modifier = Modifier.NONE)
{
Id = id;
Name = name;
@ -27,12 +28,6 @@ namespace NzbDrone.Core.Qualities
Modifier = modifier;
}
private Quality(int id, string name, Source source, int resolution, Modifier modifier = Modifier.NONE)
: this(id, name, source, (Resolution) resolution, modifier)
{
}
public override string ToString()
{
return Name;
@ -105,11 +100,16 @@ namespace NzbDrone.Core.Qualities
public static Quality Remux1080p => new Quality(30, "Remux-1080p", Source.BLURAY, 1080, Modifier.REMUX);
public static Quality Remux2160p => new Quality(31, "Remux-2160p", Source.BLURAY, 2160, Modifier.REMUX);
public static Quality BRDISK => new Quality(22, "BR-DISK", Source.BLURAY, 0, Modifier.BRDISK); // new
public static Quality BRDISK => new Quality(22, "BR-DISK", Source.BLURAY, 1080, Modifier.BRDISK); // new
// Others
public static Quality RAWHD => new Quality(10, "Raw-HD", Source.TV, 1080, Modifier.RAWHD);
public static Quality WEBRip480p => new Quality(12, "WEBRip-480p", Source.WEBRIP, 480);
public static Quality WEBRip720p => new Quality(14, "WEBRip-720p", Source.WEBRIP, 720);
public static Quality WEBRip1080p => new Quality(15, "WEBRip-1080p", Source.WEBRIP, 1080);
public static Quality WEBRip2160p => new Quality(17, "WEBRip-2160p", Source.WEBRIP, 2160);
static Quality()
{
All = new List<Quality>
@ -131,6 +131,10 @@ namespace NzbDrone.Core.Qualities
WEBDL720p,
WEBDL1080p,
WEBDL2160p,
WEBRip480p,
WEBRip720p,
WEBRip1080p,
WEBRip2160p,
Bluray480p,
Bluray576p,
Bluray720p,
@ -161,21 +165,25 @@ namespace NzbDrone.Core.Qualities
new QualityDefinition(Quality.DVD) { Weight = 9, MinSize = 0, MaxSize = 100 },
new QualityDefinition(Quality.DVDR) { Weight = 10, MinSize = 0, MaxSize = 100 },
new QualityDefinition(Quality.WEBDL480p) { Weight = 11, MinSize = 0, MaxSize = 100 },
new QualityDefinition(Quality.WEBDL480p) { Weight = 11, MinSize = 0, MaxSize = 100, GroupName = "WEB 480p" },
new QualityDefinition(Quality.WEBRip480p) { Weight = 11, MinSize = 0, MaxSize = 100, GroupName = "WEB 480p" },
new QualityDefinition(Quality.Bluray480p) { Weight = 12, MinSize = 0, MaxSize = 100 },
new QualityDefinition(Quality.Bluray576p) { Weight = 13, MinSize = 0, MaxSize = 100 },
new QualityDefinition(Quality.HDTV720p) { Weight = 14, MinSize = 0, MaxSize = 100 },
new QualityDefinition(Quality.WEBDL720p) { Weight = 15, MinSize = 0, MaxSize = 100 },
new QualityDefinition(Quality.WEBDL720p) { Weight = 15, MinSize = 0, MaxSize = 100, GroupName = "WEB 720p" },
new QualityDefinition(Quality.WEBRip720p) { Weight = 15, MinSize = 0, MaxSize = 100, GroupName = "WEB 720p" },
new QualityDefinition(Quality.Bluray720p) { Weight = 16, MinSize = 0, MaxSize = 100 },
new QualityDefinition(Quality.HDTV1080p) { Weight = 17, MinSize = 0, MaxSize = 100 },
new QualityDefinition(Quality.WEBDL1080p) { Weight = 18, MinSize = 0, MaxSize = 100 },
new QualityDefinition(Quality.WEBDL1080p) { Weight = 18, MinSize = 0, MaxSize = 100, GroupName = "WEB 1080p" },
new QualityDefinition(Quality.WEBRip1080p) { Weight = 18, MinSize = 0, MaxSize = 100, GroupName = "WEB 1080p" },
new QualityDefinition(Quality.Bluray1080p) { Weight = 19, MinSize = 0, MaxSize = null },
new QualityDefinition(Quality.Remux1080p) { Weight = 20, MinSize = 0, MaxSize = null },
new QualityDefinition(Quality.HDTV2160p) { Weight = 21, MinSize = 0, MaxSize = null },
new QualityDefinition(Quality.WEBDL2160p) { Weight = 22, MinSize = 0, MaxSize = null },
new QualityDefinition(Quality.WEBDL2160p) { Weight = 22, MinSize = 0, MaxSize = null, GroupName = "WEB 2160p" },
new QualityDefinition(Quality.WEBRip2160p) { Weight = 22, MinSize = 0, MaxSize = null, GroupName = "WEB 2160p" },
new QualityDefinition(Quality.Bluray2160p) { Weight = 23, MinSize = 0, MaxSize = null },
new QualityDefinition(Quality.Remux2160p) { Weight = 24, MinSize = 0, MaxSize = null },

@ -2,6 +2,7 @@ using System.Linq;
using NLog;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.CustomFormats;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Qualities
{
@ -9,7 +10,7 @@ namespace NzbDrone.Core.Qualities
{
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(QualityFinder));
public static Quality FindBySourceAndResolution(Source source, Resolution resolution, Modifier modifer)
public static Quality FindBySourceAndResolution(Source source, int resolution, Modifier modifer)
{
// Check for a perfect 3-way match
var matchingQuality = Quality.All.SingleOrDefault(q => q.Source == source && q.Resolution == resolution && q.Modifier == modifer);
@ -20,7 +21,7 @@ namespace NzbDrone.Core.Qualities
}
// Check for Source and Modifier Match for Qualities with Unknown Resolution
var matchingQualitiesUnknownResolution = Quality.All.Where(q => q.Source == source && (q.Resolution == Resolution.Unknown) && q.Modifier == modifer && q != Quality.Unknown);
var matchingQualitiesUnknownResolution = Quality.All.Where(q => q.Source == source && (q.Resolution == 0) && q.Modifier == modifer && q != Quality.Unknown);
if (matchingQualitiesUnknownResolution.Any())
{

@ -12,13 +12,6 @@ namespace NzbDrone.Core.Qualities
public List<CustomFormat> CustomFormats { get; set; }
[JsonIgnore]
public Resolution Resolution { get; set; }
[JsonIgnore]
public Source Source { get; set; }
[JsonIgnore]
public Modifier Modifier { get; set; }
public Revision Revision { get; set; }
@ -33,11 +26,11 @@ namespace NzbDrone.Core.Qualities
}
public QualityModel(Quality quality, Revision revision = null)
public QualityModel(Quality quality, Revision revision = null, List<CustomFormat> customFormats = null)
{
Quality = quality;
Revision = revision ?? new Revision();
CustomFormats = new List<CustomFormat>();
CustomFormats = customFormats ?? new List<CustomFormat>();
}
public override string ToString()

Loading…
Cancel
Save