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