mirror of
https://github.com/lidarr/Lidarr
synced 2024-12-24 16:51:58 +00:00
Fixed: Extrapolate scene numbering but won't auto import.
This commit is contained in:
parent
23bd9440b3
commit
6d046a8df8
8 changed files with 240 additions and 4 deletions
|
@ -24,6 +24,7 @@ public class EpisodeResource : RestResource
|
|||
public Nullable<Int32> SceneAbsoluteEpisodeNumber { get; set; }
|
||||
public Nullable<Int32> SceneEpisodeNumber { get; set; }
|
||||
public Nullable<Int32> SceneSeasonNumber { get; set; }
|
||||
public Boolean UnverifiedSceneNumbering { get; set; }
|
||||
public DateTime? EndTime { get; set; }
|
||||
public DateTime? GrabDate { get; set; }
|
||||
public String SeriesTitle { get; set; }
|
||||
|
|
|
@ -48,6 +48,8 @@ public void SetUp()
|
|||
_episodes.Add(new Episode { SeasonNumber = 2, EpisodeNumber = 3 });
|
||||
_episodes.Add(new Episode { SeasonNumber = 2, EpisodeNumber = 4 });
|
||||
_episodes.Add(new Episode { SeasonNumber = 2, EpisodeNumber = 5 });
|
||||
_episodes.Add(new Episode { SeasonNumber = 3, EpisodeNumber = 1 });
|
||||
_episodes.Add(new Episode { SeasonNumber = 3, EpisodeNumber = 2 });
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(v => v.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
|
@ -143,5 +145,122 @@ public void should_not_clear_scenenumbering_if_no_results_at_all_from_thexem()
|
|||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_flag_unknown_future_episodes_if_existing_season_is_mapped()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
_theXemTvdbMappings.RemoveAll(v => v.Tvdb.Season == 2 && v.Tvdb.Episode == 5);
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
var episode = _episodes.First(v => v.SeasonNumber == 2 && v.EpisodeNumber == 5);
|
||||
|
||||
episode.UnverifiedSceneNumbering.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_flag_unknown_future_season_if_future_season_is_shifted()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
var episode = _episodes.First(v => v.SeasonNumber == 3 && v.EpisodeNumber == 1);
|
||||
|
||||
episode.UnverifiedSceneNumbering.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_flag_unknown_future_season_if_future_season_is_not_shifted()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
_theXemTvdbMappings.RemoveAll(v => v.Scene.Season == 3);
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
var episode = _episodes.First(v => v.SeasonNumber == 3 && v.EpisodeNumber == 1);
|
||||
|
||||
episode.UnverifiedSceneNumbering.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_extrapolate_season_with_specials()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
var specialMapping = _theXemTvdbMappings.First(v => v.Tvdb.Season == 2 && v.Tvdb.Episode == 5);
|
||||
specialMapping.Tvdb.Season = 0;
|
||||
specialMapping.Tvdb.Episode = 1;
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
var episode = _episodes.First(v => v.SeasonNumber == 2 && v.EpisodeNumber == 5);
|
||||
|
||||
episode.UnverifiedSceneNumbering.Should().BeTrue();
|
||||
episode.SceneSeasonNumber.Should().NotHaveValue();
|
||||
episode.SceneEpisodeNumber.Should().NotHaveValue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_extrapolate_season_with_future_episodes()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
_theXemTvdbMappings.RemoveAll(v => v.Tvdb.Season == 2 && v.Tvdb.Episode == 5);
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
var episode = _episodes.First(v => v.SeasonNumber == 2 && v.EpisodeNumber == 5);
|
||||
|
||||
episode.UnverifiedSceneNumbering.Should().BeTrue();
|
||||
episode.SceneSeasonNumber.Should().Be(3);
|
||||
episode.SceneEpisodeNumber.Should().Be(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_extrapolate_season_with_shifted_episodes()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
_theXemTvdbMappings.RemoveAll(v => v.Tvdb.Season == 2 && v.Tvdb.Episode == 5);
|
||||
var dualMapping = _theXemTvdbMappings.First(v => v.Tvdb.Season == 2 && v.Tvdb.Episode == 4);
|
||||
dualMapping.Scene.Season = 2;
|
||||
dualMapping.Scene.Episode = 3;
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
var episode = _episodes.First(v => v.SeasonNumber == 2 && v.EpisodeNumber == 5);
|
||||
|
||||
episode.UnverifiedSceneNumbering.Should().BeTrue();
|
||||
episode.SceneSeasonNumber.Should().Be(2);
|
||||
episode.SceneEpisodeNumber.Should().Be(4);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_extrapolate_shifted_future_seasons()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
var episode = _episodes.First(v => v.SeasonNumber == 3 && v.EpisodeNumber == 2);
|
||||
|
||||
episode.UnverifiedSceneNumbering.Should().BeTrue();
|
||||
episode.SceneSeasonNumber.Should().Be(4);
|
||||
episode.SceneEpisodeNumber.Should().Be(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_extrapolate_matching_future_seasons()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
_theXemTvdbMappings.RemoveAll(v => v.Scene.Season != 1);
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
var episode = _episodes.First(v => v.SeasonNumber == 3 && v.EpisodeNumber == 2);
|
||||
|
||||
episode.UnverifiedSceneNumbering.Should().BeFalse();
|
||||
episode.SceneSeasonNumber.Should().NotHaveValue();
|
||||
episode.SceneEpisodeNumber.Should().NotHaveValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ private void PerformUpdate(Series series)
|
|||
episode.SceneAbsoluteEpisodeNumber = null;
|
||||
episode.SceneSeasonNumber = null;
|
||||
episode.SceneEpisodeNumber = null;
|
||||
episode.UnverifiedSceneNumbering = false;
|
||||
}
|
||||
|
||||
foreach (var mapping in mappings)
|
||||
|
@ -71,6 +72,11 @@ private void PerformUpdate(Series series)
|
|||
episode.SceneEpisodeNumber = mapping.Scene.Episode;
|
||||
}
|
||||
|
||||
if (episodes.Any(v => v.SceneEpisodeNumber.HasValue && v.SceneSeasonNumber != 0))
|
||||
{
|
||||
ExtrapolateMappings(series, episodes, mappings);
|
||||
}
|
||||
|
||||
_episodeService.UpdateEpisodes(episodes);
|
||||
series.UseSceneNumbering = mappings.Any();
|
||||
_seriesService.UpdateSeries(series);
|
||||
|
@ -83,6 +89,70 @@ private void PerformUpdate(Series series)
|
|||
}
|
||||
}
|
||||
|
||||
private void ExtrapolateMappings(Series series, List<Episode> episodes, List<Model.XemSceneTvdbMapping> mappings)
|
||||
{
|
||||
var mappedEpisodes = episodes.Where(v => v.SeasonNumber != 0 && v.SceneEpisodeNumber.HasValue).ToList();
|
||||
var mappedSeasons = new HashSet<int>(mappedEpisodes.Select(v => v.SeasonNumber).Distinct());
|
||||
var lastSceneSeason = mappings.Select(v => v.Scene.Season).Max();
|
||||
var lastTvdbSeason = mappings.Select(v => v.Tvdb.Season).Max();
|
||||
|
||||
// Mark all episodes not on the xem as unverified.
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
if (episode.SeasonNumber == 0) continue;
|
||||
if (episode.SceneEpisodeNumber.HasValue) continue;
|
||||
|
||||
if (mappedSeasons.Contains(episode.SeasonNumber))
|
||||
{
|
||||
episode.UnverifiedSceneNumbering = true;
|
||||
}
|
||||
|
||||
if (lastSceneSeason != lastTvdbSeason && episode.SeasonNumber > lastTvdbSeason)
|
||||
{
|
||||
episode.UnverifiedSceneNumbering = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
if (episode.SeasonNumber == 0) continue;
|
||||
if (episode.SceneEpisodeNumber.HasValue) continue;
|
||||
if (episode.SeasonNumber < lastTvdbSeason) continue;
|
||||
if (!episode.UnverifiedSceneNumbering) continue;
|
||||
|
||||
var seasonMappings = mappings.Where(v => v.Tvdb.Season == episode.SeasonNumber).ToList();
|
||||
if (seasonMappings.Any(v => v.Tvdb.Episode >= episode.EpisodeNumber))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (seasonMappings.Any())
|
||||
{
|
||||
var lastEpisodeMapping = seasonMappings.OrderBy(v => v.Tvdb.Episode).Last();
|
||||
var lastSceneSeasonMapping = mappings.Where(v => v.Scene.Season == lastEpisodeMapping.Scene.Season).OrderBy(v => v.Scene.Episode).Last();
|
||||
|
||||
if (lastSceneSeasonMapping.Tvdb.Season == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var offset = episode.EpisodeNumber - lastEpisodeMapping.Tvdb.Episode;
|
||||
|
||||
episode.SceneSeasonNumber = lastEpisodeMapping.Scene.Season;
|
||||
episode.SceneEpisodeNumber = lastEpisodeMapping.Scene.Episode + offset;
|
||||
episode.SceneAbsoluteEpisodeNumber = lastEpisodeMapping.Scene.Absolute + offset;
|
||||
}
|
||||
else if (lastTvdbSeason != lastSceneSeason)
|
||||
{
|
||||
var offset = episode.SeasonNumber - lastTvdbSeason;
|
||||
|
||||
episode.SceneSeasonNumber = lastSceneSeason + offset;
|
||||
episode.SceneEpisodeNumber = episode.EpisodeNumber;
|
||||
// TODO: SceneAbsoluteEpisodeNumber.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshCache()
|
||||
{
|
||||
var ids = _xemProxy.GetXemSeriesIds();
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(92)]
|
||||
public class add_unverifiedscenenumbering : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("Episodes").AddColumn("UnverifiedSceneNumbering").AsBoolean().WithDefaultValue(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
{
|
||||
public class UnverifiedSceneNumberingSpecification : IImportDecisionEngineSpecification
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
|
||||
public UnverifiedSceneNumberingSpecification(Logger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalEpisode localEpisode)
|
||||
{
|
||||
if (localEpisode.Episodes.Any(v => v.UnverifiedSceneNumbering))
|
||||
{
|
||||
_logger.Debug("This file uses unverified scene numbers, will not auto-import until numbering is confirmed on TheXEM. Skipping {0}", localEpisode.Path);
|
||||
return Decision.Reject("This show has individual episode mappings on TheXEM but the mapping for this episode has not been confirmed yet by their administrators. TheXEM needs manual input.");
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -264,6 +264,7 @@
|
|||
<Compile Include="Datastore\Migration\083_additonal_blacklist_columns.cs" />
|
||||
<Compile Include="Datastore\Migration\082_add_fanzub_settings.cs" />
|
||||
<Compile Include="Datastore\Migration\088_pushbullet_devices_channels_list.cs" />
|
||||
<Compile Include="Datastore\Migration\092_add_unverifiedscenenumbering.cs" />
|
||||
<Compile Include="Datastore\Migration\090_update_kickass_url.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||
|
@ -621,6 +622,7 @@
|
|||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotSampleSpecification.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotUnpackingSpecification.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\SameEpisodesImportSpecification.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\UnverifiedSceneNumberingSpecification.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecification.cs" />
|
||||
<Compile Include="MediaFiles\Events\EpisodeDownloadedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\EpisodeFileAddedEvent.cs" />
|
||||
|
|
|
@ -29,6 +29,7 @@ public Episode()
|
|||
public Nullable<Int32> SceneAbsoluteEpisodeNumber { get; set; }
|
||||
public Nullable<Int32> SceneSeasonNumber { get; set; }
|
||||
public Nullable<Int32> SceneEpisodeNumber { get; set; }
|
||||
public bool UnverifiedSceneNumbering { get; set; }
|
||||
public Ratings Ratings { get; set; }
|
||||
public List<MediaCover.MediaCover> Images { get; set; }
|
||||
|
||||
|
|
|
@ -7,10 +7,12 @@ module.exports = NzbDroneCell.extend({
|
|||
render : function() {
|
||||
this.$el.empty();
|
||||
|
||||
if (SeriesCollection.get(this.model.get('seriesId')).get('seriesType') === 'anime') {
|
||||
if (this.model.get('seasonNumber') > 0 && !this.model.has('absoluteEpisodeNumber')) {
|
||||
this.$el.html('<i class="icon-sonarr-form-warning" title="Episode does not have an absolute episode number"></i>');
|
||||
}
|
||||
if (this.model.get('unverifiedSceneNumbering')) {
|
||||
this.$el.html('<i class="icon-sonarr-form-warning" title="Scene number hasn\'t been verified yet."></i>');
|
||||
}
|
||||
|
||||
else if (SeriesCollection.get(this.model.get('seriesId')).get('seriesType') === 'anime' && this.model.get('seasonNumber') > 0 && !this.model.has('absoluteEpisodeNumber')) {
|
||||
this.$el.html('<i class="icon-sonarr-form-warning" title="Episode does not have an absolute episode number"></i>');
|
||||
}
|
||||
|
||||
this.delegateEvents();
|
||||
|
|
Loading…
Reference in a new issue