mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-19 21:13:28 -07:00
New: Added option to filter Release Profile to a specific indexer
This commit is contained in:
parent
06c79b283c
commit
a035a78a2b
30 changed files with 309 additions and 66 deletions
|
@ -2,6 +2,7 @@ using System.Collections.Generic;
|
|||
using FluentValidation;
|
||||
using Lidarr.Http;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
|
||||
namespace Lidarr.Api.V1.Profiles.Release
|
||||
|
@ -9,10 +10,12 @@ namespace Lidarr.Api.V1.Profiles.Release
|
|||
public class ReleaseProfileModule : LidarrRestModule<ReleaseProfileResource>
|
||||
{
|
||||
private readonly IReleaseProfileService _releaseProfileService;
|
||||
private readonly IIndexerFactory _indexerFactory;
|
||||
|
||||
public ReleaseProfileModule(IReleaseProfileService releaseProfileService)
|
||||
public ReleaseProfileModule(IReleaseProfileService releaseProfileService, IIndexerFactory indexerFactory)
|
||||
{
|
||||
_releaseProfileService = releaseProfileService;
|
||||
_indexerFactory = indexerFactory;
|
||||
|
||||
GetResourceById = GetById;
|
||||
GetResourceAll = GetAll;
|
||||
|
@ -26,6 +29,11 @@ namespace Lidarr.Api.V1.Profiles.Release
|
|||
{
|
||||
context.AddFailure("Either 'Must contain' or 'Must not contain' is required");
|
||||
}
|
||||
|
||||
if (restriction.Enabled && restriction.IndexerId != 0 && !_indexerFactory.Exists(restriction.IndexerId))
|
||||
{
|
||||
context.AddFailure(nameof(ReleaseProfile.IndexerId), "Indexer does not exist");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -7,10 +7,12 @@ namespace Lidarr.Api.V1.Profiles.Release
|
|||
{
|
||||
public class ReleaseProfileResource : RestResource
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public string Required { get; set; }
|
||||
public string Ignored { get; set; }
|
||||
public List<KeyValuePair<string, int>> Preferred { get; set; }
|
||||
public bool IncludePreferredWhenRenaming { get; set; }
|
||||
public int IndexerId { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
|
||||
public ReleaseProfileResource()
|
||||
|
@ -32,10 +34,12 @@ namespace Lidarr.Api.V1.Profiles.Release
|
|||
{
|
||||
Id = model.Id,
|
||||
|
||||
Enabled = model.Enabled,
|
||||
Required = model.Required,
|
||||
Ignored = model.Ignored,
|
||||
Preferred = model.Preferred,
|
||||
IncludePreferredWhenRenaming = model.IncludePreferredWhenRenaming,
|
||||
IndexerId = model.IndexerId,
|
||||
Tags = new HashSet<int>(model.Tags)
|
||||
};
|
||||
}
|
||||
|
@ -51,10 +55,12 @@ namespace Lidarr.Api.V1.Profiles.Release
|
|||
{
|
||||
Id = resource.Id,
|
||||
|
||||
Enabled = resource.Enabled,
|
||||
Required = resource.Required,
|
||||
Ignored = resource.Ignored,
|
||||
Preferred = resource.Preferred,
|
||||
IncludePreferredWhenRenaming = resource.IncludePreferredWhenRenaming,
|
||||
IndexerId = resource.IndexerId,
|
||||
Tags = new HashSet<int>(resource.Tags)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
private void GivenRestictions(string required, string ignored)
|
||||
{
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Setup(s => s.EnabledForTags(It.IsAny<HashSet<int>>(), It.IsAny<int>()))
|
||||
.Returns(new List<ReleaseProfile>
|
||||
{
|
||||
new ReleaseProfile()
|
||||
|
@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
public void should_be_true_when_restrictions_are_empty()
|
||||
{
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Setup(s => s.EnabledForTags(It.IsAny<HashSet<int>>(), It.IsAny<int>()))
|
||||
.Returns(new List<ReleaseProfile>());
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteAlbum, null).Accepted.Should().BeTrue();
|
||||
|
@ -117,7 +117,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
_remoteAlbum.Release.Title = "[ www.Speed.cd ] - Katy Perry - Witness (2017) MP3 [320 kbps] ";
|
||||
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Setup(s => s.EnabledForTags(It.IsAny<HashSet<int>>(), It.IsAny<int>()))
|
||||
.Returns(new List<ReleaseProfile>
|
||||
{
|
||||
new ReleaseProfile { Required = "320", Ignored = "www.Speed.cd" }
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
});
|
||||
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Setup(s => s.EnabledForTags(It.IsAny<HashSet<int>>(), It.IsAny<int>()))
|
||||
.Returns(_releaseProfiles);
|
||||
}
|
||||
|
||||
|
@ -51,10 +51,10 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
public void should_return_0_when_there_are_no_release_profiles()
|
||||
{
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Setup(s => s.EnabledForTags(It.IsAny<HashSet<int>>(), It.IsAny<int>()))
|
||||
.Returns(new List<ReleaseProfile>());
|
||||
|
||||
Subject.Calculate(_artist, _title).Should().Be(0);
|
||||
Subject.Calculate(_artist, _title, 0).Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -62,7 +62,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
{
|
||||
GivenMatchingTerms();
|
||||
|
||||
Subject.Calculate(_artist, _title).Should().Be(0);
|
||||
Subject.Calculate(_artist, _title, 0).Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -70,7 +70,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
{
|
||||
GivenMatchingTerms("24bit");
|
||||
|
||||
Subject.Calculate(_artist, _title).Should().Be(5);
|
||||
Subject.Calculate(_artist, _title, 0).Should().Be(5);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
{
|
||||
GivenMatchingTerms("16bit");
|
||||
|
||||
Subject.Calculate(_artist, _title).Should().Be(-10);
|
||||
Subject.Calculate(_artist, _title, 0).Should().Be(-10);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -88,7 +88,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
|
||||
GivenMatchingTerms("24bit");
|
||||
|
||||
Subject.Calculate(_artist, _title).Should().Be(10);
|
||||
Subject.Calculate(_artist, _title, 0).Should().Be(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
private void GivenReleaseProfile()
|
||||
{
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Setup(s => s.EnabledForTags(It.IsAny<HashSet<int>>(), It.IsAny<int>()))
|
||||
.Returns(_releaseProfiles);
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
|||
public void should_return_empty_list_when_there_are_no_release_profiles()
|
||||
{
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Setup(s => s.EnabledForTags(It.IsAny<HashSet<int>>(), It.IsAny<int>()))
|
||||
.Returns(new List<ReleaseProfile>());
|
||||
|
||||
Subject.GetMatchingPreferredWords(_artist, _title).Should().BeEmpty();
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace NzbDrone.Core.Datastore
|
|||
{
|
||||
IEnumerable<TModel> All();
|
||||
int Count();
|
||||
TModel Find(int id);
|
||||
TModel Get(int id);
|
||||
TModel Insert(TModel model);
|
||||
TModel Update(TModel model);
|
||||
|
@ -87,10 +88,17 @@ namespace NzbDrone.Core.Datastore
|
|||
return Query(Builder());
|
||||
}
|
||||
|
||||
public TModel Get(int id)
|
||||
public TModel Find(int id)
|
||||
{
|
||||
var model = Query(x => x.Id == id).FirstOrDefault();
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public TModel Get(int id)
|
||||
{
|
||||
var model = Find(id);
|
||||
|
||||
if (model == null)
|
||||
{
|
||||
throw new ModelNotFoundException(typeof(TModel), id);
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(041)]
|
||||
public class add_indexer_and_enabled_to_release_profiles : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("ReleaseProfiles").AddColumn("Enabled").AsBoolean().WithDefaultValue(true);
|
||||
Alter.Table("ReleaseProfiles").AddColumn("IndexerId").AsInt32().WithDefaultValue(0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -58,7 +58,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
|
||||
if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
|
||||
currentQualities,
|
||||
_preferredWordServiceCalculator.Calculate(subject.Artist, trackFiles[0].GetSceneOrFileName()),
|
||||
_preferredWordServiceCalculator.Calculate(subject.Artist, trackFiles[0].GetSceneOrFileName(), subject.Release.IndexerId),
|
||||
subject.ParsedAlbumInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
{
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
|
||||
_logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0}", remoteAlbum.ParsedAlbumInfo.Quality);
|
||||
|
||||
var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Artist, queueItem.Title);
|
||||
var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Artist, queueItem.Title, subject.Release?.IndexerId ?? 0);
|
||||
|
||||
if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
|
||||
new List<QualityModel> { remoteAlbum.ParsedAlbumInfo.Quality },
|
||||
|
|
|
@ -30,10 +30,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
_logger.Debug("Checking if release meets restrictions: {0}", subject);
|
||||
|
||||
var title = subject.Release.Title;
|
||||
var restrictions = _releaseProfileService.AllForTags(subject.Artist.Tags);
|
||||
var releaseProfiles = _releaseProfileService.EnabledForTags(subject.Artist.Tags, subject.Release.IndexerId);
|
||||
|
||||
var required = restrictions.Where(r => r.Required.IsNotNullOrWhiteSpace());
|
||||
var ignored = restrictions.Where(r => r.Ignored.IsNotNullOrWhiteSpace());
|
||||
var required = releaseProfiles.Where(r => r.Required.IsNotNullOrWhiteSpace());
|
||||
var ignored = releaseProfiles.Where(r => r.Ignored.IsNotNullOrWhiteSpace());
|
||||
|
||||
foreach (var r in required)
|
||||
{
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
|
||||
// The artist will be the same as the one in history since it's the same album.
|
||||
// Instead of fetching the artist from the DB reuse the known artist.
|
||||
var preferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Artist, mostRecent.SourceTitle);
|
||||
var preferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Artist, mostRecent.SourceTitle, subject.Release?.IndexerId ?? 0);
|
||||
|
||||
var cutoffUnmet = _upgradableSpecification.CutoffNotMet(
|
||||
subject.Artist.QualityProfile,
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
|
||||
if (!_upgradableSpecification.IsUpgradable(subject.Artist.QualityProfile,
|
||||
currentQualities,
|
||||
_preferredWordServiceCalculator.Calculate(subject.Artist, trackFiles[0].GetSceneOrFileName()),
|
||||
_preferredWordServiceCalculator.Calculate(subject.Artist, trackFiles[0].GetSceneOrFileName(), subject.Release?.IndexerId ?? 0),
|
||||
subject.ParsedAlbumInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
{
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace NzbDrone.Core.Download.Aggregation.Aggregators
|
|||
|
||||
public RemoteAlbum Aggregate(RemoteAlbum remoteAlbum)
|
||||
{
|
||||
remoteAlbum.PreferredWordScore = _preferredWordServiceCalculator.Calculate(remoteAlbum.Artist, remoteAlbum.Release.Title);
|
||||
remoteAlbum.PreferredWordScore = _preferredWordServiceCalculator.Calculate(remoteAlbum.Artist, remoteAlbum.Release.Title, remoteAlbum.Release.IndexerId);
|
||||
|
||||
return remoteAlbum;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace NzbDrone.Core.Profiles.Releases
|
|||
{
|
||||
public interface IPreferredWordService
|
||||
{
|
||||
int Calculate(Artist artist, string title);
|
||||
int Calculate(Artist artist, string title, int indexerId);
|
||||
List<string> GetMatchingPreferredWords(Artist artist, string title);
|
||||
}
|
||||
|
||||
|
@ -25,11 +25,11 @@ namespace NzbDrone.Core.Profiles.Releases
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public int Calculate(Artist series, string title)
|
||||
public int Calculate(Artist artist, string title, int indexerId)
|
||||
{
|
||||
_logger.Trace("Calculating preferred word score for '{0}'", title);
|
||||
|
||||
var releaseProfiles = _releaseProfileService.AllForTags(series.Tags);
|
||||
var releaseProfiles = _releaseProfileService.EnabledForTags(artist.Tags, indexerId);
|
||||
var matchingPairs = new List<KeyValuePair<string, int>>();
|
||||
|
||||
foreach (var releaseProfile in releaseProfiles)
|
||||
|
@ -54,7 +54,7 @@ namespace NzbDrone.Core.Profiles.Releases
|
|||
|
||||
public List<string> GetMatchingPreferredWords(Artist artist, string title)
|
||||
{
|
||||
var releaseProfiles = _releaseProfileService.AllForTags(artist.Tags);
|
||||
var releaseProfiles = _releaseProfileService.EnabledForTags(artist.Tags, 0);
|
||||
var matchingPairs = new List<KeyValuePair<string, int>>();
|
||||
|
||||
_logger.Trace("Calculating preferred word score for '{0}'", title);
|
||||
|
|
|
@ -5,17 +5,21 @@ namespace NzbDrone.Core.Profiles.Releases
|
|||
{
|
||||
public class ReleaseProfile : ModelBase
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public string Required { get; set; }
|
||||
public string Ignored { get; set; }
|
||||
public List<KeyValuePair<string, int>> Preferred { get; set; }
|
||||
public bool IncludePreferredWhenRenaming { get; set; }
|
||||
public int IndexerId { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
|
||||
public ReleaseProfile()
|
||||
{
|
||||
Enabled = true;
|
||||
Preferred = new List<KeyValuePair<string, int>>();
|
||||
IncludePreferredWhenRenaming = true;
|
||||
Tags = new HashSet<int>();
|
||||
IndexerId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ namespace NzbDrone.Core.Profiles.Releases
|
|||
List<ReleaseProfile> All();
|
||||
List<ReleaseProfile> AllForTag(int tagId);
|
||||
List<ReleaseProfile> AllForTags(HashSet<int> tagIds);
|
||||
List<ReleaseProfile> EnabledForTags(HashSet<int> tagIds, int indexerId);
|
||||
ReleaseProfile Get(int id);
|
||||
void Delete(int id);
|
||||
ReleaseProfile Add(ReleaseProfile restriction);
|
||||
|
@ -48,6 +49,13 @@ namespace NzbDrone.Core.Profiles.Releases
|
|||
return _repo.All().Where(r => r.Tags.Intersect(tagIds).Any() || r.Tags.Empty()).ToList();
|
||||
}
|
||||
|
||||
public List<ReleaseProfile> EnabledForTags(HashSet<int> tagIds, int indexerId)
|
||||
{
|
||||
return AllForTags(tagIds)
|
||||
.Where(r => r.Enabled)
|
||||
.Where(r => r.IndexerId == indexerId || r.IndexerId == 0).ToList();
|
||||
}
|
||||
|
||||
public ReleaseProfile Get(int id)
|
||||
{
|
||||
return _repo.Get(id);
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace NzbDrone.Core.ThingiProvider
|
|||
{
|
||||
List<TProviderDefinition> All();
|
||||
List<TProvider> GetAvailableProviders();
|
||||
bool Exists(int id);
|
||||
TProviderDefinition Get(int id);
|
||||
TProviderDefinition Create(TProviderDefinition definition);
|
||||
void Update(TProviderDefinition definition);
|
||||
|
|
|
@ -91,6 +91,11 @@ namespace NzbDrone.Core.ThingiProvider
|
|||
return Active().Select(GetInstance).ToList();
|
||||
}
|
||||
|
||||
public bool Exists(int id)
|
||||
{
|
||||
return _providerRepository.Find(id) != null;
|
||||
}
|
||||
|
||||
public TProviderDefinition Get(int id)
|
||||
{
|
||||
return _providerRepository.Get(id);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue