Updated QualityProfile to contain a list of Items each with a 'Allowed' bool.
This commit is contained in:
parent
6ead44ca1b
commit
3e97106aa7
|
@ -41,7 +41,8 @@ namespace NzbDrone.Api.Test.MappingTests
|
||||||
[TestCase(typeof(ParsedEpisodeInfo), typeof(ReleaseResource))]
|
[TestCase(typeof(ParsedEpisodeInfo), typeof(ReleaseResource))]
|
||||||
[TestCase(typeof(DownloadDecision), typeof(ReleaseResource))]
|
[TestCase(typeof(DownloadDecision), typeof(ReleaseResource))]
|
||||||
[TestCase(typeof(Core.History.History), typeof(HistoryResource))]
|
[TestCase(typeof(Core.History.History), typeof(HistoryResource))]
|
||||||
[TestCase(typeof(Quality), typeof(QualityResource))]
|
[TestCase(typeof(QualityProfile), typeof(QualityProfileResource))]
|
||||||
|
[TestCase(typeof(QualityProfileItem), typeof(QualityProfileItemResource))]
|
||||||
[TestCase(typeof(Log), typeof(LogResource))]
|
[TestCase(typeof(Log), typeof(LogResource))]
|
||||||
[TestCase(typeof(Command), typeof(CommandResource))]
|
[TestCase(typeof(Command), typeof(CommandResource))]
|
||||||
public void matching_fields(Type modelType, Type resourceType)
|
public void matching_fields(Type modelType, Type resourceType)
|
||||||
|
@ -109,7 +110,8 @@ namespace NzbDrone.Api.Test.MappingTests
|
||||||
{
|
{
|
||||||
var profileResource = new QualityProfileResource
|
var profileResource = new QualityProfileResource
|
||||||
{
|
{
|
||||||
Allowed = Builder<QualityResource>.CreateListOfSize(1).Build().ToList(),
|
Cutoff = Quality.WEBDL1080p,
|
||||||
|
Items = new List<QualityProfileItemResource> { new QualityProfileItemResource { Quality = Quality.WEBDL1080p, Allowed = true } }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace NzbDrone.Api.Qualities
|
||||||
|
|
||||||
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
||||||
SharedValidator.RuleFor(c => c.Cutoff).NotNull();
|
SharedValidator.RuleFor(c => c.Cutoff).NotNull();
|
||||||
SharedValidator.RuleFor(c => c.Allowed).NotEmpty();
|
SharedValidator.RuleFor(c => c.Items).NotEmpty();
|
||||||
|
|
||||||
GetResourceAll = GetAll;
|
GetResourceAll = GetAll;
|
||||||
|
|
||||||
|
@ -48,46 +48,23 @@ namespace NzbDrone.Api.Qualities
|
||||||
private void Update(QualityProfileResource resource)
|
private void Update(QualityProfileResource resource)
|
||||||
{
|
{
|
||||||
var model = _qualityProfileService.Get(resource.Id);
|
var model = _qualityProfileService.Get(resource.Id);
|
||||||
|
|
||||||
model.Name = resource.Name;
|
model.Name = resource.Name;
|
||||||
model.Cutoff = (Quality)resource.Cutoff.Id;
|
model.Cutoff = (Quality)resource.Cutoff.Id;
|
||||||
model.Allowed = resource.Allowed.Select(p => (Quality)p.Id).ToList();
|
model.Items = resource.Items.InjectTo<List<QualityProfileItem>>();
|
||||||
_qualityProfileService.Update(model);
|
_qualityProfileService.Update(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
private QualityProfileResource GetById(int id)
|
private QualityProfileResource GetById(int id)
|
||||||
{
|
{
|
||||||
return MapToResource(_qualityProfileService.Get(id));
|
return _qualityProfileService.Get(id).InjectTo<QualityProfileResource>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<QualityProfileResource> GetAll()
|
private List<QualityProfileResource> GetAll()
|
||||||
{
|
{
|
||||||
var profiles = _qualityProfileService.All().Select(MapToResource).ToList();
|
var profiles = _qualityProfileService.All().InjectTo<List<QualityProfileResource>>();
|
||||||
|
|
||||||
return profiles;
|
return profiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
private QualityProfileResource MapToResource(QualityProfile profile)
|
|
||||||
{
|
|
||||||
return new QualityProfileResource
|
|
||||||
{
|
|
||||||
Cutoff = MapToResource(_qualityDefinitionService.Get(profile.Cutoff)),
|
|
||||||
Available = _qualityDefinitionService.All()
|
|
||||||
.Where(c => !profile.Allowed.Any(q => c.Quality == q))
|
|
||||||
.Select(MapToResource).ToList(),
|
|
||||||
Allowed = profile.Allowed.Select(_qualityDefinitionService.Get).Select(MapToResource).ToList(),
|
|
||||||
Name = profile.Name,
|
|
||||||
Id = profile.Id
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private QualityResource MapToResource(QualityDefinition config)
|
|
||||||
{
|
|
||||||
return new QualityResource
|
|
||||||
{
|
|
||||||
Id = config.Quality.Id,
|
|
||||||
Name = config.Quality.Name,
|
|
||||||
Weight = config.Weight
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,21 +1,20 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Api.REST;
|
using NzbDrone.Api.REST;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Qualities
|
namespace NzbDrone.Api.Qualities
|
||||||
{
|
{
|
||||||
public class QualityProfileResource : RestResource
|
public class QualityProfileResource : RestResource
|
||||||
{
|
{
|
||||||
public String Name { get; set; }
|
public String Name { get; set; }
|
||||||
public QualityResource Cutoff { get; set; }
|
public Quality Cutoff { get; set; }
|
||||||
public List<QualityResource> Available { get; set; }
|
public List<QualityProfileItemResource> Items { get; set; }
|
||||||
public List<QualityResource> Allowed { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class QualityResource : RestResource
|
public class QualityProfileItemResource : RestResource
|
||||||
{
|
{
|
||||||
public String Name { get; set; }
|
public Quality Quality { get; set; }
|
||||||
|
public bool Allowed { get; set; }
|
||||||
public Int32 Weight { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,34 +19,16 @@ namespace NzbDrone.Api.Qualities
|
||||||
|
|
||||||
private List<QualityProfileResource> GetAll()
|
private List<QualityProfileResource> GetAll()
|
||||||
{
|
{
|
||||||
|
var items = _qualityDefinitionService.All()
|
||||||
|
.OrderBy(v => v.Weight)
|
||||||
|
.Select(v => new QualityProfileItem { Quality = v.Quality, Allowed = false })
|
||||||
|
.ToList();
|
||||||
|
|
||||||
var profile = new QualityProfile();
|
var profile = new QualityProfile();
|
||||||
profile.Cutoff = Quality.Unknown;
|
profile.Cutoff = Quality.Unknown;
|
||||||
profile.Allowed = new List<Quality>();
|
profile.Items = items;
|
||||||
|
|
||||||
return new List<QualityProfileResource> { QualityToResource(profile) };
|
return new List<QualityProfileResource> { profile.InjectTo<QualityProfileResource>() };
|
||||||
}
|
|
||||||
|
|
||||||
private QualityProfileResource QualityToResource(QualityProfile profile)
|
|
||||||
{
|
|
||||||
return new QualityProfileResource
|
|
||||||
{
|
|
||||||
Cutoff = QualityToResource(_qualityDefinitionService.Get(profile.Cutoff)),
|
|
||||||
Available = _qualityDefinitionService.All().Select(QualityToResource).ToList(),
|
|
||||||
Allowed = profile.Allowed.Select(_qualityDefinitionService.Get).Select(QualityToResource).ToList(),
|
|
||||||
Name = profile.Name,
|
|
||||||
Id = profile.Id
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private QualityResource QualityToResource(QualityDefinition config)
|
|
||||||
{
|
|
||||||
return new QualityResource
|
|
||||||
{
|
|
||||||
Id = config.Quality.Id,
|
|
||||||
Name = config.Quality.Name,
|
|
||||||
Weight = config.Weight
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,35 +13,35 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
[Test]
|
[Test]
|
||||||
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(new QualityProfile { Cutoff = Quality.Bluray1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() },
|
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.Bluray1080p, Items = Qualities.QualityFixture.GetDefaultQualities() },
|
||||||
new QualityModel(Quality.DVD, true)).Should().BeTrue();
|
new QualityModel(Quality.DVD, true)).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
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(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() },
|
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Items = Qualities.QualityFixture.GetDefaultQualities() },
|
||||||
new QualityModel(Quality.HDTV720p, true)).Should().BeFalse();
|
new QualityModel(Quality.HDTV720p, true)).Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
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(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() },
|
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Items = Qualities.QualityFixture.GetDefaultQualities() },
|
||||||
new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse();
|
new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
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(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() },
|
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Items = Qualities.QualityFixture.GetDefaultQualities() },
|
||||||
new QualityModel(Quality.HDTV720p, false), new QualityModel(Quality.HDTV720p, true)).Should().BeTrue();
|
new QualityModel(Quality.HDTV720p, false), new QualityModel(Quality.HDTV720p, true)).Should().BeTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
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(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() },
|
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Items = Qualities.QualityFixture.GetDefaultQualities() },
|
||||||
new QualityModel(Quality.HDTV720p, true), new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse();
|
new QualityModel(Quality.HDTV720p, true), new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
};
|
};
|
||||||
|
|
||||||
_fakeSeries = Builder<Series>.CreateNew()
|
_fakeSeries = Builder<Series>.CreateNew()
|
||||||
.With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
.With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p, Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_parseResultMulti = new RemoteEpisode
|
_parseResultMulti = new RemoteEpisode
|
||||||
|
@ -130,7 +130,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
[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.QualityProfile = new QualityProfile { Cutoff = Quality.WEBDL1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() };
|
_fakeSeries.QualityProfile = new QualityProfile { Cutoff = Quality.WEBDL1080p, Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||||
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, false);
|
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, false);
|
||||||
_upgradableQuality = new QualityModel(Quality.WEBDL1080p, false);
|
_upgradableQuality = new QualityModel(Quality.WEBDL1080p, false);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
_series = Builder<Series>.CreateNew()
|
_series = Builder<Series>.CreateNew()
|
||||||
.With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
.With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_episode = Builder<Episode>.CreateNew()
|
_episode = Builder<Episode>.CreateNew()
|
||||||
|
|
|
@ -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.QualityProfile.Value.Allowed = new List<Quality> { Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p };
|
remoteEpisode.Series.QualityProfile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p);
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(remoteEpisode, null).Should().BeTrue();
|
Subject.IsSatisfiedBy(remoteEpisode, null).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.QualityProfile.Value.Allowed = new List<Quality> { Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p };
|
remoteEpisode.Series.QualityProfile.Value.Items = Qualities.QualityFixture.GetDefaultQualities(Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p);
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(remoteEpisode, null).Should().BeFalse();
|
Subject.IsSatisfiedBy(remoteEpisode, null).Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
{
|
{
|
||||||
GivenAutoDownloadPropers(true);
|
GivenAutoDownloadPropers(true);
|
||||||
|
|
||||||
var qualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() };
|
var qualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||||
|
|
||||||
Subject.IsUpgradable(qualityProfile, new QualityModel(current, currentProper), new QualityModel(newQuality, newProper))
|
Subject.IsUpgradable(qualityProfile, new QualityModel(current, currentProper), new QualityModel(newQuality, newProper))
|
||||||
.Should().Be(expected);
|
.Should().Be(expected);
|
||||||
|
@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
{
|
{
|
||||||
GivenAutoDownloadPropers(false);
|
GivenAutoDownloadPropers(false);
|
||||||
|
|
||||||
var qualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() };
|
var qualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() };
|
||||||
|
|
||||||
Subject.IsUpgradable(qualityProfile, new QualityModel(Quality.DVD, true), new QualityModel(Quality.DVD, false))
|
Subject.IsUpgradable(qualityProfile, new QualityModel(Quality.DVD, true), new QualityModel(Quality.DVD, false))
|
||||||
.Should().BeFalse();
|
.Should().BeFalse();
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
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.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
.With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p, Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_parseResultMulti = new RemoteEpisode
|
_parseResultMulti = new RemoteEpisode
|
||||||
|
|
|
@ -38,7 +38,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.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
.With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return remoteEpisode;
|
return remoteEpisode;
|
||||||
|
|
|
@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
||||||
remoteEpisode.Release.Size = size;
|
remoteEpisode.Release.Size = size;
|
||||||
|
|
||||||
remoteEpisode.Series = Builder<Series>.CreateNew()
|
remoteEpisode.Series = Builder<Series>.CreateNew()
|
||||||
.With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
.With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return remoteEpisode;
|
return remoteEpisode;
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
||||||
|
|
||||||
_videoFiles = new List<string> { @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi" };
|
_videoFiles = new List<string> { @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi" };
|
||||||
_series = Builder<Series>.CreateNew()
|
_series = Builder<Series>.CreateNew()
|
||||||
.With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
.With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_quality = new QualityModel(Quality.DVD);
|
_quality = new QualityModel(Quality.DVD);
|
||||||
|
|
|
@ -23,7 +23,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.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
.With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
_localEpisode = new LocalEpisode
|
_localEpisode = new LocalEpisode
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
||||||
_approvedDecisions = new List<ImportDecision>();
|
_approvedDecisions = new List<ImportDecision>();
|
||||||
|
|
||||||
var series = Builder<Series>.CreateNew()
|
var series = Builder<Series>.CreateNew()
|
||||||
.With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
.With(e => e.QualityProfile = new QualityProfile { Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var episodes = Builder<Episode>.CreateListOfSize(5)
|
var episodes = Builder<Episode>.CreateListOfSize(5)
|
||||||
|
|
|
@ -44,9 +44,9 @@ namespace NzbDrone.Core.Test.Qualities
|
||||||
i.Should().Be(expected);
|
i.Should().Be(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Quality> GetDefaultQualities()
|
public static List<QualityProfileItem> GetDefaultQualities(params Quality[] allowed)
|
||||||
{
|
{
|
||||||
return new List<Quality>
|
var qualities = new List<Quality>
|
||||||
{
|
{
|
||||||
Quality.SDTV,
|
Quality.SDTV,
|
||||||
Quality.WEBDL480p,
|
Quality.WEBDL480p,
|
||||||
|
@ -59,6 +59,16 @@ namespace NzbDrone.Core.Test.Qualities
|
||||||
Quality.WEBDL1080p,
|
Quality.WEBDL1080p,
|
||||||
Quality.Bluray1080p
|
Quality.Bluray1080p
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (allowed.Length == 0)
|
||||||
|
allowed = qualities.ToArray();
|
||||||
|
|
||||||
|
var items = qualities
|
||||||
|
.Except(allowed)
|
||||||
|
.Concat(allowed)
|
||||||
|
.Select(v => new QualityProfileItem { Quality = v, Allowed = allowed.Contains(v) }).ToList();
|
||||||
|
|
||||||
|
return items;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@ namespace NzbDrone.Core.Test.Qualities
|
||||||
|
|
||||||
private void GivenDefaultQualityProfile()
|
private void GivenDefaultQualityProfile()
|
||||||
{
|
{
|
||||||
Subject = new QualityModelComparer(new QualityProfile { Allowed = QualityFixture.GetDefaultQualities() });
|
Subject = new QualityModelComparer(new QualityProfile { Items = QualityFixture.GetDefaultQualities() });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenCustomQualityProfile()
|
private void GivenCustomQualityProfile()
|
||||||
{
|
{
|
||||||
Subject = new QualityModelComparer(new QualityProfile { Allowed = new List<Quality> { Quality.Bluray720p, Quality.DVD } });
|
Subject = new QualityModelComparer(new QualityProfile { Items = QualityFixture.GetDefaultQualities(Quality.Bluray720p, Quality.DVD) });
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -87,31 +87,5 @@ namespace NzbDrone.Core.Test.Qualities
|
||||||
|
|
||||||
compare.Should().BeGreaterThan(0);
|
compare.Should().BeGreaterThan(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Icomparer_missing_custom_order()
|
|
||||||
{
|
|
||||||
GivenCustomQualityProfile();
|
|
||||||
|
|
||||||
var first = new QualityModel(Quality.Bluray720p, true);
|
|
||||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
|
||||||
|
|
||||||
var compare = Subject.Compare(first, second);
|
|
||||||
|
|
||||||
compare.Should().BeGreaterThan(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void Icomparer_missing_both_custom_order()
|
|
||||||
{
|
|
||||||
GivenCustomQualityProfile();
|
|
||||||
|
|
||||||
var first = new QualityModel(Quality.SDTV, true);
|
|
||||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
|
||||||
|
|
||||||
var compare = Subject.Compare(first, second);
|
|
||||||
|
|
||||||
compare.Should().Be(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,7 @@ namespace NzbDrone.Core.Test.Qualities
|
||||||
{
|
{
|
||||||
var profile = new QualityProfile
|
var profile = new QualityProfile
|
||||||
{
|
{
|
||||||
Allowed = new List<Quality>
|
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
|
||||||
{
|
|
||||||
Quality.Bluray1080p,
|
|
||||||
Quality.DVD,
|
|
||||||
Quality.HDTV720p
|
|
||||||
},
|
|
||||||
|
|
||||||
Cutoff = Quality.Bluray1080p,
|
Cutoff = Quality.Bluray1080p,
|
||||||
Name = "TestProfile"
|
Name = "TestProfile"
|
||||||
};
|
};
|
||||||
|
@ -30,7 +24,7 @@ namespace NzbDrone.Core.Test.Qualities
|
||||||
StoredModel.Name.Should().Be(profile.Name);
|
StoredModel.Name.Should().Be(profile.Name);
|
||||||
StoredModel.Cutoff.Should().Be(profile.Cutoff);
|
StoredModel.Cutoff.Should().Be(profile.Cutoff);
|
||||||
|
|
||||||
StoredModel.Allowed.Should().BeEquivalentTo(profile.Allowed);
|
StoredModel.Items.Should().Equal(profile.Items, (a,b) => a.Quality == b.Quality && a.Allowed == b.Allowed);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,7 @@ namespace NzbDrone.Core.Test.TvTests.SeriesRepositoryTests
|
||||||
{
|
{
|
||||||
var profile = new QualityProfile
|
var profile = new QualityProfile
|
||||||
{
|
{
|
||||||
Allowed = new List<Quality>
|
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.Bluray1080p, Quality.DVD, Quality.HDTV720p),
|
||||||
{
|
|
||||||
Quality.Bluray1080p,
|
|
||||||
Quality.DVD,
|
|
||||||
Quality.HDTV720p
|
|
||||||
},
|
|
||||||
|
|
||||||
Cutoff = Quality.Bluray1080p,
|
Cutoff = Quality.Bluray1080p,
|
||||||
Name = "TestProfile"
|
Name = "TestProfile"
|
||||||
|
|
|
@ -2,11 +2,33 @@
|
||||||
using Marr.Data.Converters;
|
using Marr.Data.Converters;
|
||||||
using Marr.Data.Mapping;
|
using Marr.Data.Mapping;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore.Converters
|
namespace NzbDrone.Core.Datastore.Converters
|
||||||
{
|
{
|
||||||
public class EmbeddedDocumentConverter : IConverter
|
public class EmbeddedDocumentConverter : IConverter
|
||||||
{
|
{
|
||||||
|
private readonly JsonSerializerSettings SerializerSetting;
|
||||||
|
|
||||||
|
public EmbeddedDocumentConverter(params JsonConverter[] converters)
|
||||||
|
{
|
||||||
|
SerializerSetting = new JsonSerializerSettings
|
||||||
|
{
|
||||||
|
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
|
||||||
|
NullValueHandling = NullValueHandling.Ignore,
|
||||||
|
Formatting = Formatting.Indented,
|
||||||
|
DefaultValueHandling = DefaultValueHandling.Include,
|
||||||
|
ContractResolver = new CamelCasePropertyNamesContractResolver()
|
||||||
|
};
|
||||||
|
|
||||||
|
SerializerSetting.Converters.Add(new StringEnumConverter { CamelCaseText = true });
|
||||||
|
SerializerSetting.Converters.Add(new VersionConverter());
|
||||||
|
foreach (var converter in converters)
|
||||||
|
SerializerSetting.Converters.Add(converter);
|
||||||
|
}
|
||||||
|
|
||||||
public virtual object FromDB(ConverterContext context)
|
public virtual object FromDB(ConverterContext context)
|
||||||
{
|
{
|
||||||
if (context.DbValue == DBNull.Value)
|
if (context.DbValue == DBNull.Value)
|
||||||
|
@ -20,8 +42,7 @@ namespace NzbDrone.Core.Datastore.Converters
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
return JsonConvert.DeserializeObject(stringValue, context.ColumnMap.FieldType, SerializerSetting);
|
||||||
return Json.Deserialize(stringValue, context.ColumnMap.FieldType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
public object FromDB(ColumnMap map, object dbValue)
|
||||||
|
@ -33,7 +54,7 @@ namespace NzbDrone.Core.Datastore.Converters
|
||||||
{
|
{
|
||||||
if (clrValue == null) return null;
|
if (clrValue == null) return null;
|
||||||
|
|
||||||
return clrValue.ToJson();
|
return JsonConvert.SerializeObject(clrValue, SerializerSetting);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type DbType
|
public Type DbType
|
||||||
|
|
|
@ -4,10 +4,11 @@ using Marr.Data.Mapping;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore.Converters
|
namespace NzbDrone.Core.Datastore.Converters
|
||||||
{
|
{
|
||||||
public class QualityIntConverter : IConverter
|
public class QualityIntConverter : JsonConverter, IConverter
|
||||||
{
|
{
|
||||||
public object FromDB(ConverterContext context)
|
public object FromDB(ConverterContext context)
|
||||||
{
|
{
|
||||||
|
@ -46,5 +47,23 @@ namespace NzbDrone.Core.Datastore.Converters
|
||||||
return typeof(int);
|
return typeof(int);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region JsonConverter
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return objectType == typeof(Quality);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
var item = reader.Value;
|
||||||
|
return (Quality)Convert.ToInt32(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
writer.WriteValue(ToDB(value));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,52 +0,0 @@
|
||||||
using System;
|
|
||||||
using Marr.Data.Converters;
|
|
||||||
using Marr.Data.Mapping;
|
|
||||||
using NzbDrone.Core.Qualities;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore.Converters
|
|
||||||
{
|
|
||||||
public class QualityListConverter : IConverter
|
|
||||||
{
|
|
||||||
public object FromDB(ConverterContext context)
|
|
||||||
{
|
|
||||||
if (context.DbValue == DBNull.Value)
|
|
||||||
{
|
|
||||||
return DBNull.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
var val = Convert.ToString(context.DbValue);
|
|
||||||
|
|
||||||
var qualityList = Json.Deserialize<List<int>>(val).ConvertAll(Quality.FindById);
|
|
||||||
|
|
||||||
return qualityList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
|
||||||
{
|
|
||||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
|
||||||
{
|
|
||||||
if (clrValue == DBNull.Value) return null;
|
|
||||||
|
|
||||||
var qualityList = clrValue as List<Quality>;
|
|
||||||
|
|
||||||
if (qualityList == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Can only store a list of qualities in this database column.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var intList = qualityList.ConvertAll(v => v.Id);
|
|
||||||
|
|
||||||
return intList.ToJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type DbType
|
|
||||||
{
|
|
||||||
get { return typeof(string); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
using System;
|
|
||||||
using Marr.Data.Converters;
|
|
||||||
using Marr.Data.Mapping;
|
|
||||||
using NzbDrone.Core.Qualities;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using NzbDrone.Common.Serializer;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore.Converters
|
|
||||||
{
|
|
||||||
public class QualityModelConverter : IConverter
|
|
||||||
{
|
|
||||||
public object FromDB(ConverterContext context)
|
|
||||||
{
|
|
||||||
if (context.DbValue == DBNull.Value)
|
|
||||||
{
|
|
||||||
return new QualityModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
var val = Convert.ToString(context.DbValue);
|
|
||||||
|
|
||||||
var jsonObject = Json.Deserialize<Dictionary<string, object>>(val);
|
|
||||||
|
|
||||||
return new QualityModel((Quality)Convert.ToInt32(jsonObject["id"]), Convert.ToBoolean(jsonObject["proper"]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public object FromDB(ColumnMap map, object dbValue)
|
|
||||||
{
|
|
||||||
return FromDB(new ConverterContext { ColumnMap = map, DbValue = dbValue });
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ToDB(object clrValue)
|
|
||||||
{
|
|
||||||
if (clrValue == DBNull.Value)
|
|
||||||
clrValue = new QualityModel();
|
|
||||||
|
|
||||||
var qualityModel = clrValue as QualityModel;
|
|
||||||
|
|
||||||
if (qualityModel == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("Can only store a QualityModel in this database column.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var jsonObject = new Dictionary<string, object>();
|
|
||||||
jsonObject["id"] = (int)qualityModel.Quality;
|
|
||||||
jsonObject["proper"] = qualityModel.Proper;
|
|
||||||
|
|
||||||
return jsonObject.ToJson();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type DbType
|
|
||||||
{
|
|
||||||
get { return typeof(string); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@ using System;
|
||||||
using NzbDrone.Common.Serializer;
|
using NzbDrone.Common.Serializer;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Core.Datastore.Converters;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore.Migration
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
{
|
{
|
||||||
|
@ -14,6 +15,8 @@ namespace NzbDrone.Core.Datastore.Migration
|
||||||
{
|
{
|
||||||
protected override void MainDbUpgrade()
|
protected override void MainDbUpgrade()
|
||||||
{
|
{
|
||||||
|
Alter.Table("QualityProfiles").AddColumn("Items").AsString().Nullable();
|
||||||
|
|
||||||
Execute.WithConnection(ConvertQualityProfiles);
|
Execute.WithConnection(ConvertQualityProfiles);
|
||||||
|
|
||||||
Execute.WithConnection(ConvertQualityModels);
|
Execute.WithConnection(ConvertQualityModels);
|
||||||
|
@ -21,7 +24,7 @@ namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
|
||||||
private void ConvertQualityProfiles(IDbConnection conn, IDbTransaction tran)
|
private void ConvertQualityProfiles(IDbConnection conn, IDbTransaction tran)
|
||||||
{
|
{
|
||||||
var qualityListConverter = new NzbDrone.Core.Datastore.Converters.QualityListConverter();
|
var qualityProfileItemConverter = new EmbeddedDocumentConverter(new QualityIntConverter());
|
||||||
|
|
||||||
// Convert 'Allowed' column in QualityProfiles from Json List<object> to Json List<int> (int = Quality)
|
// Convert 'Allowed' column in QualityProfiles from Json List<object> to Json List<int> (int = Quality)
|
||||||
using (IDbCommand qualityProfileCmd = conn.CreateCommand())
|
using (IDbCommand qualityProfileCmd = conn.CreateCommand())
|
||||||
|
@ -37,12 +40,14 @@ namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
|
||||||
var allowed = Json.Deserialize<List<Quality>>(allowedJson);
|
var allowed = Json.Deserialize<List<Quality>>(allowedJson);
|
||||||
|
|
||||||
var allowedNewJson = qualityListConverter.ToDB(allowed);
|
var items = Quality.DefaultQualityDefinitions.OrderBy(v => v.Weight).Select(v => new QualityProfileItem { Quality = v.Quality, Allowed = allowed.Contains(v.Quality) }).ToList();
|
||||||
|
|
||||||
|
var allowedNewJson = qualityProfileItemConverter.ToDB(items);
|
||||||
|
|
||||||
using (IDbCommand updateCmd = conn.CreateCommand())
|
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||||
{
|
{
|
||||||
updateCmd.Transaction = tran;
|
updateCmd.Transaction = tran;
|
||||||
updateCmd.CommandText = "UPDATE QualityProfiles SET Allowed = ? WHERE Id = ?";
|
updateCmd.CommandText = "UPDATE QualityProfiles SET Items = ? WHERE Id = ?";
|
||||||
updateCmd.AddParameter(allowedNewJson);
|
updateCmd.AddParameter(allowedNewJson);
|
||||||
updateCmd.AddParameter(id);
|
updateCmd.AddParameter(id);
|
||||||
|
|
||||||
|
@ -63,7 +68,7 @@ namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
|
||||||
private void ConvertQualityModel(IDbConnection conn, IDbTransaction tran, string tableName)
|
private void ConvertQualityModel(IDbConnection conn, IDbTransaction tran, string tableName)
|
||||||
{
|
{
|
||||||
var qualityModelConverter = new NzbDrone.Core.Datastore.Converters.QualityModelConverter();
|
var qualityModelConverter = new EmbeddedDocumentConverter(new QualityIntConverter());
|
||||||
|
|
||||||
using (IDbCommand qualityModelCmd = conn.CreateCommand())
|
using (IDbCommand qualityModelCmd = conn.CreateCommand())
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,9 @@ namespace NzbDrone.Core.Datastore.Migration
|
||||||
{
|
{
|
||||||
protected override void MainDbUpgrade()
|
protected override void MainDbUpgrade()
|
||||||
{
|
{
|
||||||
|
SqLiteAlter.DropColumns("QualityProfiles", new[] { "Allowed" });
|
||||||
|
Alter.Column("Items").OnTable("QualityProfiles").AsString().NotNullable();
|
||||||
|
|
||||||
Create.TableForModel("QualityDefinitions")
|
Create.TableForModel("QualityDefinitions")
|
||||||
.WithColumn("Quality").AsInt32().Unique()
|
.WithColumn("Quality").AsInt32().Unique()
|
||||||
.WithColumn("Title").AsString().Unique()
|
.WithColumn("Title").AsString().Unique()
|
||||||
|
|
|
@ -81,8 +81,8 @@ namespace NzbDrone.Core.Datastore
|
||||||
MapRepository.Instance.RegisterTypeConverter(typeof(Boolean), new BooleanIntConverter());
|
MapRepository.Instance.RegisterTypeConverter(typeof(Boolean), 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<Quality>), new QualityListConverter());
|
MapRepository.Instance.RegisterTypeConverter(typeof(List<QualityProfileItem>), new EmbeddedDocumentConverter(new QualityIntConverter()));
|
||||||
MapRepository.Instance.RegisterTypeConverter(typeof(QualityModel), new QualityModelConverter());
|
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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||||
public virtual bool IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
public virtual bool IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||||
{
|
{
|
||||||
_logger.Trace("Checking if report meets quality requirements. {0}", subject.ParsedEpisodeInfo.Quality);
|
_logger.Trace("Checking if report meets quality requirements. {0}", subject.ParsedEpisodeInfo.Quality);
|
||||||
if (!subject.Series.QualityProfile.Value.Allowed.Contains(subject.ParsedEpisodeInfo.Quality.Quality))
|
if (!subject.Series.QualityProfile.Value.Items.Exists(v => v.Allowed && v.Quality == subject.ParsedEpisodeInfo.Quality.Quality))
|
||||||
{
|
{
|
||||||
_logger.Trace("Quality {0} rejected by Series' quality profile", subject.ParsedEpisodeInfo.Quality);
|
_logger.Trace("Quality {0} rejected by Series' quality profile", subject.ParsedEpisodeInfo.Quality);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -145,8 +145,6 @@
|
||||||
<Compile Include="Datastore\Converters\BooleanIntConverter.cs" />
|
<Compile Include="Datastore\Converters\BooleanIntConverter.cs" />
|
||||||
<Compile Include="Datastore\Converters\ProviderSettingConverter.cs" />
|
<Compile Include="Datastore\Converters\ProviderSettingConverter.cs" />
|
||||||
<Compile Include="Datastore\Converters\QualityIntConverter.cs" />
|
<Compile Include="Datastore\Converters\QualityIntConverter.cs" />
|
||||||
<Compile Include="Datastore\Converters\QualityListConverter.cs" />
|
|
||||||
<Compile Include="Datastore\Converters\QualityModelConverter.cs" />
|
|
||||||
<Compile Include="Datastore\Converters\Int32Converter.cs" />
|
<Compile Include="Datastore\Converters\Int32Converter.cs" />
|
||||||
<Compile Include="Datastore\Converters\EmbeddedDocumentConverter.cs" />
|
<Compile Include="Datastore\Converters\EmbeddedDocumentConverter.cs" />
|
||||||
<Compile Include="Datastore\Converters\UtcConverter.cs" />
|
<Compile Include="Datastore\Converters\UtcConverter.cs" />
|
||||||
|
@ -461,6 +459,7 @@
|
||||||
<Compile Include="Parser\ParsingService.cs" />
|
<Compile Include="Parser\ParsingService.cs" />
|
||||||
<Compile Include="Parser\QualityParser.cs" />
|
<Compile Include="Parser\QualityParser.cs" />
|
||||||
<Compile Include="Qualities\QualityModelComparer.cs" />
|
<Compile Include="Qualities\QualityModelComparer.cs" />
|
||||||
|
<Compile Include="Qualities\QualityProfileItem.cs" />
|
||||||
<Compile Include="Rest\JsonNetSerializer.cs" />
|
<Compile Include="Rest\JsonNetSerializer.cs" />
|
||||||
<Compile Include="RootFolders\RootFolderRepository.cs" />
|
<Compile Include="RootFolders\RootFolderRepository.cs" />
|
||||||
<Compile Include="ThingiProvider\ConfigContractNotFoundException.cs" />
|
<Compile Include="ThingiProvider\ConfigContractNotFoundException.cs" />
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace NzbDrone.Core.Qualities
|
||||||
public static Quality WEBDL480p { get { return new Quality(8, "WEBDL-480p"); } }
|
public static Quality WEBDL480p { get { return new Quality(8, "WEBDL-480p"); } }
|
||||||
public static Quality HDTV1080p { get { return new Quality(9, "HDTV-1080p"); } }
|
public static Quality HDTV1080p { get { return new Quality(9, "HDTV-1080p"); } }
|
||||||
public static Quality RAWHD { get { return new Quality(10, "Raw-HD"); } }
|
public static Quality RAWHD { get { return new Quality(10, "Raw-HD"); } }
|
||||||
public static Quality HDTV480p { get { return new Quality(11, "HDTV-480p"); } }
|
//public static Quality HDTV480p { get { return new Quality(11, "HDTV-480p"); } }
|
||||||
|
|
||||||
public static List<Quality> All
|
public static List<Quality> All
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,15 +14,15 @@ namespace NzbDrone.Core.Qualities
|
||||||
public QualityModelComparer(QualityProfile qualityProfile)
|
public QualityModelComparer(QualityProfile qualityProfile)
|
||||||
{
|
{
|
||||||
Ensure.That(qualityProfile, () => qualityProfile).IsNotNull();
|
Ensure.That(qualityProfile, () => qualityProfile).IsNotNull();
|
||||||
Ensure.That(qualityProfile.Allowed, () => qualityProfile.Allowed).HasItems();
|
Ensure.That(qualityProfile.Items, () => qualityProfile.Items).HasItems();
|
||||||
|
|
||||||
_qualityProfile = qualityProfile;
|
_qualityProfile = qualityProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Compare(Quality left, Quality right)
|
public int Compare(Quality left, Quality right)
|
||||||
{
|
{
|
||||||
int leftIndex = _qualityProfile.Allowed.IndexOf(left);
|
int leftIndex = _qualityProfile.Items.FindIndex(v => v.Quality == left);
|
||||||
int rightIndex = _qualityProfile.Allowed.IndexOf(right);
|
int rightIndex = _qualityProfile.Items.FindIndex(v => v.Quality == right);
|
||||||
|
|
||||||
return leftIndex.CompareTo(rightIndex);
|
return leftIndex.CompareTo(rightIndex);
|
||||||
}
|
}
|
||||||
|
@ -36,32 +36,5 @@ namespace NzbDrone.Core.Qualities
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
public string GetName(Quality quality)
|
|
||||||
{
|
|
||||||
QualityDefinition qualityDefinition = _qualityDefinitionService.Get(quality);
|
|
||||||
|
|
||||||
return qualityDefinition.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetName(QualityModel quality)
|
|
||||||
{
|
|
||||||
QualityDefinition qualityDefinition = _qualityDefinitionService.Get(quality.Quality);
|
|
||||||
|
|
||||||
if (quality.Proper)
|
|
||||||
return qualityDefinition.Name + " Proper";
|
|
||||||
else
|
|
||||||
return qualityDefinition.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetSceneName(QualityModel quality)
|
|
||||||
{
|
|
||||||
QualityDefinition qualityDefinition = _qualityDefinitionService.Get(quality.Quality);
|
|
||||||
|
|
||||||
if (quality.Proper)
|
|
||||||
return qualityDefinition.SceneName + " PROPER";
|
|
||||||
else
|
|
||||||
return qualityDefinition.SceneName;
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ namespace NzbDrone.Core.Qualities
|
||||||
public class QualityProfile : ModelBase
|
public class QualityProfile : ModelBase
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public List<Quality> Allowed { get; set; }
|
|
||||||
public Quality Cutoff { get; set; }
|
public Quality Cutoff { get; set; }
|
||||||
|
public List<QualityProfileItem> Items { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Qualities
|
||||||
|
{
|
||||||
|
public class QualityProfileItem : IEmbeddedDocument
|
||||||
|
{
|
||||||
|
public Quality Quality { get; set; }
|
||||||
|
public bool Allowed { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -60,68 +60,46 @@ namespace NzbDrone.Core.Qualities
|
||||||
return _qualityProfileRepository.Get(id);
|
return _qualityProfileRepository.Get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private QualityProfile AddDefaultQualityProfile(string name, Quality cutoff, params Quality[] allowed)
|
||||||
|
{
|
||||||
|
var items = Quality.DefaultQualityDefinitions
|
||||||
|
.OrderBy(v => v.Weight)
|
||||||
|
.Select(v => new QualityProfileItem { Quality = v.Quality, Allowed = allowed.Contains(v.Quality) })
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var qualityProfile = new QualityProfile { Name = name, Cutoff = cutoff, Items = items };
|
||||||
|
|
||||||
|
return Add(qualityProfile);
|
||||||
|
}
|
||||||
|
|
||||||
public void Handle(ApplicationStartedEvent message)
|
public void Handle(ApplicationStartedEvent message)
|
||||||
{
|
{
|
||||||
if (All().Any()) return;
|
if (All().Any()) return;
|
||||||
|
|
||||||
_logger.Info("Setting up default quality profiles");
|
_logger.Info("Setting up default quality profiles");
|
||||||
|
|
||||||
var sd = new QualityProfile
|
AddDefaultQualityProfile("SD", Quality.SDTV,
|
||||||
{
|
|
||||||
Name = "SD",
|
|
||||||
Allowed = new List<Quality>
|
|
||||||
{
|
|
||||||
Quality.SDTV,
|
Quality.SDTV,
|
||||||
Quality.WEBDL480p,
|
Quality.WEBDL480p,
|
||||||
Quality.DVD
|
Quality.DVD);
|
||||||
},
|
|
||||||
Cutoff = Quality.SDTV
|
|
||||||
};
|
|
||||||
|
|
||||||
var hd720p = new QualityProfile
|
AddDefaultQualityProfile("HD-720p", Quality.HDTV720p,
|
||||||
{
|
|
||||||
Name = "HD 720p",
|
|
||||||
Allowed = new List<Quality>
|
|
||||||
{
|
|
||||||
Quality.HDTV720p,
|
Quality.HDTV720p,
|
||||||
Quality.WEBDL720p,
|
Quality.WEBDL720p,
|
||||||
Quality.Bluray720p
|
Quality.Bluray720p);
|
||||||
},
|
|
||||||
Cutoff = Quality.HDTV720p
|
|
||||||
};
|
|
||||||
|
|
||||||
|
AddDefaultQualityProfile("HD-1080p", Quality.HDTV1080p,
|
||||||
var hd1080p = new QualityProfile
|
|
||||||
{
|
|
||||||
Name = "HD 1080p",
|
|
||||||
Allowed = new List<Quality>
|
|
||||||
{
|
|
||||||
Quality.HDTV1080p,
|
Quality.HDTV1080p,
|
||||||
Quality.WEBDL1080p,
|
Quality.WEBDL1080p,
|
||||||
Quality.Bluray1080p
|
Quality.Bluray1080p);
|
||||||
},
|
|
||||||
Cutoff = Quality.HDTV1080p
|
|
||||||
};
|
|
||||||
|
|
||||||
var hdAll = new QualityProfile
|
AddDefaultQualityProfile("HD - All", Quality.HDTV720p,
|
||||||
{
|
|
||||||
Name = "HD - All",
|
|
||||||
Allowed = new List<Quality>
|
|
||||||
{
|
|
||||||
Quality.HDTV720p,
|
Quality.HDTV720p,
|
||||||
|
Quality.HDTV1080p,
|
||||||
Quality.WEBDL720p,
|
Quality.WEBDL720p,
|
||||||
|
Quality.WEBDL1080p,
|
||||||
Quality.Bluray720p,
|
Quality.Bluray720p,
|
||||||
Quality.HDTV1080p,
|
Quality.Bluray1080p);
|
||||||
Quality.WEBDL1080p,
|
|
||||||
Quality.Bluray1080p
|
|
||||||
},
|
|
||||||
Cutoff = Quality.HDTV720p
|
|
||||||
};
|
|
||||||
|
|
||||||
Add(sd);
|
|
||||||
Add(hd720p);
|
|
||||||
Add(hd1080p);
|
|
||||||
Add(hdAll);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -875,7 +875,7 @@
|
||||||
{
|
{
|
||||||
if( _.contains( this.selectedItems, clickedItemId ) )
|
if( _.contains( this.selectedItems, clickedItemId ) )
|
||||||
this.setSelectedModels( _.without( this.selectedItems, clickedItemId ), { by : "cid" } );
|
this.setSelectedModels( _.without( this.selectedItems, clickedItemId ), { by : "cid" } );
|
||||||
else this.setSelectedModels( _.union( this.selectedItems, clickedItemId ), { by : "cid" } );
|
else this.setSelectedModels( _.union( this.selectedItems, [ clickedItemId ] ), { by : "cid" } );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.setSelectedModels( [ clickedItemId ], { by : "cid" } );
|
this.setSelectedModels( [ clickedItemId ], { by : "cid" } );
|
||||||
|
|
|
@ -7,13 +7,14 @@ define(
|
||||||
Handlebars.registerHelper('allowedLabeler', function () {
|
Handlebars.registerHelper('allowedLabeler', function () {
|
||||||
var ret = '';
|
var ret = '';
|
||||||
var cutoff = this.cutoff;
|
var cutoff = this.cutoff;
|
||||||
_.each(this.allowed, function (allowed) {
|
_.each(this.items, function (item) {
|
||||||
if (allowed.id === cutoff.id) {
|
if (item.allowed) {
|
||||||
ret += '<span class="label label-info" title="Cutoff">' + allowed.name + '</span> ';
|
if (item.quality.id === cutoff.id) {
|
||||||
|
ret += '<span class="label label-info" title="Cutoff">' + item.quality.name + '</span> ';
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
ret += '<span class="label">' + allowed.name + '</span> ';
|
ret += '<span class="label">' + item.quality.name + '</span> ';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
<span class="move-handle x-move"><i class="move-left-handle pull-left icon-chevron-left" /></span>
|
<i class="select-handle pull-left icon-chevron-right x-select" />
|
||||||
<span>{{name}}</span>
|
<span class="quality-label">{{quality.name}}</span>
|
||||||
<i class="drag-handle pull-right icon-resize-vertical advanced-setting x-drag-handle" />
|
<i class="drag-handle pull-right icon-resize-vertical advanced-setting x-drag-handle" />
|
||||||
<span class="move-handle x-move"><i class="move-right-handle pull-right icon-chevron-right" /><span>
|
|
||||||
|
|
|
@ -15,7 +15,6 @@ define(
|
||||||
template: 'Settings/Quality/Profile/EditQualityProfileViewTemplate',
|
template: 'Settings/Quality/Profile/EditQualityProfileViewTemplate',
|
||||||
|
|
||||||
ui: {
|
ui: {
|
||||||
available: '.x-available-list',
|
|
||||||
allowed : '.x-allowed-list',
|
allowed : '.x-allowed-list',
|
||||||
cutoff : '.x-cutoff'
|
cutoff : '.x-cutoff'
|
||||||
},
|
},
|
||||||
|
@ -27,29 +26,27 @@ define(
|
||||||
initialize: function (options) {
|
initialize: function (options) {
|
||||||
this.profileCollection = options.profileCollection;
|
this.profileCollection = options.profileCollection;
|
||||||
|
|
||||||
this.availableCollection = new Backbone.Collection(this.model.get('available'));
|
this.allowedCollection = new Backbone.Collection(_.toArray(this.model.get('items')).reverse());
|
||||||
this.availableCollection.comparator = function (model) { return -model.get('weight'); };
|
|
||||||
this.availableCollection.sort();
|
|
||||||
|
|
||||||
this.allowedCollection = new Backbone.Collection(this.model.get('allowed'));
|
|
||||||
this.allowedCollection.comparator = function (model) { return -model.get('weight'); };
|
|
||||||
this.allowedCollection.sort();
|
|
||||||
this.allowedCollection.comparator = undefined;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onRender: function() {
|
onRender: function() {
|
||||||
var listViewAvailable = new BackboneSortableCollectionView({
|
var MyCollectionView = BackboneSortableCollectionView.extend({
|
||||||
el : this.ui.available,
|
events : {
|
||||||
modelView : EditQualityProfileItemView,
|
// Backbone.CollectionView used mousedown for the click event, which interferes with the sortable.
|
||||||
selectable: false,
|
"click li, td" : "_listItem_onMousedown",
|
||||||
sortable : false,
|
"dblclick li, td" : "_listItem_onDoubleClick",
|
||||||
collection: this.availableCollection
|
"click" : "_listBackground_onClick",
|
||||||
|
"click ul.collection-list, table.collection-list" : "_listBackground_onClick",
|
||||||
|
"keydown" : "_onKeydown"
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
var listViewAllowed = new MyCollectionView({
|
||||||
var listViewAllowed = new BackboneSortableCollectionView({
|
|
||||||
el : this.ui.allowed,
|
el : this.ui.allowed,
|
||||||
modelView : EditQualityProfileItemView,
|
modelView : EditQualityProfileItemView,
|
||||||
selectable: false,
|
selectable : true,
|
||||||
|
selectMultiple : true,
|
||||||
|
clickToSelect : true,
|
||||||
|
clickToToggle : true,
|
||||||
sortable : true,
|
sortable : true,
|
||||||
sortableOptions : {
|
sortableOptions : {
|
||||||
handle: '.x-drag-handle'
|
handle: '.x-drag-handle'
|
||||||
|
@ -57,70 +54,33 @@ define(
|
||||||
collection : this.allowedCollection
|
collection : this.allowedCollection
|
||||||
});
|
});
|
||||||
|
|
||||||
listViewAvailable.render();
|
listViewAllowed.setSelectedModels(this.allowedCollection.filter(function(item) { return item.get('allowed') === true; }));
|
||||||
|
|
||||||
listViewAllowed.render();
|
listViewAllowed.render();
|
||||||
|
|
||||||
this.listenTo(listViewAvailable, 'doubleClick', this._moveQuality);
|
this.listenTo(listViewAllowed, 'selectionChanged', this._selectionChanged);
|
||||||
this.listenTo(listViewAllowed, 'doubleClick', this._moveQuality);
|
|
||||||
|
|
||||||
this.listenTo(listViewAvailable, 'moveClicked', this._moveQuality);
|
|
||||||
this.listenTo(listViewAllowed, 'moveClicked', this._moveQuality);
|
|
||||||
|
|
||||||
this.listenTo(listViewAllowed, 'sortStop', this._updateModel);
|
this.listenTo(listViewAllowed, 'sortStop', this._updateModel);
|
||||||
},
|
},
|
||||||
|
|
||||||
_moveQuality: function (event) {
|
_selectionChanged: function(newSelectedModels, oldSelectedModels) {
|
||||||
|
var addedModels = _.difference(newSelectedModels, oldSelectedModels);
|
||||||
|
var removeModels = _.difference(oldSelectedModels, newSelectedModels);
|
||||||
|
|
||||||
var quality;
|
_.each(removeModels, function(item) { item.set('allowed', false); });
|
||||||
var qualityId = event.get('id');
|
_.each(addedModels, function(item) { item.set('allowed', true); });
|
||||||
|
|
||||||
if (this.availableCollection.get(qualityId)) {
|
|
||||||
quality = this.availableCollection.get(qualityId);
|
|
||||||
var idealIndex = 0;
|
|
||||||
var idealMismatches = 1000;
|
|
||||||
// Insert it at the best possible spot.
|
|
||||||
for (var i = 0; i <= this.allowedCollection.length; i++) {
|
|
||||||
var mismatches = 0;
|
|
||||||
for (var j = 0; j < i; j++) {
|
|
||||||
if (this.allowedCollection.at(j).get('weight') < quality.get('weight'))
|
|
||||||
mismatches++;
|
|
||||||
}
|
|
||||||
for (j = i; j < this.allowedCollection.length; j++) {
|
|
||||||
if (this.allowedCollection.at(j).get('weight') > quality.get('weight'))
|
|
||||||
mismatches++;
|
|
||||||
}
|
|
||||||
if (mismatches <= idealMismatches) {
|
|
||||||
idealIndex = i;
|
|
||||||
idealMismatches = mismatches;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.availableCollection.remove(quality);
|
|
||||||
this.allowedCollection.add(quality, {at: idealIndex});
|
|
||||||
}
|
|
||||||
else if (this.allowedCollection.get(qualityId)) {
|
|
||||||
quality = this.allowedCollection.get(qualityId);
|
|
||||||
|
|
||||||
this.allowedCollection.remove(quality);
|
|
||||||
this.availableCollection.add(quality);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw 'couldnt find quality id ' + qualityId;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._updateModel();
|
this._updateModel();
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateModel: function() {
|
_updateModel: function() {
|
||||||
this.model.set('available', this.availableCollection.toJSON().reverse());
|
this.model.set('items', this.allowedCollection.toJSON().reverse());
|
||||||
this.model.set('allowed', this.allowedCollection.toJSON().reverse());
|
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
},
|
},
|
||||||
|
|
||||||
_saveQualityProfile: function () {
|
_saveQualityProfile: function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
var cutoff = _.findWhere(this.model.get('allowed'), { id: parseInt(this.ui.cutoff.val(), 10)});
|
var cutoff = _.findWhere(_.pluck(this.model.get('items'), 'quality'), { id: parseInt(self.ui.cutoff.val(), 10)});
|
||||||
this.model.set('cutoff', cutoff);
|
this.model.set('cutoff', cutoff);
|
||||||
|
|
||||||
var promise = this.model.save();
|
var promise = this.model.save();
|
||||||
|
|
|
@ -18,8 +18,10 @@
|
||||||
<label class="control-label">Cutoff</label>
|
<label class="control-label">Cutoff</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<select class="x-cutoff" name="cutoff.id" validation-name="cutoff">
|
<select class="x-cutoff" name="cutoff.id" validation-name="cutoff">
|
||||||
{{#eachReverse allowed}}
|
{{#eachReverse items}}
|
||||||
<option value="{{id}}">{{name}}</option>
|
{{#if allowed}}
|
||||||
|
<option value="{{quality.id}}">{{quality.name}}</option>
|
||||||
|
{{/if}}
|
||||||
{{/eachReverse}}
|
{{/eachReverse}}
|
||||||
</select>
|
</select>
|
||||||
<span class="help-inline">
|
<span class="help-inline">
|
||||||
|
@ -30,11 +32,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="offset1 span2">
|
<div class="offset1 span2">
|
||||||
<h3>Available</h3>
|
|
||||||
<ul class="available-list x-available-list">
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="span2">
|
|
||||||
<h3>
|
<h3>
|
||||||
Allowed
|
Allowed
|
||||||
<span class="help-inline">
|
<span class="help-inline">
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.available-list, ul.allowed-list {
|
ul.allowed-list {
|
||||||
.user-select(none);
|
.user-select(none);
|
||||||
|
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
|
@ -52,51 +52,41 @@ ul.available-list, ul.allowed-list {
|
||||||
border: 1px solid #AAA;
|
border: 1px solid #AAA;
|
||||||
border-radius: 4px; /* may need vendor varients */
|
border-radius: 4px; /* may need vendor varients */
|
||||||
background: #FAFAFA;
|
background: #FAFAFA;
|
||||||
cursor: default;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
.quality-label {
|
||||||
border-color: #888;
|
color: #CCC;
|
||||||
background: #EEE;
|
|
||||||
}
|
}
|
||||||
|
.drag-handle, .select-handle {
|
||||||
.drag-handle, .move-left-handle, .move-right-handle {
|
opacity: 0.2;
|
||||||
opacity: 0.0;
|
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.move-handle {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.available-list li {
|
|
||||||
.move-right-handle {
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drag-handle {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover .move-right-handle {
|
|
||||||
opacity: 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.allowed-list li {
|
|
||||||
.drag-handle, .move-left-handle {
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.drag-handle:hover {
|
.drag-handle:hover {
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&:hover .move-left-handle {
|
li.selected {
|
||||||
|
.select-handle {
|
||||||
opacity: 1.0;
|
opacity: 1.0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quality-label {
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
li:hover {
|
||||||
|
border-color: #888;
|
||||||
|
background: #EEE;
|
||||||
|
|
||||||
|
.select-handle {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue