Add upgrade allowed to language and profiles

This commit is contained in:
Mark McDowall 2018-11-28 20:26:49 -08:00 committed by Taloth Saldono
parent 853f25468c
commit f345977e3f
67 changed files with 426 additions and 266 deletions

View File

@ -66,7 +66,7 @@ namespace NzbDrone.Api.EpisodeFiles
SceneName = model.SceneName, SceneName = model.SceneName,
Quality = model.Quality, Quality = model.Quality,
Language = model.Language, Language = model.Language,
QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(series.Profile.Value, model.Quality), QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(series.QualityProfile.Value, model.Quality),
MediaInfo = model.MediaInfo.ToResource(model.SceneName), MediaInfo = model.MediaInfo.ToResource(model.SceneName),
OriginalFilePath = model.OriginalFilePath OriginalFilePath = model.OriginalFilePath
}; };

View File

@ -43,7 +43,7 @@ namespace NzbDrone.Api.History
if (model.Series != null) if (model.Series != null)
{ {
resource.QualityCutoffNotMet = _upgradableSpecification.QualityCutoffNotMet(model.Series.Profile.Value, model.Quality); resource.QualityCutoffNotMet = _upgradableSpecification.QualityCutoffNotMet(model.Series.QualityProfile.Value, model.Quality);
} }
return resource; return resource;

View File

@ -29,7 +29,7 @@ namespace NzbDrone.Api.Indexers
if (decision.RemoteEpisode.Series != null) if (decision.RemoteEpisode.Series != null)
{ {
release.QualityWeight = decision.RemoteEpisode.Series release.QualityWeight = decision.RemoteEpisode.Series
.Profile.Value .QualityProfile.Value
.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100; .Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100;
} }

View File

@ -10,6 +10,7 @@ namespace NzbDrone.Api.Profiles
public class ProfileResource : RestResource public class ProfileResource : RestResource
{ {
public string Name { get; set; } public string Name { get; set; }
public bool UpgradeAllowed { get; set; }
public Quality Cutoff { get; set; } public Quality Cutoff { get; set; }
public List<ProfileQualityItemResource> Items { get; set; } public List<ProfileQualityItemResource> Items { get; set; }
} }
@ -22,7 +23,7 @@ namespace NzbDrone.Api.Profiles
public static class ProfileResourceMapper public static class ProfileResourceMapper
{ {
public static ProfileResource ToResource(this Profile model) public static ProfileResource ToResource(this QualityProfile model)
{ {
if (model == null) return null; if (model == null) return null;
@ -44,6 +45,7 @@ namespace NzbDrone.Api.Profiles
Id = model.Id, Id = model.Id,
Name = model.Name, Name = model.Name,
UpgradeAllowed = model.UpgradeAllowed,
Cutoff = cutoff, Cutoff = cutoff,
// Flatten groups so things don't explode // Flatten groups so things don't explode
@ -64,7 +66,7 @@ namespace NzbDrone.Api.Profiles
}; };
} }
public static ProfileQualityItemResource ToResource(this ProfileQualityItem model) public static ProfileQualityItemResource ToResource(this QualityProfileQualityItem model)
{ {
if (model == null) return null; if (model == null) return null;
@ -75,32 +77,33 @@ namespace NzbDrone.Api.Profiles
}; };
} }
public static Profile ToModel(this ProfileResource resource) public static QualityProfile ToModel(this ProfileResource resource)
{ {
if (resource == null) return null; if (resource == null) return null;
return new Profile return new QualityProfile
{ {
Id = resource.Id, Id = resource.Id,
Name = resource.Name, Name = resource.Name,
UpgradeAllowed = resource.UpgradeAllowed,
Cutoff = resource.Cutoff.Id, Cutoff = resource.Cutoff.Id,
Items = resource.Items.ConvertAll(ToModel) Items = resource.Items.ConvertAll(ToModel)
}; };
} }
public static ProfileQualityItem ToModel(this ProfileQualityItemResource resource) public static QualityProfileQualityItem ToModel(this ProfileQualityItemResource resource)
{ {
if (resource == null) return null; if (resource == null) return null;
return new ProfileQualityItem return new QualityProfileQualityItem
{ {
Quality = (Quality)resource.Quality.Id, Quality = (Quality)resource.Quality.Id,
Allowed = resource.Allowed Allowed = resource.Allowed
}; };
} }
public static List<ProfileResource> ToResource(this IEnumerable<Profile> models) public static List<ProfileResource> ToResource(this IEnumerable<QualityProfile> models)
{ {
return models.Select(ToResource).ToList(); return models.Select(ToResource).ToList();
} }

View File

@ -23,10 +23,10 @@ namespace NzbDrone.Api.Profiles
{ {
var items = _qualityDefinitionService.All() var items = _qualityDefinitionService.All()
.OrderBy(v => v.Weight) .OrderBy(v => v.Weight)
.Select(v => new ProfileQualityItem { Quality = v.Quality, Allowed = false }) .Select(v => new QualityProfileQualityItem { Quality = v.Quality, Allowed = false })
.ToList(); .ToList();
var profile = new Profile(); var profile = new QualityProfile();
profile.Cutoff = Quality.Unknown.Id; profile.Cutoff = Quality.Unknown.Id;
profile.Items = items; profile.Items = items;

View File

@ -16,7 +16,7 @@ namespace NzbDrone.Api.Series
//Todo: Sorters should be done completely on the client //Todo: Sorters should be done completely on the client
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing? //Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
//Todo: We should get the entire Profile instead of ID and Name separately //Todo: We should get the entire QualityProfile instead of ID and Name separately
//View Only //View Only
public string Title { get; set; } public string Title { get; set; }
@ -124,7 +124,7 @@ namespace NzbDrone.Api.Series
Year = model.Year, Year = model.Year,
Path = model.Path, Path = model.Path,
ProfileId = model.ProfileId, ProfileId = model.QualityProfileId,
LanguageProfileId = model.LanguageProfileId, LanguageProfileId = model.LanguageProfileId,
SeasonFolder = model.SeasonFolder, SeasonFolder = model.SeasonFolder,
@ -179,7 +179,7 @@ namespace NzbDrone.Api.Series
Year = resource.Year, Year = resource.Year,
Path = resource.Path, Path = resource.Path,
ProfileId = resource.ProfileId, QualityProfileId = resource.ProfileId,
LanguageProfileId = resource.LanguageProfileId, LanguageProfileId = resource.LanguageProfileId,
SeasonFolder = resource.SeasonFolder, SeasonFolder = resource.SeasonFolder,

View File

@ -20,7 +20,7 @@ namespace NzbDrone.Core.Test.Datastore
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
var profile = new Profile var profile = new QualityProfile
{ {
Name = "Test", Name = "Test",
Cutoff = Quality.WEBDL720p.Id, Cutoff = Quality.WEBDL720p.Id,
@ -39,7 +39,7 @@ namespace NzbDrone.Core.Test.Datastore
var series = Builder<Series>.CreateListOfSize(1) var series = Builder<Series>.CreateListOfSize(1)
.All() .All()
.With(v => v.ProfileId = profile.Id) .With(v => v.QualityProfileId = profile.Id)
.With(v => v.LanguageProfileId = languageProfile.Id) .With(v => v.LanguageProfileId = languageProfile.Id)
.BuildListOfNew(); .BuildListOfNew();
@ -76,7 +76,7 @@ namespace NzbDrone.Core.Test.Datastore
foreach (var episode in episodes) foreach (var episode in episodes)
{ {
Assert.IsNotNull(episode.Series); Assert.IsNotNull(episode.Series);
Assert.IsFalse(episode.Series.Profile.IsLoaded); Assert.IsFalse(episode.Series.QualityProfile.IsLoaded);
Assert.IsFalse(episode.Series.LanguageProfile.IsLoaded); Assert.IsFalse(episode.Series.LanguageProfile.IsLoaded);
} }
} }
@ -106,13 +106,13 @@ namespace NzbDrone.Core.Test.Datastore
var episodes = DataMapper.Query<Episode>() var episodes = DataMapper.Query<Episode>()
.Join<Episode, Series>(Marr.Data.QGen.JoinType.Inner, v => v.Series, (l, r) => l.SeriesId == r.Id) .Join<Episode, Series>(Marr.Data.QGen.JoinType.Inner, v => v.Series, (l, r) => l.SeriesId == r.Id)
.Join<Series, Profile>(Marr.Data.QGen.JoinType.Inner, v => v.Profile, (l, r) => l.ProfileId == r.Id) .Join<Series, QualityProfile>(Marr.Data.QGen.JoinType.Inner, v => v.QualityProfile, (l, r) => l.QualityProfileId == r.Id)
.ToList(); .ToList();
foreach (var episode in episodes) foreach (var episode in episodes)
{ {
Assert.IsNotNull(episode.Series); Assert.IsNotNull(episode.Series);
Assert.IsTrue(episode.Series.Profile.IsLoaded); Assert.IsTrue(episode.Series.QualityProfile.IsLoaded);
Assert.IsFalse(episode.Series.LanguageProfile.IsLoaded); Assert.IsFalse(episode.Series.LanguageProfile.IsLoaded);
} }
} }
@ -125,13 +125,13 @@ namespace NzbDrone.Core.Test.Datastore
var episodes = DataMapper.Query<Episode>() var episodes = DataMapper.Query<Episode>()
.Join<Episode, Series>(Marr.Data.QGen.JoinType.Inner, v => v.Series, (l, r) => l.SeriesId == r.Id) .Join<Episode, Series>(Marr.Data.QGen.JoinType.Inner, v => v.Series, (l, r) => l.SeriesId == r.Id)
.Join<Series, LanguageProfile>(Marr.Data.QGen.JoinType.Inner, v => v.LanguageProfile, (l, r) => l.ProfileId == r.Id) .Join<Series, LanguageProfile>(Marr.Data.QGen.JoinType.Inner, v => v.LanguageProfile, (l, r) => l.QualityProfileId == r.Id)
.ToList(); .ToList();
foreach (var episode in episodes) foreach (var episode in episodes)
{ {
Assert.IsNotNull(episode.Series); Assert.IsNotNull(episode.Series);
Assert.IsFalse(episode.Series.Profile.IsLoaded); Assert.IsFalse(episode.Series.QualityProfile.IsLoaded);
Assert.IsTrue(episode.Series.LanguageProfile.IsLoaded); Assert.IsTrue(episode.Series.LanguageProfile.IsLoaded);
} }
} }

View File

@ -19,7 +19,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_return_true_if_current_episode_is_less_than_cutoff() public void should_return_true_if_current_episode_is_less_than_cutoff()
{ {
Subject.CutoffNotMet( Subject.CutoffNotMet(
new Profile new QualityProfile
{ {
Cutoff = Quality.Bluray1080p.Id, Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities() Items = Qualities.QualityFixture.GetDefaultQualities()
@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_return_false_if_current_episode_is_equal_to_cutoff() public void should_return_false_if_current_episode_is_equal_to_cutoff()
{ {
Subject.CutoffNotMet( Subject.CutoffNotMet(
new Profile new QualityProfile
{ {
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities() Items = Qualities.QualityFixture.GetDefaultQualities()
@ -57,7 +57,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_return_false_if_current_episode_is_greater_than_cutoff() public void should_return_false_if_current_episode_is_greater_than_cutoff()
{ {
Subject.CutoffNotMet( Subject.CutoffNotMet(
new Profile new QualityProfile
{ {
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities() Items = Qualities.QualityFixture.GetDefaultQualities()
@ -76,7 +76,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_return_true_when_new_episode_is_proper_but_existing_is_not() public void should_return_true_when_new_episode_is_proper_but_existing_is_not()
{ {
Subject.CutoffNotMet( Subject.CutoffNotMet(
new Profile new QualityProfile
{ {
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities() Items = Qualities.QualityFixture.GetDefaultQualities()
@ -97,7 +97,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_return_false_if_cutoff_is_met_and_quality_is_higher() public void should_return_false_if_cutoff_is_met_and_quality_is_higher()
{ {
Subject.CutoffNotMet( Subject.CutoffNotMet(
new Profile new QualityProfile
{ {
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities() Items = Qualities.QualityFixture.GetDefaultQualities()
@ -117,7 +117,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_true_if_quality_cutoff_is_met_and_quality_is_higher_but_language_is_not_met() public void should_return_true_if_quality_cutoff_is_met_and_quality_is_higher_but_language_is_not_met()
{ {
Profile _profile = new Profile QualityProfile _profile = new QualityProfile
{ {
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
@ -141,7 +141,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_false_if_cutoff_is_met_and_quality_is_higher_and_language_is_met() public void should_return_false_if_cutoff_is_met_and_quality_is_higher_and_language_is_met()
{ {
Profile _profile = new Profile QualityProfile _profile = new QualityProfile
{ {
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
@ -166,7 +166,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_false_if_cutoff_is_met_and_quality_is_higher_and_language_is_higher() public void should_return_false_if_cutoff_is_met_and_quality_is_higher_and_language_is_higher()
{ {
Profile _profile = new Profile QualityProfile _profile = new QualityProfile
{ {
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
@ -191,7 +191,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_true_if_cutoff_is_not_met_and_new_quality_is_higher_and_language_is_higher() public void should_return_true_if_cutoff_is_not_met_and_new_quality_is_higher_and_language_is_higher()
{ {
Profile _profile = new Profile QualityProfile _profile = new QualityProfile
{ {
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
@ -216,7 +216,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_true_if_cutoff_is_not_met_and_language_is_higher() public void should_return_true_if_cutoff_is_not_met_and_language_is_higher()
{ {
Profile _profile = new Profile QualityProfile _profile = new QualityProfile
{ {
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
@ -239,7 +239,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_true_if_cutoffs_are_met_and_score_is_higher() public void should_return_true_if_cutoffs_are_met_and_score_is_higher()
{ {
Profile _profile = new Profile QualityProfile _profile = new QualityProfile
{ {
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),

View File

@ -53,7 +53,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
remoteEpisode.Release.DownloadProtocol = downloadProtocol; remoteEpisode.Release.DownloadProtocol = downloadProtocol;
remoteEpisode.Series = Builder<Series>.CreateNew() remoteEpisode.Series = Builder<Series>.CreateNew()
.With(e => e.Profile = new Profile .With(e => e.QualityProfile = new QualityProfile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities() Items = Qualities.QualityFixture.GetDefaultQualities()
}) })

View File

@ -35,7 +35,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void Setup() public void Setup()
{ {
var fakeSeries = Builder<Series>.CreateNew() var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.Profile = (LazyLoaded<Profile>)new Profile { Cutoff = Quality.Bluray1080p.Id }) .With(c => c.QualityProfile = (LazyLoaded<QualityProfile>)new QualityProfile { Cutoff = Quality.Bluray1080p.Id })
.Build(); .Build();
remoteEpisode = new RemoteEpisode remoteEpisode = new RemoteEpisode
@ -49,7 +49,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_allow_if_quality_is_defined_in_profile(Quality qualityType) public void should_allow_if_quality_is_defined_in_profile(Quality qualityType)
{ {
remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType; remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType;
remoteEpisode.Series.Profile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p); remoteEpisode.Series.QualityProfile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p);
Subject.IsSatisfiedBy(remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(remoteEpisode, null).Accepted.Should().BeTrue();
} }
@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public void should_not_allow_if_quality_is_not_defined_in_profile(Quality qualityType) public void should_not_allow_if_quality_is_not_defined_in_profile(Quality qualityType)
{ {
remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType; remoteEpisode.ParsedEpisodeInfo.Quality.Quality = qualityType;
remoteEpisode.Series.Profile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p); remoteEpisode.Series.QualityProfile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p);
Subject.IsSatisfiedBy(remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(remoteEpisode, null).Accepted.Should().BeFalse();
} }

View File

@ -33,13 +33,15 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Mocker.Resolve<UpgradableSpecification>(); Mocker.Resolve<UpgradableSpecification>();
_series = Builder<Series>.CreateNew() _series = Builder<Series>.CreateNew()
.With(e => e.Profile = new Profile .With(e => e.QualityProfile = new QualityProfile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), UpgradeAllowed = true,
Items = Qualities.QualityFixture.GetDefaultQualities()
}) })
.With(l => l.LanguageProfile = new LanguageProfile .With(l => l.LanguageProfile = new LanguageProfile
{ {
Languages = Languages.LanguageFixture.GetDefaultLanguages(), Languages = Languages.LanguageFixture.GetDefaultLanguages(),
UpgradeAllowed = true,
Cutoff = Language.Spanish Cutoff = Language.Spanish
}) })
.Build(); .Build();
@ -109,10 +111,31 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
} }
[Test]
public void should_return_false_if_everything_is_the_same()
{
_series.QualityProfile.Value.Cutoff = Quality.Bluray1080p.Id;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
.With(r => r.Series = _series)
.With(r => r.Episodes = new List<Episode> { _episode })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo
{
Quality = new QualityModel(Quality.DVD),
Language = Language.Spanish
})
.With(r => r.Release = _releaseInfo)
.Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
[Test] [Test]
public void should_return_true_when_quality_in_queue_is_lower() public void should_return_true_when_quality_in_queue_is_lower()
{ {
_series.Profile.Value.Cutoff = Quality.Bluray1080p.Id; _series.QualityProfile.Value.Cutoff = Quality.Bluray1080p.Id;
_series.LanguageProfile.Value.Cutoff = Language.Spanish; _series.LanguageProfile.Value.Cutoff = Language.Spanish;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
@ -133,7 +156,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_true_when_quality_in_queue_is_lower_but_language_is_higher() public void should_return_true_when_quality_in_queue_is_lower_but_language_is_higher()
{ {
_series.Profile.Value.Cutoff = Quality.Bluray1080p.Id; _series.QualityProfile.Value.Cutoff = Quality.Bluray1080p.Id;
_series.LanguageProfile.Value.Cutoff = Language.Spanish; _series.LanguageProfile.Value.Cutoff = Language.Spanish;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
@ -224,10 +247,31 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue(); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
} }
[Test]
public void should_return_true_when_quality_is_better_language_is_better_and_upgrade_allowed_is_false_for_quality_profile()
{
_series.QualityProfile.Value.Cutoff = Quality.Bluray1080p.Id;
_series.QualityProfile.Value.UpgradeAllowed = false;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
.With(r => r.Series = _series)
.With(r => r.Episodes = new List<Episode> { _episode })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo
{
Quality = new QualityModel(Quality.SDTV),
Language = Language.English
})
.With(r => r.Release = _releaseInfo)
.Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
}
[Test] [Test]
public void should_return_false_when_quality_in_queue_is_better() public void should_return_false_when_quality_in_queue_is_better()
{ {
_series.Profile.Value.Cutoff = Quality.Bluray1080p.Id; _series.QualityProfile.Value.Cutoff = Quality.Bluray1080p.Id;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Series = _series)
@ -330,7 +374,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
[Test] [Test]
public void should_return_false_if_quality_and_language_in_queue_meets_cutoff() public void should_return_false_if_quality_and_language_in_queue_meets_cutoff()
{ {
_series.Profile.Value.Cutoff = _remoteEpisode.ParsedEpisodeInfo.Quality.Quality.Id; _series.QualityProfile.Value.Cutoff = _remoteEpisode.ParsedEpisodeInfo.Quality.Quality.Id;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew() var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
.With(r => r.Series = _series) .With(r => r.Series = _series)
@ -347,5 +391,46 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse(); Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
} }
[Test]
public void should_return_false_when_quality_are_the_same_language_is_better_and_upgrade_allowed_is_false_for_language_profile()
{
_series.LanguageProfile.Value.UpgradeAllowed = false;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
.With(r => r.Series = _series)
.With(r => r.Episodes = new List<Episode> { _episode })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo
{
Quality = new QualityModel(Quality.DVD),
Language = Language.English
})
.With(r => r.Release = _releaseInfo)
.Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
[Test]
public void should_return_false_when_quality_is_better_languages_are_the_same_and_upgrade_allowed_is_false_for_quality_profile()
{
_series.QualityProfile.Value.Cutoff = Quality.Bluray1080p.Id;
_series.QualityProfile.Value.UpgradeAllowed = false;
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
.With(r => r.Series = _series)
.With(r => r.Episodes = new List<Episode> { _episode })
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo
{
Quality = new QualityModel(Quality.Bluray1080p),
Language = Language.Spanish
})
.With(r => r.Release = _releaseInfo)
.Build();
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
}
} }
} }

View File

@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[TestFixture] [TestFixture]
public class DelaySpecificationFixture : CoreTest<DelaySpecification> public class DelaySpecificationFixture : CoreTest<DelaySpecification>
{ {
private Profile _profile; private QualityProfile _profile;
private LanguageProfile _langProfile; private LanguageProfile _langProfile;
private DelayProfile _delayProfile; private DelayProfile _delayProfile;
private RemoteEpisode _remoteEpisode; private RemoteEpisode _remoteEpisode;
@ -34,7 +34,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_profile = Builder<Profile>.CreateNew() _profile = Builder<QualityProfile>.CreateNew()
.Build(); .Build();
_langProfile = Builder<LanguageProfile>.CreateNew() _langProfile = Builder<LanguageProfile>.CreateNew()
@ -45,7 +45,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
.Build(); .Build();
var series = Builder<Series>.CreateNew() var series = Builder<Series>.CreateNew()
.With(s => s.Profile = _profile) .With(s => s.QualityProfile = _profile)
.With(s => s.LanguageProfile = _langProfile) .With(s => s.LanguageProfile = _langProfile)
.Build(); .Build();
@ -53,10 +53,10 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
.With(r => r.Series = series) .With(r => r.Series = series)
.Build(); .Build();
_profile.Items = new List<ProfileQualityItem>(); _profile.Items = new List<QualityProfileQualityItem>();
_profile.Items.Add(new ProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p }); _profile.Items.Add(new QualityProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p });
_profile.Items.Add(new ProfileQualityItem { Allowed = true, Quality = Quality.WEBDL720p }); _profile.Items.Add(new QualityProfileQualityItem { Allowed = true, Quality = Quality.WEBDL720p });
_profile.Items.Add(new ProfileQualityItem { Allowed = true, Quality = Quality.Bluray720p }); _profile.Items.Add(new QualityProfileQualityItem { Allowed = true, Quality = Quality.Bluray720p });
_profile.Cutoff = Quality.WEBDL720p.Id; _profile.Cutoff = Quality.WEBDL720p.Id;
@ -94,7 +94,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
private void GivenUpgradeForExistingFile() private void GivenUpgradeForExistingFile()
{ {
Mocker.GetMock<IUpgradableSpecification>() Mocker.GetMock<IUpgradableSpecification>()
.Setup(s => s.IsUpgradable(It.IsAny<Profile>(), It.IsAny<LanguageProfile>(), It.IsAny<QualityModel>(), It.IsAny<Language>(), It.IsAny<int>(), It.IsAny<QualityModel>(), It.IsAny<Language>(), It.IsAny<int>())) .Setup(s => s.IsUpgradable(It.IsAny<QualityProfile>(), It.IsAny<LanguageProfile>(), It.IsAny<QualityModel>(), It.IsAny<Language>(), It.IsAny<int>(), It.IsAny<QualityModel>(), It.IsAny<Language>(), It.IsAny<int>()))
.Returns(true); .Returns(true);
} }

View File

@ -55,7 +55,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
}; };
var fakeSeries = Builder<Series>.CreateNew() var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id }) .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p.Id })
.With(c => c.Path = @"C:\Series\My.Series".AsOsAgnostic()) .With(c => c.Path = @"C:\Series\My.Series".AsOsAgnostic())
.Build(); .Build();

View File

@ -12,7 +12,6 @@ using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.DecisionEngine.Specifications;
using NzbDrone.Core.Profiles.Qualities; using NzbDrone.Core.Profiles.Qualities;
using NzbDrone.Core.Profiles.Languages; using NzbDrone.Core.Profiles.Languages;
@ -48,8 +47,18 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
}; };
_fakeSeries = Builder<Series>.CreateNew() _fakeSeries = Builder<Series>.CreateNew()
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() }) .With(c => c.QualityProfile = new QualityProfile
.With(l => l.LanguageProfile = new LanguageProfile { Cutoff = Language.Spanish, Languages = LanguageFixture.GetDefaultLanguages() }) {
UpgradeAllowed = true,
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities()
})
.With(l => l.LanguageProfile = new LanguageProfile
{
UpgradeAllowed = true,
Cutoff = Language.Spanish,
Languages = LanguageFixture.GetDefaultLanguages()
})
.Build(); .Build();
_parseResultMulti = new RemoteEpisode _parseResultMulti = new RemoteEpisode
@ -164,7 +173,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_not_be_upgradable_if_episode_is_of_same_quality_as_existing() public void should_not_be_upgradable_if_episode_is_of_same_quality_as_existing()
{ {
_fakeSeries.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() }; _fakeSeries.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() };
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)); _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); _upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.English);
@ -176,7 +185,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_be_upgradable_if_episode_is_of_same_quality_as_existing_but_new_has_better_language() 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.Id, Items = Qualities.QualityFixture.GetDefaultQualities() }; _fakeSeries.QualityProfile = new QualityProfile { Cutoff = Quality.WEBDL1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() };
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)); _parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1));
_parseResultSingle.ParsedEpisodeInfo.Language = Language.Spanish; _parseResultSingle.ParsedEpisodeInfo.Language = Language.Spanish;
_upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.English); _upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.English);
@ -189,7 +198,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
[Test] [Test]
public void should_not_be_upgradable_if_cutoff_already_met() public void should_not_be_upgradable_if_cutoff_already_met()
{ {
_fakeSeries.Profile = new Profile { Cutoff = Quality.WEBDL1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() }; _fakeSeries.QualityProfile = new QualityProfile { Cutoff = Quality.WEBDL1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() };
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)); _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); _upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.Spanish);
@ -217,7 +226,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
public void should_return_false_if_cutoff_already_met_and_cdh_is_disabled() public void should_return_false_if_cutoff_already_met_and_cdh_is_disabled()
{ {
GivenCdhDisabled(); GivenCdhDisabled();
_fakeSeries.Profile = new Profile { Cutoff = Quality.WEBDL1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() }; _fakeSeries.QualityProfile = new QualityProfile { Cutoff = Quality.WEBDL1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities() };
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.Bluray1080p, new Revision(version: 1)); _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); _upgradableQuality = new Tuple<QualityModel, Language>(new QualityModel(Quality.WEBDL1080p, new Revision(version: 1)), Language.Spanish);

View File

@ -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 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() var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id }) .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p.Id })
.Build(); .Build();
_parseResultMulti = new RemoteEpisode _parseResultMulti = new RemoteEpisode

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using FizzWare.NBuilder; using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
@ -42,8 +42,18 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
var languages = Languages.LanguageFixture.GetDefaultLanguages(Language.English, Language.Spanish); var languages = Languages.LanguageFixture.GetDefaultLanguages(Language.English, Language.Spanish);
var fakeSeries = Builder<Series>.CreateNew() var fakeSeries = Builder<Series>.CreateNew()
.With(c => c.Profile = new Profile { Cutoff = Quality.Bluray1080p.Id, Items = Qualities.QualityFixture.GetDefaultQualities()}) .With(c => c.QualityProfile = new QualityProfile
.With(l => l.LanguageProfile = new LanguageProfile { Cutoff = Language.Spanish, Languages = languages }) {
UpgradeAllowed = true,
Cutoff = Quality.Bluray1080p.Id,
Items = Qualities.QualityFixture.GetDefaultQualities()
})
.With(l => l.LanguageProfile = new LanguageProfile
{
UpgradeAllowed = true,
Cutoff = Language.Spanish,
Languages = languages
})
.Build(); .Build();
_parseResultMulti = new RemoteEpisode _parseResultMulti = new RemoteEpisode

View File

@ -51,13 +51,15 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
GivenAutoDownloadPropers(true); GivenAutoDownloadPropers(true);
var profile = new Profile var profile = new QualityProfile
{ {
UpgradeAllowed = true,
Items = Qualities.QualityFixture.GetDefaultQualities() Items = Qualities.QualityFixture.GetDefaultQualities()
}; };
var langProfile = new LanguageProfile var langProfile = new LanguageProfile
{ {
UpgradeAllowed = true,
Languages = LanguageFixture.GetDefaultLanguages(), Languages = LanguageFixture.GetDefaultLanguages(),
Cutoff = Language.English Cutoff = Language.English
}; };
@ -79,14 +81,16 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenAutoDownloadPropers(true); GivenAutoDownloadPropers(true);
var profile = new Profile var profile = new QualityProfile
{ {
UpgradeAllowed = true,
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
Cutoff = cutoff.Id, Cutoff = cutoff.Id,
}; };
var langProfile = new LanguageProfile var langProfile = new LanguageProfile
{ {
UpgradeAllowed = true,
Languages = LanguageFixture.GetDefaultLanguages(), Languages = LanguageFixture.GetDefaultLanguages(),
Cutoff = languageCutoff Cutoff = languageCutoff
}; };
@ -108,7 +112,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{ {
GivenAutoDownloadPropers(false); GivenAutoDownloadPropers(false);
var profile = new Profile var profile = new QualityProfile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
}; };

View File

@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
remoteEpisode.Release.PublishDate = DateTime.UtcNow; remoteEpisode.Release.PublishDate = DateTime.UtcNow;
remoteEpisode.Series = Builder<Series>.CreateNew() remoteEpisode.Series = Builder<Series>.CreateNew()
.With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() })
.Build(); .Build();
return remoteEpisode; return remoteEpisode;

View File

@ -23,7 +23,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
private DownloadDecision _temporarilyRejected; private DownloadDecision _temporarilyRejected;
private Series _series; private Series _series;
private Episode _episode; private Episode _episode;
private Profile _profile; private QualityProfile _profile;
private ReleaseInfo _release; private ReleaseInfo _release;
private ParsedEpisodeInfo _parsedEpisodeInfo; private ParsedEpisodeInfo _parsedEpisodeInfo;
private RemoteEpisode _remoteEpisode; private RemoteEpisode _remoteEpisode;
@ -38,19 +38,19 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
_episode = Builder<Episode>.CreateNew() _episode = Builder<Episode>.CreateNew()
.Build(); .Build();
_profile = new Profile _profile = new QualityProfile
{ {
Name = "Test", Name = "Test",
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = new List<ProfileQualityItem> Items = new List<QualityProfileQualityItem>
{ {
new ProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p }, new QualityProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p },
new ProfileQualityItem { Allowed = true, Quality = Quality.WEBDL720p }, new QualityProfileQualityItem { Allowed = true, Quality = Quality.WEBDL720p },
new ProfileQualityItem { Allowed = true, Quality = Quality.Bluray720p } new QualityProfileQualityItem { Allowed = true, Quality = Quality.Bluray720p }
}, },
}; };
_series.Profile = new LazyLoaded<Profile>(_profile); _series.QualityProfile = new LazyLoaded<QualityProfile>(_profile);
_release = Builder<ReleaseInfo>.CreateNew().Build(); _release = Builder<ReleaseInfo>.CreateNew().Build();

View File

@ -23,7 +23,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
private DownloadDecision _temporarilyRejected; private DownloadDecision _temporarilyRejected;
private Series _series; private Series _series;
private Episode _episode; private Episode _episode;
private Profile _profile; private QualityProfile _profile;
private ReleaseInfo _release; private ReleaseInfo _release;
private ParsedEpisodeInfo _parsedEpisodeInfo; private ParsedEpisodeInfo _parsedEpisodeInfo;
private RemoteEpisode _remoteEpisode; private RemoteEpisode _remoteEpisode;
@ -38,19 +38,19 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
_episode = Builder<Episode>.CreateNew() _episode = Builder<Episode>.CreateNew()
.Build(); .Build();
_profile = new Profile _profile = new QualityProfile
{ {
Name = "Test", Name = "Test",
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = new List<ProfileQualityItem> Items = new List<QualityProfileQualityItem>
{ {
new ProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p }, new QualityProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p },
new ProfileQualityItem { Allowed = true, Quality = Quality.WEBDL720p }, new QualityProfileQualityItem { Allowed = true, Quality = Quality.WEBDL720p },
new ProfileQualityItem { Allowed = true, Quality = Quality.Bluray720p } new QualityProfileQualityItem { Allowed = true, Quality = Quality.Bluray720p }
}, },
}; };
_series.Profile = new LazyLoaded<Profile>(_profile); _series.QualityProfile = new LazyLoaded<QualityProfile>(_profile);
_release = Builder<ReleaseInfo>.CreateNew().Build(); _release = Builder<ReleaseInfo>.CreateNew().Build();

View File

@ -24,7 +24,7 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
private DownloadDecision _temporarilyRejected; private DownloadDecision _temporarilyRejected;
private Series _series; private Series _series;
private Episode _episode; private Episode _episode;
private Profile _profile; private QualityProfile _profile;
private ReleaseInfo _release; private ReleaseInfo _release;
private ParsedEpisodeInfo _parsedEpisodeInfo; private ParsedEpisodeInfo _parsedEpisodeInfo;
private RemoteEpisode _remoteEpisode; private RemoteEpisode _remoteEpisode;
@ -38,19 +38,19 @@ namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
_episode = Builder<Episode>.CreateNew() _episode = Builder<Episode>.CreateNew()
.Build(); .Build();
_profile = new Profile _profile = new QualityProfile
{ {
Name = "Test", Name = "Test",
Cutoff = Quality.HDTV720p.Id, Cutoff = Quality.HDTV720p.Id,
Items = new List<ProfileQualityItem> Items = new List<QualityProfileQualityItem>
{ {
new ProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p }, new QualityProfileQualityItem { Allowed = true, Quality = Quality.HDTV720p },
new ProfileQualityItem { Allowed = true, Quality = Quality.WEBDL720p }, new QualityProfileQualityItem { Allowed = true, Quality = Quality.WEBDL720p },
new ProfileQualityItem { Allowed = true, Quality = Quality.Bluray720p } new QualityProfileQualityItem { Allowed = true, Quality = Quality.Bluray720p }
}, },
}; };
_series.Profile = new LazyLoaded<Profile>(_profile); _series.QualityProfile = new LazyLoaded<QualityProfile>(_profile);
_release = Builder<ReleaseInfo>.CreateNew().Build(); _release = Builder<ReleaseInfo>.CreateNew().Build();

View File

@ -21,20 +21,20 @@ namespace NzbDrone.Core.Test.HistoryTests
{ {
public class HistoryServiceFixture : CoreTest<HistoryService> public class HistoryServiceFixture : CoreTest<HistoryService>
{ {
private Profile _profile; private QualityProfile _profile;
private Profile _profileCustom; private QualityProfile _profileCustom;
private LanguageProfile _languageProfile; private LanguageProfile _languageProfile;
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
_profile = new Profile _profile = new QualityProfile
{ {
Cutoff = Quality.WEBDL720p.Id, Cutoff = Quality.WEBDL720p.Id,
Items = QualityFixture.GetDefaultQualities(), Items = QualityFixture.GetDefaultQualities(),
}; };
_profileCustom = new Profile _profileCustom = new QualityProfile
{ {
Cutoff = Quality.WEBDL720p.Id, Cutoff = Quality.WEBDL720p.Id,
Items = QualityFixture.GetDefaultQualities(Quality.DVD), Items = QualityFixture.GetDefaultQualities(Quality.DVD),

View File

@ -57,7 +57,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
_series = Builder<Series>.CreateNew() _series = Builder<Series>.CreateNew()
.With(e => e.Path = @"C:\Test\Series".AsOsAgnostic()) .With(e => e.Path = @"C:\Test\Series".AsOsAgnostic())
.With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() })
.With(e => e.LanguageProfile = new LanguageProfile { Languages = Languages.LanguageFixture.GetDefaultLanguages() }) .With(e => e.LanguageProfile = new LanguageProfile { Languages = Languages.LanguageFixture.GetDefaultLanguages() })
.Build(); .Build();

View File

@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
{ {
_series = Builder<Series>.CreateNew() _series = Builder<Series>.CreateNew()
.With(s => s.SeriesType = SeriesTypes.Standard) .With(s => s.SeriesType = SeriesTypes.Standard)
.With(e => e.Profile = new Profile .With(e => e.QualityProfile = new QualityProfile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(), Items = Qualities.QualityFixture.GetDefaultQualities(),
}) })

View File

@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.MediaFiles
var outputPath = @"C:\Test\Unsorted\TV\30.Rock.S01E01".AsOsAgnostic(); var outputPath = @"C:\Test\Unsorted\TV\30.Rock.S01E01".AsOsAgnostic();
var series = Builder<Series>.CreateNew() var series = Builder<Series>.CreateNew()
.With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() }) .With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() })
.With(l => l.LanguageProfile = new LanguageProfile .With(l => l.LanguageProfile = new LanguageProfile
{ {
Cutoff = Language.Spanish, Cutoff = Language.Spanish,
@ -86,6 +86,13 @@ namespace NzbDrone.Core.Test.MediaFiles
_approvedDecisions.ForEach(a => a.LocalEpisode.Path = Path.Combine(_downloadClientItem.OutputPath.ToString(), Path.GetFileName(a.LocalEpisode.Path))); _approvedDecisions.ForEach(a => a.LocalEpisode.Path = Path.Combine(_downloadClientItem.OutputPath.ToString(), Path.GetFileName(a.LocalEpisode.Path)));
} }
private void GivenExistingFileOnDisk()
{
Mocker.GetMock<IMediaFileService>()
.Setup(s => s.GetFilesWithRelativePath(It.IsAny<int>(), It.IsAny<string>()))
.Returns(new List<EpisodeFile>());
}
[Test] [Test]
public void should_not_import_any_if_there_are_no_approved_decisions() public void should_not_import_any_if_there_are_no_approved_decisions()
{ {
@ -97,12 +104,16 @@ namespace NzbDrone.Core.Test.MediaFiles
[Test] [Test]
public void should_import_each_approved() public void should_import_each_approved()
{ {
GivenExistingFileOnDisk();
Subject.Import(_approvedDecisions, false).Should().HaveCount(5); Subject.Import(_approvedDecisions, false).Should().HaveCount(5);
} }
[Test] [Test]
public void should_only_import_approved() public void should_only_import_approved()
{ {
GivenExistingFileOnDisk();
var all = new List<ImportDecision>(); var all = new List<ImportDecision>();
all.AddRange(_rejectedDecisions); all.AddRange(_rejectedDecisions);
all.AddRange(_approvedDecisions); all.AddRange(_approvedDecisions);
@ -116,6 +127,8 @@ namespace NzbDrone.Core.Test.MediaFiles
[Test] [Test]
public void should_only_import_each_episode_once() public void should_only_import_each_episode_once()
{ {
GivenExistingFileOnDisk();
var all = new List<ImportDecision>(); var all = new List<ImportDecision>();
all.AddRange(_approvedDecisions); all.AddRange(_approvedDecisions);
all.Add(new ImportDecision(_approvedDecisions.First().LocalEpisode)); all.Add(new ImportDecision(_approvedDecisions.First().LocalEpisode));
@ -147,6 +160,8 @@ namespace NzbDrone.Core.Test.MediaFiles
[Test] [Test]
public void should_not_move_existing_files() public void should_not_move_existing_files()
{ {
GivenExistingFileOnDisk();
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, false); Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, false);
Mocker.GetMock<IUpgradeMediaFiles>() Mocker.GetMock<IUpgradeMediaFiles>()
@ -217,6 +232,8 @@ namespace NzbDrone.Core.Test.MediaFiles
[Test] [Test]
public void should_import_larger_files_first() public void should_import_larger_files_first()
{ {
GivenExistingFileOnDisk();
var fileDecision = _approvedDecisions.First(); var fileDecision = _approvedDecisions.First();
fileDecision.LocalEpisode.Size = 1.Gigabytes(); fileDecision.LocalEpisode.Size = 1.Gigabytes();

View File

@ -7,12 +7,12 @@ using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.Profiles namespace NzbDrone.Core.Test.Profiles
{ {
[TestFixture] [TestFixture]
public class ProfileRepositoryFixture : DbTest<ProfileRepository, Profile> public class ProfileRepositoryFixture : DbTest<QualityProfileRepository, QualityProfile>
{ {
[Test] [Test]
public void should_be_able_to_read_and_write() public void should_be_able_to_read_and_write()
{ {
var profile = new Profile var profile = new QualityProfile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p), Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
Cutoff = Quality.Bluray1080p.Id, Cutoff = Quality.Bluray1080p.Id,

View File

@ -10,7 +10,7 @@ using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Profiles namespace NzbDrone.Core.Test.Profiles
{ {
[TestFixture] [TestFixture]
public class ProfileServiceFixture : CoreTest<ProfileService> public class ProfileServiceFixture : CoreTest<QualityProfileService>
{ {
[Test] [Test]
public void init_should_add_default_profiles() public void init_should_add_default_profiles()
@ -18,7 +18,7 @@ namespace NzbDrone.Core.Test.Profiles
Subject.Handle(new ApplicationStartedEvent()); Subject.Handle(new ApplicationStartedEvent());
Mocker.GetMock<IProfileRepository>() Mocker.GetMock<IProfileRepository>()
.Verify(v => v.Insert(It.IsAny<Profile>()), Times.Exactly(6)); .Verify(v => v.Insert(It.IsAny<QualityProfile>()), Times.Exactly(6));
} }
[Test] [Test]
@ -28,32 +28,32 @@ namespace NzbDrone.Core.Test.Profiles
{ {
Mocker.GetMock<IProfileRepository>() Mocker.GetMock<IProfileRepository>()
.Setup(s => s.All()) .Setup(s => s.All())
.Returns(Builder<Profile>.CreateListOfSize(2).Build().ToList()); .Returns(Builder<QualityProfile>.CreateListOfSize(2).Build().ToList());
Subject.Handle(new ApplicationStartedEvent()); Subject.Handle(new ApplicationStartedEvent());
Mocker.GetMock<IProfileRepository>() Mocker.GetMock<IProfileRepository>()
.Verify(v => v.Insert(It.IsAny<Profile>()), Times.Never()); .Verify(v => v.Insert(It.IsAny<QualityProfile>()), Times.Never());
} }
[Test] [Test]
public void should_not_be_able_to_delete_profile_if_assigned_to_series() public void should_not_be_able_to_delete_profile_if_assigned_to_series()
{ {
var profile = Builder<Profile>.CreateNew() var profile = Builder<QualityProfile>.CreateNew()
.With(p => p.Id = 2) .With(p => p.Id = 2)
.Build(); .Build();
var seriesList = Builder<Series>.CreateListOfSize(3) var seriesList = Builder<Series>.CreateListOfSize(3)
.Random(1) .Random(1)
.With(c => c.ProfileId = profile.Id) .With(c => c.QualityProfileId = profile.Id)
.Build().ToList(); .Build().ToList();
Mocker.GetMock<ISeriesService>().Setup(c => c.GetAllSeries()).Returns(seriesList); Mocker.GetMock<ISeriesService>().Setup(c => c.GetAllSeries()).Returns(seriesList);
Mocker.GetMock<IProfileRepository>().Setup(c => c.Get(profile.Id)).Returns(profile); Mocker.GetMock<IProfileRepository>().Setup(c => c.Get(profile.Id)).Returns(profile);
Assert.Throws<ProfileInUseException>(() => Subject.Delete(profile.Id)); Assert.Throws<QualityProfileInUseException>(() => Subject.Delete(profile.Id));
Mocker.GetMock<IProfileRepository>().Verify(c => c.Delete(It.IsAny<int>()), Times.Never()); Mocker.GetMock<IProfileRepository>().Verify(c => c.Delete(It.IsAny<int>()), Times.Never());
@ -65,7 +65,7 @@ namespace NzbDrone.Core.Test.Profiles
{ {
var seriesList = Builder<Series>.CreateListOfSize(3) var seriesList = Builder<Series>.CreateListOfSize(3)
.All() .All()
.With(c => c.ProfileId = 2) .With(c => c.QualityProfileId = 2)
.Build().ToList(); .Build().ToList();

View File

@ -61,7 +61,7 @@ namespace NzbDrone.Core.Test.Qualities
i.Should().Be(expected); i.Should().Be(expected);
} }
public static List<ProfileQualityItem> GetDefaultQualities(params Quality[] allowed) public static List<QualityProfileQualityItem> GetDefaultQualities(params Quality[] allowed)
{ {
var qualities = new List<Quality> var qualities = new List<Quality>
{ {
@ -87,7 +87,7 @@ namespace NzbDrone.Core.Test.Qualities
var items = qualities var items = qualities
.Except(allowed) .Except(allowed)
.Concat(allowed) .Concat(allowed)
.Select(v => new ProfileQualityItem { Quality = v, Allowed = allowed.Contains(v) }).ToList(); .Select(v => new QualityProfileQualityItem { Quality = v, Allowed = allowed.Contains(v) }).ToList();
return items; return items;
} }

View File

@ -14,48 +14,48 @@ namespace NzbDrone.Core.Test.Qualities
private void GivenDefaultProfile() private void GivenDefaultProfile()
{ {
Subject = new QualityModelComparer(new Profile { Items = QualityFixture.GetDefaultQualities() }); Subject = new QualityModelComparer(new QualityProfile { Items = QualityFixture.GetDefaultQualities() });
} }
private void GivenCustomProfile() private void GivenCustomProfile()
{ {
Subject = new QualityModelComparer(new Profile { Items = QualityFixture.GetDefaultQualities(Quality.Bluray720p, Quality.DVD) }); Subject = new QualityModelComparer(new QualityProfile { Items = QualityFixture.GetDefaultQualities(Quality.Bluray720p, Quality.DVD) });
} }
private void GivenGroupedProfile() private void GivenGroupedProfile()
{ {
var profile = new Profile var profile = new QualityProfile
{ {
Items = new List<ProfileQualityItem> Items = new List<QualityProfileQualityItem>
{ {
new ProfileQualityItem new QualityProfileQualityItem
{ {
Allowed = false, Allowed = false,
Quality = Quality.SDTV Quality = Quality.SDTV
}, },
new ProfileQualityItem new QualityProfileQualityItem
{ {
Allowed = false, Allowed = false,
Quality = Quality.DVD Quality = Quality.DVD
}, },
new ProfileQualityItem new QualityProfileQualityItem
{ {
Allowed = true, Allowed = true,
Items = new List<ProfileQualityItem> Items = new List<QualityProfileQualityItem>
{ {
new ProfileQualityItem new QualityProfileQualityItem
{ {
Allowed = true, Allowed = true,
Quality = Quality.HDTV720p Quality = Quality.HDTV720p
}, },
new ProfileQualityItem new QualityProfileQualityItem
{ {
Allowed = true, Allowed = true,
Quality = Quality.WEBDL720p Quality = Quality.WEBDL720p
} }
} }
}, },
new ProfileQualityItem new QualityProfileQualityItem
{ {
Allowed = true, Allowed = true,
Quality = Quality.Bluray720p Quality = Quality.Bluray720p

View File

@ -28,15 +28,15 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
[SetUp] [SetUp]
public void Setup() public void Setup()
{ {
var profile = new Profile var profile = new QualityProfile
{ {
Id = 1, Id = 1,
Cutoff = Quality.WEBDL480p.Id, Cutoff = Quality.WEBDL480p.Id,
Items = new List<ProfileQualityItem> Items = new List<QualityProfileQualityItem>
{ {
new ProfileQualityItem { Allowed = true, Quality = Quality.SDTV }, new QualityProfileQualityItem { Allowed = true, Quality = Quality.SDTV },
new ProfileQualityItem { Allowed = true, Quality = Quality.WEBDL480p }, new QualityProfileQualityItem { Allowed = true, Quality = Quality.WEBDL480p },
new ProfileQualityItem { Allowed = true, Quality = Quality.RAWHD } new QualityProfileQualityItem { Allowed = true, Quality = Quality.RAWHD }
} }
}; };
@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
.With(s => s.Runtime = 30) .With(s => s.Runtime = 30)
.With(s => s.Monitored = true) .With(s => s.Monitored = true)
.With(s => s.TitleSlug = "Title3") .With(s => s.TitleSlug = "Title3")
.With(s => s.ProfileId = profile.Id) .With(s => s.QualityProfileId = profile.Id)
.With(s => s.LanguageProfileId = langProfile.Id) .With(s => s.LanguageProfileId = langProfile.Id)
.BuildNew(); .BuildNew();
@ -61,7 +61,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
.With(s => s.Runtime = 30) .With(s => s.Runtime = 30)
.With(s => s.Monitored = false) .With(s => s.Monitored = false)
.With(s => s.TitleSlug = "Title2") .With(s => s.TitleSlug = "Title2")
.With(s => s.ProfileId = profile.Id) .With(s => s.QualityProfileId = profile.Id)
.With(s => s.LanguageProfileId = langProfile.Id) .With(s => s.LanguageProfileId = langProfile.Id)
.BuildNew(); .BuildNew();

View File

@ -18,7 +18,7 @@ namespace NzbDrone.Core.Test.TvTests.SeriesRepositoryTests
[Test] [Test]
public void should_lazyload_quality_profile() public void should_lazyload_quality_profile()
{ {
var profile = new Profile var profile = new QualityProfile
{ {
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p), Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
@ -34,17 +34,17 @@ namespace NzbDrone.Core.Test.TvTests.SeriesRepositoryTests
}; };
Mocker.Resolve<ProfileRepository>().Insert(profile); Mocker.Resolve<QualityProfileRepository>().Insert(profile);
Mocker.Resolve<LanguageProfileRepository>().Insert(langProfile); Mocker.Resolve<LanguageProfileRepository>().Insert(langProfile);
var series = Builder<Series>.CreateNew().BuildNew(); var series = Builder<Series>.CreateNew().BuildNew();
series.ProfileId = profile.Id; series.QualityProfileId = profile.Id;
series.LanguageProfileId = langProfile.Id; series.LanguageProfileId = langProfile.Id;
Subject.Insert(series); Subject.Insert(series);
StoredModel.Profile.Should().NotBeNull(); StoredModel.QualityProfile.Should().NotBeNull();
StoredModel.LanguageProfile.Should().NotBeNull(); StoredModel.LanguageProfile.Should().NotBeNull();

View File

@ -23,7 +23,7 @@ namespace NzbDrone.Core.Test.TvTests.SeriesServiceTests
{ {
_series = Builder<Series>.CreateListOfSize(5) _series = Builder<Series>.CreateListOfSize(5)
.All() .All()
.With(s => s.ProfileId = 1) .With(s => s.QualityProfileId = 1)
.With(s => s.Monitored) .With(s => s.Monitored)
.With(s => s.SeasonFolder) .With(s => s.SeasonFolder)
.With(s => s.Path = @"C:\Test\name".AsOsAgnostic()) .With(s => s.Path = @"C:\Test\name".AsOsAgnostic())

View File

@ -42,7 +42,7 @@ namespace NzbDrone.Core.Datastore.Migration
var allowed = Json.Deserialize<List<Quality>>(allowedJson); var allowed = Json.Deserialize<List<Quality>>(allowedJson);
var items = Quality.DefaultQualityDefinitions.OrderBy(v => v.Weight).Select(v => new ProfileQualityItem { Quality = v.Quality, Allowed = allowed.Contains(v.Quality) }).ToList(); var items = Quality.DefaultQualityDefinitions.OrderBy(v => v.Weight).Select(v => new QualityProfileQualityItem { Quality = v.Quality, Allowed = allowed.Contains(v.Quality) }).ToList();
var allowedNewJson = qualityProfileItemConverter.ToDB(items); var allowedNewJson = qualityProfileItemConverter.ToDB(items);

View File

@ -0,0 +1,23 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(128)]
public class rename_quality_profiles_add_upgrade_allowed : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Rename.Table("Profiles").To("QualityProfiles");
Alter.Table("QualityProfiles").AddColumn("UpgradeAllowed").AsInt32().Nullable();
Alter.Table("LanguageProfiles").AddColumn("UpgradeAllowed").AsInt32().Nullable();
// Set upgrade allowed for existing profiles (default will be false for new profiles)
Update.Table("QualityProfiles").Set(new { UpgradeAllowed = true }).AllRows();
Update.Table("LanguageProfiles").Set(new { UpgradeAllowed = true }).AllRows();
Rename.Column("ProfileId").OnTable("Series").To("QualityProfileId");
}
}
}

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Text; using System.Text;
@ -148,7 +148,8 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
{ {
var start = Index; var start = Index;
var end = start + 1; var end = start + 1;
while (end < Buffer.Length && (char.IsLetter(Buffer[end]) || Buffer[end] == '_')) end++; while (end < Buffer.Length && (char.IsLetter(Buffer[end]) || char.IsNumber(Buffer[end]) || Buffer[end] == '_' || Buffer[end] == '(')) end++;
if (end >= Buffer.Length || Buffer[end] == ',' || Buffer[end] == ')' || char.IsWhiteSpace(Buffer[end])) if (end >= Buffer.Length || Buffer[end] == ',' || Buffer[end] == ')' || char.IsWhiteSpace(Buffer[end]))
{ {
Index = end; Index = end;

View File

@ -84,7 +84,7 @@ namespace NzbDrone.Core.Datastore
Mapper.Entity<Series>().RegisterModel("Series") Mapper.Entity<Series>().RegisterModel("Series")
.Ignore(s => s.RootFolderPath) .Ignore(s => s.RootFolderPath)
.Relationship() .Relationship()
.HasOne(s => s.Profile, s => s.ProfileId) .HasOne(s => s.QualityProfile, s => s.QualityProfileId)
.HasOne(s => s.LanguageProfile, s => s.LanguageProfileId); .HasOne(s => s.LanguageProfile, s => s.LanguageProfileId);
Mapper.Entity<EpisodeFile>().RegisterModel("EpisodeFiles") Mapper.Entity<EpisodeFile>().RegisterModel("EpisodeFiles")
@ -106,7 +106,7 @@ namespace NzbDrone.Core.Datastore
.Ignore(d => d.GroupName) .Ignore(d => d.GroupName)
.Ignore(d => d.Weight); .Ignore(d => d.Weight);
Mapper.Entity<Profile>().RegisterModel("Profiles"); Mapper.Entity<QualityProfile>().RegisterModel("QualityProfiles");
Mapper.Entity<LanguageProfile>().RegisterModel("LanguageProfiles"); Mapper.Entity<LanguageProfile>().RegisterModel("LanguageProfiles");
Mapper.Entity<Log>().RegisterModel("Logs"); Mapper.Entity<Log>().RegisterModel("Logs");
Mapper.Entity<NamingConfig>().RegisterModel("NamingConfig"); Mapper.Entity<NamingConfig>().RegisterModel("NamingConfig");
@ -145,7 +145,7 @@ namespace NzbDrone.Core.Datastore
MapRepository.Instance.RegisterTypeConverter(typeof(bool), new BooleanIntConverter()); MapRepository.Instance.RegisterTypeConverter(typeof(bool), new BooleanIntConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(Enum), new EnumIntConverter()); MapRepository.Instance.RegisterTypeConverter(typeof(Enum), new EnumIntConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(Quality), new QualityIntConverter()); MapRepository.Instance.RegisterTypeConverter(typeof(Quality), new QualityIntConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(List<ProfileQualityItem>), new EmbeddedDocumentConverter(new QualityIntConverter())); MapRepository.Instance.RegisterTypeConverter(typeof(List<QualityProfileQualityItem>), new EmbeddedDocumentConverter(new QualityIntConverter()));
MapRepository.Instance.RegisterTypeConverter(typeof(QualityModel), new EmbeddedDocumentConverter(new QualityIntConverter())); MapRepository.Instance.RegisterTypeConverter(typeof(QualityModel), new EmbeddedDocumentConverter(new QualityIntConverter()));
MapRepository.Instance.RegisterTypeConverter(typeof(Dictionary<string, string>), new EmbeddedDocumentConverter()); MapRepository.Instance.RegisterTypeConverter(typeof(Dictionary<string, string>), new EmbeddedDocumentConverter());
MapRepository.Instance.RegisterTypeConverter(typeof(List<int>), new EmbeddedDocumentConverter()); MapRepository.Instance.RegisterTypeConverter(typeof(List<int>), new EmbeddedDocumentConverter());

View File

@ -59,7 +59,7 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareQuality(DownloadDecision x, DownloadDecision y) private int CompareQuality(DownloadDecision x, DownloadDecision y)
{ {
return CompareAll(CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Series.Profile.Value.GetIndex(remoteEpisode.ParsedEpisodeInfo.Quality.Quality)), return CompareAll(CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Series.QualityProfile.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.Real),
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Version)); CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Version));
} }

View File

@ -24,7 +24,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{ {
var profile = subject.Series.Profile.Value; var profile = subject.Series.QualityProfile.Value;
foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value)) foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value))
{ {

View File

@ -21,7 +21,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
{ {
_logger.Debug("Checking if report meets quality requirements. {0}", subject.ParsedEpisodeInfo.Quality); _logger.Debug("Checking if report meets quality requirements. {0}", subject.ParsedEpisodeInfo.Quality);
var profile = subject.Series.Profile.Value; var profile = subject.Series.QualityProfile.Value;
var qualityIndex = profile.GetIndex(subject.ParsedEpisodeInfo.Quality.Quality); var qualityIndex = profile.GetIndex(subject.ParsedEpisodeInfo.Quality.Quality);
var qualityOrGroup = profile.Items[qualityIndex.Index]; var qualityOrGroup = profile.Items[qualityIndex.Index];

View File

@ -31,7 +31,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria) public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{ {
var queue = _queueService.GetQueue(); var queue = _queueService.GetQueue();
var matchingSeries = queue.Where(q => q.Series.Id == subject.Series.Id); var matchingSeries = queue.Where(q => q.RemoteEpisode.Series.Id == subject.Series.Id);
var matchingEpisode = matchingSeries.Where(q => q.RemoteEpisode.Episodes.Select(e => e.Id).Intersect(subject.Episodes.Select(e => e.Id)).Any()); var matchingEpisode = matchingSeries.Where(q => q.RemoteEpisode.Episodes.Select(e => e.Id).Intersect(subject.Episodes.Select(e => e.Id)).Any());
foreach (var queueItem in matchingEpisode) foreach (var queueItem in matchingEpisode)
@ -41,7 +41,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
_logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language); _logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, queueItem.Title); var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, queueItem.Title);
if (!_upgradableSpecification.CutoffNotMet(subject.Series.Profile, if (!_upgradableSpecification.CutoffNotMet(subject.Series.QualityProfile,
subject.Series.LanguageProfile, subject.Series.LanguageProfile,
remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Quality,
remoteEpisode.ParsedEpisodeInfo.Language, remoteEpisode.ParsedEpisodeInfo.Language,
@ -54,7 +54,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
_logger.Debug("Checking if release is higher quality than queued release. Queued quality is: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language); _logger.Debug("Checking if release is higher quality than queued release. Queued quality is: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
if (!_upgradableSpecification.IsUpgradable(subject.Series.Profile, if (!_upgradableSpecification.IsUpgradable(subject.Series.QualityProfile,
subject.Series.LanguageProfile, subject.Series.LanguageProfile,
remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Quality,
remoteEpisode.ParsedEpisodeInfo.Language, remoteEpisode.ParsedEpisodeInfo.Language,

View File

@ -42,7 +42,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
return Decision.Accept(); return Decision.Accept();
} }
var profile = subject.Series.Profile.Value; var profile = subject.Series.QualityProfile.Value;
var languageProfile = subject.Series.LanguageProfile.Value; var languageProfile = subject.Series.LanguageProfile.Value;
var delayProfile = _delayProfileService.BestForTags(subject.Series.Tags); var delayProfile = _delayProfileService.BestForTags(subject.Series.Tags);
var delay = delayProfile.GetProtocolDelay(subject.Release.DownloadProtocol); var delay = delayProfile.GetProtocolDelay(subject.Release.DownloadProtocol);
@ -50,7 +50,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
if (delay == 0) if (delay == 0)
{ {
_logger.Debug("Profile does not require a waiting period before download for {0}.", subject.Release.DownloadProtocol); _logger.Debug("QualityProfile does not require a waiting period before download for {0}.", subject.Release.DownloadProtocol);
return Decision.Accept(); return Decision.Accept();
} }

View File

@ -58,7 +58,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
var preferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, mostRecent.SourceTitle); var preferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, mostRecent.SourceTitle);
var cutoffUnmet = _upgradableSpecification.CutoffNotMet( var cutoffUnmet = _upgradableSpecification.CutoffNotMet(
subject.Series.Profile, subject.Series.QualityProfile,
subject.Series.LanguageProfile, subject.Series.LanguageProfile,
mostRecent.Quality, mostRecent.Quality,
mostRecent.Language, mostRecent.Language,
@ -67,7 +67,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
subject.PreferredWordScore); subject.PreferredWordScore);
var upgradeable = _upgradableSpecification.IsUpgradable( var upgradeable = _upgradableSpecification.IsUpgradable(
subject.Series.Profile, subject.Series.QualityProfile,
subject.Series.LanguageProfile, subject.Series.LanguageProfile,
mostRecent.Quality, mostRecent.Quality,
mostRecent.Language, mostRecent.Language,

View File

@ -8,10 +8,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
{ {
public interface IUpgradableSpecification public interface IUpgradableSpecification
{ {
bool IsUpgradable(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality, Language newLanguage, int newScore); bool IsUpgradable(QualityProfile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality, Language newLanguage, int newScore);
bool QualityCutoffNotMet(Profile profile, QualityModel currentQuality, QualityModel newQuality = null); bool QualityCutoffNotMet(QualityProfile profile, QualityModel currentQuality, QualityModel newQuality = null);
bool LanguageCutoffNotMet(LanguageProfile languageProfile, Language currentLanguage); bool LanguageCutoffNotMet(LanguageProfile languageProfile, Language currentLanguage);
bool CutoffNotMet(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality = null, int newScore = 0); bool CutoffNotMet(QualityProfile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality = null, int newScore = 0);
bool IsRevisionUpgrade(QualityModel currentQuality, QualityModel newQuality); bool IsRevisionUpgrade(QualityModel currentQuality, QualityModel newQuality);
} }
@ -37,14 +37,15 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
return true; return true;
} }
private bool IsQualityUpgradable(Profile profile, QualityModel currentQuality, QualityModel newQuality = null) private bool IsQualityUpgradable(QualityProfile profile, QualityModel currentQuality, QualityModel newQuality = null)
{ {
if (newQuality != null) if (newQuality != null)
{ {
var compare = new QualityModelComparer(profile).Compare(newQuality, currentQuality); var compare = new QualityModelComparer(profile).Compare(newQuality, currentQuality);
if (compare <= 0) if (compare <= 0)
{ {
_logger.Debug("existing item has better quality. skipping"); _logger.Debug("Existing item has better quality, skipping");
return false; return false;
} }
} }
@ -56,25 +57,25 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
return newScore > currentScore; return newScore > currentScore;
} }
public bool IsUpgradable(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality, Language newLanguage, int newScore) public bool IsUpgradable(QualityProfile qualityProfile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality, Language newLanguage, int newScore)
{ {
if (IsQualityUpgradable(profile, currentQuality, newQuality)) if (IsQualityUpgradable(qualityProfile, currentQuality, newQuality) && qualityProfile.UpgradeAllowed)
{ {
return true; return true;
} }
if (new QualityModelComparer(profile).Compare(newQuality, currentQuality) != 0) if (new QualityModelComparer(qualityProfile).Compare(newQuality, currentQuality) < 0)
{ {
_logger.Debug("Existing item has better qualitys, skipping"); _logger.Debug("Existing item has better quality, skipping");
return false; return false;
} }
if (IsLanguageUpgradable(languageProfile, currentLanguage, newLanguage)) if (IsLanguageUpgradable(languageProfile, currentLanguage, newLanguage) && languageProfile.UpgradeAllowed)
{ {
return true; return true;
} }
if (new LanguageComparer(languageProfile).Compare(newLanguage, currentLanguage) != 0) if (new LanguageComparer(languageProfile).Compare(newLanguage, currentLanguage) < 0)
{ {
_logger.Debug("Existing item has better language, skipping"); _logger.Debug("Existing item has better language, skipping");
return false; return false;
@ -89,7 +90,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
return true; return true;
} }
public bool QualityCutoffNotMet(Profile profile, QualityModel currentQuality, QualityModel newQuality = null) public bool QualityCutoffNotMet(QualityProfile profile, QualityModel currentQuality, QualityModel newQuality = null)
{ {
var qualityCompare = new QualityModelComparer(profile).Compare(currentQuality.Quality.Id, profile.Cutoff); var qualityCompare = new QualityModelComparer(profile).Compare(currentQuality.Quality.Id, profile.Cutoff);
@ -113,7 +114,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
return languageCompare < 0; return languageCompare < 0;
} }
public bool CutoffNotMet(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality = null, int newScore = 0) public bool CutoffNotMet(QualityProfile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality = null, int newScore = 0)
{ {
// If we can upgrade the language (it is not the cutoff) then the quality doesn't // If we can upgrade the language (it is not the cutoff) then the quality doesn't
// matter as we can always get same quality with prefered language. // matter as we can always get same quality with prefered language.

View File

@ -34,8 +34,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
_logger.Debug("Comparing file quality and language with report. Existing file is {0} - {1}", file.Quality, file.Language); _logger.Debug("Comparing file quality and language with report. Existing file is {0} - {1}", file.Quality, file.Language);
if (!_upgradableSpecification.IsUpgradable(subject.Series.QualityProfile,
if (!_upgradableSpecification.IsUpgradable(subject.Series.Profile,
subject.Series.LanguageProfile, subject.Series.LanguageProfile,
file.Quality, file.Quality,
file.Language, file.Language,
@ -44,7 +43,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
subject.ParsedEpisodeInfo.Language, subject.ParsedEpisodeInfo.Language,
subject.PreferredWordScore)) subject.PreferredWordScore))
{ {
return Decision.Reject("Quality for existing file on disk is of equal or higher preference: {0} - {1}", file.Quality, file.Language); return Decision.Reject("Existing file on disk is of equal or higher preference: {0} - {1}", file.Quality, file.Language);
} }
} }

View File

@ -216,7 +216,7 @@ namespace NzbDrone.Core.Download.Pending
{ {
var series = g.First().Series; var series = g.First().Series;
return g.OrderByDescending(e => e.Quality, new QualityModelComparer(series.Profile)) return g.OrderByDescending(e => e.Quality, new QualityModelComparer(series.QualityProfile))
.ThenBy(q => PrioritizeDownloadProtocol(q.Series, q.Protocol)) .ThenBy(q => PrioritizeDownloadProtocol(q.Series, q.Protocol))
.First(); .First();
}); });
@ -375,7 +375,7 @@ namespace NzbDrone.Core.Download.Pending
return; return;
} }
var profile = remoteEpisode.Series.Profile.Value; var profile = remoteEpisode.Series.QualityProfile.Value;
foreach (var existingReport in existingReports) foreach (var existingReport in existingReports)
{ {

View File

@ -50,7 +50,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
{ {
var qualifiedImports = decisions.Where(c => c.Approved) var qualifiedImports = decisions.Where(c => c.Approved)
.GroupBy(c => c.LocalEpisode.Series.Id, (i, s) => s .GroupBy(c => c.LocalEpisode.Series.Id, (i, s) => s
.OrderByDescending(c => c.LocalEpisode.Quality, new QualityModelComparer(s.First().LocalEpisode.Series.Profile)) .OrderByDescending(c => c.LocalEpisode.Quality, new QualityModelComparer(s.First().LocalEpisode.Series.QualityProfile))
.ThenByDescending(c => c.LocalEpisode.Language, new LanguageComparer(s.First().LocalEpisode.Series.LanguageProfile)) .ThenByDescending(c => c.LocalEpisode.Language, new LanguageComparer(s.First().LocalEpisode.Series.LanguageProfile))
.ThenByDescending(c => c.LocalEpisode.Size)) .ThenByDescending(c => c.LocalEpisode.Size))
.SelectMany(c => c) .SelectMany(c => c)

View File

@ -19,7 +19,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem)
{ {
var qualityComparer = new QualityModelComparer(localEpisode.Series.Profile); var qualityComparer = new QualityModelComparer(localEpisode.Series.QualityProfile);
var languageComparer = new LanguageComparer(localEpisode.Series.LanguageProfile); var languageComparer = new LanguageComparer(localEpisode.Series.LanguageProfile);
if (localEpisode.Episodes.Any(e => e.EpisodeFileId != 0 && qualityComparer.Compare(e.EpisodeFile.Value.Quality, localEpisode.Quality) > 0)) if (localEpisode.Episodes.Any(e => e.EpisodeFileId != 0 && qualityComparer.Compare(e.EpisodeFile.Value.Quality, localEpisode.Quality) > 0))

View File

@ -137,6 +137,7 @@
<Compile Include="Configuration\ResetApiKeyCommand.cs" /> <Compile Include="Configuration\ResetApiKeyCommand.cs" />
<Compile Include="Datastore\Migration\130_episode_last_searched_time.cs" /> <Compile Include="Datastore\Migration\130_episode_last_searched_time.cs" />
<Compile Include="Datastore\Migration\129_add_relative_original_path_to_episode_file.cs" /> <Compile Include="Datastore\Migration\129_add_relative_original_path_to_episode_file.cs" />
<Compile Include="Datastore\Migration\128_rename_quality_profiles_add_upgrade_allowed.cs" />
<Compile Include="DecisionEngine\Specifications\AlreadyImportedSpecification.cs" /> <Compile Include="DecisionEngine\Specifications\AlreadyImportedSpecification.cs" />
<Compile Include="CustomFilters\CustomFilter.cs" /> <Compile Include="CustomFilters\CustomFilter.cs" />
<Compile Include="CustomFilters\CustomFilterRepository.cs" /> <Compile Include="CustomFilters\CustomFilterRepository.cs" />
@ -1000,11 +1001,11 @@
<Compile Include="Profiles\Delay\DelayProfileTagInUseValidator.cs" /> <Compile Include="Profiles\Delay\DelayProfileTagInUseValidator.cs" />
<Compile Include="Profiles\Languages\LanguageProfileItem.cs" /> <Compile Include="Profiles\Languages\LanguageProfileItem.cs" />
<Compile Include="Profiles\Languages\LanguageProfileRepository.cs" /> <Compile Include="Profiles\Languages\LanguageProfileRepository.cs" />
<Compile Include="Profiles\Qualities\Profile.cs" /> <Compile Include="Profiles\Qualities\QualityProfile.cs" />
<Compile Include="Profiles\Qualities\ProfileInUseException.cs" /> <Compile Include="Profiles\Qualities\QualityProfileInUseException.cs" />
<Compile Include="Profiles\Qualities\ProfileQualityItem.cs" /> <Compile Include="Profiles\Qualities\QualityProfileQualityItem.cs" />
<Compile Include="Profiles\Qualities\ProfileRepository.cs" /> <Compile Include="Profiles\Qualities\QualityProfileRepository.cs" />
<Compile Include="Profiles\Qualities\ProfileService.cs" /> <Compile Include="Profiles\Qualities\QualityProfileService.cs" />
<Compile Include="Profiles\Qualities\QualityIndex.cs" /> <Compile Include="Profiles\Qualities\QualityIndex.cs" />
<Compile Include="Profiles\Releases\PreferredWordService.cs" /> <Compile Include="Profiles\Releases\PreferredWordService.cs" />
<Compile Include="ProgressMessaging\ProgressMessageContext.cs" /> <Compile Include="ProgressMessaging\ProgressMessageContext.cs" />

View File

@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Languages; using NzbDrone.Core.Languages;
@ -9,6 +9,7 @@ namespace NzbDrone.Core.Profiles.Languages
{ {
public string Name { get; set; } public string Name { get; set; }
public List<LanguageProfileItem> Languages { get; set; } public List<LanguageProfileItem> Languages { get; set; }
public bool UpgradeAllowed { get; set; }
public Language Cutoff { get; set; } public Language Cutoff { get; set; }
public Language LastAllowedLanguage() public Language LastAllowedLanguage()

View File

@ -1,13 +0,0 @@
using System.Net;
using NzbDrone.Core.Exceptions;
namespace NzbDrone.Core.Profiles.Qualities
{
public class ProfileInUseException : NzbDroneClientException
{
public ProfileInUseException(string name)
: base(HttpStatusCode.BadRequest, "Profile [{0}] is in use.", name)
{
}
}
}

View File

@ -1,23 +0,0 @@
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Profiles.Qualities
{
public interface IProfileRepository : IBasicRepository<Profile>
{
bool Exists(int id);
}
public class ProfileRepository : BasicRepository<Profile>, IProfileRepository
{
public ProfileRepository(IMainDatabase database, IEventAggregator eventAggregator)
: base(database, eventAggregator)
{
}
public bool Exists(int id)
{
return DataMapper.Query<Profile>().Where(p => p.Id == id).GetRowCount() == 1;
}
}
}

View File

@ -1,15 +1,16 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Qualities; using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Profiles.Qualities namespace NzbDrone.Core.Profiles.Qualities
{ {
public class Profile : ModelBase public class QualityProfile : ModelBase
{ {
public string Name { get; set; } public string Name { get; set; }
public bool UpgradeAllowed { get; set; }
public int Cutoff { get; set; } public int Cutoff { get; set; }
public List<ProfileQualityItem> Items { get; set; } public List<QualityProfileQualityItem> Items { get; set; }
public Quality LastAllowedQuality() public Quality LastAllowedQuality()
{ {

View File

@ -0,0 +1,13 @@
using System.Net;
using NzbDrone.Core.Exceptions;
namespace NzbDrone.Core.Profiles.Qualities
{
public class QualityProfileInUseException : NzbDroneClientException
{
public QualityProfileInUseException(string name)
: base(HttpStatusCode.BadRequest, "QualityProfile [{0}] is in use.", name)
{
}
}
}

View File

@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Newtonsoft.Json; using Newtonsoft.Json;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@ -7,19 +7,19 @@ using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Profiles.Qualities namespace NzbDrone.Core.Profiles.Qualities
{ {
public class ProfileQualityItem : IEmbeddedDocument public class QualityProfileQualityItem : IEmbeddedDocument
{ {
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public int Id { get; set; } public int Id { get; set; }
public string Name { get; set; } public string Name { get; set; }
public Quality Quality { get; set; } public Quality Quality { get; set; }
public List<ProfileQualityItem> Items { get; set; } public List<QualityProfileQualityItem> Items { get; set; }
public bool Allowed { get; set; } public bool Allowed { get; set; }
public ProfileQualityItem() public QualityProfileQualityItem()
{ {
Items = new List<ProfileQualityItem>(); Items = new List<QualityProfileQualityItem>();
} }
public List<Quality> GetQualities() public List<Quality> GetQualities()

View File

@ -0,0 +1,23 @@
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Profiles.Qualities
{
public interface IProfileRepository : IBasicRepository<QualityProfile>
{
bool Exists(int id);
}
public class QualityProfileRepository : BasicRepository<QualityProfile>, IProfileRepository
{
public QualityProfileRepository(IMainDatabase database, IEventAggregator eventAggregator)
: base(database, eventAggregator)
{
}
public bool Exists(int id)
{
return DataMapper.Query<QualityProfile>().Where(p => p.Id == id).GetRowCount() == 1;
}
}
}

View File

@ -10,55 +10,55 @@ namespace NzbDrone.Core.Profiles.Qualities
{ {
public interface IProfileService public interface IProfileService
{ {
Profile Add(Profile profile); QualityProfile Add(QualityProfile profile);
void Update(Profile profile); void Update(QualityProfile profile);
void Delete(int id); void Delete(int id);
List<Profile> All(); List<QualityProfile> All();
Profile Get(int id); QualityProfile Get(int id);
bool Exists(int id); bool Exists(int id);
Profile GetDefaultProfile(string name, Quality cutoff = null, params Quality[] allowed); QualityProfile GetDefaultProfile(string name, Quality cutoff = null, params Quality[] allowed);
} }
public class ProfileService : IProfileService, IHandle<ApplicationStartedEvent> public class QualityProfileService : IProfileService, IHandle<ApplicationStartedEvent>
{ {
private readonly IProfileRepository _profileRepository; private readonly IProfileRepository _profileRepository;
private readonly ISeriesService _seriesService; private readonly ISeriesService _seriesService;
private readonly Logger _logger; private readonly Logger _logger;
public ProfileService(IProfileRepository profileRepository, ISeriesService seriesService, Logger logger) public QualityProfileService(IProfileRepository profileRepository, ISeriesService seriesService, Logger logger)
{ {
_profileRepository = profileRepository; _profileRepository = profileRepository;
_seriesService = seriesService; _seriesService = seriesService;
_logger = logger; _logger = logger;
} }
public Profile Add(Profile profile) public QualityProfile Add(QualityProfile profile)
{ {
return _profileRepository.Insert(profile); return _profileRepository.Insert(profile);
} }
public void Update(Profile profile) public void Update(QualityProfile profile)
{ {
_profileRepository.Update(profile); _profileRepository.Update(profile);
} }
public void Delete(int id) public void Delete(int id)
{ {
if (_seriesService.GetAllSeries().Any(c => c.ProfileId == id)) if (_seriesService.GetAllSeries().Any(c => c.QualityProfileId == id))
{ {
var profile = _profileRepository.Get(id); var profile = _profileRepository.Get(id);
throw new ProfileInUseException(profile.Name); throw new QualityProfileInUseException(profile.Name);
} }
_profileRepository.Delete(id); _profileRepository.Delete(id);
} }
public List<Profile> All() public List<QualityProfile> All()
{ {
return _profileRepository.All().ToList(); return _profileRepository.All().ToList();
} }
public Profile Get(int id) public QualityProfile Get(int id)
{ {
return _profileRepository.Get(id); return _profileRepository.Get(id);
} }
@ -123,10 +123,10 @@ namespace NzbDrone.Core.Profiles.Qualities
Quality.Bluray1080p); Quality.Bluray1080p);
} }
public Profile GetDefaultProfile(string name, Quality cutoff = null, params Quality[] allowed) public QualityProfile GetDefaultProfile(string name, Quality cutoff = null, params Quality[] allowed)
{ {
var groupedQualites = Quality.DefaultQualityDefinitions.GroupBy(q => q.Weight); var groupedQualites = Quality.DefaultQualityDefinitions.GroupBy(q => q.Weight);
var items = new List<ProfileQualityItem>(); var items = new List<QualityProfileQualityItem>();
var groupId = 1000; var groupId = 1000;
var profileCutoff = cutoff == null ? Quality.Unknown.Id : cutoff.Id; var profileCutoff = cutoff == null ? Quality.Unknown.Id : cutoff.Id;
@ -136,17 +136,17 @@ namespace NzbDrone.Core.Profiles.Qualities
{ {
var quality = group.First().Quality; var quality = group.First().Quality;
items.Add(new ProfileQualityItem { Quality = group.First().Quality, Allowed = allowed.Contains(quality) }); items.Add(new QualityProfileQualityItem { Quality = group.First().Quality, Allowed = allowed.Contains(quality) });
continue; continue;
} }
var groupAllowed = group.Any(g => allowed.Contains(g.Quality)); var groupAllowed = group.Any(g => allowed.Contains(g.Quality));
items.Add(new ProfileQualityItem items.Add(new QualityProfileQualityItem
{ {
Id = groupId, Id = groupId,
Name = group.First().GroupName, Name = group.First().GroupName,
Items = group.Select(g => new ProfileQualityItem Items = group.Select(g => new QualityProfileQualityItem
{ {
Quality = g.Quality, Quality = g.Quality,
Allowed = groupAllowed Allowed = groupAllowed
@ -162,7 +162,7 @@ namespace NzbDrone.Core.Profiles.Qualities
groupId++; groupId++;
} }
var qualityProfile = new Profile var qualityProfile = new QualityProfile
{ {
Name = name, Name = name,
Cutoff = profileCutoff, Cutoff = profileCutoff,
@ -172,7 +172,7 @@ namespace NzbDrone.Core.Profiles.Qualities
return qualityProfile; return qualityProfile;
} }
private Profile AddDefaultProfile(string name, Quality cutoff, params Quality[] allowed) private QualityProfile AddDefaultProfile(string name, Quality cutoff, params Quality[] allowed)
{ {
var profile = GetDefaultProfile(name, cutoff, allowed); var profile = GetDefaultProfile(name, cutoff, allowed);

View File

@ -6,9 +6,9 @@ namespace NzbDrone.Core.Qualities
{ {
public class QualityModelComparer : IComparer<Quality>, IComparer<QualityModel> public class QualityModelComparer : IComparer<Quality>, IComparer<QualityModel>
{ {
private readonly Profile _profile; private readonly QualityProfile _profile;
public QualityModelComparer(Profile profile) public QualityModelComparer(QualityProfile profile)
{ {
Ensure.That(profile, () => profile).IsNotNull(); Ensure.That(profile, () => profile).IsNotNull();
Ensure.That(profile.Items, () => profile.Items).HasItems(); Ensure.That(profile.Items, () => profile.Items).HasItems();

View File

@ -262,7 +262,7 @@ namespace NzbDrone.Core.Tv
{ {
foreach (var belowCutoff in profile.QualityIds) foreach (var belowCutoff in profile.QualityIds)
{ {
clauses.Add(string.Format("([t1].[ProfileId] = {0} AND [t2].[Quality] LIKE '%_quality_: {1},%')", profile.ProfileId, belowCutoff)); clauses.Add(string.Format("([t1].[QualityProfileId] = {0} AND [t2].[Quality] LIKE '%_quality_: {1},%')", profile.ProfileId, belowCutoff));
} }
} }

View File

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Marr.Data; using Marr.Data;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Tv
public string Overview { get; set; } public string Overview { get; set; }
public string AirTime { get; set; } public string AirTime { get; set; }
public bool Monitored { get; set; } public bool Monitored { get; set; }
public int ProfileId { get; set; } public int QualityProfileId { get; set; }
public int LanguageProfileId { get; set; } public int LanguageProfileId { get; set; }
public bool SeasonFolder { get; set; } public bool SeasonFolder { get; set; }
public DateTime? LastInfoSync { get; set; } public DateTime? LastInfoSync { get; set; }
@ -49,7 +49,7 @@ namespace NzbDrone.Core.Tv
public string RootFolderPath { get; set; } public string RootFolderPath { get; set; }
public DateTime Added { get; set; } public DateTime Added { get; set; }
public DateTime? FirstAired { get; set; } public DateTime? FirstAired { get; set; }
public LazyLoaded<Profile> Profile { get; set; } public LazyLoaded<QualityProfile> QualityProfile { get; set; }
public LazyLoaded<LanguageProfile> LanguageProfile { get; set; } public LazyLoaded<LanguageProfile> LanguageProfile { get; set; }
public List<Season> Seasons { get; set; } public List<Season> Seasons { get; set; }
@ -67,7 +67,7 @@ namespace NzbDrone.Core.Tv
Seasons = otherSeries.Seasons; Seasons = otherSeries.Seasons;
Path = otherSeries.Path; Path = otherSeries.Path;
ProfileId = otherSeries.ProfileId; QualityProfileId = otherSeries.QualityProfileId;
LanguageProfileId = otherSeries.LanguageProfileId; LanguageProfileId = otherSeries.LanguageProfileId;
SeasonFolder = otherSeries.SeasonFolder; SeasonFolder = otherSeries.SeasonFolder;

View File

@ -8,7 +8,7 @@ namespace NzbDrone.Core.Validation
private readonly IProfileService _profileService; private readonly IProfileService _profileService;
public ProfileExistsValidator(IProfileService profileService) public ProfileExistsValidator(IProfileService profileService)
: base("Profile does not exist") : base("QualityProfile does not exist")
{ {
_profileService = profileService; _profileService = profileService;
} }

View File

@ -69,7 +69,7 @@ namespace Sonarr.Api.V3.EpisodeFiles
Language = model.Language, Language = model.Language,
Quality = model.Quality, Quality = model.Quality,
MediaInfo = model.MediaInfo.ToResource(model.SceneName), MediaInfo = model.MediaInfo.ToResource(model.SceneName),
QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(series.Profile.Value, model.Quality), QualityCutoffNotMet = upgradableSpecification.QualityCutoffNotMet(series.QualityProfile.Value, model.Quality),
LanguageCutoffNotMet = upgradableSpecification.LanguageCutoffNotMet(series.LanguageProfile.Value, model.Language) LanguageCutoffNotMet = upgradableSpecification.LanguageCutoffNotMet(series.LanguageProfile.Value, model.Language)
}; };
} }

View File

@ -51,7 +51,7 @@ namespace Sonarr.Api.V3.History
if (model.Series != null) if (model.Series != null)
{ {
resource.QualityCutoffNotMet = _upgradableSpecification.QualityCutoffNotMet(model.Series.Profile.Value, model.Quality); resource.QualityCutoffNotMet = _upgradableSpecification.QualityCutoffNotMet(model.Series.QualityProfile.Value, model.Quality);
resource.LanguageCutoffNotMet = _upgradableSpecification.LanguageCutoffNotMet(model.Series.LanguageProfile, model.Language); resource.LanguageCutoffNotMet = _upgradableSpecification.LanguageCutoffNotMet(model.Series.LanguageProfile, model.Language);
} }

View File

@ -30,7 +30,7 @@ namespace Sonarr.Api.V3.Indexers
{ {
release.QualityWeight = decision.RemoteEpisode release.QualityWeight = decision.RemoteEpisode
.Series .Series
.Profile.Value .QualityProfile.Value
.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100; .Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100;
release.LanguageWeight = decision.RemoteEpisode release.LanguageWeight = decision.RemoteEpisode

View File

@ -8,6 +8,7 @@ namespace Sonarr.Api.V3.Profiles.Language
public class LanguageProfileResource : RestResource public class LanguageProfileResource : RestResource
{ {
public string Name { get; set; } public string Name { get; set; }
public bool UpgradeAllowed { get; set; }
public NzbDrone.Core.Languages.Language Cutoff { get; set; } public NzbDrone.Core.Languages.Language Cutoff { get; set; }
public List<LanguageProfileItemResource> Languages { get; set; } public List<LanguageProfileItemResource> Languages { get; set; }
} }
@ -28,6 +29,7 @@ namespace Sonarr.Api.V3.Profiles.Language
{ {
Id = model.Id, Id = model.Id,
Name = model.Name, Name = model.Name,
UpgradeAllowed = model.UpgradeAllowed,
Cutoff = model.Cutoff, Cutoff = model.Cutoff,
Languages = model.Languages.ConvertAll(ToResource) Languages = model.Languages.ConvertAll(ToResource)
}; };
@ -52,6 +54,7 @@ namespace Sonarr.Api.V3.Profiles.Language
{ {
Id = resource.Id, Id = resource.Id,
Name = resource.Name, Name = resource.Name,
UpgradeAllowed = resource.UpgradeAllowed,
Cutoff = (NzbDrone.Core.Languages.Language)resource.Cutoff.Id, Cutoff = (NzbDrone.Core.Languages.Language)resource.Cutoff.Id,
Languages = resource.Languages.ConvertAll(ToModel) Languages = resource.Languages.ConvertAll(ToModel)
}; };

View File

@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Core.Profiles.Qualities; using NzbDrone.Core.Profiles.Qualities;
using Sonarr.Http.REST; using Sonarr.Http.REST;
@ -8,6 +8,7 @@ namespace Sonarr.Api.V3.Profiles.Quality
public class QualityProfileResource : RestResource public class QualityProfileResource : RestResource
{ {
public string Name { get; set; } public string Name { get; set; }
public bool UpgradeAllowed { get; set; }
public int Cutoff { get; set; } public int Cutoff { get; set; }
public List<QualityProfileQualityItemResource> Items { get; set; } public List<QualityProfileQualityItemResource> Items { get; set; }
} }
@ -27,7 +28,7 @@ namespace Sonarr.Api.V3.Profiles.Quality
public static class ProfileResourceMapper public static class ProfileResourceMapper
{ {
public static QualityProfileResource ToResource(this Profile model) public static QualityProfileResource ToResource(this QualityProfile model)
{ {
if (model == null) return null; if (model == null) return null;
@ -35,12 +36,13 @@ namespace Sonarr.Api.V3.Profiles.Quality
{ {
Id = model.Id, Id = model.Id,
Name = model.Name, Name = model.Name,
UpgradeAllowed = model.UpgradeAllowed,
Cutoff = model.Cutoff, Cutoff = model.Cutoff,
Items = model.Items.ConvertAll(ToResource), Items = model.Items.ConvertAll(ToResource),
}; };
} }
public static QualityProfileQualityItemResource ToResource(this ProfileQualityItem model) public static QualityProfileQualityItemResource ToResource(this QualityProfileQualityItem model)
{ {
if (model == null) return null; if (model == null) return null;
@ -54,24 +56,25 @@ namespace Sonarr.Api.V3.Profiles.Quality
}; };
} }
public static Profile ToModel(this QualityProfileResource resource) public static QualityProfile ToModel(this QualityProfileResource resource)
{ {
if (resource == null) return null; if (resource == null) return null;
return new Profile return new QualityProfile
{ {
Id = resource.Id, Id = resource.Id,
Name = resource.Name, Name = resource.Name,
UpgradeAllowed = resource.UpgradeAllowed,
Cutoff = resource.Cutoff, Cutoff = resource.Cutoff,
Items = resource.Items.ConvertAll(ToModel) Items = resource.Items.ConvertAll(ToModel)
}; };
} }
public static ProfileQualityItem ToModel(this QualityProfileQualityItemResource resource) public static QualityProfileQualityItem ToModel(this QualityProfileQualityItemResource resource)
{ {
if (resource == null) return null; if (resource == null) return null;
return new ProfileQualityItem return new QualityProfileQualityItem
{ {
Id = resource.Id, Id = resource.Id,
Name = resource.Name, Name = resource.Name,
@ -81,7 +84,7 @@ namespace Sonarr.Api.V3.Profiles.Quality
}; };
} }
public static List<QualityProfileResource> ToResource(this IEnumerable<Profile> models) public static List<QualityProfileResource> ToResource(this IEnumerable<QualityProfile> models)
{ {
return models.Select(ToResource).ToList(); return models.Select(ToResource).ToList();
} }

View File

@ -38,7 +38,7 @@ namespace Sonarr.Api.V3.Series
if (resource.QualityProfileId.HasValue) if (resource.QualityProfileId.HasValue)
{ {
series.ProfileId = resource.QualityProfileId.Value; series.QualityProfileId = resource.QualityProfileId.Value;
} }
if (resource.LanguageProfileId.HasValue) if (resource.LanguageProfileId.HasValue)

View File

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using Sonarr.Http.REST; using Sonarr.Http.REST;
@ -12,7 +11,7 @@ namespace Sonarr.Api.V3.Series
{ {
//Todo: Sorters should be done completely on the client //Todo: Sorters should be done completely on the client
//Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing? //Todo: Is there an easy way to keep IgnoreArticlesWhenSorting in sync between, Series, History, Missing?
//Todo: We should get the entire Profile instead of ID and Name separately //Todo: We should get the entire QualityProfile instead of ID and Name separately
//View Only //View Only
public string Title { get; set; } public string Title { get; set; }
@ -97,7 +96,7 @@ namespace Sonarr.Api.V3.Series
Year = model.Year, Year = model.Year,
Path = model.Path, Path = model.Path,
QualityProfileId = model.ProfileId, QualityProfileId = model.QualityProfileId,
LanguageProfileId = model.LanguageProfileId, LanguageProfileId = model.LanguageProfileId,
SeasonFolder = model.SeasonFolder, SeasonFolder = model.SeasonFolder,
@ -155,7 +154,7 @@ namespace Sonarr.Api.V3.Series
Year = resource.Year, Year = resource.Year,
Path = resource.Path, Path = resource.Path,
ProfileId = resource.QualityProfileId, QualityProfileId = resource.QualityProfileId,
LanguageProfileId = resource.LanguageProfileId, LanguageProfileId = resource.LanguageProfileId,
SeasonFolder = resource.SeasonFolder, SeasonFolder = resource.SeasonFolder,