mirror of
https://github.com/Prowlarr/Prowlarr
synced 2026-05-01 09:10:50 +02:00
Quality Order can now be change on per Quality Profile. Quality Title used in Renaming can now be changed by the user. Both options require Advanced Settings to be enabled.
This commit is contained in:
parent
47a8d93c18
commit
c90791b266
99 changed files with 6904 additions and 996 deletions
|
|
@ -107,7 +107,6 @@ public void should_map_wrapped_models()
|
|||
[Test]
|
||||
public void should_map_qualityprofile()
|
||||
{
|
||||
|
||||
var profileResource = new QualityProfileResource
|
||||
{
|
||||
Allowed = Builder<QualityResource>.CreateListOfSize(1).Build().ToList(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Api.EpisodeFiles
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Api.History
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Api.Indexers
|
||||
|
|
|
|||
|
|
@ -166,8 +166,8 @@
|
|||
<Compile Include="NzbDroneApiModule.cs" />
|
||||
<Compile Include="Qualities\QualityProfileResource.cs" />
|
||||
<Compile Include="Qualities\QualityProfileModule.cs" />
|
||||
<Compile Include="Qualities\QualitySizeResource.cs" />
|
||||
<Compile Include="Qualities\QualitySizeModule.cs" />
|
||||
<Compile Include="Qualities\QualityDefinitionResource.cs" />
|
||||
<Compile Include="Qualities\QualityDefinitionModule.cs" />
|
||||
<Compile Include="Extensions\ReqResExtensions.cs" />
|
||||
<Compile Include="Config\SettingsModule.cs" />
|
||||
<Compile Include="System\SystemModule.cs" />
|
||||
|
|
|
|||
38
src/NzbDrone.Api/Qualities/QualityDefinitionModule.cs
Normal file
38
src/NzbDrone.Api/Qualities/QualityDefinitionModule.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Api.Mapping;
|
||||
|
||||
namespace NzbDrone.Api.Qualities
|
||||
{
|
||||
public class QualityDefinitionModule : NzbDroneRestModule<QualityDefinitionResource>
|
||||
{
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
|
||||
public QualityDefinitionModule(IQualityDefinitionService qualityDefinitionService)
|
||||
{
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
|
||||
GetResourceById = GetById;
|
||||
|
||||
UpdateResource = Update;
|
||||
}
|
||||
|
||||
private void Update(QualityDefinitionResource resource)
|
||||
{
|
||||
var model = resource.InjectTo<QualityDefinition>();
|
||||
_qualityDefinitionService.Update(model);
|
||||
}
|
||||
|
||||
private QualityDefinitionResource GetById(int id)
|
||||
{
|
||||
return _qualityDefinitionService.Get((Quality)id).InjectTo<QualityDefinitionResource>();
|
||||
}
|
||||
|
||||
private List<QualityDefinitionResource> GetAll()
|
||||
{
|
||||
return ToListResource(_qualityDefinitionService.All);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/NzbDrone.Api/Qualities/QualityDefinitionResource.cs
Normal file
18
src/NzbDrone.Api/Qualities/QualityDefinitionResource.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Api.Qualities
|
||||
{
|
||||
public class QualityDefinitionResource : RestResource
|
||||
{
|
||||
public Quality Quality { get; set; }
|
||||
|
||||
public String Title { get; set; }
|
||||
|
||||
public Int32 Weight { get; set; }
|
||||
|
||||
public Int32 MinSize { get; set; }
|
||||
public Int32 MaxSize { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -9,11 +9,14 @@ namespace NzbDrone.Api.Qualities
|
|||
public class QualityProfileModule : NzbDroneRestModule<QualityProfileResource>
|
||||
{
|
||||
private readonly IQualityProfileService _qualityProfileService;
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
|
||||
public QualityProfileModule(IQualityProfileService qualityProfileService)
|
||||
public QualityProfileModule(IQualityProfileService qualityProfileService,
|
||||
IQualityDefinitionService qualityDefinitionService)
|
||||
: base("/qualityprofiles")
|
||||
{
|
||||
_qualityProfileService = qualityProfileService;
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
|
||||
SharedValidator.RuleFor(c => c.Name).NotEmpty();
|
||||
SharedValidator.RuleFor(c => c.Cutoff).NotNull();
|
||||
|
|
@ -44,38 +47,47 @@ private void DeleteProfile(int id)
|
|||
|
||||
private void Update(QualityProfileResource resource)
|
||||
{
|
||||
var model = resource.InjectTo<QualityProfile>();
|
||||
var model = _qualityProfileService.Get(resource.Id);
|
||||
model.Name = resource.Name;
|
||||
model.Cutoff = (Quality)resource.Cutoff.Id;
|
||||
model.Allowed = resource.Allowed.Select(p => (Quality)p.Id).ToList();
|
||||
_qualityProfileService.Update(model);
|
||||
}
|
||||
|
||||
private QualityProfileResource GetById(int id)
|
||||
{
|
||||
return QualityToResource(_qualityProfileService.Get(id));
|
||||
return MapToResource(_qualityProfileService.Get(id));
|
||||
}
|
||||
|
||||
private List<QualityProfileResource> GetAll()
|
||||
{
|
||||
var allProfiles = _qualityProfileService.All();
|
||||
|
||||
|
||||
var profiles = allProfiles.Select(QualityToResource).ToList();
|
||||
var profiles = _qualityProfileService.All().Select(MapToResource).ToList();
|
||||
|
||||
return profiles;
|
||||
}
|
||||
|
||||
private static QualityProfileResource QualityToResource(QualityProfile profile)
|
||||
private QualityProfileResource MapToResource(QualityProfile profile)
|
||||
{
|
||||
return new QualityProfileResource
|
||||
{
|
||||
Cutoff = profile.Cutoff.InjectTo<QualityResource>(),
|
||||
Available = Quality.All()
|
||||
.Where(c => !profile.Allowed.Any(q => c.Id == q.Id))
|
||||
.InjectTo<List<QualityResource>>(),
|
||||
|
||||
Allowed = profile.Allowed.InjectTo<List<QualityResource>>(),
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,8 @@ public class QualityProfileResource : RestResource
|
|||
|
||||
public class QualityResource : RestResource
|
||||
{
|
||||
public Int32 Weight { get; set; }
|
||||
public String Name { get; set; }
|
||||
|
||||
public Int32 Weight { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -7,9 +7,13 @@ namespace NzbDrone.Api.Qualities
|
|||
{
|
||||
public class QualityProfileSchemaModule : NzbDroneRestModule<QualityProfileResource>
|
||||
{
|
||||
public QualityProfileSchemaModule()
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
|
||||
public QualityProfileSchemaModule(IQualityDefinitionService qualityDefinitionService)
|
||||
: base("/qualityprofiles/schema")
|
||||
{
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
}
|
||||
|
||||
|
|
@ -19,21 +23,30 @@ private List<QualityProfileResource> GetAll()
|
|||
profile.Cutoff = Quality.Unknown;
|
||||
profile.Allowed = new List<Quality>();
|
||||
|
||||
return new List<QualityProfileResource>{ QualityToResource(profile)};
|
||||
return new List<QualityProfileResource> { QualityToResource(profile) };
|
||||
}
|
||||
|
||||
private static QualityProfileResource QualityToResource(QualityProfile profile)
|
||||
private QualityProfileResource QualityToResource(QualityProfile profile)
|
||||
{
|
||||
return new QualityProfileResource
|
||||
{
|
||||
Available = Quality.All()
|
||||
.Where(c => !profile.Allowed.Any(q => c.Id == q.Id))
|
||||
.InjectTo<List<QualityResource>>(),
|
||||
{
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
Allowed = profile.Allowed.InjectTo<List<QualityResource>>(),
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Api.Mapping;
|
||||
|
||||
namespace NzbDrone.Api.Qualities
|
||||
{
|
||||
public class QualitySizeModule : NzbDroneRestModule<QualitySizeResource>
|
||||
{
|
||||
private readonly IQualitySizeService _qualityTypeProvider;
|
||||
|
||||
public QualitySizeModule(IQualitySizeService qualityTypeProvider)
|
||||
{
|
||||
_qualityTypeProvider = qualityTypeProvider;
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
|
||||
GetResourceById = GetById;
|
||||
|
||||
UpdateResource = Update;
|
||||
}
|
||||
|
||||
private void Update(QualitySizeResource resource)
|
||||
{
|
||||
var model = resource.InjectTo<QualitySize>();
|
||||
_qualityTypeProvider.Update(model);
|
||||
}
|
||||
|
||||
private QualitySizeResource GetById(int id)
|
||||
{
|
||||
return _qualityTypeProvider.Get(id).InjectTo<QualitySizeResource>();
|
||||
}
|
||||
|
||||
private List<QualitySizeResource> GetAll()
|
||||
{
|
||||
return ToListResource(_qualityTypeProvider.All);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using System;
|
||||
using NzbDrone.Api.REST;
|
||||
|
||||
namespace NzbDrone.Api.Qualities
|
||||
{
|
||||
public class QualitySizeResource : RestResource
|
||||
{
|
||||
public Int32 QualityId { get; set; }
|
||||
public String Name { get; set; }
|
||||
public Int32 MinSize { get; set; }
|
||||
public Int32 MaxSize { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Api.Queue
|
||||
|
|
|
|||
|
|
@ -75,6 +75,7 @@ public void one_to_many()
|
|||
public void one_to_one()
|
||||
{
|
||||
var episodeFile = Builder<EpisodeFile>.CreateNew()
|
||||
.With(c => c.Quality = new QualityModel())
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(episodeFile);
|
||||
|
|
|
|||
|
|
@ -81,25 +81,25 @@ public void should_transfer_table_with_data()
|
|||
[Test]
|
||||
public void should_read_existing_indexes()
|
||||
{
|
||||
var indexes = _subject.GetIndexes("QualitySizes");
|
||||
var indexes = _subject.GetIndexes("QualityDefinitions");
|
||||
|
||||
indexes.Should().NotBeEmpty();
|
||||
|
||||
indexes.Should().OnlyContain(c => c != null);
|
||||
indexes.Should().OnlyContain(c => !string.IsNullOrWhiteSpace(c.Column));
|
||||
indexes.Should().OnlyContain(c => c.Table == "QualitySizes");
|
||||
indexes.Should().OnlyContain(c => c.Table == "QualityDefinitions");
|
||||
indexes.Should().OnlyContain(c => c.Unique);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_add_indexes_when_creating_new_table()
|
||||
{
|
||||
var columns = _subject.GetColumns("QualitySizes");
|
||||
var indexes = _subject.GetIndexes("QualitySizes");
|
||||
var columns = _subject.GetColumns("QualityDefinitions");
|
||||
var indexes = _subject.GetIndexes("QualityDefinitions");
|
||||
|
||||
_subject.CreateTable("QualityB", columns.Values, indexes);
|
||||
_subject.CreateTable("QualityDefinitionsB", columns.Values, indexes);
|
||||
|
||||
var newIndexes = _subject.GetIndexes("QualityB");
|
||||
var newIndexes = _subject.GetIndexes("QualityDefinitionsB");
|
||||
|
||||
newIndexes.Should().HaveSameCount(indexes);
|
||||
newIndexes.Select(c=>c.Column).Should().BeEquivalentTo(indexes.Select(c=>c.Column));
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public class AcceptableSizeSpecificationFixture : CoreTest<AcceptableSizeSpecifi
|
|||
private RemoteEpisode parseResultSingle;
|
||||
private Series series30minutes;
|
||||
private Series series60minutes;
|
||||
private QualitySize qualityType;
|
||||
private QualityDefinition qualityType;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
|
|
@ -47,10 +47,10 @@ public void Setup()
|
|||
.With(c => c.Runtime = 60)
|
||||
.Build();
|
||||
|
||||
qualityType = Builder<QualitySize>.CreateNew()
|
||||
qualityType = Builder<QualityDefinition>.CreateNew()
|
||||
.With(q => q.MinSize = 0)
|
||||
.With(q => q.MaxSize = 10)
|
||||
.With(q => q.QualityId = 1)
|
||||
.With(q => q.Quality = Quality.SDTV)
|
||||
.Build();
|
||||
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ public void IsAcceptableSize_true_single_episode_not_first_or_last_30_minute()
|
|||
parseResultSingle.Series = series30minutes;
|
||||
parseResultSingle.Release.Size = 184572800;
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -80,7 +80,7 @@ public void IsAcceptableSize_true_single_episode_not_first_or_last_60_minute()
|
|||
parseResultSingle.Series = series60minutes;
|
||||
parseResultSingle.Release.Size = 368572800;
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -99,7 +99,7 @@ public void IsAcceptableSize_false_single_episode_not_first_or_last_30_minute()
|
|||
parseResultSingle.Series = series30minutes;
|
||||
parseResultSingle.Release.Size = 1.Gigabytes();
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -118,7 +118,7 @@ public void IsAcceptableSize_false_single_episode_not_first_or_last_60_minute()
|
|||
parseResultSingle.Series = series60minutes;
|
||||
parseResultSingle.Release.Size = 1.Gigabytes();
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -135,7 +135,7 @@ public void IsAcceptableSize_true_multi_episode_not_first_or_last_30_minute()
|
|||
parseResultMulti.Series = series30minutes;
|
||||
parseResultMulti.Release.Size = 184572800;
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -154,7 +154,7 @@ public void IsAcceptableSize_true_multi_episode_not_first_or_last_60_minute()
|
|||
parseResultMulti.Series = series60minutes;
|
||||
parseResultMulti.Release.Size = 368572800;
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -173,7 +173,7 @@ public void IsAcceptableSize_false_multi_episode_not_first_or_last_30_minute()
|
|||
parseResultMulti.Series = series30minutes;
|
||||
parseResultMulti.Release.Size = 1.Gigabytes();
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -192,7 +192,7 @@ public void IsAcceptableSize_false_multi_episode_not_first_or_last_60_minute()
|
|||
parseResultMulti.Series = series60minutes;
|
||||
parseResultMulti.Release.Size = 10.Gigabytes();
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -211,7 +211,7 @@ public void IsAcceptableSize_true_single_episode_first_30_minute()
|
|||
parseResultSingle.Series = series30minutes;
|
||||
parseResultSingle.Release.Size = 184572800;
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -230,7 +230,7 @@ public void IsAcceptableSize_true_single_episode_first_60_minute()
|
|||
parseResultSingle.Series = series60minutes;
|
||||
parseResultSingle.Release.Size = 368572800;
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -249,7 +249,7 @@ public void IsAcceptableSize_false_single_episode_first_30_minute()
|
|||
parseResultSingle.Series = series30minutes;
|
||||
parseResultSingle.Release.Size = 1.Gigabytes();
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -270,7 +270,7 @@ public void IsAcceptableSize_false_single_episode_first_60_minute()
|
|||
parseResultSingle.Series = series60minutes;
|
||||
parseResultSingle.Release.Size = 10.Gigabytes();
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -292,7 +292,7 @@ public void IsAcceptableSize_true_unlimited_30_minute()
|
|||
parseResultSingle.Release.Size = 18457280000;
|
||||
qualityType.MaxSize = 0;
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -314,7 +314,7 @@ public void IsAcceptableSize_true_unlimited_60_minute()
|
|||
parseResultSingle.Release.Size = 36857280000;
|
||||
qualityType.MaxSize = 0;
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -338,7 +338,7 @@ public void IsAcceptableSize_should_treat_daily_series_as_single_episode()
|
|||
|
||||
qualityType.MaxSize = (int)600.Megabytes();
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Setup(s => s.Get(1)).Returns(qualityType);
|
||||
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(
|
||||
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
|
||||
|
|
@ -374,7 +374,7 @@ public void should_always_return_false_if_unknow()
|
|||
Subject.IsSatisfiedBy(parseResult, null).Should().BeFalse();
|
||||
|
||||
|
||||
Mocker.GetMock<IQualitySizeService>().Verify(c=>c.Get(It.IsAny<int>()),Times.Never());
|
||||
Mocker.GetMock<IQualityDefinitionService>().Verify(c => c.Get(It.IsAny<Quality>()), Times.Never());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,35 +13,35 @@ public class CutoffSpecificationFixture : CoreTest<QualityUpgradableSpecificatio
|
|||
[Test]
|
||||
public void should_return_true_if_current_episode_is_less_than_cutoff()
|
||||
{
|
||||
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.Bluray1080p },
|
||||
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.Bluray1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() },
|
||||
new QualityModel(Quality.DVD, true)).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_current_episode_is_equal_to_cutoff()
|
||||
{
|
||||
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p },
|
||||
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() },
|
||||
new QualityModel(Quality.HDTV720p, true)).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_current_episode_is_greater_than_cutoff()
|
||||
{
|
||||
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p },
|
||||
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() },
|
||||
new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_new_episode_is_proper_but_existing_is_not()
|
||||
{
|
||||
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p },
|
||||
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() },
|
||||
new QualityModel(Quality.HDTV720p, false), new QualityModel(Quality.HDTV720p, true)).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_cutoff_is_met_and_quality_is_higher()
|
||||
{
|
||||
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p },
|
||||
Subject.CutoffNotMet(new QualityProfile { Cutoff = Quality.HDTV720p, Allowed = Qualities.QualityFixture.GetDefaultQualities() },
|
||||
new QualityModel(Quality.HDTV720p, true), new QualityModel(Quality.Bluray1080p, true)).Should().BeFalse();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public void Setup()
|
|||
};
|
||||
|
||||
_fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p })
|
||||
.With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
||||
.Build();
|
||||
|
||||
_parseResultMulti = new RemoteEpisode
|
||||
|
|
@ -62,8 +62,6 @@ public void Setup()
|
|||
_upgradableQuality = new QualityModel(Quality.SDTV, false);
|
||||
_notupgradableQuality = new QualityModel(Quality.HDTV1080p, true);
|
||||
|
||||
|
||||
|
||||
Mocker.GetMock<IHistoryService>().Setup(c => c.GetBestQualityInHistory(1)).Returns(_notupgradableQuality);
|
||||
Mocker.GetMock<IHistoryService>().Setup(c => c.GetBestQualityInHistory(2)).Returns(_notupgradableQuality);
|
||||
Mocker.GetMock<IHistoryService>().Setup(c => c.GetBestQualityInHistory(3)).Returns<QualityModel>(null);
|
||||
|
|
@ -132,7 +130,7 @@ public void should_be_not_upgradable_if_only_second_episodes_is_upgradable()
|
|||
[Test]
|
||||
public void should_not_be_upgradable_if_episode_is_of_same_quality_as_existing()
|
||||
{
|
||||
_fakeSeries.QualityProfile = new QualityProfile { Cutoff = Quality.WEBDL1080p };
|
||||
_fakeSeries.QualityProfile = new QualityProfile { Cutoff = Quality.WEBDL1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
_parseResultSingle.ParsedEpisodeInfo.Quality = new QualityModel(Quality.WEBDL1080p, false);
|
||||
_upgradableQuality = new QualityModel(Quality.WEBDL1080p, false);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ public class NotInQueueSpecificationFixture : CoreTest<NotInQueueSpecification>
|
|||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_series = Builder<Series>.CreateNew().Build();
|
||||
_series = Builder<Series>.CreateNew()
|
||||
.With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
||||
.Build();
|
||||
|
||||
_episode = Builder<Episode>.CreateNew()
|
||||
.With(e => e.SeriesId = _series.Id)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using FluentAssertions;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
|
@ -23,6 +24,12 @@ public class QualityUpgradeSpecificationFixture : CoreTest<QualityUpgradableSpec
|
|||
new object[] { Quality.SDTV, false, Quality.SDTV, true, Quality.SDTV, true },
|
||||
new object[] { Quality.WEBDL1080p, false, Quality.WEBDL1080p, false, Quality.WEBDL1080p, false }
|
||||
};
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void GivenAutoDownloadPropers(bool autoDownloadPropers)
|
||||
{
|
||||
|
|
@ -36,7 +43,9 @@ public void IsUpgradeTest(Quality current, bool currentProper, Quality newQualit
|
|||
{
|
||||
GivenAutoDownloadPropers(true);
|
||||
|
||||
Subject.IsUpgradable(new QualityModel(current, currentProper), new QualityModel(newQuality, newProper))
|
||||
var qualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
|
||||
Subject.IsUpgradable(qualityProfile, new QualityModel(current, currentProper), new QualityModel(newQuality, newProper))
|
||||
.Should().Be(expected);
|
||||
}
|
||||
|
||||
|
|
@ -45,8 +54,10 @@ public void should_return_false_if_proper_and_autoDownloadPropers_is_false()
|
|||
{
|
||||
GivenAutoDownloadPropers(false);
|
||||
|
||||
Subject.IsUpgradable(new QualityModel(Quality.DVD, true),
|
||||
new QualityModel(Quality.DVD, false)).Should().BeFalse();
|
||||
var qualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() };
|
||||
|
||||
Subject.IsUpgradable(qualityProfile, new QualityModel(Quality.DVD, true), new QualityModel(Quality.DVD, false))
|
||||
.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ public void Setup()
|
|||
var doubleEpisodeList = new List<Episode> { new Episode { EpisodeFile = _firstFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = _secondFile, EpisodeFileId = 1 }, new Episode { EpisodeFile = null } };
|
||||
|
||||
var fakeSeries = Builder<Series>.CreateNew()
|
||||
.With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p })
|
||||
.With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p, Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
||||
.Build();
|
||||
|
||||
_parseResultMulti = new RemoteEpisode
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ private RemoteEpisode GetRemoteEpisode(List<Episode> episodes, QualityModel qual
|
|||
remoteEpisode.Release = new ReleaseInfo();
|
||||
remoteEpisode.Release.PublishDate = DateTime.UtcNow;
|
||||
|
||||
remoteEpisode.Series = Builder<Series>.CreateNew()
|
||||
.With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
||||
.Build();
|
||||
|
||||
return remoteEpisode;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,10 @@ private RemoteEpisode GetRemoteEpisode(List<Episode> episodes, QualityModel qual
|
|||
remoteEpisode.Release.PublishDate = DateTime.Now.AddDays(-Age);
|
||||
remoteEpisode.Release.Size = size;
|
||||
|
||||
remoteEpisode.Series = Builder<Series>.CreateNew()
|
||||
.With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
||||
.Build();
|
||||
|
||||
return remoteEpisode;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ public void should_not_attempt_download_if_client_isnt_configure()
|
|||
{
|
||||
Mocker.GetMock<IDownloadClient>().Setup(c => c.IsConfigured).Returns(false);
|
||||
|
||||
|
||||
Subject.DownloadReport(_parseResult);
|
||||
|
||||
Mocker.GetMock<IDownloadClient>().Verify(c => c.DownloadNzb(It.IsAny<RemoteEpisode>()), Times.Never());
|
||||
|
|
|
|||
|
|
@ -80,6 +80,20 @@ public void should_skip_if_file_is_in_use_by_another_process()
|
|||
.Returns(true);
|
||||
|
||||
Subject.Execute(new DownloadedEpisodesScanCommand());
|
||||
|
||||
VerifyNoImport();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_skip_if_no_series_found()
|
||||
{
|
||||
Mocker.GetMock<IParsingService>().Setup(c => c.GetSeries("foldername")).Returns((Series)null);
|
||||
|
||||
Subject.Execute(new DownloadedEpisodesScanCommand());
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(c => c.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Series>(), It.IsAny<bool>(), It.IsAny<Core.Qualities.QualityModel>()),
|
||||
Times.Never());
|
||||
|
||||
VerifyNoImport();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
using FizzWare.NBuilder;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
||||
{
|
||||
|
|
@ -63,7 +64,10 @@ public void Setup()
|
|||
_fail3.Setup(c => c.RejectionReason).Returns("_fail3");
|
||||
|
||||
_videoFiles = new List<string> { @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi" };
|
||||
_series = new Series();
|
||||
_series = Builder<Series>.CreateNew()
|
||||
.With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
||||
.Build();
|
||||
|
||||
_quality = new QualityModel(Quality.DVD);
|
||||
_localEpisode = new LocalEpisode
|
||||
{
|
||||
|
|
@ -80,7 +84,6 @@ public void Setup()
|
|||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(c => c.FilterExistingFiles(_videoFiles, It.IsAny<int>()))
|
||||
.Returns(_videoFiles);
|
||||
|
||||
}
|
||||
|
||||
private void GivenSpecifications(params Mock<IImportDecisionEngineSpecification>[] mocks)
|
||||
|
|
@ -162,7 +165,7 @@ public void failed_parse_shouldnt_blowup_the_process()
|
|||
.Setup(c => c.FilterExistingFiles(_videoFiles, It.IsAny<int>()))
|
||||
.Returns(_videoFiles);
|
||||
|
||||
Subject.GetImportDecisions(_videoFiles, new Series(), false);
|
||||
Subject.GetImportDecisions(_videoFiles, _series, false);
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(c => c.GetEpisodes(It.IsAny<String>(), It.IsAny<Series>(), It.IsAny<Boolean>()), Times.Exactly(_videoFiles.Count));
|
||||
|
|
@ -176,7 +179,7 @@ public void should_use_file_quality_if_folder_quality_is_null()
|
|||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
var expectedQuality = QualityParser.ParseQuality(_videoFiles.Single());
|
||||
|
||||
var result = Subject.GetImportDecisions(_videoFiles, new Series(), false, null);
|
||||
var result = Subject.GetImportDecisions(_videoFiles, _series, false, null);
|
||||
|
||||
result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
|
||||
}
|
||||
|
|
@ -187,7 +190,7 @@ public void should_use_file_quality_if_folder_quality_is_lower_than_file_quality
|
|||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
var expectedQuality = QualityParser.ParseQuality(_videoFiles.Single());
|
||||
|
||||
var result = Subject.GetImportDecisions(_videoFiles, new Series(), false, new QualityModel(Quality.SDTV));
|
||||
var result = Subject.GetImportDecisions(_videoFiles, _series, false, new QualityModel(Quality.SDTV));
|
||||
|
||||
result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
|
||||
}
|
||||
|
|
@ -198,7 +201,7 @@ public void should_use_folder_quality_when_it_is_greater_than_file_quality()
|
|||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
var expectedQuality = new QualityModel(Quality.Bluray1080p);
|
||||
|
||||
var result = Subject.GetImportDecisions(_videoFiles, new Series(), false, expectedQuality);
|
||||
var result = Subject.GetImportDecisions(_videoFiles, _series, false, expectedQuality);
|
||||
|
||||
result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,13 +22,15 @@ public class UpgradeSpecificationFixture : CoreTest<UpgradeSpecification>
|
|||
public void Setup()
|
||||
{
|
||||
_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() })
|
||||
.Build();
|
||||
|
||||
_localEpisode = new LocalEpisode
|
||||
{
|
||||
Path = @"C:\Test\30 Rock\30.rock.s01e01.avi",
|
||||
Quality = new QualityModel(Quality.HDTV720p, false)
|
||||
Quality = new QualityModel(Quality.HDTV720p, false),
|
||||
Series = _series
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ public void Setup()
|
|||
_approvedDecisions = new List<ImportDecision>();
|
||||
|
||||
var series = Builder<Series>.CreateNew()
|
||||
.With(e => e.QualityProfile = new QualityProfile { Allowed = Qualities.QualityFixture.GetDefaultQualities() })
|
||||
.Build();
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(5)
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@
|
|||
<Compile Include="ParserTests\ParsingServiceTests\MapFixture.cs" />
|
||||
<Compile Include="ParserTests\SeriesTitleInfoFixture.cs" />
|
||||
<Compile Include="Providers\XemProxyFixture.cs" />
|
||||
<Compile Include="Qualities\QualitySizeRepositoryFixture.cs" />
|
||||
<Compile Include="Qualities\QualityDefinitionRepositoryFixture.cs" />
|
||||
<Compile Include="Qualities\QualityProfileRepositoryFixture.cs" />
|
||||
<Compile Include="RootFolderTests\FreeSpaceOnDrivesFixture.cs" />
|
||||
<Compile Include="Qualities\QualityFixture.cs" />
|
||||
|
|
@ -217,14 +217,14 @@
|
|||
<Compile Include="TvTests\SeriesServiceTests\UpdateSeriesFixture.cs" />
|
||||
<Compile Include="UpdateTests\UpdateServiceFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\AcceptableSizeSpecificationFixture.cs" />
|
||||
<Compile Include="Qualities\QualitySizeServiceFixture.cs" />
|
||||
<Compile Include="Qualities\QualityDefinitionServiceFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeProviderTests\EpisodeProviderTest_GetEpisodesByParseResult.cs" />
|
||||
<Compile Include="FluentTest.cs" />
|
||||
<Compile Include="InstrumentationTests\DatabaseTargetFixture.cs" />
|
||||
<Compile Include="OrganizerTests\GetNewFilenameFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\MonitoredEpisodeSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\DownloadDecisionMakerFixture.cs" />
|
||||
<Compile Include="TvTests\QualityModelFixture.cs" />
|
||||
<Compile Include="Qualities\QualityModelComparerFixture.cs" />
|
||||
<Compile Include="RootFolderTests\RootFolderServiceFixture.cs" />
|
||||
<Compile Include="HistoryTests\HistoryRepositoryFixture.cs" />
|
||||
<Compile Include="MediaFiles\MediaFileServiceTest.cs" />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
|
|
@ -50,6 +51,10 @@ public void Setup()
|
|||
.Build();
|
||||
|
||||
_episodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p), ReleaseGroup = "DRONE" };
|
||||
|
||||
Mocker.GetMock<IQualityDefinitionService>()
|
||||
.Setup(v => v.Get(Moq.It.IsAny<Quality>()))
|
||||
.Returns<Quality>(v => Quality.DefaultQualityDefinitions.First(c => c.Quality == v));
|
||||
}
|
||||
|
||||
private void GivenProper()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
|
@ -150,9 +151,9 @@ public void quality_parse(string title, bool proper)
|
|||
}
|
||||
|
||||
[Test, TestCaseSource("SelfQualityParserCases")]
|
||||
public void parsing_our_own_quality_enum(Quality quality)
|
||||
public void parsing_our_own_quality_enum_name(Quality quality)
|
||||
{
|
||||
var fileName = String.Format("My series S01E01 [{0}]", quality);
|
||||
var fileName = String.Format("My series S01E01 [{0}]", quality.Name);
|
||||
var result = Parser.QualityParser.ParseQuality(fileName);
|
||||
result.Quality.Should().Be(quality);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,25 +4,27 @@
|
|||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using FluentAssertions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Test.Qualities
|
||||
{
|
||||
[TestFixture]
|
||||
|
||||
public class QualitySizeRepositoryFixture : DbTest<QualitySizeRepository, QualitySize>
|
||||
public class QualityDefinitionRepositoryFixture : DbTest<QualityDefinitionRepository, QualityDefinition>
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Mocker.SetConstant<IQualitySizeRepository>(Subject);
|
||||
Mocker.Resolve<QualitySizeService>().Handle(new ApplicationStartedEvent());
|
||||
foreach (var qualityDefault in Quality.DefaultQualityDefinitions)
|
||||
{
|
||||
qualityDefault.Id = 0;
|
||||
Storage.Insert(qualityDefault);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_get_quality_size_by_id()
|
||||
public void should_get_qualitydefinition_by_id()
|
||||
{
|
||||
var size = Subject.GetByQualityId(Quality.Bluray1080p.Id);
|
||||
var size = Subject.GetByQualityId((int)Quality.Bluray1080p);
|
||||
|
||||
size.Should().NotBeNull();
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Qualities
|
||||
{
|
||||
[TestFixture]
|
||||
public class QualityDefinitionServiceFixture : CoreTest<QualityDefinitionService>
|
||||
{
|
||||
[Test]
|
||||
public void init_should_add_all_definitions()
|
||||
{
|
||||
Subject.Handle(new ApplicationStartedEvent());
|
||||
|
||||
Mocker.GetMock<IQualityDefinitionRepository>()
|
||||
.Verify(v => v.Insert(It.IsAny<QualityDefinition>()), Times.Exactly(Quality.All.Count));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void init_should_insert_any_missing_definitions()
|
||||
{
|
||||
Mocker.GetMock<IQualityDefinitionRepository>()
|
||||
.Setup(s => s.All())
|
||||
.Returns(new List<QualityDefinition>
|
||||
{
|
||||
new QualityDefinition(Quality.SDTV) { Weight = 1, MinSize = 0, MaxSize = 100, Id = 20 }
|
||||
});
|
||||
|
||||
Subject.Handle(new ApplicationStartedEvent());
|
||||
|
||||
Mocker.GetMock<IQualityDefinitionRepository>()
|
||||
.Verify(v => v.Insert(It.IsAny<QualityDefinition>()), Times.Exactly(Quality.All.Count - 1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void init_should_insert_missing_definitions_preserving_weight()
|
||||
{
|
||||
// User moved HDTV1080p to a higher weight.
|
||||
var currentQualities = new List<QualityDefinition>
|
||||
{
|
||||
new QualityDefinition(Quality.SDTV) { Id = 5, Title = "SDTV", Weight = 1, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.WEBDL720p) { Id = 2, Title = "720p WEB-DL", Weight = 2, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.HDTV1080p) { Id = 4, Title = "1080p HDTV", Weight = 3, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.WEBDL1080p) { Id = 8, Title = "1080p WEB-DL", Weight = 4, MinSize=0, MaxSize=100 },
|
||||
};
|
||||
|
||||
// Expected to insert Bluray720p above HDTV1080p.
|
||||
// Expected to insert Bluray1080p above WEBDL1080p.
|
||||
var addBluray1080p = new List<QualityDefinition>
|
||||
{
|
||||
new QualityDefinition(Quality.SDTV) { Title = "SDTV", Weight = 1, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.HDTV1080p) { Title = "1080p HDTV", Weight = 2, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.WEBDL720p) { Title = "720p WEB-DL", Weight = 3, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.Bluray720p) { Title = "720p BluRay", Weight = 4, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.WEBDL1080p) { Title = "1080p WEB-DL", Weight = 5, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.Bluray1080p) { Title = "1080p BluRay", Weight = 6, MinSize=0, MaxSize=100 }
|
||||
};
|
||||
|
||||
Mocker.GetMock<IQualityDefinitionRepository>()
|
||||
.Setup(v => v.All())
|
||||
.Returns(currentQualities);
|
||||
|
||||
Subject.InsertMissingDefinitions(addBluray1080p);
|
||||
|
||||
Mocker.GetMock<IQualityDefinitionRepository>()
|
||||
.Verify(v => v.Insert(It.Is<QualityDefinition>(p => p.Quality == Quality.Bluray720p && p.Weight == 4)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IQualityDefinitionRepository>()
|
||||
.Verify(v => v.Update(It.Is<QualityDefinition>(p => p.Quality == Quality.WEBDL1080p && p.Weight == 5)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IQualityDefinitionRepository>()
|
||||
.Verify(v => v.Insert(It.Is<QualityDefinition>(p => p.Quality == Quality.Bluray1080p && p.Weight == 6)), Times.Once());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
using FluentAssertions;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
|
@ -42,81 +44,21 @@ public void should_be_able_to_convert_qualityTypes_to_int(Quality source, int ex
|
|||
i.Should().Be(expected);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void Icomparer_greater_test()
|
||||
public static List<Quality> GetDefaultQualities()
|
||||
{
|
||||
var first = Quality.DVD;
|
||||
var second = Quality.Bluray1080p;
|
||||
|
||||
second.Should().BeGreaterThan(first);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Icomparer_lesser()
|
||||
{
|
||||
var first = Quality.DVD;
|
||||
var second = Quality.Bluray1080p;
|
||||
|
||||
first.Should().BeLessThan(second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void equal_operand()
|
||||
{
|
||||
var first = Quality.Bluray1080p;
|
||||
var second = Quality.Bluray1080p;
|
||||
|
||||
(first == second).Should().BeTrue();
|
||||
(first >= second).Should().BeTrue();
|
||||
(first <= second).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void equal_operand_false()
|
||||
{
|
||||
var first = Quality.Bluray1080p;
|
||||
var second = Quality.Unknown;
|
||||
|
||||
(first == second).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void not_equal_operand()
|
||||
{
|
||||
var first = Quality.Bluray1080p;
|
||||
var second = Quality.Bluray1080p;
|
||||
|
||||
(first != second).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void not_equal_operand_false()
|
||||
{
|
||||
var first = Quality.Bluray1080p;
|
||||
var second = Quality.Unknown;
|
||||
|
||||
(first != second).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void greater_operand()
|
||||
{
|
||||
var first = Quality.DVD;
|
||||
var second = Quality.Bluray1080p;
|
||||
|
||||
(first < second).Should().BeTrue();
|
||||
(first <= second).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void lesser_operand()
|
||||
{
|
||||
var first = Quality.DVD;
|
||||
var second = Quality.Bluray1080p;
|
||||
|
||||
(second > first).Should().BeTrue();
|
||||
(second >= first).Should().BeTrue();
|
||||
return new List<Quality>
|
||||
{
|
||||
Quality.SDTV,
|
||||
Quality.WEBDL480p,
|
||||
Quality.DVD,
|
||||
Quality.HDTV720p,
|
||||
Quality.HDTV1080p,
|
||||
Quality.RAWHD,
|
||||
Quality.WEBDL720p,
|
||||
Quality.Bluray720p,
|
||||
Quality.WEBDL1080p,
|
||||
Quality.Bluray1080p
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
117
src/NzbDrone.Core.Test/Qualities/QualityModelComparerFixture.cs
Normal file
117
src/NzbDrone.Core.Test/Qualities/QualityModelComparerFixture.cs
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Qualities
|
||||
{
|
||||
[TestFixture]
|
||||
public class QualityModelComparerFixture : CoreTest
|
||||
{
|
||||
public QualityModelComparer Subject { get; set; }
|
||||
|
||||
private void GivenDefaultQualityProfile()
|
||||
{
|
||||
Subject = new QualityModelComparer(new QualityProfile { Allowed = QualityFixture.GetDefaultQualities() });
|
||||
}
|
||||
|
||||
private void GivenCustomQualityProfile()
|
||||
{
|
||||
Subject = new QualityModelComparer(new QualityProfile { Allowed = new List<Quality> { Quality.Bluray720p, Quality.DVD } });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Icomparer_greater_test()
|
||||
{
|
||||
GivenDefaultQualityProfile();
|
||||
|
||||
var first = new QualityModel(Quality.DVD, true);
|
||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
||||
|
||||
var compare = Subject.Compare(second, first);
|
||||
|
||||
compare.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Icomparer_greater_proper()
|
||||
{
|
||||
GivenDefaultQualityProfile();
|
||||
|
||||
var first = new QualityModel(Quality.Bluray1080p, false);
|
||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
||||
|
||||
var compare = Subject.Compare(second, first);
|
||||
|
||||
compare.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Icomparer_lesser()
|
||||
{
|
||||
GivenDefaultQualityProfile();
|
||||
|
||||
var first = new QualityModel(Quality.DVD, true);
|
||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
compare.Should().BeLessThan(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Icomparer_lesser_proper()
|
||||
{
|
||||
GivenDefaultQualityProfile();
|
||||
|
||||
var first = new QualityModel(Quality.DVD, false);
|
||||
var second = new QualityModel(Quality.DVD, true);
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
compare.Should().BeLessThan(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Icomparer_greater_custom_order()
|
||||
{
|
||||
GivenCustomQualityProfile();
|
||||
|
||||
var first = new QualityModel(Quality.DVD, true);
|
||||
var second = new QualityModel(Quality.Bluray720p, true);
|
||||
|
||||
var compare = Subject.Compare(first, second);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
namespace NzbDrone.Core.Test.Qualities
|
||||
{
|
||||
[TestFixture]
|
||||
|
||||
public class QualityProfileRepositoryFixture : DbTest<QualityProfileRepository, QualityProfile>
|
||||
{
|
||||
[Test]
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Qualities
|
||||
{
|
||||
[TestFixture]
|
||||
|
||||
public class QualitySizeServiceFixture : CoreTest<QualitySizeService>
|
||||
{
|
||||
[Test]
|
||||
public void Init_should_add_all_sizes()
|
||||
{
|
||||
Subject.Handle(new ApplicationStartedEvent());
|
||||
|
||||
Mocker.GetMock<IQualitySizeRepository>()
|
||||
.Verify(v => v.Insert(It.IsAny<QualitySize>()), Times.Exactly(Quality.All().Count));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Init_should_insert_any_missing_sizes()
|
||||
{
|
||||
Mocker.GetMock<IQualitySizeRepository>()
|
||||
.Setup(s => s.All())
|
||||
.Returns(new List<QualitySize>
|
||||
{
|
||||
new QualitySize { QualityId = 1, Name = "SDTV", MinSize = 0, MaxSize = 100 }
|
||||
});
|
||||
|
||||
Subject.Handle(new ApplicationStartedEvent());
|
||||
|
||||
Mocker.GetMock<IQualitySizeRepository>()
|
||||
.Verify(v => v.Insert(It.IsAny<QualitySize>()), Times.Exactly(Quality.All().Count - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests
|
||||
{
|
||||
[TestFixture]
|
||||
|
||||
public class QualityModelFixture : CoreTest
|
||||
{
|
||||
[Test]
|
||||
public void Icomparer_greater_test()
|
||||
{
|
||||
var first = new QualityModel(Quality.DVD, true);
|
||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
||||
|
||||
second.Should().BeGreaterThan(first);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Icomparer_greater_proper()
|
||||
{
|
||||
var first = new QualityModel(Quality.Bluray1080p, false);
|
||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
||||
|
||||
second.Should().BeGreaterThan(first);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Icomparer_lesser()
|
||||
{
|
||||
var first = new QualityModel(Quality.DVD, true);
|
||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
||||
|
||||
first.Should().BeLessThan(second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Icomparer_lesser_proper()
|
||||
{
|
||||
var first = new QualityModel(Quality.DVD, false);
|
||||
var second = new QualityModel(Quality.DVD, true);
|
||||
|
||||
first.Should().BeLessThan(second);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void equal_operand()
|
||||
{
|
||||
var first = new QualityModel(Quality.Bluray1080p, true);
|
||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
||||
|
||||
(first == second).Should().BeTrue();
|
||||
(first >= second).Should().BeTrue();
|
||||
(first <= second).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void equal_operand_false()
|
||||
{
|
||||
var first = new QualityModel(Quality.Bluray1080p, true);
|
||||
var second = new QualityModel(Quality.Unknown, true);
|
||||
|
||||
(first == second).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void equal_operand_false_proper()
|
||||
{
|
||||
var first = new QualityModel(Quality.Bluray1080p, true);
|
||||
var second = new QualityModel(Quality.Bluray1080p, false);
|
||||
|
||||
(first == second).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void not_equal_operand()
|
||||
{
|
||||
var first = new QualityModel(Quality.Bluray1080p, true);
|
||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
||||
|
||||
(first != second).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void not_equal_operand_false()
|
||||
{
|
||||
var first = new QualityModel(Quality.Bluray1080p, true);
|
||||
var second = new QualityModel(Quality.Unknown, true);
|
||||
|
||||
(first != second).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void not_equal_operand_false_proper()
|
||||
{
|
||||
var first = new QualityModel(Quality.Bluray1080p, true);
|
||||
var second = new QualityModel(Quality.Bluray1080p, false);
|
||||
|
||||
(first != second).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void greater_operand()
|
||||
{
|
||||
var first = new QualityModel(Quality.DVD, true);
|
||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
||||
|
||||
(first < second).Should().BeTrue();
|
||||
(first <= second).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void lesser_operand()
|
||||
{
|
||||
var first = new QualityModel(Quality.DVD, true);
|
||||
var second = new QualityModel(Quality.Bluray1080p, true);
|
||||
|
||||
(second > first).Should().BeTrue();
|
||||
(second >= first).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Blacklisting
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
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
|
||||
{
|
||||
|
|
@ -26,7 +28,7 @@ public object FromDB(ColumnMap map, object dbValue)
|
|||
|
||||
public object ToDB(object clrValue)
|
||||
{
|
||||
if(clrValue == null) return 0;
|
||||
if(clrValue == DBNull.Value) return 0;
|
||||
|
||||
if(clrValue as Quality == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(36)]
|
||||
public class update_with_quality_converters : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Execute.WithConnection(ConvertQualityProfiles);
|
||||
|
||||
Execute.WithConnection(ConvertQualityModels);
|
||||
}
|
||||
|
||||
private void ConvertQualityProfiles(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
var qualityListConverter = new NzbDrone.Core.Datastore.Converters.QualityListConverter();
|
||||
|
||||
// Convert 'Allowed' column in QualityProfiles from Json List<object> to Json List<int> (int = Quality)
|
||||
using (IDbCommand qualityProfileCmd = conn.CreateCommand())
|
||||
{
|
||||
qualityProfileCmd.Transaction = tran;
|
||||
qualityProfileCmd.CommandText = @"SELECT Id, Allowed FROM QualityProfiles";
|
||||
using (IDataReader qualityProfileReader = qualityProfileCmd.ExecuteReader())
|
||||
{
|
||||
while (qualityProfileReader.Read())
|
||||
{
|
||||
var id = qualityProfileReader.GetInt32(0);
|
||||
var allowedJson = qualityProfileReader.GetString(1);
|
||||
|
||||
var allowed = Json.Deserialize<List<Quality>>(allowedJson);
|
||||
|
||||
var allowedNewJson = qualityListConverter.ToDB(allowed);
|
||||
|
||||
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||
{
|
||||
updateCmd.Transaction = tran;
|
||||
updateCmd.CommandText = "UPDATE QualityProfiles SET Allowed = ? WHERE Id = ?";
|
||||
updateCmd.AddParameter(allowedNewJson);
|
||||
updateCmd.AddParameter(id);
|
||||
|
||||
updateCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ConvertQualityModels(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
// Converts the QualityModel JSON objects to their new format (only storing the QualityId instead of the entire object)
|
||||
ConvertQualityModel(conn, tran, "Blacklist");
|
||||
ConvertQualityModel(conn, tran, "EpisodeFiles");
|
||||
ConvertQualityModel(conn, tran, "History");
|
||||
}
|
||||
|
||||
private void ConvertQualityModel(IDbConnection conn, IDbTransaction tran, string tableName)
|
||||
{
|
||||
var qualityModelConverter = new NzbDrone.Core.Datastore.Converters.QualityModelConverter();
|
||||
|
||||
using (IDbCommand qualityModelCmd = conn.CreateCommand())
|
||||
{
|
||||
qualityModelCmd.Transaction = tran;
|
||||
qualityModelCmd.CommandText = @"SELECT Id, Quality FROM " + tableName;
|
||||
using (IDataReader qualityModelReader = qualityModelCmd.ExecuteReader())
|
||||
{
|
||||
while (qualityModelReader.Read())
|
||||
{
|
||||
var id = qualityModelReader.GetInt32(0);
|
||||
var qualityJson = qualityModelReader.GetString(1);
|
||||
|
||||
var quality = Json.Deserialize<QualityModel>(qualityJson);
|
||||
|
||||
var qualityNewJson = qualityModelConverter.ToDB(quality);
|
||||
|
||||
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||
{
|
||||
updateCmd.Transaction = tran;
|
||||
updateCmd.CommandText = "UPDATE " + tableName + " SET Quality = ? WHERE Id = ?";
|
||||
updateCmd.AddParameter(qualityNewJson);
|
||||
updateCmd.AddParameter(id);
|
||||
|
||||
updateCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(37)]
|
||||
public class add_configurable_qualities : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Create.TableForModel("QualityDefinitions")
|
||||
.WithColumn("Quality").AsInt32().Unique()
|
||||
.WithColumn("Title").AsString().Unique()
|
||||
.WithColumn("Weight").AsInt32().Unique()
|
||||
.WithColumn("MinSize").AsInt32()
|
||||
.WithColumn("MaxSize").AsInt32();
|
||||
|
||||
Execute.WithConnection(ConvertQualities);
|
||||
|
||||
Delete.Table("QualitySizes");
|
||||
}
|
||||
|
||||
private void ConvertQualities(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
// Convert QualitySizes to a more generic QualityDefinitions table.
|
||||
using (IDbCommand qualitySizeCmd = conn.CreateCommand())
|
||||
{
|
||||
qualitySizeCmd.Transaction = tran;
|
||||
qualitySizeCmd.CommandText = @"SELECT QualityId, MinSize, MaxSize FROM QualitySizes";
|
||||
using (IDataReader qualitySizeReader = qualitySizeCmd.ExecuteReader())
|
||||
{
|
||||
while (qualitySizeReader.Read())
|
||||
{
|
||||
var qualityId = qualitySizeReader.GetInt32(0);
|
||||
var minSize = qualitySizeReader.GetInt32(1);
|
||||
var maxSize = qualitySizeReader.GetInt32(2);
|
||||
|
||||
var defaultConfig = Quality.DefaultQualityDefinitions.Single(p => (int)p.Quality == qualityId);
|
||||
|
||||
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||
{
|
||||
updateCmd.Transaction = tran;
|
||||
updateCmd.CommandText = "INSERT INTO QualityDefinitions (Quality, Title, Weight, MinSize, MaxSize) VALUES (?, ?, ?, ?, ?)";
|
||||
updateCmd.AddParameter(qualityId);
|
||||
updateCmd.AddParameter(defaultConfig.Title);
|
||||
updateCmd.AddParameter(defaultConfig.Weight);
|
||||
updateCmd.AddParameter(minSize);
|
||||
updateCmd.AddParameter(maxSize);
|
||||
|
||||
updateCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,5 +10,11 @@ public static ICreateTableColumnOptionOrWithColumnSyntax TableForModel(this ICre
|
|||
return expressionRoot.Table(name).WithColumn("Id").AsInt32().PrimaryKey().Identity();
|
||||
}
|
||||
|
||||
public static void AddParameter(this System.Data.IDbCommand command, object value)
|
||||
{
|
||||
var parameter = command.CreateParameter();
|
||||
parameter.Value = value;
|
||||
command.Parameters.Add(parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ public static void Map()
|
|||
|
||||
Mapper.Entity<QualityProfile>().RegisterModel("QualityProfiles");
|
||||
|
||||
Mapper.Entity<QualitySize>().RegisterModel("QualitySizes");
|
||||
Mapper.Entity<QualityDefinition>().RegisterModel("QualityDefinitions");
|
||||
|
||||
Mapper.Entity<Log>().RegisterModel("Logs");
|
||||
|
||||
|
|
@ -81,6 +81,8 @@ private static void RegisterMappers()
|
|||
MapRepository.Instance.RegisterTypeConverter(typeof(Boolean), new BooleanIntConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Enum), new EnumIntConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Quality), new QualityIntConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<Quality>), new QualityListConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(QualityModel), new QualityModelConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Dictionary<string, string>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<int>), new EmbeddedDocumentConverter());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
{
|
||||
public interface IQualityUpgradableSpecification
|
||||
{
|
||||
bool IsUpgradable(QualityModel currentQuality, QualityModel newQuality = null);
|
||||
bool IsUpgradable(QualityProfile profile, QualityModel currentQuality, QualityModel newQuality = null);
|
||||
bool CutoffNotMet(QualityProfile profile, QualityModel currentQuality, QualityModel newQuality = null);
|
||||
bool IsProperUpgrade(QualityModel currentQuality, QualityModel newQuality);
|
||||
}
|
||||
|
|
@ -20,11 +20,12 @@ public QualityUpgradableSpecification(Logger logger)
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public bool IsUpgradable(QualityModel currentQuality, QualityModel newQuality = null)
|
||||
public bool IsUpgradable(QualityProfile profile, QualityModel currentQuality, QualityModel newQuality = null)
|
||||
{
|
||||
if (newQuality != null)
|
||||
{
|
||||
if (currentQuality >= newQuality)
|
||||
int compare = new QualityModelComparer(profile).Compare(newQuality, currentQuality);
|
||||
if (compare <= 0)
|
||||
{
|
||||
_logger.Trace("existing item has better or equal quality. skipping");
|
||||
return false;
|
||||
|
|
@ -41,7 +42,9 @@ public bool IsUpgradable(QualityModel currentQuality, QualityModel newQuality =
|
|||
|
||||
public bool CutoffNotMet(QualityProfile profile, QualityModel currentQuality, QualityModel newQuality = null)
|
||||
{
|
||||
if (currentQuality.Quality >= profile.Cutoff)
|
||||
int compare = new QualityModelComparer(profile).Compare(currentQuality.Quality, profile.Cutoff);
|
||||
|
||||
if (compare >= 0)
|
||||
{
|
||||
if (newQuality != null && IsProperUpgrade(currentQuality, newQuality))
|
||||
{
|
||||
|
|
@ -57,7 +60,9 @@ public bool CutoffNotMet(QualityProfile profile, QualityModel currentQuality, Qu
|
|||
|
||||
public bool IsProperUpgrade(QualityModel currentQuality, QualityModel newQuality)
|
||||
{
|
||||
if (currentQuality.Quality == newQuality.Quality && newQuality > currentQuality)
|
||||
int compare = newQuality.Proper.CompareTo(currentQuality.Proper);
|
||||
|
||||
if (currentQuality.Quality == newQuality.Quality && compare > 0)
|
||||
{
|
||||
_logger.Trace("New quality is a proper for existing quality");
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
{
|
||||
public class AcceptableSizeSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly IQualitySizeService _qualityTypeProvider;
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public AcceptableSizeSpecification(IQualitySizeService qualityTypeProvider, IEpisodeService episodeService, Logger logger)
|
||||
public AcceptableSizeSpecification(IQualityDefinitionService qualityDefinitionService, IEpisodeService episodeService, Logger logger)
|
||||
{
|
||||
_qualityTypeProvider = qualityTypeProvider;
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
_episodeService = episodeService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
|
@ -44,15 +44,15 @@ public virtual bool IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase sear
|
|||
return false;
|
||||
}
|
||||
|
||||
var qualityType = _qualityTypeProvider.Get(quality.Id);
|
||||
var qualityDefinition = _qualityDefinitionService.Get(quality);
|
||||
|
||||
if (qualityType.MaxSize == 0)
|
||||
if (qualityDefinition.MaxSize == 0)
|
||||
{
|
||||
_logger.Trace("Max size is 0 (unlimited) - skipping check.");
|
||||
return true;
|
||||
}
|
||||
|
||||
var maxSize = qualityType.MaxSize.Megabytes();
|
||||
var maxSize = qualityDefinition.MaxSize.Megabytes();
|
||||
|
||||
//Multiply maxSize by Series.Runtime
|
||||
maxSize = maxSize * subject.Series.Runtime * subject.Episodes.Count;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
|
|
@ -44,7 +46,7 @@ public bool IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriter
|
|||
private bool IsInQueue(RemoteEpisode newEpisode, IEnumerable<RemoteEpisode> queue)
|
||||
{
|
||||
var matchingSeries = queue.Where(q => q.Series.Id == newEpisode.Series.Id);
|
||||
var matchingSeriesAndQuality = matchingSeries.Where(q => q.ParsedEpisodeInfo.Quality >= newEpisode.ParsedEpisodeInfo.Quality);
|
||||
var matchingSeriesAndQuality = matchingSeries.Where(q => new QualityModelComparer(q.Series.QualityProfile).Compare(q.ParsedEpisodeInfo.Quality, newEpisode.ParsedEpisodeInfo.Quality) >= 0);
|
||||
|
||||
return matchingSeriesAndQuality.Any(q => q.Episodes.Select(e => e.Id).Intersect(newEpisode.Episodes.Select(e => e.Id)).Any());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public virtual bool IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase sear
|
|||
if (bestQualityInHistory != null)
|
||||
{
|
||||
_logger.Trace("Comparing history quality with report. History is {0}", bestQualityInHistory);
|
||||
if (!_qualityUpgradableSpecification.IsUpgradable(bestQualityInHistory, subject.ParsedEpisodeInfo.Quality))
|
||||
if (!_qualityUpgradableSpecification.IsUpgradable(subject.Series.QualityProfile, bestQualityInHistory, subject.ParsedEpisodeInfo.Quality))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public virtual bool IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase sear
|
|||
{
|
||||
_logger.Trace("Comparing file quality with report. Existing file is {0}", file.Quality);
|
||||
|
||||
if (!_qualityUpgradableSpecification.IsUpgradable(file.Quality, subject.ParsedEpisodeInfo.Quality))
|
||||
if (!_qualityUpgradableSpecification.IsUpgradable(subject.Series.QualityProfile, file.Quality, subject.ParsedEpisodeInfo.Quality))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
|
|
@ -16,7 +18,7 @@ public class DownloadApprovedReports : IDownloadApprovedReports
|
|||
private readonly IDownloadService _downloadService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public DownloadApprovedReports(IDownloadService downloadService, Logger logger)
|
||||
public DownloadApprovedReports(IDownloadService downloadService, Logger logger)
|
||||
{
|
||||
_downloadService = downloadService;
|
||||
_logger = logger;
|
||||
|
|
@ -57,11 +59,13 @@ public List<DownloadDecision> DownloadApproved(List<DownloadDecision> decisions)
|
|||
public List<DownloadDecision> GetQualifiedReports(IEnumerable<DownloadDecision> decisions)
|
||||
{
|
||||
return decisions.Where(c => c.Approved && c.RemoteEpisode.Episodes.Any())
|
||||
.OrderByDescending(c => c.RemoteEpisode.ParsedEpisodeInfo.Quality)
|
||||
.ThenBy(c => c.RemoteEpisode.Episodes.Select(e => e.EpisodeNumber).MinOrDefault())
|
||||
.ThenBy(c => c.RemoteEpisode.Release.Size.Round(200.Megabytes()) / c.RemoteEpisode.Episodes.Count)
|
||||
.ThenBy(c => c.RemoteEpisode.Release.Age)
|
||||
.ToList();
|
||||
.GroupBy(c => c.RemoteEpisode.Series.Id, (i,s) => s
|
||||
.OrderByDescending(c => c.RemoteEpisode.ParsedEpisodeInfo.Quality, new QualityModelComparer(s.First().RemoteEpisode.Series.QualityProfile))
|
||||
.ThenBy(c => c.RemoteEpisode.Episodes.Select(e => e.EpisodeNumber).MinOrDefault())
|
||||
.ThenBy(c => c.RemoteEpisode.Release.Size.Round(200.Megabytes()) / c.RemoteEpisode.Episodes.Count)
|
||||
.ThenBy(c => c.RemoteEpisode.Release.Age))
|
||||
.SelectMany(c => c)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Common.Messaging;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.History
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using Marr.Data.QGen;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.History
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.History
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
|
|
@ -40,8 +42,11 @@ public ImportApprovedEpisodes(IUpgradeMediaFiles episodeFileUpgrader,
|
|||
public List<ImportDecision> Import(List<ImportDecision> decisions, bool newDownload = false)
|
||||
{
|
||||
var qualifiedImports = decisions.Where(c => c.Approved)
|
||||
.OrderByDescending(c => c.LocalEpisode.Quality)
|
||||
.ThenByDescending(c => c.LocalEpisode.Size);
|
||||
.GroupBy(c => c.LocalEpisode.Series.Id, (i, s) => s
|
||||
.OrderByDescending(c => c.LocalEpisode.Quality, new QualityModelComparer(s.First().LocalEpisode.Series.QualityProfile))
|
||||
.ThenByDescending(c => c.LocalEpisode.Size))
|
||||
.SelectMany(c => c)
|
||||
.ToList();
|
||||
|
||||
var imported = new List<ImportDecision>();
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
|
||||
|
|
@ -60,7 +61,7 @@ private IEnumerable<ImportDecision> GetDecisions(IEnumerable<String> videoFiles,
|
|||
|
||||
if (parsedEpisode != null)
|
||||
{
|
||||
if (quality != null && quality > parsedEpisode.Quality)
|
||||
if (quality != null && new QualityModelComparer(parsedEpisode.Series.QualityProfile).Compare(quality, parsedEpisode.Quality) > 0)
|
||||
{
|
||||
_logger.Trace("Using quality from folder: {0}", quality);
|
||||
parsedEpisode.Quality = quality;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
{
|
||||
|
|
@ -17,7 +19,8 @@ public UpgradeSpecification(Logger logger)
|
|||
|
||||
public bool IsSatisfiedBy(LocalEpisode localEpisode)
|
||||
{
|
||||
if (localEpisode.Episodes.Any(e => e.EpisodeFileId != 0 && e.EpisodeFile.Value.Quality > localEpisode.Quality))
|
||||
var qualityComparer = new QualityModelComparer(localEpisode.Series.QualityProfile);
|
||||
if (localEpisode.Episodes.Any(e => e.EpisodeFileId != 0 && qualityComparer.Compare(e.EpisodeFile.Value.Quality, localEpisode.Quality) > 0))
|
||||
{
|
||||
_logger.Trace("This file isn't an upgrade for all episodes. Skipping {0}", localEpisode.Path);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Notifications
|
||||
|
|
|
|||
|
|
@ -145,6 +145,8 @@
|
|||
<Compile Include="Datastore\Converters\BooleanIntConverter.cs" />
|
||||
<Compile Include="Datastore\Converters\ProviderSettingConverter.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\EmbeddedDocumentConverter.cs" />
|
||||
<Compile Include="Datastore\Converters\UtcConverter.cs" />
|
||||
|
|
@ -191,6 +193,8 @@
|
|||
<Compile Include="Datastore\Migration\033_add_api_key_to_pushover.cs" />
|
||||
<Compile Include="Datastore\Migration\034_remove_series_contraints.cs" />
|
||||
<Compile Include="Datastore\Migration\035_add_series_folder_format_to_naming_config.cs" />
|
||||
<Compile Include="Datastore\Migration\036_update_with_quality_converters.cs" />
|
||||
<Compile Include="Datastore\Migration\037_add_configurable_qualities.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationExtension.cs" />
|
||||
|
|
@ -456,12 +460,13 @@
|
|||
<Compile Include="Parser\Parser.cs" />
|
||||
<Compile Include="Parser\ParsingService.cs" />
|
||||
<Compile Include="Parser\QualityParser.cs" />
|
||||
<Compile Include="Qualities\QualityModelComparer.cs" />
|
||||
<Compile Include="Rest\JsonNetSerializer.cs" />
|
||||
<Compile Include="RootFolders\RootFolderRepository.cs" />
|
||||
<Compile Include="ThingiProvider\ConfigContractNotFoundException.cs" />
|
||||
<Compile Include="ThingiProvider\IProvider.cs" />
|
||||
<Compile Include="Qualities\QualityProfileInUseException.cs" />
|
||||
<Compile Include="Qualities\QualitySizeRepository.cs" />
|
||||
<Compile Include="Qualities\QualityDefinitionRepository.cs" />
|
||||
<Compile Include="Qualities\QualityProfileRepository.cs" />
|
||||
<Compile Include="Queue\Queue.cs" />
|
||||
<Compile Include="Queue\UpdateQueueEvent.cs" />
|
||||
|
|
@ -489,7 +494,7 @@
|
|||
<Compile Include="Tv\Commands\RefreshSeriesCommand.cs" />
|
||||
<Compile Include="Tv\RefreshEpisodeService.cs" />
|
||||
<Compile Include="Tv\SeriesRepository.cs" />
|
||||
<Compile Include="Tv\QualityModel.cs" />
|
||||
<Compile Include="Qualities\QualityModel.cs" />
|
||||
<Compile Include="Download\Clients\Sabnzbd\SabAddResponse.cs" />
|
||||
<Compile Include="Download\Clients\Sabnzbd\SabHistoryItem.cs" />
|
||||
<Compile Include="Download\Clients\Sabnzbd\SabHistory.cs" />
|
||||
|
|
@ -575,7 +580,7 @@
|
|||
<Compile Include="Qualities\QualityProfileService.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Qualities\QualitySizeService.cs">
|
||||
<Compile Include="Qualities\QualityDefinitionService.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="RootFolders\UnmappedFolder.cs" />
|
||||
|
|
@ -597,7 +602,7 @@
|
|||
<Compile Include="Tv\Episode.cs" />
|
||||
<Compile Include="Instrumentation\Log.cs" />
|
||||
<Compile Include="History\History.cs" />
|
||||
<Compile Include="Qualities\QualitySize.cs" />
|
||||
<Compile Include="Qualities\QualityDefinition.cs" />
|
||||
<Compile Include="Qualities\QualityProfile.cs" />
|
||||
<Compile Include="RootFolders\RootFolder.cs" />
|
||||
<Compile Include="Tv\Series.cs" />
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Organizer
|
||||
|
|
@ -22,6 +23,7 @@ public interface IBuildFileNames
|
|||
public class FileNameBuilder : IBuildFileNames
|
||||
{
|
||||
private readonly INamingConfigService _namingConfigService;
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
private readonly ICached<EpisodeFormat> _patternCache;
|
||||
private readonly Logger _logger;
|
||||
|
||||
|
|
@ -43,10 +45,12 @@ public class FileNameBuilder : IBuildFileNames
|
|||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public FileNameBuilder(INamingConfigService namingConfigService,
|
||||
IQualityDefinitionService qualityDefinitionService,
|
||||
ICacheManger cacheManger,
|
||||
Logger logger)
|
||||
{
|
||||
_namingConfigService = namingConfigService;
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
_patternCache = cacheManger.GetCache<EpisodeFormat>(GetType());
|
||||
_logger = logger;
|
||||
}
|
||||
|
|
@ -87,12 +91,10 @@ public string BuildFilename(IList<Episode> episodes, Series series, EpisodeFile
|
|||
sortedEpisodes.First().Title
|
||||
};
|
||||
|
||||
var tokenValues = new Dictionary<string, string>(FilenameBuilderTokenEqualityComparer.Instance)
|
||||
{
|
||||
{"{Series Title}", series.Title},
|
||||
{"Original Title", episodeFile.SceneName}
|
||||
};
|
||||
var tokenValues = new Dictionary<string, string>(FilenameBuilderTokenEqualityComparer.Instance);
|
||||
|
||||
tokenValues.Add("{Series Title}", series.Title);
|
||||
tokenValues.Add("{Original Title}", episodeFile.SceneName);
|
||||
tokenValues.Add("{Release Group}", episodeFile.ReleaseGroup);
|
||||
|
||||
if (series.SeriesType == SeriesTypes.Daily)
|
||||
|
|
@ -146,7 +148,7 @@ public string BuildFilename(IList<Episode> episodes, Series series, EpisodeFile
|
|||
}
|
||||
|
||||
tokenValues.Add("{Episode Title}", GetEpisodeTitle(episodeTitles));
|
||||
tokenValues.Add("{Quality Title}", episodeFile.Quality.ToString());
|
||||
tokenValues.Add("{Quality Title}", GetQualityTitle(episodeFile.Quality));
|
||||
|
||||
|
||||
return CleanFilename(ReplaceTokens(pattern, tokenValues).Trim());
|
||||
|
|
@ -341,6 +343,14 @@ private string GetEpisodeTitle(List<string> episodeTitles)
|
|||
|
||||
return String.Join(" + ", episodeTitles.Select(Parser.Parser.CleanupEpisodeTitle).Distinct());
|
||||
}
|
||||
|
||||
private string GetQualityTitle(QualityModel quality)
|
||||
{
|
||||
if (quality.Proper)
|
||||
return _qualityDefinitionService.Get(quality.Quality).Title + " Proper";
|
||||
else
|
||||
return _qualityDefinitionService.Get(quality.Quality).Title;
|
||||
}
|
||||
}
|
||||
|
||||
public enum MultiEpisodeStyle
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Parser.Model
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Parser.Model
|
||||
|
|
|
|||
|
|
@ -2,65 +2,24 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Datastore.Converters;
|
||||
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public class Quality : IComparable<Quality>, IEmbeddedDocument
|
||||
public class Quality : IEmbeddedDocument, IEquatable<Quality>
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int Weight { get; set; }
|
||||
|
||||
public int CompareTo(Quality other)
|
||||
public Quality()
|
||||
{
|
||||
if (other.Weight > Weight)
|
||||
return -1;
|
||||
|
||||
if (other.Weight < Weight)
|
||||
return 1;
|
||||
|
||||
if (other.Weight == Weight)
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static bool operator !=(Quality x, Quality y)
|
||||
private Quality(int id, string name)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
public static bool operator ==(Quality x, Quality y)
|
||||
{
|
||||
var xObj = (Object)x;
|
||||
var yObj = (object)y;
|
||||
|
||||
if (xObj == null || yObj == null)
|
||||
{
|
||||
return xObj == yObj;
|
||||
}
|
||||
|
||||
return x.CompareTo(y) == 0;
|
||||
}
|
||||
|
||||
public static bool operator >(Quality x, Quality y)
|
||||
{
|
||||
return x.CompareTo(y) > 0;
|
||||
}
|
||||
|
||||
public static bool operator <(Quality x, Quality y)
|
||||
{
|
||||
return x.CompareTo(y) < 0;
|
||||
}
|
||||
|
||||
public static bool operator <=(Quality x, Quality y)
|
||||
{
|
||||
return x.CompareTo(y) <= 0;
|
||||
}
|
||||
|
||||
public static bool operator >=(Quality x, Quality y)
|
||||
{
|
||||
return x.CompareTo(y) >= 0;
|
||||
Id = id;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
|
@ -70,110 +29,96 @@ public override string ToString()
|
|||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked // Overflow is fine, just wrap
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 23 + Weight.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
return Id.GetHashCode();
|
||||
}
|
||||
|
||||
public bool Equals(Quality other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return Equals(other.Weight, Weight);
|
||||
return Id.Equals(other.Id);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != typeof(Quality)) return false;
|
||||
return Equals((Quality)obj);
|
||||
|
||||
return Equals(obj as Quality);
|
||||
}
|
||||
|
||||
public static Quality Unknown
|
||||
public static bool operator ==(Quality left, Quality right)
|
||||
{
|
||||
get { return new Quality { Id = 0, Name = "Unknown", Weight = 0 }; }
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static Quality SDTV
|
||||
public static bool operator !=(Quality left, Quality right)
|
||||
{
|
||||
get { return new Quality { Id = 1, Name = "SDTV", Weight = 1 }; }
|
||||
return !Equals(left, right);
|
||||
}
|
||||
|
||||
public static Quality WEBDL480p
|
||||
public static Quality Unknown { get { return new Quality(0, "Unknown"); } }
|
||||
public static Quality SDTV { get { return new Quality(1, "SDTV"); } }
|
||||
public static Quality DVD { get { return new Quality(2, "DVD"); } }
|
||||
public static Quality WEBDL1080p { get { return new Quality(3, "WEBDL-1080p"); } }
|
||||
public static Quality HDTV720p { get { return new Quality(4, "HDTV-720p"); } }
|
||||
public static Quality WEBDL720p { get { return new Quality(5, "WEBDL-720p"); } }
|
||||
public static Quality Bluray720p { get { return new Quality(6, "Bluray-720p"); } }
|
||||
public static Quality Bluray1080p { get { return new Quality(7, "Bluray-1080p"); } }
|
||||
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 RAWHD { get { return new Quality(10, "Raw-HD"); } }
|
||||
public static Quality HDTV480p { get { return new Quality(11, "HDTV-480p"); } }
|
||||
|
||||
public static List<Quality> All
|
||||
{
|
||||
get { return new Quality { Id = 8, Name = "WEBDL-480p", Weight = 2 }; }
|
||||
get
|
||||
{
|
||||
return new List<Quality>
|
||||
{
|
||||
SDTV,
|
||||
DVD,
|
||||
WEBDL1080p,
|
||||
HDTV720p,
|
||||
WEBDL720p,
|
||||
Bluray720p,
|
||||
Bluray1080p,
|
||||
WEBDL480p,
|
||||
HDTV1080p,
|
||||
RAWHD
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static Quality DVD
|
||||
public static HashSet<QualityDefinition> DefaultQualityDefinitions
|
||||
{
|
||||
get { return new Quality { Id = 2, Name = "DVD", Weight = 3 }; }
|
||||
}
|
||||
|
||||
public static Quality HDTV720p
|
||||
{
|
||||
get { return new Quality { Id = 4, Name = "HDTV-720p", Weight = 4 }; }
|
||||
}
|
||||
|
||||
public static Quality HDTV1080p
|
||||
{
|
||||
get { return new Quality { Id = 9, Name = "HDTV-1080p", Weight = 5 }; }
|
||||
}
|
||||
|
||||
public static Quality RAWHD
|
||||
{
|
||||
get { return new Quality { Id = 10, Name = "Raw-HD", Weight = 6 }; }
|
||||
}
|
||||
|
||||
public static Quality WEBDL720p
|
||||
{
|
||||
get { return new Quality { Id = 5, Name = "WEBDL-720p", Weight = 7 }; }
|
||||
}
|
||||
|
||||
public static Quality Bluray720p
|
||||
{
|
||||
get { return new Quality { Id = 6, Name = "Bluray720p", Weight = 8 }; }
|
||||
}
|
||||
|
||||
public static Quality WEBDL1080p
|
||||
{
|
||||
get { return new Quality { Id = 3, Name = "WEBDL-1080p", Weight = 9 }; }
|
||||
}
|
||||
|
||||
public static Quality Bluray1080p
|
||||
{
|
||||
get { return new Quality { Id = 7, Name = "Bluray1080p", Weight = 10 }; }
|
||||
}
|
||||
|
||||
public static List<Quality> All()
|
||||
{
|
||||
return new List<Quality>
|
||||
{
|
||||
SDTV,
|
||||
WEBDL480p,
|
||||
DVD,
|
||||
HDTV720p,
|
||||
HDTV1080p,
|
||||
RAWHD,
|
||||
WEBDL720p,
|
||||
WEBDL1080p,
|
||||
Bluray720p,
|
||||
Bluray1080p
|
||||
};
|
||||
get
|
||||
{
|
||||
return new HashSet<QualityDefinition>
|
||||
{
|
||||
new QualityDefinition(Quality.SDTV) { /*Title = "SDTV", */ Weight = 1, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.WEBDL480p) { /*Title = "WEB-DL", */ Weight = 2, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.DVD) { /*Title = "DVD", */ Weight = 3, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.HDTV720p) { /*Title = "720p HDTV", */ Weight = 4, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.HDTV1080p) { /*Title = "1080p HDTV", */ Weight = 5, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.RAWHD) { /*Title = "RawHD", */ Weight = 6, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.WEBDL720p) { /*Title = "720p WEB-DL", */ Weight = 7, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.Bluray720p) { /*Title = "720p BluRay", */ Weight = 8, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.WEBDL1080p) { /*Title = "1080p WEB-DL",*/ Weight = 9, MinSize=0, MaxSize=100 },
|
||||
new QualityDefinition(Quality.Bluray1080p) { /*Title = "1080p BluRay",*/ Weight = 10, MinSize=0, MaxSize=100 }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static Quality FindById(int id)
|
||||
{
|
||||
if (id == 0) return Unknown;
|
||||
|
||||
var quality = All().SingleOrDefault(q => q.Id == id);
|
||||
Quality quality = All.FirstOrDefault(v => v.Id == id);
|
||||
|
||||
if (quality == null)
|
||||
throw new ArgumentException("ID does not match a known quality", "id");
|
||||
|
||||
|
||||
return quality;
|
||||
}
|
||||
|
||||
|
|
|
|||
33
src/NzbDrone.Core/Qualities/QualityDefinition.cs
Normal file
33
src/NzbDrone.Core/Qualities/QualityDefinition.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using NzbDrone.Core.Datastore;
|
||||
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public class QualityDefinition : ModelBase
|
||||
{
|
||||
public Quality Quality { get; set; }
|
||||
|
||||
public string Title { get; set; }
|
||||
|
||||
public int Weight { get; set; }
|
||||
|
||||
public int MinSize { get; set; }
|
||||
public int MaxSize { get; set; }
|
||||
|
||||
public QualityDefinition()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public QualityDefinition(Quality quality)
|
||||
{
|
||||
Quality = quality;
|
||||
Title = quality.Name;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Quality.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/NzbDrone.Core/Qualities/QualityDefinitionRepository.cs
Normal file
33
src/NzbDrone.Core/Qualities/QualityDefinitionRepository.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public interface IQualityDefinitionRepository : IBasicRepository<QualityDefinition>
|
||||
{
|
||||
QualityDefinition GetByQualityId(int qualityId);
|
||||
}
|
||||
|
||||
public class QualityDefinitionRepository : BasicRepository<QualityDefinition>, IQualityDefinitionRepository
|
||||
{
|
||||
public QualityDefinitionRepository(IDatabase database, IEventAggregator eventAggregator)
|
||||
: base(database, eventAggregator)
|
||||
{
|
||||
}
|
||||
|
||||
public QualityDefinition GetByQualityId(int qualityId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Query.Single(q => (int)q.Quality == qualityId);
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
throw new ModelNotFoundException(typeof(QualityDefinition), qualityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
src/NzbDrone.Core/Qualities/QualityDefinitionService.cs
Normal file
101
src/NzbDrone.Core/Qualities/QualityDefinitionService.cs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public interface IQualityDefinitionService
|
||||
{
|
||||
void Update(QualityDefinition qualityDefinition);
|
||||
List<QualityDefinition> All();
|
||||
QualityDefinition Get(Quality quality);
|
||||
}
|
||||
|
||||
public class QualityDefinitionService : IQualityDefinitionService, IHandle<ApplicationStartedEvent>
|
||||
{
|
||||
private readonly IQualityDefinitionRepository _qualityDefinitionRepository;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public QualityDefinitionService(IQualityDefinitionRepository qualityDefinitionRepository, Logger logger)
|
||||
{
|
||||
_qualityDefinitionRepository = qualityDefinitionRepository;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Update(QualityDefinition qualityDefinition)
|
||||
{
|
||||
_qualityDefinitionRepository.Update(qualityDefinition);
|
||||
}
|
||||
|
||||
public List<QualityDefinition> All()
|
||||
{
|
||||
return _qualityDefinitionRepository.All().ToList();
|
||||
}
|
||||
|
||||
public QualityDefinition Get(Quality quality)
|
||||
{
|
||||
if (quality == Quality.Unknown)
|
||||
return new QualityDefinition(Quality.Unknown);
|
||||
|
||||
return _qualityDefinitionRepository.GetByQualityId((int)quality);
|
||||
}
|
||||
|
||||
public void InsertMissingDefinitions(List<QualityDefinition> allDefinitions)
|
||||
{
|
||||
allDefinitions.OrderBy(v => v.Weight).ToList();
|
||||
var existingDefinitions = _qualityDefinitionRepository.All().OrderBy(v => v.Weight).ToList();
|
||||
|
||||
// Try insert each item intelligently to merge the lists preserving the Weight the user set.
|
||||
for (int i = 0; i < allDefinitions.Count;i++)
|
||||
{
|
||||
// Skip if this definition isn't missing.
|
||||
if (existingDefinitions.Any(v => v.Quality == allDefinitions[i].Quality))
|
||||
continue;
|
||||
|
||||
int targetIndexMinimum = 0;
|
||||
for (int j = 0; j < i; j++)
|
||||
targetIndexMinimum = Math.Max(targetIndexMinimum, existingDefinitions.FindIndex(v => v.Quality == allDefinitions[j].Quality) + 1);
|
||||
|
||||
int targetIndexMaximum = existingDefinitions.Count;
|
||||
for (int j = i + 1; j < allDefinitions.Count; j++)
|
||||
{
|
||||
var index = existingDefinitions.FindIndex(v => v.Quality == allDefinitions[j].Quality);
|
||||
if (index != -1)
|
||||
targetIndexMaximum = Math.Min(targetIndexMaximum, index);
|
||||
}
|
||||
|
||||
// Rounded down average sounds reasonable.
|
||||
int targetIndex = (targetIndexMinimum + targetIndexMaximum) / 2;
|
||||
|
||||
existingDefinitions.Insert(targetIndex, allDefinitions[i]);
|
||||
}
|
||||
|
||||
// Update all Weights.
|
||||
List<QualityDefinition> insertList = new List<QualityDefinition>();
|
||||
List<QualityDefinition> updateList = new List<QualityDefinition>();
|
||||
for (int i = 0; i < existingDefinitions.Count; i++)
|
||||
{
|
||||
if (existingDefinitions[i].Id == 0)
|
||||
{
|
||||
existingDefinitions[i].Weight = i + 1;
|
||||
_qualityDefinitionRepository.Insert(existingDefinitions[i]);
|
||||
}
|
||||
else if (existingDefinitions[i].Weight != i + 1)
|
||||
{
|
||||
existingDefinitions[i].Weight = i + 1;
|
||||
_qualityDefinitionRepository.Update(existingDefinitions[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Handle(ApplicationStartedEvent message)
|
||||
{
|
||||
_logger.Debug("Setting up default quality config");
|
||||
|
||||
InsertMissingDefinitions(Quality.DefaultQualityDefinitions.ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
73
src/NzbDrone.Core/Qualities/QualityModel.cs
Normal file
73
src/NzbDrone.Core/Qualities/QualityModel.cs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public class QualityModel : IEmbeddedDocument, IEquatable<QualityModel>
|
||||
{
|
||||
public Quality Quality { get; set; }
|
||||
|
||||
public Boolean Proper { get; set; }
|
||||
|
||||
public QualityModel()
|
||||
: this(Quality.Unknown)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public QualityModel(Quality quality, Boolean proper = false)
|
||||
{
|
||||
Quality = quality;
|
||||
Proper = proper;
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = Quality.ToString();
|
||||
if (Proper)
|
||||
{
|
||||
result += " Proper";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked // Overflow is fine, just wrap
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 23 + Proper.GetHashCode();
|
||||
hash = hash * 23 + Quality.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(QualityModel other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return other.Quality.Equals(Quality) && other.Proper.Equals(Proper);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
|
||||
return Equals(obj as QualityModel);
|
||||
}
|
||||
|
||||
public static bool operator ==(QualityModel left, QualityModel right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(QualityModel left, QualityModel right)
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
67
src/NzbDrone.Core/Qualities/QualityModelComparer.cs
Normal file
67
src/NzbDrone.Core/Qualities/QualityModelComparer.cs
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NLog;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public class QualityModelComparer : IComparer<Quality>, IComparer<QualityModel>
|
||||
{
|
||||
private readonly QualityProfile _qualityProfile;
|
||||
|
||||
public QualityModelComparer(QualityProfile qualityProfile)
|
||||
{
|
||||
Ensure.That(qualityProfile, () => qualityProfile).IsNotNull();
|
||||
Ensure.That(qualityProfile.Allowed, () => qualityProfile.Allowed).HasItems();
|
||||
|
||||
_qualityProfile = qualityProfile;
|
||||
}
|
||||
|
||||
public int Compare(Quality left, Quality right)
|
||||
{
|
||||
int leftIndex = _qualityProfile.Allowed.IndexOf(left);
|
||||
int rightIndex = _qualityProfile.Allowed.IndexOf(right);
|
||||
|
||||
return leftIndex.CompareTo(rightIndex);
|
||||
}
|
||||
|
||||
public int Compare(QualityModel left, QualityModel right)
|
||||
{
|
||||
int result = Compare(left.Quality, right.Quality);
|
||||
|
||||
if (result == 0)
|
||||
result = left.Proper.CompareTo(right.Proper);
|
||||
|
||||
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;
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
using NzbDrone.Core.Datastore;
|
||||
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public class QualitySize : ModelBase
|
||||
{
|
||||
public int QualityId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public int MinSize { get; set; }
|
||||
public int MaxSize { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public interface IQualitySizeRepository : IBasicRepository<QualitySize>
|
||||
{
|
||||
QualitySize GetByQualityId(int qualityId);
|
||||
}
|
||||
|
||||
public class QualitySizeRepository : BasicRepository<QualitySize>, IQualitySizeRepository
|
||||
{
|
||||
public QualitySizeRepository(IDatabase database, IEventAggregator eventAggregator)
|
||||
: base(database, eventAggregator)
|
||||
{
|
||||
}
|
||||
|
||||
public QualitySize GetByQualityId(int qualityId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Query.Single(q => q.QualityId == qualityId);
|
||||
}
|
||||
catch (InvalidOperationException e)
|
||||
{
|
||||
throw new ModelNotFoundException(typeof(QualitySize), qualityId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Qualities
|
||||
{
|
||||
public interface IQualitySizeService
|
||||
{
|
||||
void Update(QualitySize qualitySize);
|
||||
List<QualitySize> All();
|
||||
QualitySize Get(int qualityId);
|
||||
}
|
||||
|
||||
public class QualitySizeService : IQualitySizeService, IHandle<ApplicationStartedEvent>
|
||||
{
|
||||
private readonly IQualitySizeRepository _qualitySizeRepository;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public QualitySizeService(IQualitySizeRepository qualitySizeRepository, Logger logger)
|
||||
{
|
||||
_qualitySizeRepository = qualitySizeRepository;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public virtual void Update(QualitySize qualitySize)
|
||||
{
|
||||
_qualitySizeRepository.Update(qualitySize);
|
||||
}
|
||||
|
||||
|
||||
public virtual List<QualitySize> All()
|
||||
{
|
||||
return _qualitySizeRepository.All().ToList();
|
||||
}
|
||||
|
||||
public virtual QualitySize Get(int qualityId)
|
||||
{
|
||||
return _qualitySizeRepository.GetByQualityId(qualityId);
|
||||
}
|
||||
|
||||
public void Handle(ApplicationStartedEvent message)
|
||||
{
|
||||
var existing = All();
|
||||
|
||||
_logger.Debug("Setting up default quality sizes");
|
||||
|
||||
foreach (var quality in Quality.All())
|
||||
{
|
||||
if (!existing.Any(s => s.QualityId == quality.Id))
|
||||
{
|
||||
_qualitySizeRepository.Insert(new QualitySize
|
||||
{
|
||||
QualityId = quality.Id,
|
||||
Name = quality.Name,
|
||||
MinSize = 0,
|
||||
MaxSize = 100
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Queue
|
||||
|
|
|
|||
|
|
@ -1,120 +0,0 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class QualityModel : IComparable<QualityModel>, IEmbeddedDocument
|
||||
{
|
||||
public Quality Quality { get; set; }
|
||||
|
||||
public Boolean Proper { get; set; }
|
||||
|
||||
public QualityModel()
|
||||
: this(Quality.Unknown)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public QualityModel(Quality quality, Boolean proper = false)
|
||||
{
|
||||
Quality = quality;
|
||||
Proper = proper;
|
||||
}
|
||||
|
||||
public int CompareTo(QualityModel other)
|
||||
{
|
||||
if (other.Quality > Quality)
|
||||
return -1;
|
||||
|
||||
if (other.Quality < Quality)
|
||||
return 1;
|
||||
|
||||
if (other.Quality == Quality && other.Proper == Proper)
|
||||
return 0;
|
||||
|
||||
if (Proper && !other.Proper)
|
||||
return 1;
|
||||
|
||||
if (!Proper && other.Proper)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static bool operator !=(QualityModel x, QualityModel y)
|
||||
{
|
||||
return !(x == y);
|
||||
}
|
||||
|
||||
public static bool operator ==(QualityModel x, QualityModel y)
|
||||
{
|
||||
var xObj = (Object)x;
|
||||
var yObj = (object)y;
|
||||
|
||||
if (xObj == null || yObj == null)
|
||||
{
|
||||
return xObj == yObj;
|
||||
}
|
||||
|
||||
return x.CompareTo(y) == 0;
|
||||
}
|
||||
|
||||
public static bool operator >(QualityModel x, QualityModel y)
|
||||
{
|
||||
return x.CompareTo(y) > 0;
|
||||
}
|
||||
|
||||
public static bool operator <(QualityModel x, QualityModel y)
|
||||
{
|
||||
return x.CompareTo(y) < 0;
|
||||
}
|
||||
|
||||
public static bool operator <=(QualityModel x, QualityModel y)
|
||||
{
|
||||
return x.CompareTo(y) <= 0;
|
||||
}
|
||||
|
||||
public static bool operator >=(QualityModel x, QualityModel y)
|
||||
{
|
||||
return x.CompareTo(y) >= 0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = Quality.ToString();
|
||||
if (Proper)
|
||||
{
|
||||
result += " Proper";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked // Overflow is fine, just wrap
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 23 + Proper.GetHashCode();
|
||||
hash = hash * 23 + Quality.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Equals(QualityModel other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return Equals(other.Quality, Quality) && other.Proper.Equals(Proper);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != typeof(QualityModel)) return false;
|
||||
return Equals((QualityModel)obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
1072
src/UI/JsLibraries/backbone.collectionview.js
Normal file
1072
src/UI/JsLibraries/backbone.collectionview.js
Normal file
File diff suppressed because it is too large
Load diff
4233
src/UI/JsLibraries/jquery-ui.js
vendored
Normal file
4233
src/UI/JsLibraries/jquery-ui.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
11
src/UI/Quality/QualityDefinitionCollection.js
Normal file
11
src/UI/Quality/QualityDefinitionCollection.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
'use strict';
|
||||
define(
|
||||
[
|
||||
'backbone',
|
||||
'Quality/QualityDefinitionModel'
|
||||
], function (Backbone, QualityDefinitionModel) {
|
||||
return Backbone.Collection.extend({
|
||||
model: QualityDefinitionModel,
|
||||
url : window.NzbDrone.ApiRoot + '/qualitydefinition'
|
||||
});
|
||||
});
|
||||
|
|
@ -9,10 +9,10 @@ define(
|
|||
baseInitialize: ModelBase.prototype.initialize,
|
||||
|
||||
initialize: function () {
|
||||
var name = this.get('name');
|
||||
var name = this.get('quality').name;
|
||||
|
||||
this.successMessage = 'Saved ' + name + ' size settings';
|
||||
this.errorMessage = 'Couldn\'t save ' + name + ' size settings';
|
||||
this.successMessage = 'Saved ' + name + ' quality settings';
|
||||
this.errorMessage = 'Couldn\'t save ' + name + ' quality settings';
|
||||
|
||||
this.baseInitialize.call(this);
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
'use strict';
|
||||
define(
|
||||
[
|
||||
'backbone',
|
||||
'Quality/QualitySizeModel'
|
||||
], function (Backbone, QualitySizeModel) {
|
||||
return Backbone.Collection.extend({
|
||||
model: QualitySizeModel,
|
||||
url : window.NzbDrone.ApiRoot + '/qualitysize'
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<fieldset>
|
||||
<legend>Quality Definitions</legend>
|
||||
<div class="span11">
|
||||
<div id="quality-definition-list">
|
||||
<div class="x-header">
|
||||
<div class="row">
|
||||
<span class="span2">Quality</span>
|
||||
<span class="span2">Title</span>
|
||||
<span class="offset1 span4">Size Limit</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="x-rows">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
'use strict';
|
||||
|
||||
define(
|
||||
[
|
||||
'marionette',
|
||||
'backgrid',
|
||||
'Settings/Quality/Definition/QualityDefinitionView'
|
||||
], function (Marionette, Backgrid, QualityDefinitionView) {
|
||||
|
||||
return Marionette.CompositeView.extend({
|
||||
template: 'Settings/Quality/Definition/QualityDefinitionCollectionTemplate',
|
||||
|
||||
itemViewContainer: ".x-rows",
|
||||
|
||||
itemView: QualityDefinitionView
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<span class="span2">
|
||||
{{quality.name}}
|
||||
</span>
|
||||
<span class="span2">
|
||||
<input type="text" class="x-title input-block-level" value="{{title}}">
|
||||
</span>
|
||||
<span class="offset1 span4">
|
||||
<div class="x-slider"></div>
|
||||
<div class="size-label-wrapper">
|
||||
<div class="pull-left">
|
||||
<span class="label label-warning x-min-thirty"
|
||||
name="thirtyMinuteMinSize"
|
||||
title="Minimum size for a 30 minute episode">
|
||||
</span>
|
||||
<span class="label label-info x-min-sixty"
|
||||
name="sixtyMinuteMinSize"
|
||||
title="Minimum size for a 60 minute episode">
|
||||
</span>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<span class="label label-warning x-max-thirty"
|
||||
name="thirtyMinuteMaxSize"
|
||||
title="Maximum size for a 30 minute episode">
|
||||
</span>
|
||||
<span class="label label-info x-max-sixty"
|
||||
name="sixtyMinuteMaxSize"
|
||||
title="Maximum size for a 60 minute episode">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
86
src/UI/Settings/Quality/Definition/QualityDefinitionView.js
Normal file
86
src/UI/Settings/Quality/Definition/QualityDefinitionView.js
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
'use strict';
|
||||
|
||||
define(
|
||||
[
|
||||
'marionette',
|
||||
'Mixins/AsModelBoundView',
|
||||
'filesize',
|
||||
'jquery-ui'
|
||||
], function (Marionette, AsModelBoundView, fileSize) {
|
||||
|
||||
var view = Marionette.ItemView.extend({
|
||||
template: 'Settings/Quality/Definition/QualityDefinitionTemplate',
|
||||
className: 'row',
|
||||
|
||||
ui: {
|
||||
title : '.x-title',
|
||||
sizeSlider : '.x-slider',
|
||||
thirtyMinuteMinSize: '.x-min-thirty',
|
||||
sixtyMinuteMinSize : '.x-min-sixty',
|
||||
thirtyMinuteMaxSize: '.x-max-thirty',
|
||||
sixtyMinuteMaxSize : '.x-max-sixty'
|
||||
},
|
||||
|
||||
events: {
|
||||
'change .x-title': '_updateTitle',
|
||||
'slide .x-slider': '_updateSize'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.qualityProfileCollection = options.qualityProfiles;
|
||||
this.filesize = fileSize;
|
||||
},
|
||||
|
||||
onRender: function () {
|
||||
this.ui.sizeSlider.slider({
|
||||
range : true,
|
||||
min : 0,
|
||||
max : 200,
|
||||
values : [ this.model.get('minSize'), this.model.get('maxSize') ],
|
||||
});
|
||||
|
||||
this._changeSize();
|
||||
},
|
||||
|
||||
_updateTitle: function() {
|
||||
this.model.set('title', this.ui.title.val());
|
||||
},
|
||||
|
||||
_updateSize: function (event, ui) {
|
||||
this.model.set('minSize', ui.values[0]);
|
||||
this.model.set('maxSize', ui.values[1]);
|
||||
|
||||
this._changeSize();
|
||||
},
|
||||
|
||||
_changeSize: function () {
|
||||
var minSize = this.model.get('minSize');
|
||||
var maxSize = this.model.get('maxSize');
|
||||
|
||||
{
|
||||
var minBytes = minSize * 1024 * 1024;
|
||||
var minThirty = fileSize(minBytes * 30, 1, false);
|
||||
var minSixty = fileSize(minBytes * 60, 1, false);
|
||||
|
||||
this.ui.thirtyMinuteMinSize.html(minThirty);
|
||||
this.ui.sixtyMinuteMinSize.html(minSixty);
|
||||
}
|
||||
|
||||
{
|
||||
var maxBytes = maxSize * 1024 * 1024;
|
||||
var maxThirty = fileSize(maxBytes * 30, 1, false);
|
||||
var maxSixty = fileSize(maxBytes * 60, 1, false);
|
||||
|
||||
this.ui.thirtyMinuteMaxSize.html(maxThirty);
|
||||
this.ui.sixtyMinuteMaxSize.html(maxSixty);
|
||||
}
|
||||
|
||||
/*if (parseInt(maxSize, 10) === 0) {
|
||||
thirty = 'No Limit';
|
||||
sixty = 'No Limit';
|
||||
}*/
|
||||
}
|
||||
});
|
||||
|
||||
return AsModelBoundView.call(view);
|
||||
});
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
'use strict';
|
||||
define(
|
||||
[
|
||||
'marionette'
|
||||
], function (Marionette) {
|
||||
return Marionette.ItemView.extend({
|
||||
template : 'Settings/Quality/Profile/EditQualityProfileItemViewTemplate'
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<i class="x-moveleft-handle pull-left icon-chevron-left" />
|
||||
<i class="x-drag-handle pull-right icon-resize-vertical advanced-setting" />
|
||||
<i class="x-moveright-handle pull-right icon-chevron-right" />
|
||||
<span>{{name}}</span>
|
||||
|
||||
|
|
@ -29,25 +29,15 @@
|
|||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="offset1 span3">
|
||||
<div class="offset1 span2">
|
||||
<h3>Available</h3>
|
||||
<select multiple="multiple" class="x-available-list">
|
||||
{{#each available}}
|
||||
<option value="{{id}}">{{name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
<ul class="x-available-list">
|
||||
</ul>
|
||||
</div>
|
||||
<div class="span3">
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<h3>Allowed</h3>
|
||||
<select multiple="multiple" class="x-allowed-list" validation-name="allowed">
|
||||
{{#each allowed}}
|
||||
<option value="{{id}}">{{name}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span2">
|
||||
<h3>Allowed</h3>
|
||||
<ul class="x-allowed-list" validation-name="allowed">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,63 +4,113 @@ define(
|
|||
'vent',
|
||||
'marionette',
|
||||
'backbone',
|
||||
'backbone.collectionview',
|
||||
'Settings/Quality/Profile/EditQualityProfileItemView',
|
||||
'Mixins/AsModelBoundView',
|
||||
'Mixins/AsValidatedView',
|
||||
'underscore'
|
||||
], function (vent, Marionette, Backbone, AsModelBoundView, AsValidatedView, _) {
|
||||
], function (vent, Marionette, Backbone, BackboneSortableCollectionView, EditQualityProfileItemView, AsModelBoundView, AsValidatedView, _) {
|
||||
|
||||
var view = Marionette.ItemView.extend({
|
||||
template: 'Settings/Quality/Profile/EditQualityProfileTemplate',
|
||||
|
||||
ui: {
|
||||
cutoff: '.x-cutoff'
|
||||
available: '.x-available-list',
|
||||
allowed : '.x-allowed-list',
|
||||
cutoff : '.x-cutoff'
|
||||
},
|
||||
|
||||
|
||||
events: {
|
||||
'click .x-save' : '_saveQualityProfile',
|
||||
'dblclick .x-available-list': '_moveQuality',
|
||||
'dblclick .x-allowed-list' : '_moveQuality'
|
||||
//'click .x-qualityitem' : '_moveQuality',
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.profileCollection = options.profileCollection;
|
||||
|
||||
this.availableCollection = new Backbone.Collection(this.model.get('available'));
|
||||
this.availableCollection.comparator = function (model) { return -model.get('weight'); };
|
||||
this.availableCollection.sort();
|
||||
|
||||
this.allowedCollection = new Backbone.Collection(this.model.get('allowed').reverse());
|
||||
},
|
||||
|
||||
onRender: function() {
|
||||
var listViewAvailable = new BackboneSortableCollectionView( {
|
||||
el : this.ui.available,
|
||||
modelView : EditQualityProfileItemView,
|
||||
selectable: false,
|
||||
sortable : false,
|
||||
collection: this.availableCollection
|
||||
});
|
||||
listViewAvailable.render();
|
||||
|
||||
var listViewAllowed = new BackboneSortableCollectionView( {
|
||||
el : this.ui.allowed,
|
||||
modelView : EditQualityProfileItemView,
|
||||
selectable: false,
|
||||
sortable : true,
|
||||
sortableOptions : {
|
||||
handle: ".x-drag-handle"
|
||||
},
|
||||
collection : this.allowedCollection
|
||||
} );
|
||||
listViewAllowed.render();
|
||||
|
||||
this.listenTo(listViewAvailable, "doubleClick", this._moveQuality);
|
||||
this.listenTo(listViewAllowed, "doubleClick", this._moveQuality);
|
||||
this.listenTo(listViewAllowed, "sortStop", this._updateModel);
|
||||
},
|
||||
|
||||
_moveQuality: function (event) {
|
||||
|
||||
var quality;
|
||||
var qualityId = event.target.value;
|
||||
var availableCollection = new Backbone.Collection(this.model.get('available'));
|
||||
availableCollection.comparator = function (model) {
|
||||
return model.get('weight');
|
||||
};
|
||||
|
||||
var allowedCollection = new Backbone.Collection(this.model.get('allowed'));
|
||||
allowedCollection.comparator = function (model) {
|
||||
return model.get('weight');
|
||||
};
|
||||
|
||||
if (availableCollection.get(qualityId)) {
|
||||
quality = availableCollection.get(qualityId);
|
||||
availableCollection.remove(quality);
|
||||
allowedCollection.add(quality);
|
||||
var qualityId = event.get('id');
|
||||
|
||||
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 (allowedCollection.get(qualityId)) {
|
||||
quality = allowedCollection.get(qualityId);
|
||||
else if (this.allowedCollection.get(qualityId)) {
|
||||
quality = this.allowedCollection.get(qualityId);
|
||||
|
||||
allowedCollection.remove(quality);
|
||||
availableCollection.add(quality);
|
||||
this.allowedCollection.remove(quality);
|
||||
this.availableCollection.add(quality);
|
||||
}
|
||||
else {
|
||||
throw 'couldnt find quality id ' + qualityId;
|
||||
}
|
||||
|
||||
this.model.set('available', availableCollection.toJSON());
|
||||
this.model.set('allowed', allowedCollection.toJSON());
|
||||
|
||||
|
||||
this._updateModel();
|
||||
},
|
||||
|
||||
_updateModel: function() {
|
||||
this.model.set('available', this.availableCollection.toJSON().reverse());
|
||||
this.model.set('allowed', this.allowedCollection.toJSON().reverse());
|
||||
|
||||
this.render();
|
||||
},
|
||||
|
||||
|
||||
_saveQualityProfile: function () {
|
||||
var self = this;
|
||||
var cutoff = _.findWhere(this.model.get('allowed'), { id: parseInt(this.ui.cutoff.val(), 10)});
|
||||
|
|
|
|||
|
|
@ -5,27 +5,27 @@ define(
|
|||
'marionette',
|
||||
'Quality/QualityProfileCollection',
|
||||
'Settings/Quality/Profile/QualityProfileCollectionView',
|
||||
'Quality/QualitySizeCollection',
|
||||
'Settings/Quality/Size/QualitySizeCollectionView'
|
||||
], function (Marionette, QualityProfileCollection, QualityProfileCollectionView, QualitySizeCollection, QualitySizeCollectionView) {
|
||||
'Quality/QualityDefinitionCollection',
|
||||
'Settings/Quality/Definition/QualityDefinitionCollectionView'
|
||||
], function (Marionette, QualityProfileCollection, QualityProfileCollectionView, QualityDefinitionCollection, QualityDefinitionCollectionView) {
|
||||
return Marionette.Layout.extend({
|
||||
template: 'Settings/Quality/QualityLayoutTemplate',
|
||||
|
||||
regions: {
|
||||
qualityProfile : '#quality-profile',
|
||||
qualitySize : '#quality-size'
|
||||
qualityProfile : '#quality-profile',
|
||||
qualityDefinition : '#quality-definition'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.settings = options.settings;
|
||||
QualityProfileCollection.fetch();
|
||||
this.qualitySizeCollection = new QualitySizeCollection();
|
||||
this.qualitySizeCollection.fetch();
|
||||
this.qualityDefinitionCollection = new QualityDefinitionCollection();
|
||||
this.qualityDefinitionCollection.fetch();
|
||||
},
|
||||
|
||||
onShow: function () {
|
||||
this.qualityProfile.show(new QualityProfileCollectionView({collection: QualityProfileCollection}));
|
||||
this.qualitySize.show(new QualitySizeCollectionView({collection: this.qualitySizeCollection}));
|
||||
this.qualityDefinition.show(new QualityDefinitionCollectionView({collection: this.qualityDefinitionCollection}));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@
|
|||
<br/>
|
||||
|
||||
<div class="row advanced-setting">
|
||||
<div class="span12" id="quality-size"/>
|
||||
<div class="span12" id="quality-definition"/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
<fieldset>
|
||||
<legend>Quality Size Limits</legend>
|
||||
<ul class="quality-sizes"/>
|
||||
</fieldset>
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
define(['marionette', 'Settings/Quality/Size/QualitySizeView'], function (Marionette, QualitySizeView) {
|
||||
return Marionette.CompositeView.extend({
|
||||
itemView : QualitySizeView,
|
||||
itemViewContainer: '.quality-sizes',
|
||||
template : 'Settings/Quality/Size/QualitySizeCollectionTemplate'
|
||||
});
|
||||
});
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
<div class="quality-size-item">
|
||||
<h3 class="center-block">{{name}}</h3>
|
||||
<div class="size">
|
||||
<div class="size-value-wrapper">
|
||||
<div>
|
||||
<span class="label label-large label-warning x-size-thirty"
|
||||
name="thirtyMinuteSize"
|
||||
title="Maximum size for a 30 minute episode">
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="label label-large label-info x-size-sixty"
|
||||
name="sixtyMinuteSize"
|
||||
title="Maximum size for a 60 minute episode">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<input type="text" name="maxSize" class="knob x-knob" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
define(
|
||||
[
|
||||
'marionette',
|
||||
'Mixins/AsModelBoundView',
|
||||
'filesize',
|
||||
'jquery.knob'
|
||||
], function (Marionette, AsModelBoundView, fileSize) {
|
||||
|
||||
var view = Marionette.ItemView.extend({
|
||||
template: 'Settings/Quality/Size/QualitySizeTemplate',
|
||||
tagName : 'li',
|
||||
|
||||
ui: {
|
||||
knob : '.x-knob',
|
||||
thirtyMinuteSize: '.x-size-thirty',
|
||||
sixtyMinuteSize : '.x-size-sixty'
|
||||
},
|
||||
|
||||
events: {
|
||||
'change .x-knob': '_changeMaxSize'
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.qualityProfileCollection = options.qualityProfiles;
|
||||
this.filesize = fileSize;
|
||||
},
|
||||
|
||||
onRender: function () {
|
||||
this.ui.knob.knob({
|
||||
min : 0,
|
||||
max : 200,
|
||||
step : 1,
|
||||
cursor : 25,
|
||||
width : 150,
|
||||
stopper : true,
|
||||
displayInput: false
|
||||
});
|
||||
|
||||
this._changeMaxSize();
|
||||
},
|
||||
|
||||
_changeMaxSize: function () {
|
||||
var maxSize = this.model.get('maxSize');
|
||||
var bytes = maxSize * 1024 * 1024;
|
||||
var thirty = fileSize(bytes * 30, 1, false);
|
||||
var sixty = fileSize(bytes * 60, 1, false);
|
||||
|
||||
if (parseInt(maxSize, 10) === 0) {
|
||||
thirty = 'No Limit';
|
||||
sixty = 'No Limit';
|
||||
}
|
||||
|
||||
this.ui.thirtyMinuteSize.html(thirty);
|
||||
this.ui.sixtyMinuteSize.html(sixty);
|
||||
}
|
||||
});
|
||||
|
||||
return AsModelBoundView.call(view);
|
||||
});
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
@import "../../Shared/Styles/card";
|
||||
@import "../../Content/Bootstrap/mixins";
|
||||
|
||||
.quality-profiles, .quality-sizes {
|
||||
.quality-profiles {
|
||||
li {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
|
|
@ -35,41 +36,121 @@
|
|||
}
|
||||
}
|
||||
|
||||
.quality-size-item {
|
||||
ul.x-available-list, ul.x-allowed-list {
|
||||
min-height: 100px;
|
||||
|
||||
.card;
|
||||
text-align: center;
|
||||
|
||||
width: 200px;
|
||||
height: 210px;
|
||||
padding: 10px 15px;
|
||||
|
||||
h3 {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.size {
|
||||
position: relative;
|
||||
height: 100px;
|
||||
margin: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.knob {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.size-value-wrapper {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
width: 100%;
|
||||
|
||||
div {
|
||||
margin-top: 2px;
|
||||
.user-select(none);
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
|
||||
li {
|
||||
margin: 2px;
|
||||
padding: 2px;
|
||||
line-height: 20px;
|
||||
border: 1px solid #AAA;
|
||||
border-radius: 4px; /* may need vendor varients */
|
||||
background: #FAFAFA;
|
||||
|
||||
&:hover {
|
||||
border-color: #888;
|
||||
background: #EEE;
|
||||
}
|
||||
|
||||
.x-drag-handle, .x-moveleft-handle, .x-moveright-handle {
|
||||
opacity: 0.0;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#quality-size {
|
||||
overflow: hidden;
|
||||
ul.x-available-list li {
|
||||
.x-moveright-handle {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.x-drag-handle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover .x-moveright-handle {
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
ul.x-allowed-list li {
|
||||
.x-drag-handle, .x-moveleft-handle {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.x-drag-handle:hover {
|
||||
opacity: 1.0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:hover .x-moveleft-handle {
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
#quality-definition-list {
|
||||
|
||||
.x-header .row {
|
||||
font-weight: bold;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.x-rows .row {
|
||||
line-height: 30px;
|
||||
border-top: 1px solid #ddd;
|
||||
vertical-align: middle;
|
||||
padding: 5px;
|
||||
|
||||
input {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.size-label-wrapper {
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.label {
|
||||
min-width: 70px;
|
||||
text-align: center;
|
||||
margin: 0px 1px;
|
||||
padding: 1px 4px;
|
||||
}
|
||||
|
||||
.ui-slider {
|
||||
position: relative;
|
||||
text-align: left;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ccc;
|
||||
height: 8px;
|
||||
|
||||
.ui-slider-range {
|
||||
position: absolute;
|
||||
display: block;
|
||||
background-color: #ddd;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ui-slider-handle {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
width: 6px;
|
||||
height: 12px;
|
||||
cursor: default;
|
||||
background-color: #ccc;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 3px;
|
||||
top: -3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
'use strict';
|
||||
define(
|
||||
[
|
||||
'jquery',
|
||||
'vent',
|
||||
'marionette',
|
||||
'backbone',
|
||||
|
|
@ -17,7 +18,8 @@ define(
|
|||
'Settings/General/GeneralView',
|
||||
'Shared/LoadingView',
|
||||
'Config'
|
||||
], function (vent,
|
||||
], function ($,
|
||||
vent,
|
||||
Marionette,
|
||||
Backbone,
|
||||
SettingsModel,
|
||||
|
|
@ -196,7 +198,7 @@ define(
|
|||
this.ui.advancedSettings.prop('checked', checked);
|
||||
|
||||
if (checked) {
|
||||
this.$el.addClass('show-advanced-settings');
|
||||
$('body').addClass('show-advanced-settings');
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -205,11 +207,11 @@ define(
|
|||
Config.setValue('advancedSettings', checked);
|
||||
|
||||
if (checked) {
|
||||
this.$el.addClass('show-advanced-settings');
|
||||
$('body').addClass('show-advanced-settings');
|
||||
}
|
||||
|
||||
else {
|
||||
this.$el.removeClass('show-advanced-settings');
|
||||
$('body').removeClass('show-advanced-settings');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,29 +2,31 @@
|
|||
require.config({
|
||||
|
||||
paths: {
|
||||
'backbone' : 'JsLibraries/backbone',
|
||||
'moment' : 'JsLibraries/moment',
|
||||
'filesize' : 'JsLibraries/filesize',
|
||||
'handlebars' : 'JsLibraries/handlebars.runtime',
|
||||
'handlebars.helpers' : 'JsLibraries/handlebars.helpers',
|
||||
'bootstrap' : 'JsLibraries/bootstrap',
|
||||
'backbone.deepmodel' : 'JsLibraries/backbone.deep.model',
|
||||
'backbone.pageable' : 'JsLibraries/backbone.pageable',
|
||||
'backbone.validation' : 'JsLibraries/backbone.validation',
|
||||
'backbone.modelbinder': 'JsLibraries/backbone.modelbinder',
|
||||
'backgrid' : 'JsLibraries/backbone.backgrid',
|
||||
'backgrid.paginator' : 'JsLibraries/backbone.backgrid.paginator',
|
||||
'backgrid.selectall' : 'JsLibraries/backbone.backgrid.selectall',
|
||||
'fullcalendar' : 'JsLibraries/fullcalendar',
|
||||
'backstrech' : 'JsLibraries/jquery.backstretch',
|
||||
'underscore' : 'JsLibraries/lodash.underscore',
|
||||
'marionette' : 'JsLibraries/backbone.marionette',
|
||||
'signalR' : 'JsLibraries/jquery.signalR',
|
||||
'jquery.knob' : 'JsLibraries/jquery.knob',
|
||||
'jquery.dotdotdot' : 'JsLibraries/jquery.dotdotdot',
|
||||
'messenger' : 'JsLibraries/messenger',
|
||||
'jquery' : 'JsLibraries/jquery',
|
||||
'libs' : 'JsLibraries/',
|
||||
'backbone' : 'JsLibraries/backbone',
|
||||
'moment' : 'JsLibraries/moment',
|
||||
'filesize' : 'JsLibraries/filesize',
|
||||
'handlebars' : 'JsLibraries/handlebars.runtime',
|
||||
'handlebars.helpers' : 'JsLibraries/handlebars.helpers',
|
||||
'bootstrap' : 'JsLibraries/bootstrap',
|
||||
'backbone.deepmodel' : 'JsLibraries/backbone.deep.model',
|
||||
'backbone.pageable' : 'JsLibraries/backbone.pageable',
|
||||
'backbone.validation' : 'JsLibraries/backbone.validation',
|
||||
'backbone.modelbinder' : 'JsLibraries/backbone.modelbinder',
|
||||
'backbone.collectionview' : 'JsLibraries/backbone.collectionview',
|
||||
'backgrid' : 'JsLibraries/backbone.backgrid',
|
||||
'backgrid.paginator' : 'JsLibraries/backbone.backgrid.paginator',
|
||||
'backgrid.selectall' : 'JsLibraries/backbone.backgrid.selectall',
|
||||
'fullcalendar' : 'JsLibraries/fullcalendar',
|
||||
'backstrech' : 'JsLibraries/jquery.backstretch',
|
||||
'underscore' : 'JsLibraries/lodash.underscore',
|
||||
'marionette' : 'JsLibraries/backbone.marionette',
|
||||
'signalR' : 'JsLibraries/jquery.signalR',
|
||||
'jquery-ui' : 'JsLibraries/jquery-ui',
|
||||
'jquery.knob' : 'JsLibraries/jquery.knob',
|
||||
'jquery.dotdotdot' : 'JsLibraries/jquery.dotdotdot',
|
||||
'messenger' : 'JsLibraries/messenger',
|
||||
'jquery' : 'JsLibraries/jquery',
|
||||
'libs' : 'JsLibraries/',
|
||||
|
||||
'api': 'Require/require.api'
|
||||
},
|
||||
|
|
@ -105,6 +107,12 @@ require.config({
|
|||
|
||||
}
|
||||
},
|
||||
'jquery-ui' : {
|
||||
deps:
|
||||
[
|
||||
'jquery'
|
||||
]
|
||||
},
|
||||
'jquery.knob' : {
|
||||
deps:
|
||||
[
|
||||
|
|
@ -143,6 +151,14 @@ require.config({
|
|||
'backbone'
|
||||
]
|
||||
},
|
||||
'backbone.collectionview': {
|
||||
deps:
|
||||
[
|
||||
'backbone',
|
||||
'jquery-ui'
|
||||
],
|
||||
exports: 'Backbone.CollectionView'
|
||||
},
|
||||
backgrid : {
|
||||
deps:
|
||||
[
|
||||
|
|
|
|||
Loading…
Reference in a new issue