Quality groups
This commit is contained in:
parent
068ea1e934
commit
f31ac39e37
|
@ -1,8 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using Sonarr.Http;
|
||||
using Sonarr.Http.Mapping;
|
||||
|
||||
namespace NzbDrone.Api.Profiles
|
||||
{
|
||||
|
@ -53,4 +52,4 @@ namespace NzbDrone.Api.Profiles
|
|||
return _profileService.All().ToResource();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using Sonarr.Http.REST;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
|
@ -27,13 +26,41 @@ namespace NzbDrone.Api.Profiles
|
|||
{
|
||||
if (model == null) return null;
|
||||
|
||||
var cutoffItem = model.Items.First(q =>
|
||||
{
|
||||
if (q.Id == model.Cutoff) return true;
|
||||
|
||||
if (q.Quality == null) return false;
|
||||
|
||||
return q.Quality.Id == model.Cutoff;
|
||||
});
|
||||
|
||||
var cutoff = cutoffItem.Items == null || cutoffItem.Items.Empty()
|
||||
? cutoffItem.Quality
|
||||
: cutoffItem.Items.First().Quality;
|
||||
|
||||
return new ProfileResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
Name = model.Name,
|
||||
Cutoff = model.Cutoff,
|
||||
Items = model.Items.ConvertAll(ToResource)
|
||||
Cutoff = cutoff,
|
||||
|
||||
// Flatten groups so things don't explode
|
||||
Items = model.Items.SelectMany(i =>
|
||||
{
|
||||
if (i == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (i.Items.Any())
|
||||
{
|
||||
return i.Items.ConvertAll(ToResource);
|
||||
}
|
||||
|
||||
return new List<ProfileQualityItemResource> {ToResource(i)};
|
||||
}).ToList()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -57,7 +84,7 @@ namespace NzbDrone.Api.Profiles
|
|||
Id = resource.Id,
|
||||
|
||||
Name = resource.Name,
|
||||
Cutoff = (Quality)resource.Cutoff.Id,
|
||||
Cutoff = resource.Cutoff.Id,
|
||||
Items = resource.Items.ConvertAll(ToModel)
|
||||
};
|
||||
}
|
||||
|
@ -78,4 +105,4 @@ namespace NzbDrone.Api.Profiles
|
|||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace NzbDrone.Api.Profiles
|
|||
.ToList();
|
||||
|
||||
var profile = new Profile();
|
||||
profile.Cutoff = Quality.Unknown;
|
||||
profile.Cutoff = Quality.Unknown.Id;
|
||||
profile.Items = items;
|
||||
|
||||
return new List<ProfileResource> { profile.ToResource() };
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace NzbDrone.Core.Test.Datastore
|
|||
var profile = new Profile
|
||||
{
|
||||
Name = "Test",
|
||||
Cutoff = Quality.WEBDL720p,
|
||||
Cutoff = Quality.WEBDL720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
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_and_br480_qualites_in_profileFixture : MigrationTest<add_webrip_and_br480_qualites_in_profile>
|
||||
{
|
||||
private string GenerateQualityJson(int quality, bool allowed)
|
||||
{
|
||||
return $"{{ \"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<Profile117>("SELECT Items FROM Profiles LIMIT 1");
|
||||
|
||||
var items = profiles.First().Items;
|
||||
items.Should().HaveCount(6);
|
||||
items.Select(v => v.Quality).Should().BeEquivalentTo(1, null, null, null, null, null);
|
||||
items.Select(v => v.Items.Count).Should().BeEquivalentTo(0, 2, 2, 2, 2, 2);
|
||||
items.Select(v => v.Allowed).Should().BeEquivalentTo(true, false, false, false, false, false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_add_bluray480p_quality_and_group_with_dvd()
|
||||
{
|
||||
var db = WithMigrationTestDb(c =>
|
||||
{
|
||||
c.Insert.IntoTable("Profiles").Row(new
|
||||
{
|
||||
Id = 0,
|
||||
Name = "SDTV",
|
||||
Cutoff = 1,
|
||||
Items = $"[{GenerateQualityJson(1, true)}, {GenerateQualityJson((int)Quality.DVD, false)}, {GenerateQualityJson((int)Quality.Bluray480p, false)}]"
|
||||
});
|
||||
});
|
||||
|
||||
var profiles = db.Query<Profile117>("SELECT Items FROM Profiles LIMIT 1");
|
||||
|
||||
var items = profiles.First().Items;
|
||||
items.Should().HaveCount(6);
|
||||
items.Select(v => v.Quality).Should().BeEquivalentTo(1, null, null, null, null, null);
|
||||
items.Select(v => v.Items.Count).Should().BeEquivalentTo(0, 2, 2, 2, 2, 2);
|
||||
items.Select(v => v.Allowed).Should().BeEquivalentTo(true, false, 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<Profile117>("SELECT Items FROM Profiles LIMIT 1");
|
||||
|
||||
var items = profiles.First().Items;
|
||||
items.Should().HaveCount(6);
|
||||
items.Select(v => v.Quality).Should().BeEquivalentTo(1, null, null, null, null, null);
|
||||
items.Select(v => v.Items.Count).Should().BeEquivalentTo(0, 2, 2, 2, 2, 2);
|
||||
items.Select(v => v.Allowed).Should().BeEquivalentTo(true, false, 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<Profile117>("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.DVD);
|
||||
items[2].Items.Last().Quality.Should().Be((int)Quality.Bluray480p);
|
||||
|
||||
items[3].Items.First().Quality.Should().Be((int)Quality.WEBRip720p);
|
||||
items[3].Items.Last().Quality.Should().Be((int)Quality.WEBDL720p);
|
||||
|
||||
items[4].Items.First().Quality.Should().Be((int)Quality.WEBRip1080p);
|
||||
items[4].Items.Last().Quality.Should().Be((int)Quality.WEBDL1080p);
|
||||
|
||||
items[5].Items.First().Quality.Should().Be((int)Quality.WEBRip2160p);
|
||||
items[5].Items.Last().Quality.Should().Be((int)Quality.WEBDL2160p);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Subject.CutoffNotMet(
|
||||
new Profile
|
||||
{
|
||||
Cutoff = Quality.Bluray1080p,
|
||||
Cutoff = Quality.Bluray1080p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities()
|
||||
},
|
||||
new LanguageProfile
|
||||
|
@ -36,7 +36,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Subject.CutoffNotMet(
|
||||
new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities()
|
||||
},
|
||||
new LanguageProfile
|
||||
|
@ -53,7 +53,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Subject.CutoffNotMet(
|
||||
new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities()
|
||||
},
|
||||
new LanguageProfile
|
||||
|
@ -70,7 +70,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Subject.CutoffNotMet(
|
||||
new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities()
|
||||
},
|
||||
new LanguageProfile
|
||||
|
@ -89,7 +89,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Subject.CutoffNotMet(
|
||||
new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities()
|
||||
},
|
||||
new LanguageProfile
|
||||
|
@ -108,7 +108,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
};
|
||||
|
||||
|
@ -131,7 +131,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
};
|
||||
|
||||
|
@ -155,7 +155,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
};
|
||||
|
||||
|
@ -179,7 +179,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
};
|
||||
|
||||
|
@ -203,7 +203,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
};
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
public void Setup()
|
||||
{
|
||||
var fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(c => c.Profile = (LazyLoaded<Profile>)new Profile { Cutoff = Quality.Bluray1080p })
|
||||
.With(c => c.Profile = (LazyLoaded<Profile>)new Profile { Cutoff = Quality.Bluray1080p.Id })
|
||||
.Build();
|
||||
|
||||
remoteEpisode = new RemoteEpisode
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
var profile = new Profile
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
Cutoff = cutoff,
|
||||
Cutoff = cutoff.Id,
|
||||
};
|
||||
|
||||
var langProfile = new LanguageProfile
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
[Test]
|
||||
public void should_return_true_when_quality_in_queue_is_lower()
|
||||
{
|
||||
_series.Profile.Value.Cutoff = Quality.Bluray1080p;
|
||||
_series.Profile.Value.Cutoff = Quality.Bluray1080p.Id;
|
||||
_series.LanguageProfile.Value.Cutoff = Language.Spanish;
|
||||
|
||||
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
|
||||
|
@ -126,7 +126,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
[Test]
|
||||
public void should_return_true_when_quality_in_queue_is_lower_but_language_is_higher()
|
||||
{
|
||||
_series.Profile.Value.Cutoff = Quality.Bluray1080p;
|
||||
_series.Profile.Value.Cutoff = Quality.Bluray1080p.Id;
|
||||
_series.LanguageProfile.Value.Cutoff = Language.Spanish;
|
||||
|
||||
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
|
||||
|
@ -196,7 +196,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
[Test]
|
||||
public void should_return_false_when_quality_in_queue_is_better()
|
||||
{
|
||||
_series.Profile.Value.Cutoff = Quality.Bluray1080p;
|
||||
_series.Profile.Value.Cutoff = Quality.Bluray1080p.Id;
|
||||
|
||||
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
|
||||
.With(r => r.Series = _series)
|
||||
|
@ -294,7 +294,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
[Test]
|
||||
public void should_return_false_if_quality_and_language_in_queue_meets_cutoff()
|
||||
{
|
||||
_series.Profile.Value.Cutoff = _remoteEpisode.ParsedEpisodeInfo.Quality.Quality;
|
||||
_series.Profile.Value.Cutoff = _remoteEpisode.ParsedEpisodeInfo.Quality.Quality.Id;
|
||||
|
||||
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
|
||||
.With(r => r.Series = _series)
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
_profile.Items.Add(new ProfileQualityItem { Allowed = true, Quality = Quality.WEBDL720p });
|
||||
_profile.Items.Add(new ProfileQualityItem { Allowed = true, Quality = Quality.Bluray720p });
|
||||
|
||||
_profile.Cutoff = Quality.WEBDL720p;
|
||||
_profile.Cutoff = Quality.WEBDL720p.Id;
|
||||
|
||||
_langProfile.Cutoff = Language.Spanish;
|
||||
_langProfile.Languages = Languages.LanguageFixture.GetDefaultLanguages();
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
};
|
||||
|
||||
var fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p })
|
||||
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id })
|
||||
.With(c => c.Path = @"C:\Series\My.Series".AsOsAgnostic())
|
||||
.Build();
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
};
|
||||
|
||||
_fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p, Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||
.With(l => l.LanguageProfile = new LanguageProfile { Cutoff = Language.Spanish, Languages = LanguageFixture.GetDefaultLanguages() })
|
||||
.Build();
|
||||
|
||||
|
@ -163,7 +163,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
[Test]
|
||||
public void should_not_be_upgradable_if_episode_is_of_same_quality_as_existing()
|
||||
{
|
||||
_fakeSeries.Profile = new Profile { Cutoff = Quality.Bluray1080p, Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
_fakeSeries.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1));
|
||||
_upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.English);
|
||||
|
||||
|
@ -175,7 +175,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
[Test]
|
||||
public void should_be_upgradable_if_episode_is_of_same_quality_as_existing_but_new_has_better_language()
|
||||
{
|
||||
_fakeSeries.Profile = new Profile { Cutoff = Quality.WEBDL1080p, Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
_fakeSeries.Profile = new Profile { Cutoff = Quality.WEBDL1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1));
|
||||
_parseResultSingle.ParsedEpisodeInfo.Language = Language.Spanish;
|
||||
_upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.English);
|
||||
|
@ -188,7 +188,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
[Test]
|
||||
public void should_not_be_upgradable_if_cutoff_already_met()
|
||||
{
|
||||
_fakeSeries.Profile = new Profile { Cutoff = Quality.WEBDL1080p, Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
_fakeSeries.Profile = new Profile { Cutoff = Quality.WEBDL1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1));
|
||||
_upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.Spanish);
|
||||
|
||||
|
@ -216,7 +216,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
public void should_return_false_if_cutoff_already_met_and_cdh_is_disabled()
|
||||
{
|
||||
GivenCdhDisabled();
|
||||
_fakeSeries.Profile = new Profile { Cutoff = Quality.WEBDL1080p, Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
_fakeSeries.Profile = new Profile { Cutoff = Quality.WEBDL1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.Bluray1080p, new Revision(version: 1));
|
||||
_upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.Spanish);
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
var doubleEpisodeList = new List<Episode> { new Episode { EpisodeFile = _firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = _secondFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } };
|
||||
|
||||
var fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p })
|
||||
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id })
|
||||
.Build();
|
||||
|
||||
_parseResultMulti = new RemoteEpisode
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
var languages = Languages.LanguageFixture.GetDefaultLanguages(Language.English, Language.Spanish);
|
||||
|
||||
var fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p, Items = Qualities.QualityFixture.GetDefaultQualities()})
|
||||
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities()})
|
||||
.With(l => l.LanguageProfile = new LanguageProfile { Cutoff = Language.Spanish, Languages = languages })
|
||||
.Build();
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||
_profile = new Profile
|
||||
{
|
||||
Name = "Test",
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = new List<ProfileQualityItem>
|
||||
{
|
||||
new ProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p },
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||
_profile = new Profile
|
||||
{
|
||||
Name = "Test",
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = new List<ProfileQualityItem>
|
||||
{
|
||||
new ProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p },
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
|
|||
_profile = new Profile
|
||||
{
|
||||
Name = "Test",
|
||||
Cutoff = Quality.HDTV720p,
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = new List<ProfileQualityItem>
|
||||
{
|
||||
new ProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p },
|
||||
|
|
|
@ -30,13 +30,13 @@ namespace NzbDrone.Core.Test.HistoryTests
|
|||
{
|
||||
_profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.WEBDL720p,
|
||||
Cutoff = Quality.WEBDL720p.Id,
|
||||
Items = QualityFixture.GetDefaultQualities(),
|
||||
};
|
||||
|
||||
_profileCustom = new Profile
|
||||
{
|
||||
Cutoff = Quality.WEBDL720p,
|
||||
Cutoff = Quality.WEBDL720p.Id,
|
||||
Items = QualityFixture.GetDefaultQualities(Quality.DVD),
|
||||
|
||||
};
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
<Compile Include="Datastore\DatabaseRelationshipFixture.cs" />
|
||||
<Compile Include="Datastore\MappingExtentionFixture.cs" />
|
||||
<Compile Include="Datastore\MarrDataLazyLoadingFixture.cs" />
|
||||
<Compile Include="Datastore\Migration\117_add_webrip_qualites_in_profileFixture.cs" />
|
||||
<Compile Include="Datastore\Migration\108_fix_metadata_file_extensionsFixture.cs" />
|
||||
<Compile Include="Datastore\Migration\109_import_extra_files_configFixture.cs" />
|
||||
<Compile Include="Datastore\Migration\110_fix_extra_files_configFixture.cs" />
|
||||
|
@ -343,6 +344,7 @@
|
|||
<Compile Include="ParserTests\MiniSeriesEpisodeParserFixture.cs" />
|
||||
<Compile Include="ParserTests\ValidateParsedEpisodeInfoFixture.cs" />
|
||||
<Compile Include="Profiles\Delay\DelayProfileServiceFixture.cs" />
|
||||
<Compile Include="Profiles\Qualities\QualityIndexCompareToFixture.cs" />
|
||||
<Compile Include="Qualities\RevisionComparableFixture.cs" />
|
||||
<Compile Include="QueueTests\QueueServiceFixture.cs" />
|
||||
<Compile Include="RemotePathMappingsTests\RemotePathMappingServiceFixture.cs" />
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
new object[] { Quality.SDTV },
|
||||
new object[] { Quality.DVD },
|
||||
new object[] { Quality.WEBDL480p },
|
||||
new object[] { Quality.Bluray480p },
|
||||
new object[] { Quality.HDTV720p },
|
||||
new object[] { Quality.HDTV1080p },
|
||||
new object[] { Quality.HDTV2160p },
|
||||
|
@ -67,22 +68,12 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
ParseAndVerifyQuality(title, Quality.SDTV, proper);
|
||||
}
|
||||
|
||||
[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.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("Hannibal.S01E05.576p.BluRay.DD5.1.x264-HiSD", false)]
|
||||
[TestCase("Hannibal.S01E05.480p.BluRay.DD5.1.x264-HiSD", false)]
|
||||
[TestCase("Heidi Girl of the Alps (BD)(640x480(RAW) (BATCH 1) (1-13)", false)]
|
||||
[TestCase("[Doki] Clannad - 02 (848x480 XviD BD MP3) [95360783]", false)]
|
||||
public void should_parse_dvd_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.DVD, proper);
|
||||
|
@ -99,6 +90,28 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
ParseAndVerifyQuality(title, Quality.WEBDL480p, proper);
|
||||
}
|
||||
|
||||
[TestCase("WEEDS.S03E01-06.DUAL.XviD.Bluray.AC3-REPACK.-HELLYWOOD.avi", true)]
|
||||
[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.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("Hannibal.S01E05.576p.BluRay.DD5.1.x264-HiSD", false)]
|
||||
[TestCase("Hannibal.S01E05.480p.BluRay.DD5.1.x264-HiSD", false)]
|
||||
[TestCase("Heidi Girl of the Alps (BD)(640x480(RAW) (BATCH 1) (1-13)", false)]
|
||||
[TestCase("[Doki] Clannad - 02 (848x480 XviD BD MP3) [95360783]", false)]
|
||||
public void should_parse_bluray480p_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.Bluray480p, proper);
|
||||
}
|
||||
|
||||
[TestCase("Clarissa.Explains.It.All.S02E10.480p.HULU.WEBRip.x264-Puffin", false)]
|
||||
[TestCase("Duck.Dynasty.S10E14.Techs.And.Balances.480p.AE.WEBRip.AAC2.0.x264-SEA", false)]
|
||||
public void should_parse_webrip480p_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.WEBRip480p, proper);
|
||||
}
|
||||
|
||||
[TestCase("Dexter - S01E01 - Title [HDTV]", false)]
|
||||
[TestCase("Dexter - S01E01 - Title [HDTV-720p]", false)]
|
||||
[TestCase("Pawn Stars S04E87 REPACK 720p HDTV x264 aAF", true)]
|
||||
|
@ -152,7 +165,6 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
ParseAndVerifyQuality(title, Quality.HDTV2160p, proper);
|
||||
}
|
||||
|
||||
[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)]
|
||||
|
@ -176,7 +188,14 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
ParseAndVerifyQuality(title, Quality.WEBDL720p, proper);
|
||||
}
|
||||
|
||||
[TestCase("Arrested.Development.S04E01.iNTERNAL.1080p.WEBRip.x264-QRUS", false)]
|
||||
[TestCase("Arrested.Development.S04E01.720p.WEBRip.AAC2.0.x264-NFRiP", false)]
|
||||
[TestCase("American.Gods.S01E07.A.Prayer.For.Mad.Sweeney.720p.AMZN.WEBRip.DD5.1.x264-NTb", false)]
|
||||
[TestCase("LEGO.Star.Wars.The.Freemaker.Adventures.S07E01.A.New.Home.720p.DSNY.WEBRip.AAC2.0.x264-TVSmash", false)]
|
||||
public void should_parse_webrip720p_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.WEBRip720p, proper);
|
||||
}
|
||||
|
||||
[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)]
|
||||
|
@ -202,10 +221,15 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
ParseAndVerifyQuality(title, Quality.WEBDL1080p, proper);
|
||||
}
|
||||
|
||||
[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("Arrested.Development.S04E01.iNTERNAL.1080p.WEBRip.x264-QRUS", false)]
|
||||
[TestCase("Blue.Bloods.S07E20.1080p.AMZN.WEBRip.DDP5.1.x264-ViSUM ac3.(NLsub)", false)]
|
||||
[TestCase("Better.Call.Saul.S03E09.1080p.NF.WEBRip.DD5.1.x264-ViSUM", false)]
|
||||
public void should_parse_webrip1080p_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.WEBRip1080p, proper);
|
||||
}
|
||||
|
||||
|
||||
[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)]
|
||||
|
@ -216,6 +240,17 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
ParseAndVerifyQuality(title, Quality.WEBDL2160p, proper);
|
||||
}
|
||||
|
||||
[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("House.of.Cards.US.S05E08.Chapter.60.2160p.NF.WEBRip.DD5.1.x264-NTb.NLsubs", false)]
|
||||
[TestCase("Bill Nye Saves the World S01 2160p Netflix WEBRip DD5.1 x264-TrollUHD", false)]
|
||||
public void should_parse_webrip2160p_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.WEBRip2160p, proper);
|
||||
}
|
||||
|
||||
[TestCase("WEEDS.S03E01-06.DUAL.Bluray.AC3.-HELLYWOOD.avi", false)]
|
||||
[TestCase("Chuck - S01E03 - Come Fly With Me - 720p BluRay.mkv", false)]
|
||||
[TestCase("The Big Bang Theory.S03E01.The Electric Can Opener Fluctuation.m2ts", false)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using FluentAssertions;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
@ -15,7 +15,7 @@ namespace NzbDrone.Core.Test.Profiles
|
|||
var profile = new Profile
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
|
||||
Cutoff = Quality.Bluray1080p,
|
||||
Cutoff = Quality.Bluray1080p.Id,
|
||||
Name = "TestProfile"
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Qualities
|
||||
{
|
||||
[TestFixture]
|
||||
public class QualityIndexCompareToFixture : CoreTest
|
||||
{
|
||||
[TestCase(1, 0, 1, 0, 0)]
|
||||
[TestCase(1, 1, 1, 0, 1)]
|
||||
[TestCase(2, 0, 1, 0, 1)]
|
||||
[TestCase(1, 0, 1, 1, -1)]
|
||||
[TestCase(1, 0, 2, 0, -1)]
|
||||
public void should_match_expected_when_respect_group_order_is_true(int leftIndex, int leftGroupIndex, int rightIndex, int rightGroupIndex, int expected)
|
||||
{
|
||||
var left = new QualityIndex(leftIndex, leftGroupIndex);
|
||||
var right = new QualityIndex(rightIndex, rightGroupIndex);
|
||||
left.CompareTo(right, true).Should().Be(expected);
|
||||
}
|
||||
|
||||
[TestCase(1, 0, 1, 0, 0)]
|
||||
[TestCase(1, 1, 1, 0, 0)]
|
||||
[TestCase(2, 0, 1, 0, 1)]
|
||||
[TestCase(1, 0, 1, 1, 0)]
|
||||
[TestCase(1, 0, 2, 0, -1)]
|
||||
public void should_match_expected_when_respect_group_order_is_false(int leftIndex, int leftGroupIndex, int rightIndex, int rightGroupIndex, int expected)
|
||||
{
|
||||
var left = new QualityIndex(leftIndex, leftGroupIndex);
|
||||
var right = new QualityIndex(rightIndex, rightGroupIndex);
|
||||
left.CompareTo(right, false).Should().Be(expected);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using FluentAssertions;
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
@ -21,6 +22,50 @@ namespace NzbDrone.Core.Test.Qualities
|
|||
Subject = new QualityModelComparer(new Profile { Items = QualityFixture.GetDefaultQualities(Quality.Bluray720p, Quality.DVD) });
|
||||
}
|
||||
|
||||
private void GivenGroupedProfile()
|
||||
{
|
||||
var profile = new Profile
|
||||
{
|
||||
Items = new List<ProfileQualityItem>
|
||||
{
|
||||
new ProfileQualityItem
|
||||
{
|
||||
Allowed = false,
|
||||
Quality = Quality.SDTV
|
||||
},
|
||||
new ProfileQualityItem
|
||||
{
|
||||
Allowed = false,
|
||||
Quality = Quality.DVD
|
||||
},
|
||||
new ProfileQualityItem
|
||||
{
|
||||
Allowed = true,
|
||||
Items = new List<ProfileQualityItem>
|
||||
{
|
||||
new ProfileQualityItem
|
||||
{
|
||||
Allowed = true,
|
||||
Quality = Quality.HDTV720p
|
||||
},
|
||||
new ProfileQualityItem
|
||||
{
|
||||
Allowed = true,
|
||||
Quality = Quality.WEBDL720p
|
||||
}
|
||||
}
|
||||
},
|
||||
new ProfileQualityItem
|
||||
{
|
||||
Allowed = true,
|
||||
Quality = Quality.Bluray720p
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Subject = new QualityModelComparer(profile);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_greater_when_first_quality_is_greater_than_second()
|
||||
{
|
||||
|
@ -72,5 +117,31 @@ namespace NzbDrone.Core.Test.Qualities
|
|||
|
||||
compare.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_ignore_group_order_by_default()
|
||||
{
|
||||
GivenGroupedProfile();
|
||||
|
||||
var first = new QualityModel(Quality.HDTV720p);
|
||||
var second = new QualityModel(Quality.WEBDL720p);
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
compare.Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_respect_group_order()
|
||||
{
|
||||
GivenGroupedProfile();
|
||||
|
||||
var first = new QualityModel(Quality.HDTV720p);
|
||||
var second = new QualityModel(Quality.WEBDL720p);
|
||||
|
||||
var compare = Subject.Compare(first, second, true);
|
||||
|
||||
compare.Should().BeLessThan(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
|||
var profile = new Profile
|
||||
{
|
||||
Id = 1,
|
||||
Cutoff = Quality.WEBDL480p,
|
||||
Cutoff = Quality.WEBDL480p.Id,
|
||||
Items = new List<ProfileQualityItem>
|
||||
{
|
||||
new ProfileQualityItem { Allowed = true, Quality = Quality.SDTV },
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using FizzWare.NBuilder;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using System.Linq;
|
||||
|
@ -22,7 +22,7 @@ namespace NzbDrone.Core.Test.TvTests.SeriesRepositoryTests
|
|||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
|
||||
|
||||
Cutoff = Quality.Bluray1080p,
|
||||
Cutoff = Quality.Bluray1080p.Id,
|
||||
Name = "TestProfile"
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
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(117)]
|
||||
public class add_webrip_and_br480_qualites_in_profile : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Execute.WithConnection(ConvertProfile);
|
||||
}
|
||||
|
||||
private void ConvertProfile(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
var updater = new ProfileUpdater116(conn, tran);
|
||||
|
||||
updater.CreateGroupAt(8, 1000, "WEB 480p", new[] {12, 8}); // Group WEBRip480p with WEBDL480p
|
||||
updater.CreateGroupAt(2, 1001, "DVD", new[] {2, 13}); // Group Bluray480p with DVD
|
||||
updater.CreateGroupAt(5, 1002, "WEB 720p", new[] {14, 5}); // Group WEBRip720p with WEBDL720p
|
||||
updater.CreateGroupAt(3, 1003, "WEB 1080p", new[] {15, 3}); // Group WEBRip1080p with WEBDL1080p
|
||||
updater.CreateGroupAt(18, 1004, "WEB 2160p", new[] {17, 18}); // Group WEBRip2160p with WEBDL2160p
|
||||
|
||||
updater.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
public class Profile117
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int Cutoff { get; set; }
|
||||
public List<ProfileItem117> Items { get; set; }
|
||||
}
|
||||
|
||||
public class ProfileItem117
|
||||
{
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public int? Quality { get; set; }
|
||||
public List<ProfileItem117> Items { get; set; }
|
||||
public bool Allowed { get; set; }
|
||||
|
||||
public ProfileItem117()
|
||||
{
|
||||
Items = new List<ProfileItem117>();
|
||||
}
|
||||
}
|
||||
|
||||
public class ProfileUpdater116
|
||||
{
|
||||
private readonly IDbConnection _connection;
|
||||
private readonly IDbTransaction _transaction;
|
||||
|
||||
private List<Profile117> _profiles;
|
||||
private HashSet<Profile117> _changedProfiles = new HashSet<Profile117>();
|
||||
|
||||
public ProfileUpdater116(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, int groupId, string name, int[] qualities)
|
||||
{
|
||||
foreach (var profile in _profiles)
|
||||
{
|
||||
var findIndex = profile.Items.FindIndex(v => v.Quality == find);
|
||||
|
||||
if (findIndex > -1)
|
||||
{
|
||||
var findQuality = profile.Items[findIndex];
|
||||
|
||||
profile.Items.Insert(findIndex, new ProfileItem117
|
||||
{
|
||||
Id = groupId,
|
||||
Name = name,
|
||||
Quality = null,
|
||||
Items = qualities.Select(q => new ProfileItem117
|
||||
{
|
||||
Quality = q,
|
||||
Allowed = findQuality.Allowed
|
||||
}).ToList(),
|
||||
Allowed = findQuality.Allowed
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the ID isn't found for some reason (mangled migration 71?)
|
||||
|
||||
profile.Items.Add(new ProfileItem117
|
||||
{
|
||||
Id = groupId,
|
||||
Name = name,
|
||||
Quality = null,
|
||||
Items = qualities.Select(q => new ProfileItem117
|
||||
{
|
||||
Quality = q,
|
||||
Allowed = false
|
||||
}).ToList(),
|
||||
Allowed = false
|
||||
});
|
||||
}
|
||||
|
||||
foreach (var quality in qualities)
|
||||
{
|
||||
var index = profile.Items.FindIndex(v => v.Quality == quality);
|
||||
|
||||
if (index > -1)
|
||||
{
|
||||
profile.Items.RemoveAt(index);
|
||||
}
|
||||
|
||||
if (profile.Cutoff == quality)
|
||||
{
|
||||
profile.Cutoff = groupId;
|
||||
}
|
||||
}
|
||||
|
||||
_changedProfiles.Add(profile);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Profile117> GetProfiles()
|
||||
{
|
||||
var profiles = new List<Profile117>();
|
||||
|
||||
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 Profile117
|
||||
{
|
||||
Id = profileReader.GetInt32(0),
|
||||
Name = profileReader.GetString(1),
|
||||
Cutoff = profileReader.GetInt32(2),
|
||||
Items = Json.Deserialize<List<ProfileItem117>>(profileReader.GetString(3))
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return profiles;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -103,6 +103,7 @@ namespace NzbDrone.Core.Datastore
|
|||
.HasOne(episode => episode.EpisodeFile, episode => episode.EpisodeFileId);
|
||||
|
||||
Mapper.Entity<QualityDefinition>().RegisterModel("QualityDefinitions")
|
||||
.Ignore(d => d.GroupName)
|
||||
.Ignore(d => d.Weight);
|
||||
|
||||
Mapper.Entity<Profile>().RegisterModel("Profiles");
|
||||
|
|
|
@ -58,7 +58,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
|
||||
private int CompareQuality(DownloadDecision x, DownloadDecision y)
|
||||
{
|
||||
return CompareAll(CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Series.Profile.Value.Items.FindIndex(v => v.Quality == remoteEpisode.ParsedEpisodeInfo.Quality.Quality)),
|
||||
return CompareAll(CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Series.Profile.Value.GetIndex(remoteEpisode.ParsedEpisodeInfo.Quality.Quality)),
|
||||
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Real),
|
||||
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Version));
|
||||
}
|
||||
|
|
|
@ -21,6 +21,8 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
|
||||
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var profile = subject.Series.Profile.Value;
|
||||
|
||||
foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value))
|
||||
{
|
||||
if (file == null)
|
||||
|
@ -30,14 +32,18 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
}
|
||||
_logger.Debug("Comparing file quality and language with report. Existing file is {0} - {1}", file.Quality, file.Language);
|
||||
|
||||
if (!_upgradableSpecification.CutoffNotMet(subject.Series.Profile,
|
||||
if (!_upgradableSpecification.CutoffNotMet(profile,
|
||||
subject.Series.LanguageProfile,
|
||||
file.Quality,
|
||||
file.Language,
|
||||
subject.ParsedEpisodeInfo.Quality))
|
||||
{
|
||||
_logger.Debug("Cutoff already met, rejecting.");
|
||||
return Decision.Reject("Existing file meets cutoff: {0} - {1}", subject.Series.Profile.Value.Cutoff, subject.Series.LanguageProfile.Value.Cutoff);
|
||||
|
||||
var qualityCutoffIndex = profile.GetIndex(profile.Cutoff);
|
||||
var qualityCutoff = profile.Items[qualityCutoffIndex.Index];
|
||||
|
||||
return Decision.Reject("Existing file meets cutoff: {0} - {1}", qualityCutoff, subject.Series.LanguageProfile.Value.Cutoff);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using NLog;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -19,7 +20,12 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
_logger.Debug("Checking if report meets quality requirements. {0}", subject.ParsedEpisodeInfo.Quality);
|
||||
if (!subject.Series.Profile.Value.Items.Exists(v => v.Allowed && v.Quality == subject.ParsedEpisodeInfo.Quality.Quality))
|
||||
|
||||
var profile = subject.Series.Profile.Value;
|
||||
var qualityIndex = profile.GetIndex(subject.ParsedEpisodeInfo.Quality.Quality);
|
||||
var qualityOrGroup = profile.Items[qualityIndex.Index];
|
||||
|
||||
if (!qualityOrGroup.Allowed)
|
||||
{
|
||||
_logger.Debug("Quality {0} rejected by Series' quality profile", subject.ParsedEpisodeInfo.Quality);
|
||||
return Decision.Reject("{0} is not wanted in profile", subject.ParsedEpisodeInfo.Quality.Quality);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Linq;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
|
@ -73,8 +73,8 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
}
|
||||
|
||||
// If quality meets or exceeds the best allowed quality in the profile accept it immediately
|
||||
var bestQualityInProfile = new QualityModel(profile.LastAllowedQuality());
|
||||
var isBestInProfile = comparer.Compare(subject.ParsedEpisodeInfo.Quality, bestQualityInProfile) >= 0;
|
||||
var bestQualityInProfile = profile.LastAllowedQuality();
|
||||
var isBestInProfile = comparer.Compare(subject.ParsedEpisodeInfo.Quality.Quality, bestQualityInProfile) >= 0;
|
||||
var isBestInProfileLanguage = comparerLanguage.Compare(subject.ParsedEpisodeInfo.Language, languageProfile.LastAllowedLanguage()) >= 0;
|
||||
|
||||
if (isBestInProfile && isBestInProfileLanguage && isPreferredProtocol)
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
public bool IsUpgradable(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, QualityModel newQuality, Language newLanguage)
|
||||
{
|
||||
// If qualities are the same then check language
|
||||
if (newQuality != null && currentQuality == newQuality)
|
||||
if (newQuality != null && new QualityModelComparer(profile).Compare(newQuality, currentQuality) == 0)
|
||||
{
|
||||
return IsLanguageUpgradable(languageProfile, currentLanguage, newLanguage);
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
|
||||
public bool QualityCutoffNotMet(Profile profile, QualityModel currentQuality, QualityModel newQuality = null)
|
||||
{
|
||||
var qualityCompare = new QualityModelComparer(profile).Compare(currentQuality.Quality, profile.Cutoff);
|
||||
var qualityCompare = new QualityModelComparer(profile).Compare(currentQuality.Quality.Id, profile.Cutoff);
|
||||
|
||||
if (qualityCompare < 0)
|
||||
{
|
||||
|
@ -116,6 +116,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
{
|
||||
var compare = newQuality.Revision.CompareTo(currentQuality.Revision);
|
||||
|
||||
// Comparing the quality directly because we don't want to upgrade to a proper for a webrip from a webdl or vice versa
|
||||
if (currentQuality.Quality == newQuality.Quality && compare > 0)
|
||||
{
|
||||
_logger.Debug("New quality is a better revision for existing quality");
|
||||
|
|
|
@ -5,8 +5,6 @@ using NzbDrone.Core.Download;
|
|||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
{
|
||||
|
@ -23,7 +21,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
{
|
||||
var qualityComparer = new QualityModelComparer(localEpisode.Series.Profile);
|
||||
var languageComparer = new LanguageComparer(localEpisode.Series.LanguageProfile);
|
||||
var profile = localEpisode.Series.Profile.Value;
|
||||
|
||||
if (localEpisode.Episodes.Any(e => e.EpisodeFileId != 0 && qualityComparer.Compare(e.EpisodeFile.Value.Quality, localEpisode.Quality) > 0))
|
||||
{
|
||||
|
|
|
@ -320,6 +320,7 @@
|
|||
<Compile Include="Datastore\Migration\111_create_language_profiles.cs" />
|
||||
<Compile Include="Datastore\Migration\115_add_downloadclient_status.cs" />
|
||||
<Compile Include="Datastore\Migration\121_update_animetosho_url.cs" />
|
||||
<Compile Include="Datastore\Migration\117_add_webrip_and_br480_qualites_in_profile.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationDbFactory.cs" />
|
||||
|
@ -1003,6 +1004,7 @@
|
|||
<Compile Include="Profiles\Qualities\ProfileQualityItem.cs" />
|
||||
<Compile Include="Profiles\Qualities\ProfileRepository.cs" />
|
||||
<Compile Include="Profiles\Qualities\ProfileService.cs" />
|
||||
<Compile Include="Profiles\Qualities\QualityIndex.cs" />
|
||||
<Compile Include="ProgressMessaging\ProgressMessageContext.cs" />
|
||||
<Compile Include="Qualities\QualityDetectionSource.cs" />
|
||||
<Compile Include="Qualities\QualitySource.cs" />
|
||||
|
|
|
@ -16,7 +16,8 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
private static readonly Regex SourceRegex = new Regex(@"\b(?:
|
||||
(?<bluray>BluRay|Blu-Ray|HD-?DVD|BD)|
|
||||
(?<webdl>WEB[-_. ]DL|WEBDL|WebRip|AmazonHD|iTunesHD|NetflixU?HD|WebHD|[. ]WEB[. ](?:[xh]26[45]|DDP?5[. ]1)|\d+0p[. ]WEB[. ]|WEB-DLMux)|
|
||||
(?<webdl>WEB[-_. ]DL|WEBDL|AmazonHD|iTunesHD|NetflixU?HD|WebHD|[. ]WEB[. ](?:[xh]26[45]|DDP?5[. ]1)|\d+0p[. ]WEB[. ]|WEB-DLMux)|
|
||||
(?<webrip>WebRip)|
|
||||
(?<hdtv>HDTV)|
|
||||
(?<bdrip>BDRip)|
|
||||
(?<brrip>BRRip)|
|
||||
|
@ -99,7 +100,7 @@ namespace NzbDrone.Core.Parser
|
|||
{
|
||||
if (codecRegex.Groups["xvid"].Success || codecRegex.Groups["divx"].Success)
|
||||
{
|
||||
result.Quality = Quality.DVD;
|
||||
result.Quality = Quality.Bluray480p;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -117,7 +118,7 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
if (resolution == Resolution.R480P || resolution == Resolution.R576p)
|
||||
{
|
||||
result.Quality = Quality.DVD;
|
||||
result.Quality = Quality.Bluray480p;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -155,6 +156,30 @@ namespace NzbDrone.Core.Parser
|
|||
return result;
|
||||
}
|
||||
|
||||
if (sourceMatch.Groups["webrip"].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)
|
||||
{
|
||||
result.Quality = Quality.WEBRip720p;
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Quality = Quality.WEBRip480p;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (sourceMatch.Groups["hdtv"].Success)
|
||||
{
|
||||
if (resolution == Resolution.R2160p)
|
||||
|
@ -197,7 +222,7 @@ namespace NzbDrone.Core.Parser
|
|||
result.Quality = Quality.Bluray1080p;
|
||||
return result;
|
||||
default:
|
||||
result.Quality = Quality.DVD;
|
||||
result.Quality = Quality.Bluray480p;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,12 +8,59 @@ namespace NzbDrone.Core.Profiles.Qualities
|
|||
public class Profile : ModelBase
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Quality Cutoff { get; set; }
|
||||
public int Cutoff { get; set; }
|
||||
public List<ProfileQualityItem> Items { get; set; }
|
||||
|
||||
public Quality LastAllowedQuality()
|
||||
{
|
||||
return Items.Last(q => q.Allowed).Quality;
|
||||
var lastAllowed = Items.Last(q => q.Allowed);
|
||||
|
||||
if (lastAllowed.Quality != null)
|
||||
{
|
||||
return lastAllowed.Quality;
|
||||
}
|
||||
|
||||
// Returning any item from the group will work,
|
||||
// returning the last because it's the true last quality.
|
||||
return lastAllowed.Items.Last().Quality;
|
||||
}
|
||||
|
||||
public QualityIndex GetIndex(Quality quality)
|
||||
{
|
||||
return GetIndex(quality.Id);
|
||||
}
|
||||
|
||||
public QualityIndex GetIndex(int id)
|
||||
{
|
||||
for (var i = 0; i < Items.Count; i++)
|
||||
{
|
||||
var item = Items[i];
|
||||
var quality = item.Quality;
|
||||
|
||||
// Quality matches by ID
|
||||
if (quality != null && quality.Id == id)
|
||||
{
|
||||
return new QualityIndex(i);
|
||||
}
|
||||
|
||||
// Group matches by ID
|
||||
if (item.Id > 0 && item.Id == id)
|
||||
{
|
||||
return new QualityIndex(i);
|
||||
}
|
||||
|
||||
for (var g = 0; g < item.Items.Count; g++)
|
||||
{
|
||||
var groupItem = item.Items[g];
|
||||
|
||||
if (groupItem.Quality.Id == id)
|
||||
{
|
||||
return new QualityIndex(i, g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new QualityIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,47 @@
|
|||
using NzbDrone.Core.Datastore;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Profiles.Qualities
|
||||
{
|
||||
public class ProfileQualityItem : IEmbeddedDocument
|
||||
{
|
||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public Quality Quality { get; set; }
|
||||
public List<ProfileQualityItem> Items { get; set; }
|
||||
public bool Allowed { get; set; }
|
||||
|
||||
public ProfileQualityItem()
|
||||
{
|
||||
Items = new List<ProfileQualityItem>();
|
||||
}
|
||||
|
||||
public List<Quality> GetQualities()
|
||||
{
|
||||
if (Quality == null)
|
||||
{
|
||||
return Items.Select(s => s.Quality).ToList();
|
||||
}
|
||||
|
||||
return new List<Quality>{ Quality };
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var qualitiesString = string.Join(", ", GetQualities());
|
||||
|
||||
if (Name.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
return $"{Name} ({qualitiesString})";
|
||||
}
|
||||
|
||||
return qualitiesString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace NzbDrone.Core.Profiles.Qualities
|
|||
List<Profile> All();
|
||||
Profile Get(int id);
|
||||
bool Exists(int id);
|
||||
Profile GetDefaultProfile(string name, Quality cutoff = null, params Quality[] allowed);
|
||||
}
|
||||
|
||||
public class ProfileService : IProfileService, IHandle<ApplicationStartedEvent>
|
||||
|
@ -66,22 +67,7 @@ namespace NzbDrone.Core.Profiles.Qualities
|
|||
{
|
||||
return _profileRepository.Exists(id);
|
||||
}
|
||||
|
||||
private Profile AddDefaultProfile(string name, Quality cutoff, params Quality[] allowed)
|
||||
{
|
||||
var items = Quality.DefaultQualityDefinitions
|
||||
.OrderBy(v => v.Weight)
|
||||
.Select(v => new ProfileQualityItem { Quality = v.Quality, Allowed = allowed.Contains(v.Quality) })
|
||||
.ToList();
|
||||
|
||||
var profile = new Profile { Name = name,
|
||||
Cutoff = cutoff,
|
||||
Items = items,
|
||||
};
|
||||
|
||||
return Add(profile);
|
||||
}
|
||||
|
||||
|
||||
public void Handle(ApplicationStartedEvent message)
|
||||
{
|
||||
if (All().Any()) return;
|
||||
|
@ -90,42 +76,107 @@ namespace NzbDrone.Core.Profiles.Qualities
|
|||
|
||||
AddDefaultProfile("Any", Quality.SDTV,
|
||||
Quality.SDTV,
|
||||
Quality.WEBRip480p,
|
||||
Quality.WEBDL480p,
|
||||
Quality.DVD,
|
||||
Quality.HDTV720p,
|
||||
Quality.HDTV1080p,
|
||||
Quality.WEBRip720p,
|
||||
Quality.WEBDL720p,
|
||||
Quality.WEBRip1080p,
|
||||
Quality.WEBDL1080p,
|
||||
Quality.Bluray720p,
|
||||
Quality.Bluray1080p);
|
||||
|
||||
AddDefaultProfile("SD", Quality.SDTV,
|
||||
Quality.SDTV,
|
||||
Quality.WEBRip480p,
|
||||
Quality.WEBDL480p,
|
||||
Quality.DVD);
|
||||
|
||||
AddDefaultProfile("HD-720p", Quality.HDTV720p,
|
||||
Quality.HDTV720p,
|
||||
Quality.WEBRip720p,
|
||||
Quality.WEBDL720p,
|
||||
Quality.Bluray720p);
|
||||
|
||||
AddDefaultProfile("HD-1080p", Quality.HDTV1080p,
|
||||
Quality.HDTV1080p,
|
||||
Quality.WEBRip1080p,
|
||||
Quality.WEBDL1080p,
|
||||
Quality.Bluray1080p);
|
||||
|
||||
AddDefaultProfile("Ultra-HD", Quality.HDTV2160p,
|
||||
Quality.HDTV2160p,
|
||||
Quality.WEBRip2160p,
|
||||
Quality.WEBDL2160p,
|
||||
Quality.Bluray2160p);
|
||||
|
||||
AddDefaultProfile("HD - 720p/1080p", Quality.HDTV720p,
|
||||
Quality.HDTV720p,
|
||||
Quality.HDTV1080p,
|
||||
Quality.WEBRip720p,
|
||||
Quality.WEBDL720p,
|
||||
Quality.WEBRip1080p,
|
||||
Quality.WEBDL1080p,
|
||||
Quality.Bluray720p,
|
||||
Quality.Bluray1080p);
|
||||
}
|
||||
|
||||
public Profile GetDefaultProfile(string name, Quality cutoff = null, params Quality[] allowed)
|
||||
{
|
||||
var groupedQualites = Quality.DefaultQualityDefinitions.GroupBy(q => q.Weight);
|
||||
var items = new List<ProfileQualityItem>();
|
||||
var groupId = 1000;
|
||||
var profileCutoff = cutoff == null ? Quality.Unknown.Id : cutoff.Id;
|
||||
|
||||
foreach (var group in groupedQualites)
|
||||
{
|
||||
if (group.Count() == 1)
|
||||
{
|
||||
var quality = group.First().Quality;
|
||||
|
||||
items.Add(new ProfileQualityItem { Quality = group.First().Quality, Allowed = allowed.Contains(quality) });
|
||||
continue;
|
||||
}
|
||||
|
||||
var groupAllowed = group.Any(g => allowed.Contains(g.Quality));
|
||||
|
||||
items.Add(new ProfileQualityItem
|
||||
{
|
||||
Id = groupId,
|
||||
Name = group.First().GroupName,
|
||||
Items = group.Select(g => new ProfileQualityItem
|
||||
{
|
||||
Quality = g.Quality,
|
||||
Allowed = groupAllowed
|
||||
}).ToList(),
|
||||
Allowed = groupAllowed
|
||||
});
|
||||
|
||||
if (group.Any(g => g.Quality.Id == profileCutoff))
|
||||
{
|
||||
profileCutoff = groupId;
|
||||
}
|
||||
|
||||
groupId++;
|
||||
}
|
||||
|
||||
var qualityProfile = new Profile
|
||||
{
|
||||
Name = name,
|
||||
Cutoff = profileCutoff,
|
||||
Items = items
|
||||
};
|
||||
|
||||
return qualityProfile;
|
||||
}
|
||||
|
||||
private Profile AddDefaultProfile(string name, Quality cutoff, params Quality[] allowed)
|
||||
{
|
||||
var profile = GetDefaultProfile(name, cutoff, allowed);
|
||||
|
||||
return Add(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Profiles.Qualities
|
||||
{
|
||||
public class QualityIndex : IComparable, IComparable<QualityIndex>
|
||||
{
|
||||
public int Index { get; set; }
|
||||
public int GroupIndex { get; set; }
|
||||
|
||||
public QualityIndex()
|
||||
{
|
||||
Index = 0;
|
||||
GroupIndex = 0;
|
||||
}
|
||||
|
||||
public QualityIndex(int index)
|
||||
{
|
||||
Index = index;
|
||||
GroupIndex = 0;
|
||||
}
|
||||
|
||||
public QualityIndex(int index, int groupIndex)
|
||||
{
|
||||
Index = index;
|
||||
GroupIndex = groupIndex;
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
return CompareTo((QualityIndex)obj, true);
|
||||
}
|
||||
|
||||
public int CompareTo(QualityIndex other)
|
||||
{
|
||||
return CompareTo(other, true);
|
||||
}
|
||||
|
||||
public int CompareTo(QualityIndex right, bool respectGroupOrder)
|
||||
{
|
||||
if (right == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
var indexCompare = Index.CompareTo(right.Index);
|
||||
|
||||
if (respectGroupOrder && indexCompare == 0)
|
||||
{
|
||||
return GroupIndex.CompareTo(right.GroupIndex);
|
||||
}
|
||||
|
||||
return indexCompare;;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -71,12 +71,12 @@ namespace NzbDrone.Core.Qualities
|
|||
public static Quality HDTV1080p => new Quality(9, "HDTV-1080p", QualitySource.Television, 1080);
|
||||
public static Quality RAWHD => new Quality(10, "Raw-HD", QualitySource.TelevisionRaw, 1080);
|
||||
//public static Quality HDTV480p { get { return new Quality(11, "HDTV-480p", QualitySource.Television, 480); } }
|
||||
//public static Quality WEBRip480p { get { return new Quality(12, "WEBRip-480p", QualitySource.WebRip, 480); } }
|
||||
//public static Quality Bluray480p { get { return new Quality(13, "Bluray-480p", QualitySource.Bluray, 480); } }
|
||||
//public static Quality WEBRip720p { get { return new Quality(14, "WEBRip-720p", QualitySource.WebRip, 720); } }
|
||||
//public static Quality WEBRip1080p { get { return new Quality(15, "WEBRip-1080p", QualitySource.WebRip, 1080); } }
|
||||
public static Quality WEBRip480p { get { return new Quality(12, "WEBRip-480p", QualitySource.WebRip, 480); } }
|
||||
public static Quality Bluray480p { get { return new Quality(13, "Bluray-480p", QualitySource.Bluray, 480); } }
|
||||
public static Quality WEBRip720p { get { return new Quality(14, "WEBRip-720p", QualitySource.WebRip, 720); } }
|
||||
public static Quality WEBRip1080p { get { return new Quality(15, "WEBRip-1080p", QualitySource.WebRip, 1080); } }
|
||||
public static Quality HDTV2160p => new Quality(16, "HDTV-2160p", QualitySource.Television, 2160);
|
||||
//public static Quality WEBRip2160p { get { return new Quality(17, "WEBRip-2160p", QualitySource.WebRip, 2160); } }
|
||||
public static Quality WEBRip2160p { get { return new Quality(17, "WEBRip-2160p", QualitySource.WebRip, 2160); } }
|
||||
public static Quality WEBDL2160p => new Quality(18, "WEBDL-2160p", QualitySource.Web, 2160);
|
||||
public static Quality Bluray2160p => new Quality(19, "Bluray-2160p", QualitySource.Bluray, 2160);
|
||||
|
||||
|
@ -87,17 +87,22 @@ namespace NzbDrone.Core.Qualities
|
|||
Unknown,
|
||||
SDTV,
|
||||
DVD,
|
||||
WEBDL1080p,
|
||||
WEBRip480p,
|
||||
WEBDL480p,
|
||||
Bluray480p,
|
||||
HDTV720p,
|
||||
WEBRip720p,
|
||||
WEBDL720p,
|
||||
Bluray720p,
|
||||
Bluray1080p,
|
||||
WEBDL480p,
|
||||
HDTV1080p,
|
||||
WEBRip1080p,
|
||||
WEBDL1080p,
|
||||
RAWHD,
|
||||
HDTV2160p,
|
||||
WEBRip2160p,
|
||||
WEBDL2160p,
|
||||
Bluray2160p,
|
||||
Bluray2160p
|
||||
};
|
||||
|
||||
AllLookup = new Quality[All.Select(v => v.Id).Max() + 1];
|
||||
|
@ -110,18 +115,23 @@ namespace NzbDrone.Core.Qualities
|
|||
{
|
||||
new QualityDefinition(Quality.Unknown) { Weight = 1, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.SDTV) { Weight = 2, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.WEBDL480p) { Weight = 3, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.DVD) { Weight = 4, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.HDTV720p) { Weight = 5, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.HDTV1080p) { Weight = 6, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.RAWHD) { Weight = 7, MinSize = 0, MaxSize = null },
|
||||
new QualityDefinition(Quality.WEBDL720p) { Weight = 8, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.Bluray720p) { Weight = 9, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.WEBDL1080p) { Weight = 10, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.Bluray1080p) { Weight = 11, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.HDTV2160p) { Weight = 12, MinSize = 0, MaxSize = null },
|
||||
new QualityDefinition(Quality.WEBDL2160p) { Weight = 13, MinSize = 0, MaxSize = null },
|
||||
new QualityDefinition(Quality.Bluray2160p) { Weight = 14, MinSize = 0, MaxSize = null },
|
||||
new QualityDefinition(Quality.WEBRip480p) { Weight = 3, MinSize = 0, MaxSize = 100, GroupName = "WEB 480p" },
|
||||
new QualityDefinition(Quality.WEBDL480p) { Weight = 3, MinSize = 0, MaxSize = 100, GroupName = "WEB 480p" },
|
||||
new QualityDefinition(Quality.DVD) { Weight = 4, MinSize = 0, MaxSize = 100, GroupName = "DVD" },
|
||||
new QualityDefinition(Quality.Bluray480p) { Weight = 5, MinSize = 0, MaxSize = 100, GroupName = "DVD" },
|
||||
new QualityDefinition(Quality.HDTV720p) { Weight = 6, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.HDTV1080p) { Weight = 7, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.RAWHD) { Weight = 8, MinSize = 0, MaxSize = null },
|
||||
new QualityDefinition(Quality.WEBRip720p) { Weight = 9, MinSize = 0, MaxSize = 100, GroupName = "WEB 720p" },
|
||||
new QualityDefinition(Quality.WEBDL720p) { Weight = 9, MinSize = 0, MaxSize = 100, GroupName = "WEB 720p" },
|
||||
new QualityDefinition(Quality.Bluray720p) { Weight = 10, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.WEBRip1080p) { Weight = 11, MinSize = 0, MaxSize = 100, GroupName = "WEB 1080p" },
|
||||
new QualityDefinition(Quality.WEBDL1080p) { Weight = 11, MinSize = 0, MaxSize = 100, GroupName = "WEB 1080p" },
|
||||
new QualityDefinition(Quality.Bluray1080p) { Weight = 12, MinSize = 0, MaxSize = 100 },
|
||||
new QualityDefinition(Quality.HDTV2160p) { Weight = 13, MinSize = 0, MaxSize = null },
|
||||
new QualityDefinition(Quality.WEBRip2160p) { Weight = 14, MinSize = 0, MaxSize = null, GroupName = "WEB 2160p" },
|
||||
new QualityDefinition(Quality.WEBDL2160p) { Weight = 14, MinSize = 0, MaxSize = null, GroupName = "WEB 2160p" },
|
||||
new QualityDefinition(Quality.Bluray2160p) { Weight = 15, MinSize = 0, MaxSize = null }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using NzbDrone.Core.Datastore;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
|
@ -9,6 +10,7 @@ namespace NzbDrone.Core.Qualities
|
|||
|
||||
public string Title { get; set; }
|
||||
|
||||
public string GroupName { get; set; }
|
||||
public int Weight { get; set; }
|
||||
|
||||
public double? MinSize { get; set; }
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace NzbDrone.Core.Qualities
|
|||
return 1;
|
||||
}
|
||||
|
||||
if(definition.Weight < otherDefinition.Weight)
|
||||
if (definition.Weight < otherDefinition.Weight)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -16,17 +16,35 @@ namespace NzbDrone.Core.Qualities
|
|||
_profile = profile;
|
||||
}
|
||||
|
||||
public int Compare(int left, int right, bool respectGroupOrder = false)
|
||||
{
|
||||
var leftIndex = _profile.GetIndex(left);
|
||||
var rightIndex = _profile.GetIndex(right);
|
||||
|
||||
return leftIndex.CompareTo(rightIndex, respectGroupOrder);
|
||||
}
|
||||
|
||||
public int Compare(Quality left, Quality right)
|
||||
{
|
||||
int leftIndex = _profile.Items.FindIndex(v => v.Quality == left);
|
||||
int rightIndex = _profile.Items.FindIndex(v => v.Quality == right);
|
||||
return Compare(left, right, false);
|
||||
}
|
||||
|
||||
return leftIndex.CompareTo(rightIndex);
|
||||
public int Compare(Quality left, Quality right, bool respectGroupOrder)
|
||||
{
|
||||
var leftIndex = _profile.GetIndex(left);
|
||||
var rightIndex = _profile.GetIndex(right);
|
||||
|
||||
return leftIndex.CompareTo(rightIndex, respectGroupOrder);
|
||||
}
|
||||
|
||||
public int Compare(QualityModel left, QualityModel right)
|
||||
{
|
||||
int result = Compare(left.Quality, right.Quality);
|
||||
return Compare(left, right, false);
|
||||
}
|
||||
|
||||
public int Compare(QualityModel left, QualityModel right, bool respectGroupOrder)
|
||||
{
|
||||
int result = Compare(left.Quality, right.Quality, respectGroupOrder);
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
|
|
|
@ -19,14 +19,12 @@ namespace NzbDrone.Core.Tv
|
|||
private readonly IEpisodeRepository _episodeRepository;
|
||||
private readonly IProfileService _profileService;
|
||||
private readonly ILanguageProfileService _languageProfileService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public EpisodeCutoffService(IEpisodeRepository episodeRepository, IProfileService profileService, ILanguageProfileService languageProfileService, Logger logger)
|
||||
{
|
||||
_episodeRepository = episodeRepository;
|
||||
_profileService = profileService;
|
||||
_languageProfileService = languageProfileService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec)
|
||||
|
@ -39,11 +37,12 @@ namespace NzbDrone.Core.Tv
|
|||
//Get all items less than the cutoff
|
||||
foreach (var profile in profiles)
|
||||
{
|
||||
var cutoffIndex = profile.Items.FindIndex(v => v.Quality == profile.Cutoff);
|
||||
var belowCutoff = profile.Items.Take(cutoffIndex).ToList();
|
||||
var cutoffIndex = profile.GetIndex(profile.Cutoff);
|
||||
var belowCutoff = profile.Items.Take(cutoffIndex.Index).ToList();
|
||||
|
||||
if (belowCutoff.Any())
|
||||
{
|
||||
qualitiesBelowCutoff.Add(new QualitiesBelowCutoff(profile.Id, belowCutoff.Select(i => i.Quality.Id)));
|
||||
qualitiesBelowCutoff.Add(new QualitiesBelowCutoff(profile.Id, belowCutoff.SelectMany(i => i.GetQualities().Select(q => q.Id))));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Validators;
|
||||
|
||||
namespace Sonarr.Api.V3.Profiles.Quality
|
||||
{
|
||||
public static class QualityCutoffValidator
|
||||
{
|
||||
public static IRuleBuilderOptions<T, int> ValidCutoff<T>(this IRuleBuilder<T, int> ruleBuilder)
|
||||
{
|
||||
return ruleBuilder.SetValidator(new ValidCutoffValidator<T>());
|
||||
}
|
||||
}
|
||||
|
||||
public class ValidCutoffValidator<T> : PropertyValidator
|
||||
{
|
||||
public ValidCutoffValidator()
|
||||
: base("Cutoff must be an allowed quality or group")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var cutoff = (int)context.PropertyValue;
|
||||
dynamic instance = context.ParentContext.InstanceToValidate;
|
||||
var items = instance.Items as IList<QualityProfileQualityItemResource>;
|
||||
|
||||
var cutoffItem = items.SingleOrDefault(i => (i.Quality == null && i.Id == cutoff) || i.Quality?.Id == cutoff);
|
||||
|
||||
if (cutoffItem == null) return false;
|
||||
|
||||
if (!cutoffItem.Allowed) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Validators;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace Sonarr.Api.V3.Profiles.Quality
|
||||
{
|
||||
public static class QualityItemsValidator
|
||||
{
|
||||
public static IRuleBuilderOptions<T, IList<QualityProfileQualityItemResource>> ValidItems<T>(this IRuleBuilder<T, IList<QualityProfileQualityItemResource>> ruleBuilder)
|
||||
{
|
||||
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
||||
ruleBuilder.SetValidator(new AllowedValidator<T>());
|
||||
ruleBuilder.SetValidator(new QualityNameValidator<T>());
|
||||
ruleBuilder.SetValidator(new EmptyItemGroupNameValidator<T>());
|
||||
ruleBuilder.SetValidator(new ItemGroupIdValidator<T>());
|
||||
ruleBuilder.SetValidator(new UniqueIdValidator<T>());
|
||||
ruleBuilder.SetValidator(new UniqueQualityIdValidator<T>());
|
||||
return ruleBuilder.SetValidator(new ItemGroupNameValidator<T>());
|
||||
}
|
||||
}
|
||||
|
||||
public class AllowedValidator<T> : PropertyValidator
|
||||
{
|
||||
public AllowedValidator()
|
||||
: base("Must contain at least one allowed quality")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var list = context.PropertyValue as IList<QualityProfileQualityItemResource>;
|
||||
|
||||
if (list == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!list.Any(c => c.Allowed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class EmptyItemGroupNameValidator<T> : PropertyValidator
|
||||
{
|
||||
public EmptyItemGroupNameValidator()
|
||||
: base("Groups must not be empty")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var items = context.PropertyValue as IList<QualityProfileQualityItemResource>;
|
||||
|
||||
if (items.Any(i => i.Name.IsNotNullOrWhiteSpace() && i.Items.Empty()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class QualityNameValidator<T> : PropertyValidator
|
||||
{
|
||||
public QualityNameValidator()
|
||||
: base("Individual qualities should not be named")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var items = context.PropertyValue as IList<QualityProfileQualityItemResource>;
|
||||
|
||||
if (items.Any(i => i.Name.IsNotNullOrWhiteSpace() && i.Quality != null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemGroupNameValidator<T> : PropertyValidator
|
||||
{
|
||||
public ItemGroupNameValidator()
|
||||
: base("Groups must have a name")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var items = context.PropertyValue as IList<QualityProfileQualityItemResource>;
|
||||
|
||||
if (items.Any(i => i.Quality == null && i.Name.IsNullOrWhiteSpace()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemGroupIdValidator<T> : PropertyValidator
|
||||
{
|
||||
public ItemGroupIdValidator()
|
||||
: base("Groups must have an ID")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var items = context.PropertyValue as IList<QualityProfileQualityItemResource>;
|
||||
|
||||
if (items.Any(i => i.Quality == null && i.Id == 0))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class UniqueIdValidator<T> : PropertyValidator
|
||||
{
|
||||
public UniqueIdValidator()
|
||||
: base("Groups must have a unique ID")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var items = context.PropertyValue as IList<QualityProfileQualityItemResource>;
|
||||
|
||||
if (items.Where(i => i.Id > 0).Select(i => i.Id).GroupBy(i => i).Any(g => g.Count() > 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class UniqueQualityIdValidator<T> : PropertyValidator
|
||||
{
|
||||
public UniqueQualityIdValidator()
|
||||
: base("Qualities can only be used once")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var items = context.PropertyValue as IList<QualityProfileQualityItemResource>;
|
||||
var qualityIds = new HashSet<int>();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Id > 0)
|
||||
{
|
||||
foreach (var quality in item.Items)
|
||||
{
|
||||
if (qualityIds.Contains(quality.Quality.Id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qualityIds.Add(quality.Quality.Id);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (qualityIds.Contains(item.Quality.Id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qualityIds.Add(item.Quality.Id);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,8 +13,10 @@ namespace Sonarr.Api.V3.Profiles.Quality
|
|||
{
|
||||
_profileService = profileService;
|
||||
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
||||
SharedValidator.RuleFor(c => c.Cutoff).NotNull();
|
||||
SharedValidator.RuleFor(c => c.Items).MustHaveAllowedQuality();
|
||||
// TODO: Need to validate the cutoff is allowed and the ID/quality ID exists
|
||||
// TODO: Need to validate the Items to ensure groups have names and at no item has no name, no items and no quality
|
||||
SharedValidator.RuleFor(c => c.Cutoff).ValidCutoff();
|
||||
SharedValidator.RuleFor(c => c.Items).ValidItems();
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
GetResourceById = GetById;
|
||||
|
|
|
@ -8,14 +8,21 @@ namespace Sonarr.Api.V3.Profiles.Quality
|
|||
public class QualityProfileResource : RestResource
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public NzbDrone.Core.Qualities.Quality Cutoff { get; set; }
|
||||
public int Cutoff { get; set; }
|
||||
public List<QualityProfileQualityItemResource> Items { get; set; }
|
||||
}
|
||||
|
||||
public class QualityProfileQualityItemResource : RestResource
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public NzbDrone.Core.Qualities.Quality Quality { get; set; }
|
||||
public List<QualityProfileQualityItemResource> Items { get; set; }
|
||||
public bool Allowed { get; set; }
|
||||
|
||||
public QualityProfileQualityItemResource()
|
||||
{
|
||||
Items = new List<QualityProfileQualityItemResource>();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ProfileResourceMapper
|
||||
|
@ -27,7 +34,6 @@ namespace Sonarr.Api.V3.Profiles.Quality
|
|||
return new QualityProfileResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
Name = model.Name,
|
||||
Cutoff = model.Cutoff,
|
||||
Items = model.Items.ConvertAll(ToResource),
|
||||
|
@ -40,7 +46,10 @@ namespace Sonarr.Api.V3.Profiles.Quality
|
|||
|
||||
return new QualityProfileQualityItemResource
|
||||
{
|
||||
Id = model.Id,
|
||||
Name = model.Name,
|
||||
Quality = model.Quality,
|
||||
Items = model.Items.ConvertAll(ToResource),
|
||||
Allowed = model.Allowed
|
||||
};
|
||||
}
|
||||
|
@ -52,9 +61,8 @@ namespace Sonarr.Api.V3.Profiles.Quality
|
|||
return new Profile
|
||||
{
|
||||
Id = resource.Id,
|
||||
|
||||
Name = resource.Name,
|
||||
Cutoff = (NzbDrone.Core.Qualities.Quality)resource.Cutoff.Id,
|
||||
Cutoff = resource.Cutoff,
|
||||
Items = resource.Items.ConvertAll(ToModel)
|
||||
};
|
||||
}
|
||||
|
@ -65,7 +73,10 @@ namespace Sonarr.Api.V3.Profiles.Quality
|
|||
|
||||
return new ProfileQualityItem
|
||||
{
|
||||
Quality = (NzbDrone.Core.Qualities.Quality)resource.Quality.Id,
|
||||
Id = resource.Id,
|
||||
Name = resource.Name,
|
||||
Quality = resource.Quality != null ? (NzbDrone.Core.Qualities.Quality)resource.Quality.Id : null,
|
||||
Items = resource.Items.ConvertAll(ToModel),
|
||||
Allowed = resource.Allowed
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,34 +1,24 @@
|
|||
using System.Linq;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Sonarr.Http;
|
||||
|
||||
namespace Sonarr.Api.V3.Profiles.Quality
|
||||
{
|
||||
public class QualityProfileSchemaModule : SonarrRestModule<QualityProfileResource>
|
||||
{
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
private readonly IProfileService _profileService;
|
||||
|
||||
public QualityProfileSchemaModule(IQualityDefinitionService qualityDefinitionService)
|
||||
public QualityProfileSchemaModule(IProfileService profileService)
|
||||
: base("/qualityprofile/schema")
|
||||
{
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
|
||||
_profileService = profileService;
|
||||
GetResourceSingle = GetSchema;
|
||||
}
|
||||
|
||||
private QualityProfileResource GetSchema()
|
||||
{
|
||||
var items = _qualityDefinitionService.All()
|
||||
.OrderBy(v => v.Weight)
|
||||
.Select(v => new ProfileQualityItem { Quality = v.Quality, Allowed = false })
|
||||
.ToList();
|
||||
|
||||
var qualityProfile = new Profile();
|
||||
qualityProfile.Cutoff = NzbDrone.Core.Qualities.Quality.Unknown;
|
||||
qualityProfile.Items = items;
|
||||
var qualityProfile = _profileService.GetDefaultProfile(string.Empty);
|
||||
|
||||
return qualityProfile.ToResource();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Validators;
|
||||
|
||||
namespace Sonarr.Api.V3.Profiles.Quality
|
||||
{
|
||||
public static class QualityProfileValidation
|
||||
{
|
||||
public static IRuleBuilderOptions<T, IList<QualityProfileQualityItemResource>> MustHaveAllowedQuality<T>(this IRuleBuilder<T, IList<QualityProfileQualityItemResource>> ruleBuilder)
|
||||
{
|
||||
ruleBuilder.SetValidator(new NotEmptyValidator(null));
|
||||
|
||||
return ruleBuilder.SetValidator(new AllowedValidator<T>());
|
||||
}
|
||||
}
|
||||
|
||||
public class AllowedValidator<T> : PropertyValidator
|
||||
{
|
||||
public AllowedValidator()
|
||||
: base("Must contain at least one allowed quality")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
var list = context.PropertyValue as IList<QualityProfileQualityItemResource>;
|
||||
|
||||
if (list == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!list.Any(c => c.Allowed))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -170,7 +170,6 @@
|
|||
<Compile Include="Profiles\Quality\QualityProfileModule.cs" />
|
||||
<Compile Include="Profiles\Quality\QualityProfileResource.cs" />
|
||||
<Compile Include="Profiles\Quality\QualityProfileSchemaModule.cs" />
|
||||
<Compile Include="Profiles\Quality\QualityProfileValidation.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ProviderModuleBase.cs" />
|
||||
<Compile Include="ProviderResource.cs" />
|
||||
|
|
Loading…
Reference in New Issue