Preferred words
New: Ability to prefer releases based on terms in release title
This commit is contained in:
parent
ac709c39ab
commit
853f25468c
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.SignalR;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ using NzbDrone.Core.MediaFiles.Events;
|
|||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.SignalR;
|
||||
using Sonarr.Http;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using Sonarr.Http.REST;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using Sonarr.Http.REST;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.SignalR;
|
||||
|
||||
namespace NzbDrone.Api.Episodes
|
||||
|
|
|
@ -4,6 +4,7 @@ using NzbDrone.Api.Series;
|
|||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
|
|
@ -7,6 +7,7 @@ using Sonarr.Http.Extensions;
|
|||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.History;
|
||||
using Sonarr.Http;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using Sonarr.Http;
|
||||
using Sonarr.Http.Mapping;
|
||||
|
||||
|
@ -9,12 +9,12 @@ namespace NzbDrone.Api.Restrictions
|
|||
{
|
||||
public class RestrictionModule : SonarrRestModule<RestrictionResource>
|
||||
{
|
||||
private readonly IRestrictionService _restrictionService;
|
||||
private readonly IReleaseProfileService _releaseProfileService;
|
||||
|
||||
|
||||
public RestrictionModule(IRestrictionService restrictionService)
|
||||
public RestrictionModule(IReleaseProfileService releaseProfileService)
|
||||
{
|
||||
_restrictionService = restrictionService;
|
||||
_releaseProfileService = releaseProfileService;
|
||||
|
||||
GetResourceById = GetRestriction;
|
||||
GetResourceAll = GetAllRestrictions;
|
||||
|
@ -35,27 +35,27 @@ namespace NzbDrone.Api.Restrictions
|
|||
|
||||
private RestrictionResource GetRestriction(int id)
|
||||
{
|
||||
return _restrictionService.Get(id).ToResource();
|
||||
return _releaseProfileService.Get(id).ToResource();
|
||||
}
|
||||
|
||||
private List<RestrictionResource> GetAllRestrictions()
|
||||
{
|
||||
return _restrictionService.All().ToResource();
|
||||
return _releaseProfileService.All().ToResource();
|
||||
}
|
||||
|
||||
private int CreateRestriction(RestrictionResource resource)
|
||||
{
|
||||
return _restrictionService.Add(resource.ToModel()).Id;
|
||||
return _releaseProfileService.Add(resource.ToModel()).Id;
|
||||
}
|
||||
|
||||
private void UpdateRestriction(RestrictionResource resource)
|
||||
{
|
||||
_restrictionService.Update(resource.ToModel());
|
||||
_releaseProfileService.Update(resource.ToModel());
|
||||
}
|
||||
|
||||
private void DeleteRestriction(int id)
|
||||
{
|
||||
_restrictionService.Delete(id);
|
||||
_releaseProfileService.Delete(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using Sonarr.Http.REST;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
|
||||
namespace NzbDrone.Api.Restrictions
|
||||
{
|
||||
public class RestrictionResource : RestResource
|
||||
{
|
||||
public string Required { get; set; }
|
||||
public string Preferred { get; set; }
|
||||
public string Ignored { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
|
||||
|
@ -20,7 +19,7 @@ namespace NzbDrone.Api.Restrictions
|
|||
|
||||
public static class RestrictionResourceMapper
|
||||
{
|
||||
public static RestrictionResource ToResource(this Restriction model)
|
||||
public static RestrictionResource ToResource(this ReleaseProfile model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
|
@ -29,28 +28,26 @@ namespace NzbDrone.Api.Restrictions
|
|||
Id = model.Id,
|
||||
|
||||
Required = model.Required,
|
||||
Preferred = model.Preferred,
|
||||
Ignored = model.Ignored,
|
||||
Tags = new HashSet<int>(model.Tags)
|
||||
};
|
||||
}
|
||||
|
||||
public static Restriction ToModel(this RestrictionResource resource)
|
||||
public static ReleaseProfile ToModel(this RestrictionResource resource)
|
||||
{
|
||||
if (resource == null) return null;
|
||||
|
||||
return new Restriction
|
||||
return new ReleaseProfile
|
||||
{
|
||||
Id = resource.Id,
|
||||
|
||||
Required = resource.Required,
|
||||
Preferred = resource.Preferred,
|
||||
Ignored = resource.Ignored,
|
||||
Tags = new HashSet<int>(resource.Tags)
|
||||
};
|
||||
}
|
||||
|
||||
public static List<RestrictionResource> ToResource(this IEnumerable<Restriction> models)
|
||||
public static List<RestrictionResource> ToResource(this IEnumerable<ReleaseProfile> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Linq;
|
|||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.SignalR;
|
||||
using Sonarr.Http;
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Linq;
|
|||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.SignalR;
|
||||
using Sonarr.Http;
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
using FluentAssertions;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
|
@ -13,6 +13,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
[TestFixture]
|
||||
public class CutoffSpecificationFixture : CoreTest<UpgradableSpecification>
|
||||
{
|
||||
private static readonly int NoPreferredWordScore = 0;
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_current_episode_is_less_than_cutoff()
|
||||
{
|
||||
|
@ -27,7 +29,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Languages = LanguageFixture.GetDefaultLanguages(Language.English),
|
||||
Cutoff = Language.English
|
||||
},
|
||||
new QualityModel(Quality.DVD, new Revision(version: 2)), Language.English).Should().BeTrue();
|
||||
new QualityModel(Quality.DVD, new Revision(version: 2)),
|
||||
Language.English,
|
||||
NoPreferredWordScore).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -44,7 +48,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Languages = LanguageFixture.GetDefaultLanguages(Language.English),
|
||||
Cutoff = Language.English
|
||||
},
|
||||
new QualityModel(Quality.HDTV720p, new Revision(version: 2)), Language.English).Should().BeFalse();
|
||||
new QualityModel(Quality.HDTV720p, new Revision(version: 2)),
|
||||
Language.English,
|
||||
NoPreferredWordScore).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -61,7 +67,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Languages = LanguageFixture.GetDefaultLanguages(Language.English),
|
||||
Cutoff = Language.English
|
||||
},
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2)), Language.English).Should().BeFalse();
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2)),
|
||||
Language.English,
|
||||
NoPreferredWordScore).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -80,7 +88,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
},
|
||||
new QualityModel(Quality.HDTV720p, new Revision(version: 1)),
|
||||
Language.English,
|
||||
new QualityModel(Quality.HDTV720p, new Revision(version: 2))).Should().BeTrue();
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(Quality.HDTV720p, new Revision(version: 2)),
|
||||
NoPreferredWordScore).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -99,13 +109,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
},
|
||||
new QualityModel(Quality.HDTV720p, new Revision(version: 2)),
|
||||
Language.English,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2))).Should().BeFalse();
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2)),
|
||||
NoPreferredWordScore).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_quality_cutoff_is_met_and_quality_is_higher_but_language_is_not_met()
|
||||
{
|
||||
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
|
@ -122,13 +133,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
_langProfile,
|
||||
new QualityModel(Quality.HDTV720p, new Revision(version: 2)),
|
||||
Language.English,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2))).Should().BeTrue();
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2)),
|
||||
NoPreferredWordScore).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_cutoff_is_met_and_quality_is_higher_and_language_is_met()
|
||||
{
|
||||
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
|
@ -146,13 +158,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
_langProfile,
|
||||
new QualityModel(Quality.HDTV720p, new Revision(version: 2)),
|
||||
Language.Spanish,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2))).Should().BeFalse();
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2)),
|
||||
NoPreferredWordScore).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_cutoff_is_met_and_quality_is_higher_and_language_is_higher()
|
||||
{
|
||||
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
|
@ -170,13 +183,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
_langProfile,
|
||||
new QualityModel(Quality.HDTV720p, new Revision(version: 2)),
|
||||
Language.French,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2))).Should().BeFalse();
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2)),
|
||||
NoPreferredWordScore).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_cutoff_is_not_met_and_new_quality_is_higher_and_language_is_higher()
|
||||
{
|
||||
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
|
@ -194,13 +208,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
_langProfile,
|
||||
new QualityModel(Quality.SDTV, new Revision(version: 2)),
|
||||
Language.French,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2))).Should().BeTrue();
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2)),
|
||||
NoPreferredWordScore).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_cutoff_is_not_met_and_language_is_higher()
|
||||
{
|
||||
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
|
@ -217,7 +232,33 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
_profile,
|
||||
_langProfile,
|
||||
new QualityModel(Quality.SDTV, new Revision(version: 2)),
|
||||
Language.French).Should().BeTrue();
|
||||
Language.French,
|
||||
NoPreferredWordScore).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_cutoffs_are_met_and_score_is_higher()
|
||||
{
|
||||
Profile _profile = new Profile
|
||||
{
|
||||
Cutoff = Quality.HDTV720p.Id,
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(),
|
||||
};
|
||||
|
||||
LanguageProfile _langProfile = new LanguageProfile
|
||||
{
|
||||
Cutoff = Language.Spanish,
|
||||
Languages = LanguageFixture.GetDefaultLanguages()
|
||||
};
|
||||
|
||||
Subject.CutoffNotMet(
|
||||
_profile,
|
||||
_langProfile,
|
||||
new QualityModel(Quality.HDTV720p, new Revision(version: 2)),
|
||||
Language.Spanish,
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(Quality.Bluray1080p, new Revision(version: 2)),
|
||||
10).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
|
@ -11,6 +11,7 @@ using NzbDrone.Core.Test.Framework;
|
|||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
using FizzWare.NBuilder;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -26,6 +25,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
private Series _otherSeries;
|
||||
private Episode _otherEpisode;
|
||||
|
||||
private ReleaseInfo _releaseInfo;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
|
@ -58,10 +59,14 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
.With(e => e.EpisodeNumber = 2)
|
||||
.Build();
|
||||
|
||||
_releaseInfo = Builder<ReleaseInfo>.CreateNew()
|
||||
.Build();
|
||||
|
||||
_remoteEpisode = Builder<RemoteEpisode>.CreateNew()
|
||||
.With(r => r.Series = _series)
|
||||
.With(r => r.Episodes = new List<Episode> { _episode })
|
||||
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.DVD) , Language = Language.Spanish})
|
||||
.With(r => r.PreferredWordScore = 0)
|
||||
.Build();
|
||||
}
|
||||
|
||||
|
@ -95,9 +100,10 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
public void should_return_true_when_series_doesnt_match()
|
||||
{
|
||||
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
|
||||
.With(r => r.Series = _otherSeries)
|
||||
.With(r => r.Episodes = new List<Episode> { _episode })
|
||||
.Build();
|
||||
.With(r => r.Series = _otherSeries)
|
||||
.With(r => r.Episodes = new List<Episode> { _episode })
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
|
||||
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||
|
@ -117,6 +123,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Quality = new QualityModel(Quality.SDTV),
|
||||
Language = Language.Spanish
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
|
||||
|
@ -137,6 +144,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Quality = new QualityModel(Quality.SDTV),
|
||||
Language = Language.English
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
|
||||
|
@ -153,12 +161,33 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
{
|
||||
Quality = new QualityModel(Quality.DVD)
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
|
||||
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_qualities_are_the_same_and_languages_are_the_same_with_higher_preferred_word_score()
|
||||
{
|
||||
_remoteEpisode.PreferredWordScore = 1;
|
||||
|
||||
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
|
||||
.With(r => r.Series = _series)
|
||||
.With(r => r.Episodes = new List<Episode> { _episode })
|
||||
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo
|
||||
{
|
||||
Quality = new QualityModel(Quality.DVD),
|
||||
Language = Language.Spanish,
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
|
||||
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_when_qualities_are_the_same_and_languages_are_the_same()
|
||||
{
|
||||
|
@ -170,6 +199,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Quality = new QualityModel(Quality.DVD),
|
||||
Language = Language.Spanish,
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
|
||||
|
@ -187,6 +217,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Quality = new QualityModel(Quality.DVD),
|
||||
Language = Language.English,
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
|
||||
|
@ -206,6 +237,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Language = Language.English
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
|
||||
|
@ -223,6 +255,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Language = Language.English
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
|
||||
|
@ -240,6 +273,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Language = Language.English
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
_remoteEpisode.Episodes.Add(_otherEpisode);
|
||||
|
@ -259,6 +293,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Language = Language.English
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
_remoteEpisode.Episodes.Add(_otherEpisode);
|
||||
|
@ -280,6 +315,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Quality.HDTV720p),
|
||||
Language = Language.English
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.TheFirst(1)
|
||||
.With(r => r.Episodes = new List<Episode> { _episode })
|
||||
.TheNext(1)
|
||||
|
@ -304,6 +340,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Language = Language.Spanish
|
||||
})
|
||||
.With(r => r.Release = _releaseInfo)
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode });
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
|
@ -35,11 +35,11 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
|
||||
private void GivenRestictions(string required, string ignored)
|
||||
{
|
||||
Mocker.GetMock<IRestrictionService>()
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Returns(new List<Restriction>
|
||||
.Returns(new List<ReleaseProfile>
|
||||
{
|
||||
new Restriction
|
||||
new ReleaseProfile()
|
||||
{
|
||||
Required = required,
|
||||
Ignored = ignored
|
||||
|
@ -50,9 +50,9 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
[Test]
|
||||
public void should_be_true_when_restrictions_are_empty()
|
||||
{
|
||||
Mocker.GetMock<IRestrictionService>()
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Returns(new List<Restriction>());
|
||||
.Returns(new List<ReleaseProfile>());
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
@ -116,11 +116,11 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
{
|
||||
_remoteEpisode.Release.Title = "[ www.Speed.cd ] -Whose.Line.is.it.Anyway.US.S10E24.720p.HDTV.x264-BAJSKORV";
|
||||
|
||||
Mocker.GetMock<IRestrictionService>()
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Returns(new List<Restriction>
|
||||
.Returns(new List<ReleaseProfile>
|
||||
{
|
||||
new Restriction { Required = "x264", Ignored = "www.Speed.cd" }
|
||||
new ReleaseProfile { Required = "x264", Ignored = "www.Speed.cd" }
|
||||
});
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
|
@ -6,7 +6,7 @@ using FluentAssertions;
|
|||
using Marr.Data;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications.RssSync;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.Indexers;
|
||||
|
@ -86,14 +86,15 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
_remoteEpisode.Episodes.First().EpisodeFile = new LazyLoaded<EpisodeFile>(new EpisodeFile
|
||||
{
|
||||
Quality = quality,
|
||||
Language = language
|
||||
Language = language,
|
||||
SceneName = "Series.Title.S01E01.720p.HDTV.x264-Sonarr"
|
||||
});
|
||||
}
|
||||
|
||||
private void GivenUpgradeForExistingFile()
|
||||
{
|
||||
Mocker.GetMock<IUpgradableSpecification>()
|
||||
.Setup(s => s.IsUpgradable(It.IsAny<Profile>(), It.IsAny<LanguageProfile>(), It.IsAny<QualityModel>(), It.IsAny<Language>(), It.IsAny<QualityModel>(), It.IsAny<Language>()))
|
||||
.Setup(s => s.IsUpgradable(It.IsAny<Profile>(), It.IsAny<LanguageProfile>(), It.IsAny<QualityModel>(), It.IsAny<Language>(), It.IsAny<int>(), It.IsAny<QualityModel>(), It.IsAny<Language>(), It.IsAny<int>()))
|
||||
.Returns(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ using NzbDrone.Core.Qualities;
|
|||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
|
|
@ -12,7 +12,7 @@ using NzbDrone.Core.Profiles.Qualities;
|
|||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using FluentAssertions;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
|
@ -13,7 +13,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
{
|
||||
[TestFixture]
|
||||
|
||||
public class QualityUpgradeSpecificationFixture : CoreTest<UpgradableSpecification>
|
||||
public class UpgradeSpecificationFixture : CoreTest<UpgradableSpecification>
|
||||
{
|
||||
public static object[] IsUpgradeTestCases =
|
||||
{
|
||||
|
@ -36,11 +36,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
new object[] { Quality.WEBDL720p, 1, Language.Spanish, Quality.HDTV720p, 2, Language.French, Quality.WEBDL720p, Language.Spanish, false }
|
||||
};
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
|
||||
}
|
||||
private static readonly int NoPreferredWordScore = 0;
|
||||
|
||||
private void GivenAutoDownloadPropers(bool autoDownloadPropers)
|
||||
{
|
||||
|
@ -66,7 +62,15 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Cutoff = Language.English
|
||||
};
|
||||
|
||||
Subject.IsUpgradable(profile, langProfile, new QualityModel(current, new Revision(version: currentVersion)), Language.English, new QualityModel(newQuality, new Revision(version: newVersion)), Language.English)
|
||||
Subject.IsUpgradable(
|
||||
profile,
|
||||
langProfile,
|
||||
new QualityModel(current, new Revision(version: currentVersion)),
|
||||
Language.English,
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(newQuality, new Revision(version: newVersion)),
|
||||
Language.English,
|
||||
NoPreferredWordScore)
|
||||
.Should().Be(expected);
|
||||
}
|
||||
|
||||
|
@ -87,7 +91,15 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Cutoff = languageCutoff
|
||||
};
|
||||
|
||||
Subject.IsUpgradable(profile, langProfile, new QualityModel(current, new Revision(version: currentVersion)), currentLanguage, new QualityModel(newQuality, new Revision(version: newVersion)), newLanguage)
|
||||
Subject.IsUpgradable(
|
||||
profile,
|
||||
langProfile,
|
||||
new QualityModel(current, new Revision(version: currentVersion)),
|
||||
currentLanguage,
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(newQuality, new Revision(version: newVersion)),
|
||||
newLanguage,
|
||||
NoPreferredWordScore)
|
||||
.Should().Be(expected);
|
||||
}
|
||||
|
||||
|
@ -108,7 +120,15 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
};
|
||||
|
||||
|
||||
Subject.IsUpgradable(profile, langProfile, new QualityModel(Quality.DVD, new Revision(version: 2)), Language.English, new QualityModel(Quality.DVD, new Revision(version: 1)), Language.English)
|
||||
Subject.IsUpgradable(
|
||||
profile,
|
||||
langProfile,
|
||||
new QualityModel(Quality.DVD, new Revision(version: 2)),
|
||||
Language.English,
|
||||
NoPreferredWordScore,
|
||||
new QualityModel(Quality.DVD, new Revision(version: 1)),
|
||||
Language.English,
|
||||
NoPreferredWordScore)
|
||||
.Should().BeFalse();
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
using FizzWare.NBuilder;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Housekeeping.Housekeepers;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tags;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
|
||||
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
|||
var tags = Builder<Tag>.CreateListOfSize(2).BuildList();
|
||||
Db.InsertMany(tags);
|
||||
|
||||
var restrictions = Builder<Restriction>.CreateListOfSize(2)
|
||||
var restrictions = Builder<ReleaseProfile>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(v => v.Tags.Add(tags[0].Id))
|
||||
.BuildList();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
|
@ -42,7 +42,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeFileMovingServiceTests
|
|||
.Build();
|
||||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.BuildFileName(It.IsAny<List<Episode>>(), It.IsAny<Series>(), It.IsAny<EpisodeFile>(), null))
|
||||
.Setup(s => s.BuildFileName(It.IsAny<List<Episode>>(), It.IsAny<Series>(), It.IsAny<EpisodeFile>(), null, null))
|
||||
.Returns("File Name");
|
||||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
|
|
|
@ -172,7 +172,7 @@
|
|||
<Compile Include="DecisionEngineTests\ReleaseRestrictionsSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\PrioritizeDownloadDecisionFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\QualityAllowedByProfileSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\QualityUpgradeSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\UpgradeSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\MinimumAgeSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\RetentionSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\RssSync\DelaySpecificationFixture.cs" />
|
||||
|
@ -346,6 +346,7 @@
|
|||
<Compile Include="ParserTests\ValidateParsedEpisodeInfoFixture.cs" />
|
||||
<Compile Include="Profiles\Delay\DelayProfileServiceFixture.cs" />
|
||||
<Compile Include="Profiles\Qualities\QualityIndexCompareToFixture.cs" />
|
||||
<Compile Include="Profiles\Releases\PreferredWordService\CalculateFixture.cs" />
|
||||
<Compile Include="Qualities\QualityFinderFixture.cs" />
|
||||
<Compile Include="Qualities\RevisionComparableFixture.cs" />
|
||||
<Compile Include="QueueTests\QueueServiceFixture.cs" />
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.Profiles.Releases.PreferredWordService
|
||||
{
|
||||
[TestFixture]
|
||||
public class CalculateFixture : CoreTest<Core.Profiles.Releases.PreferredWordService>
|
||||
{
|
||||
private Series _series = null;
|
||||
private List<ReleaseProfile> _releaseProfiles = null;
|
||||
private string _title = "Series.Title.S01E01.720p.HDTV.x264-Sonarr";
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_series = Builder<Series>.CreateNew()
|
||||
.With(s => s.Tags = new HashSet<int>(new[] {1, 2}))
|
||||
.Build();
|
||||
|
||||
_releaseProfiles = new List<ReleaseProfile>();
|
||||
|
||||
_releaseProfiles.Add(new ReleaseProfile
|
||||
{
|
||||
Preferred = new List<KeyValuePair<string, int>>
|
||||
{
|
||||
new KeyValuePair<string, int>("x264", 5),
|
||||
new KeyValuePair<string, int>("x265", -10)
|
||||
}
|
||||
});
|
||||
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Returns(_releaseProfiles);
|
||||
}
|
||||
|
||||
|
||||
private void GivenMatchingTerms(params string[] terms)
|
||||
{
|
||||
Mocker.GetMock<ITermMatcher>()
|
||||
.Setup(s => s.IsMatch(It.IsAny<string>(), _title))
|
||||
.Returns<string, string>((term, title) => terms.Contains(term));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_0_when_there_are_no_release_profiles()
|
||||
{
|
||||
Mocker.GetMock<IReleaseProfileService>()
|
||||
.Setup(s => s.AllForTags(It.IsAny<HashSet<int>>()))
|
||||
.Returns(new List<ReleaseProfile>());
|
||||
|
||||
Subject.Calculate(_series, _title).Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_0_when_there_are_no_matching_preferred_words()
|
||||
{
|
||||
GivenMatchingTerms();
|
||||
|
||||
Subject.Calculate(_series, _title).Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_calculate_positive_score()
|
||||
{
|
||||
GivenMatchingTerms("x264");
|
||||
|
||||
Subject.Calculate(_series, _title).Should().Be(5);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_calculate_negative_score()
|
||||
{
|
||||
GivenMatchingTerms("x265");
|
||||
|
||||
Subject.Calculate(_series, _title).Should().Be(-10);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_calculate_using_multiple_profiles()
|
||||
{
|
||||
_releaseProfiles.Add(_releaseProfiles.First());
|
||||
|
||||
GivenMatchingTerms("x264");
|
||||
|
||||
Subject.Calculate(_series, _title).Should().Be(10);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(127)]
|
||||
public class rename_restrictions_to_release_profiles : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Rename.Table("Restrictions").To("ReleaseProfiles");
|
||||
Alter.Table("ReleaseProfiles").AddColumn("IncludePreferredWhenRenaming").AsBoolean().WithDefaultValue(true);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,6 @@ using NzbDrone.Core.Organizer;
|
|||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Core.SeriesStats;
|
||||
using NzbDrone.Core.Tags;
|
||||
|
@ -37,6 +36,7 @@ using NzbDrone.Core.Extras.Subtitles;
|
|||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
|
||||
namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
|
@ -121,7 +121,7 @@ namespace NzbDrone.Core.Datastore
|
|||
|
||||
Mapper.Entity<RemotePathMapping>().RegisterModel("RemotePathMappings");
|
||||
Mapper.Entity<Tag>().RegisterModel("Tags");
|
||||
Mapper.Entity<Restriction>().RegisterModel("Restrictions");
|
||||
Mapper.Entity<ReleaseProfile>().RegisterModel("ReleaseProfiles");
|
||||
|
||||
Mapper.Entity<DelayProfile>().RegisterModel("DelayProfiles");
|
||||
Mapper.Entity<User>().RegisterModel("Users");
|
||||
|
@ -149,6 +149,7 @@ namespace NzbDrone.Core.Datastore
|
|||
MapRepository.Instance.RegisterTypeConverter(typeof(QualityModel), new EmbeddedDocumentConverter(new QualityIntConverter()));
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Dictionary<string, string>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<int>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<KeyValuePair<string, int>>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(Language), new LanguageIntConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<string>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<LanguageProfileItem>), new EmbeddedDocumentConverter(new LanguageIntConverter()));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Indexers;
|
||||
|
@ -25,6 +25,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
{
|
||||
CompareQuality,
|
||||
CompareLanguage,
|
||||
ComparePreferredWordScore,
|
||||
CompareProtocol,
|
||||
CompareEpisodeCount,
|
||||
CompareEpisodeNumber,
|
||||
|
@ -68,6 +69,11 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
return CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Series.LanguageProfile.Value.Languages.FindIndex(l => l.Language == remoteEpisode.ParsedEpisodeInfo.Language));
|
||||
}
|
||||
|
||||
private int ComparePreferredWordScore(DownloadDecision x, DownloadDecision y)
|
||||
{
|
||||
return CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.PreferredWordScore);
|
||||
}
|
||||
|
||||
private int CompareProtocol(DownloadDecision x, DownloadDecision y)
|
||||
{
|
||||
var result = CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
|
||||
|
|
|
@ -5,6 +5,8 @@ using NLog;
|
|||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Download.Aggregation;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -21,12 +23,17 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
{
|
||||
private readonly IEnumerable<IDecisionEngineSpecification> _specifications;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly IRemoteEpisodeAggregationService _aggregationService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public DownloadDecisionMaker(IEnumerable<IDecisionEngineSpecification> specifications, IParsingService parsingService, Logger logger)
|
||||
public DownloadDecisionMaker(IEnumerable<IDecisionEngineSpecification> specifications,
|
||||
IParsingService parsingService,
|
||||
IRemoteEpisodeAggregationService aggregationService,
|
||||
Logger logger)
|
||||
{
|
||||
_specifications = specifications;
|
||||
_parsingService = parsingService;
|
||||
_aggregationService = aggregationService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -89,6 +96,7 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
}
|
||||
else
|
||||
{
|
||||
_aggregationService.Augment(remoteEpisode);
|
||||
remoteEpisode.DownloadAllowed = remoteEpisode.Episodes.Any();
|
||||
decision = GetDecisionForReport(remoteEpisode, searchCriteria);
|
||||
}
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
using System.Linq;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class CutoffSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public CutoffSpecification(UpgradableSpecification UpgradableSpecification, Logger logger)
|
||||
public CutoffSpecification(UpgradableSpecification upgradableSpecification, IPreferredWordService preferredWordServiceCalculator, Logger logger)
|
||||
{
|
||||
_upgradableSpecification = UpgradableSpecification;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -30,13 +33,16 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
_logger.Debug("File is no longer available, skipping this file.");
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.Debug("Comparing file quality and language with report. Existing file is {0} - {1}", file.Quality, file.Language);
|
||||
|
||||
if (!_upgradableSpecification.CutoffNotMet(profile,
|
||||
subject.Series.LanguageProfile,
|
||||
file.Quality,
|
||||
file.Language,
|
||||
subject.ParsedEpisodeInfo.Quality))
|
||||
_preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName()),
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
{
|
||||
_logger.Debug("Cutoff already met, rejecting.");
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public interface IDecisionEngineSpecification
|
||||
{
|
|
@ -2,6 +2,7 @@ using System.Linq;
|
|||
using NLog;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Queue;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
|
@ -10,14 +11,17 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
{
|
||||
private readonly IQueueService _queueService;
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public QueueSpecification(IQueueService queueService,
|
||||
UpgradableSpecification UpgradableSpecification,
|
||||
Logger logger)
|
||||
UpgradableSpecification UpgradableSpecification,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
Logger logger)
|
||||
{
|
||||
_queueService = queueService;
|
||||
_upgradableSpecification = UpgradableSpecification;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -26,21 +30,24 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
|
||||
public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
var queue = _queueService.GetQueue()
|
||||
.Select(q => q.RemoteEpisode).ToList();
|
||||
|
||||
var queue = _queueService.GetQueue();
|
||||
var matchingSeries = queue.Where(q => q.Series.Id == subject.Series.Id);
|
||||
var matchingEpisode = matchingSeries.Where(q => q.Episodes.Select(e => e.Id).Intersect(subject.Episodes.Select(e => e.Id)).Any());
|
||||
var matchingEpisode = matchingSeries.Where(q => q.RemoteEpisode.Episodes.Select(e => e.Id).Intersect(subject.Episodes.Select(e => e.Id)).Any());
|
||||
|
||||
foreach (var remoteEpisode in matchingEpisode)
|
||||
foreach (var queueItem in matchingEpisode)
|
||||
{
|
||||
var remoteEpisode = queueItem.RemoteEpisode;
|
||||
|
||||
_logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
|
||||
var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, queueItem.Title);
|
||||
|
||||
if (!_upgradableSpecification.CutoffNotMet(subject.Series.Profile,
|
||||
subject.Series.LanguageProfile,
|
||||
remoteEpisode.ParsedEpisodeInfo.Quality,
|
||||
remoteEpisode.ParsedEpisodeInfo.Language,
|
||||
subject.ParsedEpisodeInfo.Quality))
|
||||
queuedItemPreferredWordScore,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
{
|
||||
return Decision.Reject("Quality for release in queue already meets cutoff: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
|
||||
}
|
||||
|
@ -51,8 +58,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
subject.Series.LanguageProfile,
|
||||
remoteEpisode.ParsedEpisodeInfo.Quality,
|
||||
remoteEpisode.ParsedEpisodeInfo.Language,
|
||||
queuedItemPreferredWordScore,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.ParsedEpisodeInfo.Language))
|
||||
subject.ParsedEpisodeInfo.Language,
|
||||
subject.PreferredWordScore))
|
||||
{
|
||||
return Decision.Reject("Quality for release in queue is of equal or higher preference: {0} - {1}", remoteEpisode.ParsedEpisodeInfo.Quality, remoteEpisode.ParsedEpisodeInfo.Language);
|
||||
}
|
||||
|
|
|
@ -5,20 +5,20 @@ using NLog;
|
|||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class ReleaseRestrictionsSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
private readonly IRestrictionService _restrictionService;
|
||||
private readonly IReleaseProfileService _releaseProfileService;
|
||||
private readonly ITermMatcher _termMatcher;
|
||||
|
||||
public ReleaseRestrictionsSpecification(ITermMatcher termMatcher, IRestrictionService restrictionService, Logger logger)
|
||||
public ReleaseRestrictionsSpecification(ITermMatcher termMatcher, IReleaseProfileService releaseProfileService, Logger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_restrictionService = restrictionService;
|
||||
_releaseProfileService = releaseProfileService;
|
||||
_termMatcher = termMatcher;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
_logger.Debug("Checking if release meets restrictions: {0}", subject);
|
||||
|
||||
var title = subject.Release.Title;
|
||||
var restrictions = _restrictionService.AllForTags(subject.Series.Tags);
|
||||
var restrictions = _releaseProfileService.AllForTags(subject.Series.Tags);
|
||||
|
||||
var required = restrictions.Where(r => r.Required.IsNotNullOrWhiteSpace());
|
||||
var ignored = restrictions.Where(r => r.Ignored.IsNotNullOrWhiteSpace());
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Linq;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
|
@ -6,6 +6,7 @@ using NzbDrone.Core.Parser.Model;
|
|||
using NzbDrone.Core.Profiles.Delay;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
{
|
||||
|
@ -14,16 +15,19 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
private readonly IPendingReleaseService _pendingReleaseService;
|
||||
private readonly IUpgradableSpecification _upgradableSpecification;
|
||||
private readonly IDelayProfileService _delayProfileService;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public DelaySpecification(IPendingReleaseService pendingReleaseService,
|
||||
IUpgradableSpecification UpgradableSpecification,
|
||||
IUpgradableSpecification upgradableSpecification,
|
||||
IDelayProfileService delayProfileService,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
Logger logger)
|
||||
{
|
||||
_pendingReleaseService = pendingReleaseService;
|
||||
_upgradableSpecification = UpgradableSpecification;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_delayProfileService = delayProfileService;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -50,19 +54,22 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var comparer = new QualityModelComparer(profile);
|
||||
var comparerLanguage = new LanguageComparer(languageProfile);
|
||||
var qualityComparer = new QualityModelComparer(profile);
|
||||
var languageComparer = new LanguageComparer(languageProfile);
|
||||
|
||||
if (isPreferredProtocol)
|
||||
{
|
||||
foreach (var file in subject.Episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFile.Value))
|
||||
{
|
||||
var upgradable = _upgradableSpecification.IsUpgradable(profile,
|
||||
languageProfile,
|
||||
file.Quality,
|
||||
file.Language,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.ParsedEpisodeInfo.Language);
|
||||
var upgradable = _upgradableSpecification.IsUpgradable(
|
||||
profile,
|
||||
languageProfile,
|
||||
file.Quality,
|
||||
file.Language,
|
||||
_preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName()),
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.ParsedEpisodeInfo.Language,
|
||||
subject.PreferredWordScore);
|
||||
|
||||
if (upgradable)
|
||||
{
|
||||
|
@ -74,8 +81,8 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
|
||||
// If quality meets or exceeds the best allowed quality in the profile accept it immediately
|
||||
var bestQualityInProfile = profile.LastAllowedQuality();
|
||||
var isBestInProfile = comparer.Compare(subject.ParsedEpisodeInfo.Quality.Quality, bestQualityInProfile) >= 0;
|
||||
var isBestInProfileLanguage = comparerLanguage.Compare(subject.ParsedEpisodeInfo.Language, languageProfile.LastAllowedLanguage()) >= 0;
|
||||
var isBestInProfile = qualityComparer.Compare(subject.ParsedEpisodeInfo.Quality.Quality, bestQualityInProfile) >= 0;
|
||||
var isBestInProfileLanguage = languageComparer.Compare(subject.ParsedEpisodeInfo.Language, languageProfile.LastAllowedLanguage()) >= 0;
|
||||
|
||||
if (isBestInProfile && isBestInProfileLanguage && isPreferredProtocol)
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ using NzbDrone.Core.Configuration;
|
|||
using NzbDrone.Core.History;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
{
|
||||
|
@ -13,16 +14,19 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
private readonly IHistoryService _historyService;
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public HistorySpecification(IHistoryService historyService,
|
||||
UpgradableSpecification upgradableSpecification,
|
||||
IConfigService configService,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
Logger logger)
|
||||
{
|
||||
_historyService = historyService;
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_configService = configService;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -48,8 +52,29 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
if (mostRecent != null && mostRecent.EventType == HistoryEventType.Grabbed)
|
||||
{
|
||||
var recent = mostRecent.Date.After(DateTime.UtcNow.AddHours(-12));
|
||||
var cutoffUnmet = _upgradableSpecification.CutoffNotMet(subject.Series.Profile, subject.Series.LanguageProfile, mostRecent.Quality, mostRecent.Language, subject.ParsedEpisodeInfo.Quality);
|
||||
var upgradeable = _upgradableSpecification.IsUpgradable(subject.Series.Profile, subject.Series.LanguageProfile, mostRecent.Quality, mostRecent.Language, subject.ParsedEpisodeInfo.Quality, subject.ParsedEpisodeInfo.Language);
|
||||
|
||||
// The series will be the same as the one in history since it's the same episode.
|
||||
// Instead of fetching the series from the DB reuse the known series.
|
||||
var preferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Series, mostRecent.SourceTitle);
|
||||
|
||||
var cutoffUnmet = _upgradableSpecification.CutoffNotMet(
|
||||
subject.Series.Profile,
|
||||
subject.Series.LanguageProfile,
|
||||
mostRecent.Quality,
|
||||
mostRecent.Language,
|
||||
preferredWordScore,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.PreferredWordScore);
|
||||
|
||||
var upgradeable = _upgradableSpecification.IsUpgradable(
|
||||
subject.Series.Profile,
|
||||
subject.Series.LanguageProfile,
|
||||
mostRecent.Quality,
|
||||
mostRecent.Language,
|
||||
preferredWordScore,
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.ParsedEpisodeInfo.Language,
|
||||
subject.PreferredWordScore);
|
||||
|
||||
if (!recent && cdhEnabled)
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Linq;
|
|||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class SameEpisodesSpecification
|
||||
{
|
|
@ -4,14 +4,14 @@ using NzbDrone.Core.Profiles.Languages;
|
|||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public interface IUpgradableSpecification
|
||||
{
|
||||
bool IsUpgradable(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, QualityModel newQuality, Language newLanguage);
|
||||
bool IsUpgradable(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality, Language newLanguage, int newScore);
|
||||
bool QualityCutoffNotMet(Profile profile, QualityModel currentQuality, QualityModel newQuality = null);
|
||||
bool LanguageCutoffNotMet(LanguageProfile languageProfile, Language currentLanguage);
|
||||
bool CutoffNotMet(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, QualityModel newQuality = null);
|
||||
bool CutoffNotMet(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality = null, int newScore = 0);
|
||||
bool IsRevisionUpgrade(QualityModel currentQuality, QualityModel newQuality);
|
||||
}
|
||||
|
||||
|
@ -51,19 +51,38 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
public bool IsUpgradable(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, QualityModel newQuality, Language newLanguage)
|
||||
private bool IsPreferredWordUpgradable(int currentScore, int newScore)
|
||||
{
|
||||
// If qualities are the same then check language
|
||||
if (newQuality != null && new QualityModelComparer(profile).Compare(newQuality, currentQuality) == 0)
|
||||
return newScore > currentScore;
|
||||
}
|
||||
|
||||
public bool IsUpgradable(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality, Language newLanguage, int newScore)
|
||||
{
|
||||
if (IsQualityUpgradable(profile, currentQuality, newQuality))
|
||||
{
|
||||
return IsLanguageUpgradable(languageProfile, currentLanguage, newLanguage);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If quality is worse then always return false
|
||||
if (!IsQualityUpgradable(profile, currentQuality, newQuality))
|
||||
if (new QualityModelComparer(profile).Compare(newQuality, currentQuality) != 0)
|
||||
{
|
||||
_logger.Debug("existing item has better quality. skipping");
|
||||
_logger.Debug("Existing item has better qualitys, skipping");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsLanguageUpgradable(languageProfile, currentLanguage, newLanguage))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (new LanguageComparer(languageProfile).Compare(newLanguage, currentLanguage) != 0)
|
||||
{
|
||||
_logger.Debug("Existing item has better language, skipping");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsPreferredWordUpgradable(currentScore, newScore))
|
||||
{
|
||||
_logger.Debug("Existing item has a better preferred word score, skipping");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -94,9 +113,10 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
return languageCompare < 0;
|
||||
}
|
||||
|
||||
public bool CutoffNotMet(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, QualityModel newQuality = null)
|
||||
public bool CutoffNotMet(Profile profile, LanguageProfile languageProfile, QualityModel currentQuality, Language currentLanguage, int currentScore, QualityModel newQuality = null, int newScore = 0)
|
||||
{
|
||||
// If we can upgrade the language (it is not the cutoff) then doesn't matter the quality we can always get same quality with prefered language
|
||||
// If we can upgrade the language (it is not the cutoff) then the quality doesn't
|
||||
// matter as we can always get same quality with prefered language.
|
||||
if (LanguageCutoffNotMet(languageProfile, currentLanguage))
|
||||
{
|
||||
return true;
|
||||
|
@ -107,6 +127,11 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
return true;
|
||||
}
|
||||
|
||||
if (IsPreferredWordUpgradable(currentScore, newScore))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
_logger.Debug("Existing item meets cut-off. skipping.");
|
||||
|
||||
return false;
|
|
@ -1,18 +1,21 @@
|
|||
using System.Linq;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class UpgradeDiskSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public UpgradeDiskSpecification(UpgradableSpecification upgradableSpecification, Logger logger)
|
||||
public UpgradeDiskSpecification(UpgradableSpecification upgradableSpecification, IPreferredWordService preferredWordServiceCalculator, Logger logger)
|
||||
{
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -36,8 +39,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
|||
subject.Series.LanguageProfile,
|
||||
file.Quality,
|
||||
file.Language,
|
||||
_preferredWordServiceCalculator.Calculate(subject.Series, file.GetSceneOrFileName()),
|
||||
subject.ParsedEpisodeInfo.Quality,
|
||||
subject.ParsedEpisodeInfo.Language))
|
||||
subject.ParsedEpisodeInfo.Language,
|
||||
subject.PreferredWordScore))
|
||||
{
|
||||
return Decision.Reject("Quality for existing file on disk is of equal or higher preference: {0} - {1}", file.Quality, file.Language);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
|
||||
namespace NzbDrone.Core.Download.Aggregation.Aggregators
|
||||
{
|
||||
public class AggregatePreferredWordScore : IAggregateRemoteEpisode
|
||||
{
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
|
||||
public AggregatePreferredWordScore(IPreferredWordService preferredWordServiceCalculator)
|
||||
{
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
}
|
||||
|
||||
public RemoteEpisode Aggregate(RemoteEpisode remoteEpisode)
|
||||
{
|
||||
remoteEpisode.PreferredWordScore = _preferredWordServiceCalculator.Calculate(remoteEpisode.Series, remoteEpisode.Release.Title);
|
||||
|
||||
return remoteEpisode;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Download.Aggregation.Aggregators
|
||||
{
|
||||
public interface IAggregateRemoteEpisode
|
||||
{
|
||||
RemoteEpisode Aggregate(RemoteEpisode remoteEpisode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Download.Aggregation.Aggregators;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Download.Aggregation
|
||||
{
|
||||
public interface IRemoteEpisodeAggregationService
|
||||
{
|
||||
RemoteEpisode Augment(RemoteEpisode remoteEpisode);
|
||||
}
|
||||
|
||||
public class RemoteEpisodeAggregationService : IRemoteEpisodeAggregationService
|
||||
{
|
||||
private readonly IEnumerable<IAggregateRemoteEpisode> _augmenters;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public RemoteEpisodeAggregationService(IEnumerable<IAggregateRemoteEpisode> augmenters,
|
||||
Logger logger)
|
||||
{
|
||||
_augmenters = augmenters;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public RemoteEpisode Augment(RemoteEpisode remoteEpisode)
|
||||
{
|
||||
foreach (var augmenter in _augmenters)
|
||||
{
|
||||
try
|
||||
{
|
||||
augmenter.Aggregate(remoteEpisode);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return remoteEpisode;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Marr.Data;
|
||||
using NzbDrone.Common.Serializer;
|
||||
|
@ -19,7 +19,7 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
|||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
|
||||
var usedTags = new[] { "Series", "Notifications", "DelayProfiles", "Restrictions" }
|
||||
var usedTags = new[] { "Series", "Notifications", "DelayProfiles", "ReleaseProfiles" }
|
||||
.SelectMany(v => GetUsedTags(v, mapper))
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
|
|
@ -44,6 +44,11 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return System.IO.Path.GetFileName(RelativePath);
|
||||
}
|
||||
|
||||
if (Path.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
return System.IO.Path.GetFileName(Path);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@
|
|||
<Compile Include="CustomFilters\CustomFilter.cs" />
|
||||
<Compile Include="CustomFilters\CustomFilterRepository.cs" />
|
||||
<Compile Include="CustomFilters\CustomFilterService.cs" />
|
||||
<Compile Include="Datastore\Migration\127_rename_release_profiles.cs" />
|
||||
<Compile Include="Datastore\Migration\126_add_custom_filters.cs" />
|
||||
<Compile Include="Extras\Metadata\MetadataSectionType.cs" />
|
||||
<Compile Include="Download\Aggregation\RemoteEpisodeAggregationService.cs" />
|
||||
|
@ -340,12 +341,12 @@
|
|||
<Compile Include="DecisionEngine\DownloadDecisionComparer.cs" />
|
||||
<Compile Include="DecisionEngine\DownloadDecisionMaker.cs" />
|
||||
<Compile Include="DecisionEngine\DownloadDecisionPriorizationService.cs" />
|
||||
<Compile Include="DecisionEngine\IDecisionEngineSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\IDecisionEngineSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\IRejectWithReason.cs" />
|
||||
<Compile Include="DecisionEngine\UpgradableSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\UpgradableSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Rejection.cs" />
|
||||
<Compile Include="DecisionEngine\RejectionType.cs" />
|
||||
<Compile Include="DecisionEngine\SameEpisodesSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\SameEpisodesSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\SpecificationPriority.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\AcceptableSizeSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\BlacklistSpecification.cs" />
|
||||
|
@ -1005,6 +1006,7 @@
|
|||
<Compile Include="Profiles\Qualities\ProfileRepository.cs" />
|
||||
<Compile Include="Profiles\Qualities\ProfileService.cs" />
|
||||
<Compile Include="Profiles\Qualities\QualityIndex.cs" />
|
||||
<Compile Include="Profiles\Releases\PreferredWordService.cs" />
|
||||
<Compile Include="ProgressMessaging\ProgressMessageContext.cs" />
|
||||
<Compile Include="Qualities\QualityDetectionSource.cs" />
|
||||
<Compile Include="Qualities\QualityFinder.cs" />
|
||||
|
@ -1134,11 +1136,11 @@
|
|||
<Compile Include="Queue\Queue.cs" />
|
||||
<Compile Include="Queue\QueueService.cs" />
|
||||
<Compile Include="Queue\QueueUpdatedEvent.cs" />
|
||||
<Compile Include="Restrictions\PerlRegexFactory.cs" />
|
||||
<Compile Include="Restrictions\Restriction.cs" />
|
||||
<Compile Include="Restrictions\RestrictionRepository.cs" />
|
||||
<Compile Include="Restrictions\RestrictionService.cs" />
|
||||
<Compile Include="Restrictions\TermMatcher.cs" />
|
||||
<Compile Include="Profiles\Releases\PerlRegexFactory.cs" />
|
||||
<Compile Include="Profiles\Releases\ReleaseProfile.cs" />
|
||||
<Compile Include="Profiles\Releases\ReleaseProfileRepository.cs" />
|
||||
<Compile Include="Profiles\Releases\ReleaseProfileService.cs" />
|
||||
<Compile Include="Profiles\Releases\TermMatcher.cs" />
|
||||
<Compile Include="Rest\JsonNetSerializer.cs" />
|
||||
<Compile Include="Rest\RestClientFactory.cs" />
|
||||
<Compile Include="Rest\RestException.cs" />
|
||||
|
|
|
@ -10,6 +10,7 @@ using NzbDrone.Common.EnsureThat;
|
|||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
|
@ -17,7 +18,7 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
public interface IBuildFileNames
|
||||
{
|
||||
string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null);
|
||||
string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null, List<string> preferredWords = null);
|
||||
string BuildFilePath(Series series, int seasonNumber, string fileName, string extension);
|
||||
string BuildSeasonPath(Series series, int seasonNumber);
|
||||
BasicNamingConfig GetBasicNamingConfig(NamingConfig nameSpec);
|
||||
|
@ -30,6 +31,7 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
private readonly INamingConfigService _namingConfigService;
|
||||
private readonly IQualityDefinitionService _qualityDefinitionService;
|
||||
private readonly IPreferredWordService _preferredWordService;
|
||||
private readonly ICached<EpisodeFormat[]> _episodeFormatCache;
|
||||
private readonly ICached<AbsoluteEpisodeFormat[]> _absoluteEpisodeFormatCache;
|
||||
private readonly ICached<bool> _requiresEpisodeTitleCache;
|
||||
|
@ -76,17 +78,19 @@ namespace NzbDrone.Core.Organizer
|
|||
public FileNameBuilder(INamingConfigService namingConfigService,
|
||||
IQualityDefinitionService qualityDefinitionService,
|
||||
ICacheManager cacheManager,
|
||||
IPreferredWordService preferredWordService,
|
||||
Logger logger)
|
||||
{
|
||||
_namingConfigService = namingConfigService;
|
||||
_qualityDefinitionService = qualityDefinitionService;
|
||||
_preferredWordService = preferredWordService;
|
||||
_episodeFormatCache = cacheManager.GetCache<EpisodeFormat[]>(GetType(), "episodeFormat");
|
||||
_absoluteEpisodeFormatCache = cacheManager.GetCache<AbsoluteEpisodeFormat[]>(GetType(), "absoluteEpisodeFormat");
|
||||
_requiresEpisodeTitleCache = cacheManager.GetCache<bool>(GetType(), "requiresEpisodeTitle");
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null)
|
||||
public string BuildFileName(List<Episode> episodes, Series series, EpisodeFile episodeFile, NamingConfig namingConfig = null, List<string> preferredWords = null)
|
||||
{
|
||||
if (namingConfig == null)
|
||||
{
|
||||
|
@ -137,6 +141,7 @@ namespace NzbDrone.Core.Organizer
|
|||
AddEpisodeFileTokens(tokenHandlers, episodeFile);
|
||||
AddQualityTokens(tokenHandlers, series, episodeFile);
|
||||
AddMediaInfoTokens(tokenHandlers, episodeFile);
|
||||
AddPreferredWords(tokenHandlers, series, episodeFile, preferredWords);
|
||||
|
||||
var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim();
|
||||
fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString());
|
||||
|
@ -564,6 +569,16 @@ namespace NzbDrone.Core.Organizer
|
|||
tokenHandlers["{TvMazeId}"] = m => series.TvMazeId.ToString();
|
||||
}
|
||||
|
||||
private void AddPreferredWords(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Series series, EpisodeFile episodeFile, List<string> preferredWords = null)
|
||||
{
|
||||
if (preferredWords == null)
|
||||
{
|
||||
preferredWords = _preferredWordService.GetMatchingPreferredWords(series, episodeFile.GetSceneOrFileName(), true);
|
||||
}
|
||||
|
||||
tokenHandlers["{Preferred Words}"] = m => string.Join(" ", preferredWords);
|
||||
}
|
||||
|
||||
private string GetLanguagesToken(string mediaInfoLanguages)
|
||||
{
|
||||
List<string> tokens = new List<string>();
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace NzbDrone.Core.Organizer
|
|||
private static EpisodeFile _dailyEpisodeFile;
|
||||
private static EpisodeFile _animeEpisodeFile;
|
||||
private static EpisodeFile _animeMultiEpisodeFile;
|
||||
private static List<string> _preferredWords;
|
||||
|
||||
public FileNameSampleService(IBuildFileNames buildFileNames)
|
||||
{
|
||||
|
@ -162,6 +163,11 @@ namespace NzbDrone.Core.Organizer
|
|||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfoAnime
|
||||
};
|
||||
|
||||
_preferredWords = new List<string>
|
||||
{
|
||||
"iNTERNAL"
|
||||
};
|
||||
}
|
||||
|
||||
public SampleResult GetStandardSample(NamingConfig nameSpec)
|
||||
|
@ -243,7 +249,7 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
try
|
||||
{
|
||||
return _buildFileNames.BuildFileName(episodes, series, episodeFile, nameSpec);
|
||||
return _buildFileNames.BuildFileName(episodes, series, episodeFile, nameSpec, _preferredWords);
|
||||
}
|
||||
catch (NamingFormatException)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace NzbDrone.Core.Parser.Model
|
|||
public List<Episode> Episodes { get; set; }
|
||||
public bool DownloadAllowed { get; set; }
|
||||
public TorrentSeedConfiguration SeedConfiguration { get; set; }
|
||||
public int PreferredWordScore { get; set; }
|
||||
|
||||
public bool IsRecentEpisode()
|
||||
{
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using NzbDrone.Common.Exceptions;
|
||||
|
||||
namespace NzbDrone.Core.Restrictions
|
||||
namespace NzbDrone.Core.Profiles.Releases
|
||||
{
|
||||
public static class PerlRegexFactory
|
||||
{
|
|
@ -0,0 +1,76 @@
|
|||
using NLog;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Core.Profiles.Releases
|
||||
{
|
||||
public interface IPreferredWordService
|
||||
{
|
||||
int Calculate(Series series, string title);
|
||||
List<string> GetMatchingPreferredWords(Series series, string title, bool isRenaming);
|
||||
}
|
||||
|
||||
public class PreferredWordService : IPreferredWordService
|
||||
{
|
||||
private readonly IReleaseProfileService _releaseProfileService;
|
||||
private readonly ITermMatcher _termMatcher;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public PreferredWordService(IReleaseProfileService releaseProfileService, ITermMatcher termMatcher, Logger logger)
|
||||
{
|
||||
_releaseProfileService = releaseProfileService;
|
||||
_termMatcher = termMatcher;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public int Calculate(Series series, string title)
|
||||
{
|
||||
_logger.Trace("Calculating preferred word score for '{0}'", title);
|
||||
|
||||
var matchingPairs = GetMatchingPairs(series, title, false);
|
||||
var score = matchingPairs.Sum(p => p.Value);
|
||||
|
||||
_logger.Trace("Calculated preferred word score for '{0}': {1}", title, score);
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
public List<string> GetMatchingPreferredWords(Series series, string title, bool isRenaming)
|
||||
{
|
||||
var matchingPairs = GetMatchingPairs(series, title, isRenaming);
|
||||
|
||||
return matchingPairs.OrderByDescending(p => p.Value)
|
||||
.Select(p => p.Key)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private List<KeyValuePair<string, int>> GetMatchingPairs(Series series, string title, bool isRenaming)
|
||||
{
|
||||
var releaseProfiles = _releaseProfileService.AllForTags(series.Tags);
|
||||
var result = new List<KeyValuePair<string, int>>();
|
||||
|
||||
_logger.Trace("Calculating preferred word score for '{0}'", title);
|
||||
|
||||
foreach (var releaseProfile in releaseProfiles)
|
||||
{
|
||||
if (isRenaming && !releaseProfile.IncludePreferredWhenRenaming)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var preferredPair in releaseProfile.Preferred)
|
||||
{
|
||||
var term = preferredPair.Key;
|
||||
|
||||
if (_termMatcher.IsMatch(term, title))
|
||||
{
|
||||
result.Add(preferredPair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.Profiles.Releases
|
||||
{
|
||||
public class ReleaseProfile : ModelBase
|
||||
{
|
||||
public string Required { get; set; }
|
||||
public string Ignored { get; set; }
|
||||
public List<KeyValuePair<string, int>> Preferred { get; set; }
|
||||
public bool IncludePreferredWhenRenaming { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
|
||||
public ReleaseProfile()
|
||||
{
|
||||
Preferred = new List<KeyValuePair<string, int>>();
|
||||
IncludePreferredWhenRenaming = true;
|
||||
Tags = new HashSet<int>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Profiles.Releases
|
||||
{
|
||||
public interface IRestrictionRepository : IBasicRepository<ReleaseProfile>
|
||||
{
|
||||
}
|
||||
|
||||
public class ReleaseProfileRepository : BasicRepository<ReleaseProfile>, IRestrictionRepository
|
||||
{
|
||||
public ReleaseProfileRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
||||
: base(database, eventAggregator)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Core.Profiles.Releases
|
||||
{
|
||||
public interface IReleaseProfileService
|
||||
{
|
||||
List<ReleaseProfile> All();
|
||||
List<ReleaseProfile> AllForTag(int tagId);
|
||||
List<ReleaseProfile> AllForTags(HashSet<int> tagIds);
|
||||
ReleaseProfile Get(int id);
|
||||
void Delete(int id);
|
||||
ReleaseProfile Add(ReleaseProfile restriction);
|
||||
ReleaseProfile Update(ReleaseProfile restriction);
|
||||
}
|
||||
|
||||
public class ReleaseProfileService : IReleaseProfileService
|
||||
{
|
||||
private readonly IRestrictionRepository _repo;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ReleaseProfileService(IRestrictionRepository repo, Logger logger)
|
||||
{
|
||||
_repo = repo;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<ReleaseProfile> All()
|
||||
{
|
||||
return _repo.All().ToList();
|
||||
}
|
||||
|
||||
public List<ReleaseProfile> AllForTag(int tagId)
|
||||
{
|
||||
return _repo.All().Where(r => r.Tags.Contains(tagId)).ToList();
|
||||
}
|
||||
|
||||
public List<ReleaseProfile> AllForTags(HashSet<int> tagIds)
|
||||
{
|
||||
return _repo.All().Where(r => r.Tags.Intersect(tagIds).Any() || r.Tags.Empty()).ToList();
|
||||
}
|
||||
|
||||
public ReleaseProfile Get(int id)
|
||||
{
|
||||
return _repo.Get(id);
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
{
|
||||
_repo.Delete(id);
|
||||
}
|
||||
|
||||
public ReleaseProfile Add(ReleaseProfile restriction)
|
||||
{
|
||||
return _repo.Insert(restriction);
|
||||
}
|
||||
|
||||
public ReleaseProfile Update(ReleaseProfile restriction)
|
||||
{
|
||||
return _repo.Update(restriction);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using NzbDrone.Common.Cache;
|
||||
|
||||
namespace NzbDrone.Core.Restrictions
|
||||
namespace NzbDrone.Core.Profiles.Releases
|
||||
{
|
||||
public interface ITermMatcher
|
||||
{
|
|
@ -1,18 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.Restrictions
|
||||
{
|
||||
public class Restriction : ModelBase
|
||||
{
|
||||
public string Required { get; set; }
|
||||
public string Preferred { get; set; }
|
||||
public string Ignored { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
|
||||
public Restriction()
|
||||
{
|
||||
Tags = new HashSet<int>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
namespace NzbDrone.Core.Restrictions
|
||||
{
|
||||
public interface IRestrictionRepository : IBasicRepository<Restriction>
|
||||
{
|
||||
}
|
||||
|
||||
public class RestrictionRepository : BasicRepository<Restriction>, IRestrictionRepository
|
||||
{
|
||||
public RestrictionRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
||||
: base(database, eventAggregator)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Core.Restrictions
|
||||
{
|
||||
public interface IRestrictionService
|
||||
{
|
||||
List<Restriction> All();
|
||||
List<Restriction> AllForTag(int tagId);
|
||||
List<Restriction> AllForTags(HashSet<int> tagIds);
|
||||
Restriction Get(int id);
|
||||
void Delete(int id);
|
||||
Restriction Add(Restriction restriction);
|
||||
Restriction Update(Restriction restriction);
|
||||
}
|
||||
|
||||
public class RestrictionService : IRestrictionService
|
||||
{
|
||||
private readonly IRestrictionRepository _repo;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public RestrictionService(IRestrictionRepository repo, Logger logger)
|
||||
{
|
||||
_repo = repo;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<Restriction> All()
|
||||
{
|
||||
return _repo.All().ToList();
|
||||
}
|
||||
|
||||
public List<Restriction> AllForTag(int tagId)
|
||||
{
|
||||
return _repo.All().Where(r => r.Tags.Contains(tagId)).ToList();
|
||||
}
|
||||
|
||||
public List<Restriction> AllForTags(HashSet<int> tagIds)
|
||||
{
|
||||
return _repo.All().Where(r => r.Tags.Intersect(tagIds).Any() || r.Tags.Empty()).ToList();
|
||||
}
|
||||
|
||||
public Restriction Get(int id)
|
||||
{
|
||||
return _repo.Get(id);
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
{
|
||||
_repo.Delete(id);
|
||||
}
|
||||
|
||||
public Restriction Add(Restriction restriction)
|
||||
{
|
||||
return _repo.Insert(restriction);
|
||||
}
|
||||
|
||||
public Restriction Update(Restriction restriction)
|
||||
{
|
||||
return _repo.Update(restriction);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using System.Linq;
|
|||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Notifications;
|
||||
using NzbDrone.Core.Profiles.Delay;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Tags
|
||||
|
@ -27,21 +27,21 @@ namespace NzbDrone.Core.Tags
|
|||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IDelayProfileService _delayProfileService;
|
||||
private readonly INotificationFactory _notificationFactory;
|
||||
private readonly IRestrictionService _restrictionService;
|
||||
private readonly IReleaseProfileService _releaseProfileService;
|
||||
private readonly ISeriesService _seriesService;
|
||||
|
||||
public TagService(ITagRepository repo,
|
||||
IEventAggregator eventAggregator,
|
||||
IDelayProfileService delayProfileService,
|
||||
INotificationFactory notificationFactory,
|
||||
IRestrictionService restrictionService,
|
||||
IReleaseProfileService releaseProfileService,
|
||||
ISeriesService seriesService)
|
||||
{
|
||||
_repo = repo;
|
||||
_eventAggregator = eventAggregator;
|
||||
_delayProfileService = delayProfileService;
|
||||
_notificationFactory = notificationFactory;
|
||||
_restrictionService = restrictionService;
|
||||
_releaseProfileService = releaseProfileService;
|
||||
_seriesService = seriesService;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ namespace NzbDrone.Core.Tags
|
|||
var tag = GetTag(tagId);
|
||||
var delayProfiles = _delayProfileService.AllForTag(tagId);
|
||||
var notifications = _notificationFactory.AllForTag(tagId);
|
||||
var restrictions = _restrictionService.AllForTag(tagId);
|
||||
var restrictions = _releaseProfileService.AllForTag(tagId);
|
||||
var series = _seriesService.AllForTag(tagId);
|
||||
|
||||
return new TagDetails
|
||||
|
@ -91,7 +91,7 @@ namespace NzbDrone.Core.Tags
|
|||
var tags = All();
|
||||
var delayProfiles = _delayProfileService.All();
|
||||
var notifications = _notificationFactory.All();
|
||||
var restrictions = _restrictionService.All();
|
||||
var restrictions = _releaseProfileService.All();
|
||||
var series = _seriesService.GetAllSeries();
|
||||
|
||||
var details = new List<TagDetails>();
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.SignalR;
|
||||
using Sonarr.Api.V3.Episodes;
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using Nancy;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using Nancy;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.SignalR;
|
||||
using Sonarr.Http.Extensions;
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Collections.Generic;
|
|||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
using Nancy;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.History;
|
||||
using Sonarr.Api.V3.Episodes;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using Sonarr.Http;
|
||||
|
||||
|
@ -28,9 +28,15 @@ namespace Sonarr.Api.V3.Indexers
|
|||
|
||||
if (decision.RemoteEpisode.Series != null)
|
||||
{
|
||||
release.QualityWeight = decision.RemoteEpisode.Series
|
||||
.Profile.Value
|
||||
.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100;
|
||||
release.QualityWeight = decision.RemoteEpisode
|
||||
.Series
|
||||
.Profile.Value
|
||||
.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 100;
|
||||
|
||||
release.LanguageWeight = decision.RemoteEpisode
|
||||
.Series
|
||||
.LanguageProfile.Value
|
||||
.Languages.FindIndex(v => v.Language == release.Language) * 100;
|
||||
}
|
||||
|
||||
release.QualityWeight += release.Quality.Revision.Real * 10;
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace Sonarr.Api.V3.Indexers
|
|||
public bool SceneSource { get; set; }
|
||||
public int SeasonNumber { get; set; }
|
||||
public Language Language { get; set; }
|
||||
public int LanguageWeight { get; set; }
|
||||
public string AirDate { get; set; }
|
||||
public string SeriesTitle { get; set; }
|
||||
public int[] EpisodeNumbers { get; set; }
|
||||
|
@ -45,6 +46,7 @@ namespace Sonarr.Api.V3.Indexers
|
|||
public string InfoUrl { get; set; }
|
||||
public bool DownloadAllowed { get; set; }
|
||||
public int ReleaseWeight { get; set; }
|
||||
public int PreferredWordScore { get; set; }
|
||||
|
||||
public string MagnetUrl { get; set; }
|
||||
public string InfoHash { get; set; }
|
||||
|
@ -104,7 +106,7 @@ namespace Sonarr.Api.V3.Indexers
|
|||
InfoUrl = releaseInfo.InfoUrl,
|
||||
DownloadAllowed = remoteEpisode.DownloadAllowed,
|
||||
//ReleaseWeight
|
||||
|
||||
PreferredWordScore = remoteEpisode.PreferredWordScore,
|
||||
|
||||
MagnetUrl = torrentInfo.MagnetUrl,
|
||||
InfoHash = torrentInfo.InfoHash,
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
using System.Collections.Generic;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using Sonarr.Http;
|
||||
|
||||
namespace Sonarr.Api.V3.Profiles.Release
|
||||
{
|
||||
public class ReleaseProfileModule : SonarrRestModule<ReleaseProfileResource>
|
||||
{
|
||||
private readonly IReleaseProfileService _releaseProfileService;
|
||||
|
||||
|
||||
public ReleaseProfileModule(IReleaseProfileService releaseProfileService)
|
||||
{
|
||||
_releaseProfileService = releaseProfileService;
|
||||
|
||||
GetResourceById = Get;
|
||||
GetResourceAll = GetAll;
|
||||
CreateResource = Create;
|
||||
UpdateResource = Update;
|
||||
DeleteResource = Delete;
|
||||
|
||||
SharedValidator.Custom(restriction =>
|
||||
{
|
||||
if (restriction.Ignored.IsNullOrWhiteSpace() && restriction.Required.IsNullOrWhiteSpace() && restriction.Preferred.Empty())
|
||||
{
|
||||
return new ValidationFailure("", "'Must contain', 'Must not contain' or 'Preferred' is required");
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private ReleaseProfileResource Get(int id)
|
||||
{
|
||||
return _releaseProfileService.Get(id).ToResource();
|
||||
}
|
||||
|
||||
private List<ReleaseProfileResource> GetAll()
|
||||
{
|
||||
return _releaseProfileService.All().ToResource();
|
||||
}
|
||||
|
||||
private int Create(ReleaseProfileResource resource)
|
||||
{
|
||||
return _releaseProfileService.Add(resource.ToModel()).Id;
|
||||
}
|
||||
|
||||
private void Update(ReleaseProfileResource resource)
|
||||
{
|
||||
_releaseProfileService.Update(resource.ToModel());
|
||||
}
|
||||
|
||||
private void Delete(int id)
|
||||
{
|
||||
_releaseProfileService.Delete(id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,19 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using Sonarr.Http.REST;
|
||||
|
||||
namespace Sonarr.Api.V3.Restrictions
|
||||
namespace Sonarr.Api.V3.Profiles.Release
|
||||
{
|
||||
public class RestrictionResource : RestResource
|
||||
public class ReleaseProfileResource : RestResource
|
||||
{
|
||||
public string Required { get; set; }
|
||||
public string Preferred { get; set; }
|
||||
public string Ignored { get; set; }
|
||||
public List<KeyValuePair<string, int>> Preferred { get; set; }
|
||||
public bool IncludePreferredWhenRenaming { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
|
||||
public RestrictionResource()
|
||||
public ReleaseProfileResource()
|
||||
{
|
||||
Tags = new HashSet<int>();
|
||||
}
|
||||
|
@ -20,37 +21,39 @@ namespace Sonarr.Api.V3.Restrictions
|
|||
|
||||
public static class RestrictionResourceMapper
|
||||
{
|
||||
public static RestrictionResource ToResource(this Restriction model)
|
||||
public static ReleaseProfileResource ToResource(this ReleaseProfile model)
|
||||
{
|
||||
if (model == null) return null;
|
||||
|
||||
return new RestrictionResource
|
||||
return new ReleaseProfileResource
|
||||
{
|
||||
Id = model.Id,
|
||||
|
||||
Required = model.Required,
|
||||
Preferred = model.Preferred,
|
||||
Ignored = model.Ignored,
|
||||
Preferred = model.Preferred,
|
||||
IncludePreferredWhenRenaming = model.IncludePreferredWhenRenaming,
|
||||
Tags = new HashSet<int>(model.Tags)
|
||||
};
|
||||
}
|
||||
|
||||
public static Restriction ToModel(this RestrictionResource resource)
|
||||
public static ReleaseProfile ToModel(this ReleaseProfileResource resource)
|
||||
{
|
||||
if (resource == null) return null;
|
||||
|
||||
return new Restriction
|
||||
return new ReleaseProfile
|
||||
{
|
||||
Id = resource.Id,
|
||||
|
||||
Required = resource.Required,
|
||||
Preferred = resource.Preferred,
|
||||
Ignored = resource.Ignored,
|
||||
Preferred = resource.Preferred,
|
||||
IncludePreferredWhenRenaming = resource.IncludePreferredWhenRenaming,
|
||||
Tags = new HashSet<int>(resource.Tags)
|
||||
};
|
||||
}
|
||||
|
||||
public static List<RestrictionResource> ToResource(this IEnumerable<Restriction> models)
|
||||
public static List<ReleaseProfileResource> ToResource(this IEnumerable<ReleaseProfile> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Restrictions;
|
||||
using Sonarr.Http;
|
||||
|
||||
namespace Sonarr.Api.V3.Restrictions
|
||||
{
|
||||
public class RestrictionModule : SonarrRestModule<RestrictionResource>
|
||||
{
|
||||
private readonly IRestrictionService _restrictionService;
|
||||
|
||||
|
||||
public RestrictionModule(IRestrictionService restrictionService)
|
||||
{
|
||||
_restrictionService = restrictionService;
|
||||
|
||||
GetResourceById = Get;
|
||||
GetResourceAll = GetAll;
|
||||
CreateResource = Create;
|
||||
UpdateResource = Update;
|
||||
DeleteResource = Delete;
|
||||
|
||||
SharedValidator.Custom(restriction =>
|
||||
{
|
||||
if (restriction.Ignored.IsNullOrWhiteSpace() && restriction.Required.IsNullOrWhiteSpace())
|
||||
{
|
||||
return new ValidationFailure("", "Either 'Must contain' or 'Must not contain' is required");
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private RestrictionResource Get(int id)
|
||||
{
|
||||
return _restrictionService.Get(id).ToResource();
|
||||
}
|
||||
|
||||
private List<RestrictionResource> GetAll()
|
||||
{
|
||||
return _restrictionService.All().ToResource();
|
||||
}
|
||||
|
||||
private int Create(RestrictionResource resource)
|
||||
{
|
||||
return _restrictionService.Add(resource.ToModel()).Id;
|
||||
}
|
||||
|
||||
private void Update(RestrictionResource resource)
|
||||
{
|
||||
_restrictionService.Update(resource.ToModel());
|
||||
}
|
||||
|
||||
private void Delete(int id)
|
||||
{
|
||||
_restrictionService.Delete(id);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -175,8 +175,8 @@
|
|||
<Compile Include="Qualities\QualityDefinitionResource.cs" />
|
||||
<Compile Include="Queue\QueueModule.cs" />
|
||||
<Compile Include="Queue\QueueResource.cs" />
|
||||
<Compile Include="Restrictions\RestrictionModule.cs" />
|
||||
<Compile Include="Restrictions\RestrictionResource.cs" />
|
||||
<Compile Include="Profiles\Release\ReleaseProfileModule.cs" />
|
||||
<Compile Include="Profiles\Release\ReleaseProfileResource.cs" />
|
||||
<Compile Include="RootFolders\RootFolderModule.cs" />
|
||||
<Compile Include="RootFolders\RootFolderResource.cs" />
|
||||
<Compile Include="SeasonPass\SeasonPassResource.cs" />
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.SignalR;
|
||||
using Sonarr.Api.V3.Episodes;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.SignalR;
|
||||
using Sonarr.Api.V3.Episodes;
|
||||
|
|
Loading…
Reference in New Issue