mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-10 23:33:38 -07:00
Remove Remaining TV Code
This commit is contained in:
parent
81716762d8
commit
a80360f6fd
98 changed files with 135 additions and 6151 deletions
|
@ -3,7 +3,7 @@ export const BACKUP = 'Backup';
|
|||
export const CHECK_FOR_FINISHED_DOWNLOAD = 'CheckForFinishedDownload';
|
||||
export const CLEAR_BLACKLIST = 'ClearBlacklist';
|
||||
export const CLEAR_LOGS = 'ClearLog';
|
||||
export const CUTOFF_UNMET_EPISODE_SEARCH = 'CutoffUnmetEpisodeSearch';
|
||||
export const CUTOFF_UNMET_EPISODE_SEARCH = 'CutoffUnmetAlbumSearch';
|
||||
export const DELETE_LOG_FILES = 'DeleteLogFiles';
|
||||
export const DELETE_UPDATE_LOG_FILES = 'DeleteUpdateLogFiles';
|
||||
export const DOWNLOADED_ALBUMS_SCAN = 'DownloadedAlbumsScan';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
|
@ -76,8 +76,8 @@ namespace NzbDrone.App.Test
|
|||
[Test]
|
||||
public void should_return_same_instance_of_singletons_by_different_same_interface()
|
||||
{
|
||||
var first = _container.ResolveAll<IHandle<EpisodeGrabbedEvent>>().OfType<DownloadMonitoringService>().Single();
|
||||
var second = _container.ResolveAll<IHandle<EpisodeGrabbedEvent>>().OfType<DownloadMonitoringService>().Single();
|
||||
var first = _container.ResolveAll<IHandle<AlbumGrabbedEvent>>().OfType<DownloadMonitoringService>().Single();
|
||||
var second = _container.ResolveAll<IHandle<AlbumGrabbedEvent>>().OfType<DownloadMonitoringService>().Single();
|
||||
|
||||
first.Should().BeSameAs(second);
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ namespace NzbDrone.App.Test
|
|||
[Test]
|
||||
public void should_return_same_instance_of_singletons_by_different_interfaces()
|
||||
{
|
||||
var first = _container.ResolveAll<IHandle<EpisodeGrabbedEvent>>().OfType<DownloadMonitoringService>().Single();
|
||||
var first = _container.ResolveAll<IHandle<AlbumGrabbedEvent>>().OfType<DownloadMonitoringService>().Single();
|
||||
var second = (DownloadMonitoringService)_container.Resolve<IExecute<CheckForFinishedDownloadCommand>>();
|
||||
|
||||
first.Should().BeSameAs(second);
|
||||
|
|
|
@ -1,312 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DataAugmentation.Xem;
|
||||
using NzbDrone.Core.DataAugmentation.Xem.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.DataAugmentation.SceneNumbering
|
||||
{
|
||||
[TestFixture]
|
||||
public class XemServiceFixture : CoreTest<XemService>
|
||||
{
|
||||
private Series _series;
|
||||
private List<int> _theXemSeriesIds;
|
||||
private List<XemSceneTvdbMapping> _theXemTvdbMappings;
|
||||
private List<Episode> _episodes;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_series = Builder<Series>.CreateNew()
|
||||
.With(v => v.TvdbId = 10)
|
||||
.With(v => v.UseSceneNumbering = false)
|
||||
.BuildNew();
|
||||
|
||||
_theXemSeriesIds = new List<int> { 120 };
|
||||
Mocker.GetMock<IXemProxy>()
|
||||
.Setup(v => v.GetXemSeriesIds())
|
||||
.Returns(_theXemSeriesIds);
|
||||
|
||||
_theXemTvdbMappings = new List<XemSceneTvdbMapping>();
|
||||
Mocker.GetMock<IXemProxy>()
|
||||
.Setup(v => v.GetSceneTvdbMappings(10))
|
||||
.Returns(_theXemTvdbMappings);
|
||||
|
||||
_episodes = new List<Episode>();
|
||||
_episodes.Add(new Episode { SeasonNumber = 1, EpisodeNumber = 1 });
|
||||
_episodes.Add(new Episode { SeasonNumber = 1, EpisodeNumber = 2 });
|
||||
_episodes.Add(new Episode { SeasonNumber = 2, EpisodeNumber = 1 });
|
||||
_episodes.Add(new Episode { SeasonNumber = 2, EpisodeNumber = 2 });
|
||||
_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>()))
|
||||
.Returns(_episodes);
|
||||
}
|
||||
|
||||
private void GivenTvdbMappings()
|
||||
{
|
||||
_theXemSeriesIds.Add(10);
|
||||
|
||||
AddTvdbMapping(1, 1, 1, 1, 1, 1); // 1x01 -> 1x01
|
||||
AddTvdbMapping(2, 1, 2, 2, 1, 2); // 1x02 -> 1x02
|
||||
AddTvdbMapping(3, 2, 1, 3, 2, 1); // 2x01 -> 2x01
|
||||
AddTvdbMapping(4, 2, 2, 4, 2, 2); // 2x02 -> 2x02
|
||||
AddTvdbMapping(5, 2, 3, 5, 2, 3); // 2x03 -> 2x03
|
||||
AddTvdbMapping(6, 3, 1, 6, 2, 4); // 3x01 -> 2x04
|
||||
AddTvdbMapping(7, 3, 2, 7, 2, 5); // 3x02 -> 2x05
|
||||
}
|
||||
|
||||
private void GivenExistingMapping()
|
||||
{
|
||||
_series.UseSceneNumbering = true;
|
||||
|
||||
_episodes[0].SceneSeasonNumber = 1;
|
||||
_episodes[0].SceneEpisodeNumber = 1;
|
||||
_episodes[1].SceneSeasonNumber = 1;
|
||||
_episodes[1].SceneEpisodeNumber = 2;
|
||||
_episodes[2].SceneSeasonNumber = 2;
|
||||
_episodes[2].SceneEpisodeNumber = 1;
|
||||
_episodes[3].SceneSeasonNumber = 2;
|
||||
_episodes[3].SceneEpisodeNumber = 2;
|
||||
_episodes[4].SceneSeasonNumber = 2;
|
||||
_episodes[4].SceneEpisodeNumber = 3;
|
||||
_episodes[5].SceneSeasonNumber = 3;
|
||||
_episodes[5].SceneEpisodeNumber = 1;
|
||||
_episodes[6].SceneSeasonNumber = 3;
|
||||
_episodes[6].SceneEpisodeNumber = 1;
|
||||
}
|
||||
|
||||
private void AddTvdbMapping(int sceneAbsolute, int sceneSeason, int sceneEpisode, int tvdbAbsolute, int tvdbSeason, int tvdbEpisode)
|
||||
{
|
||||
_theXemTvdbMappings.Add(new XemSceneTvdbMapping
|
||||
{
|
||||
Scene = new XemValues { Absolute = sceneAbsolute, Season = sceneSeason, Episode = sceneEpisode },
|
||||
Tvdb = new XemValues { Absolute = tvdbAbsolute, Season = tvdbSeason, Episode = tvdbEpisode },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_not_fetch_scenenumbering_if_not_listed()
|
||||
{
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
Mocker.GetMock<IXemProxy>()
|
||||
.Verify(v => v.GetSceneTvdbMappings(10), Times.Never());
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_fetch_scenenumbering()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.UseSceneNumbering == true)), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_clear_scenenumbering_if_removed_from_thexem()
|
||||
{
|
||||
GivenExistingMapping();
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_clear_scenenumbering_if_no_results_at_all_from_thexem()
|
||||
{
|
||||
GivenExistingMapping();
|
||||
|
||||
_theXemSeriesIds.Clear();
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_clear_scenenumbering_if_thexem_throws()
|
||||
{
|
||||
GivenExistingMapping();
|
||||
|
||||
Mocker.GetMock<IXemProxy>()
|
||||
.Setup(v => v.GetXemSeriesIds())
|
||||
.Throws(new InvalidOperationException());
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[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_flag_past_episodes_if_not_causing_overlaps()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
_theXemTvdbMappings.RemoveAll(v => v.Scene.Season == 2);
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
var episode = _episodes.First(v => v.SeasonNumber == 2 && v.EpisodeNumber == 1);
|
||||
|
||||
episode.UnverifiedSceneNumbering.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_flag_past_episodes_if_causing_overlap()
|
||||
{
|
||||
GivenTvdbMappings();
|
||||
_theXemTvdbMappings.RemoveAll(v => v.Scene.Season == 2 && v.Tvdb.Episode <= 1);
|
||||
_theXemTvdbMappings.First(v => v.Scene.Season == 2 && v.Scene.Episode == 2).Scene.Episode = 1;
|
||||
|
||||
Subject.Handle(new SeriesUpdatedEvent(_series));
|
||||
|
||||
var episode = _episodes.First(v => v.SeasonNumber == 2 && v.EpisodeNumber == 1);
|
||||
|
||||
episode.UnverifiedSceneNumbering.Should().BeTrue();
|
||||
}
|
||||
|
||||
[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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SameEpisodesSpecificationFixture : CoreTest<SameEpisodesSpecification>
|
||||
{
|
||||
private List<Episode> _episodes;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(e => e.EpisodeFileId = 1)
|
||||
.BuildList();
|
||||
}
|
||||
|
||||
private void GivenEpisodesInFile(List<Episode> episodes)
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodesByFileId(It.IsAny<int>()))
|
||||
.Returns(episodes);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_upgrade_when_new_release_contains_less_episodes()
|
||||
{
|
||||
GivenEpisodesInFile(_episodes);
|
||||
|
||||
Subject.IsSatisfiedBy(new List<Episode> { _episodes.First() }).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_upgrade_when_new_release_contains_more_episodes()
|
||||
{
|
||||
GivenEpisodesInFile(new List<Episode> { _episodes.First() });
|
||||
|
||||
Subject.IsSatisfiedBy(_episodes).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_upgrade_when_new_release_contains_the_same_episodes()
|
||||
{
|
||||
GivenEpisodesInFile(_episodes);
|
||||
|
||||
Subject.IsSatisfiedBy(_episodes).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_upgrade_when_release_contains_the_same_episodes_as_multiple_files()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.BuildList();
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodesByFileId(episodes.First().EpisodeFileId))
|
||||
.Returns(new List<Episode> { episodes.First() });
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodesByFileId(episodes.Last().EpisodeFileId))
|
||||
.Returns(new List<Episode> { episodes.Last() });
|
||||
|
||||
Subject.IsSatisfiedBy(episodes).Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
@ -185,7 +185,7 @@ namespace NzbDrone.Core.Test.Download
|
|||
Subject.DownloadReport(_parseResult);
|
||||
|
||||
Mocker.GetMock<IDownloadClient>().Verify(c => c.Download(It.IsAny<RemoteAlbum>()), Times.Never());
|
||||
VerifyEventNotPublished<EpisodeGrabbedEvent>();
|
||||
VerifyEventNotPublished<AlbumGrabbedEvent>();
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
|
|
@ -1,182 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
||||
{
|
||||
[TestFixture]
|
||||
public class SampleServiceFixture : CoreTest<DetectSample>
|
||||
{
|
||||
private Series _series;
|
||||
private LocalEpisode _localEpisode;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_series = Builder<Series>.CreateNew()
|
||||
.With(s => s.SeriesType = SeriesTypes.Standard)
|
||||
.With(s => s.Runtime = 30)
|
||||
.Build();
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.SeasonNumber = 1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
_localEpisode = new LocalEpisode
|
||||
{
|
||||
Path = @"C:\Test\30 Rock\30.rock.s01e01.avi",
|
||||
Episodes = episodes,
|
||||
Series = _series,
|
||||
Quality = new QualityModel(Quality.MP3_256)
|
||||
};
|
||||
}
|
||||
|
||||
private void GivenFileSize(long size)
|
||||
{
|
||||
_localEpisode.Size = size;
|
||||
}
|
||||
|
||||
private void GivenRuntime(int seconds)
|
||||
{
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Setup(s => s.GetRunTime(It.IsAny<string>()))
|
||||
.Returns(new TimeSpan(0, 0, seconds));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_season_zero()
|
||||
{
|
||||
_localEpisode.Episodes[0].SeasonNumber = 0;
|
||||
ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_for_flv()
|
||||
{
|
||||
_localEpisode.Path = @"C:\Test\some.show.s01e01.flv";
|
||||
|
||||
ShouldBeFalse();
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>().Verify(c => c.GetRunTime(It.IsAny<string>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_for_strm()
|
||||
{
|
||||
_localEpisode.Path = @"C:\Test\some.show.s01e01.strm";
|
||||
|
||||
ShouldBeFalse();
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>().Verify(c => c.GetRunTime(It.IsAny<string>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_runtime()
|
||||
{
|
||||
GivenRuntime(120);
|
||||
GivenFileSize(1000.Megabytes());
|
||||
|
||||
Subject.IsSample(_localEpisode.Series,
|
||||
_localEpisode.Quality,
|
||||
_localEpisode.Path,
|
||||
_localEpisode.Size,
|
||||
_localEpisode.IsSpecial);
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>().Verify(v => v.GetRunTime(It.IsAny<string>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_if_runtime_is_less_than_minimum()
|
||||
{
|
||||
GivenRuntime(60);
|
||||
|
||||
ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_runtime_greater_than_minimum()
|
||||
{
|
||||
GivenRuntime(600);
|
||||
|
||||
ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_if_runtime_greater_than_webisode_minimum()
|
||||
{
|
||||
_series.Runtime = 6;
|
||||
GivenRuntime(299);
|
||||
|
||||
ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_fall_back_to_file_size_if_mediainfo_dll_not_found_acceptable_size()
|
||||
{
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Setup(s => s.GetRunTime(It.IsAny<string>()))
|
||||
.Throws<DllNotFoundException>();
|
||||
|
||||
GivenFileSize(1000.Megabytes());
|
||||
ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_fall_back_to_file_size_if_mediainfo_dll_not_found_undersize()
|
||||
{
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Setup(s => s.GetRunTime(It.IsAny<string>()))
|
||||
.Throws<DllNotFoundException>();
|
||||
|
||||
GivenFileSize(1.Megabytes());
|
||||
ShouldBeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_treat_daily_episode_a_special()
|
||||
{
|
||||
GivenRuntime(600);
|
||||
_series.SeriesType = SeriesTypes.Daily;
|
||||
_localEpisode.Episodes[0].SeasonNumber = 0;
|
||||
ShouldBeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_false_for_anime_special()
|
||||
{
|
||||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_localEpisode.Episodes[0].SeasonNumber = 0;
|
||||
|
||||
ShouldBeFalse();
|
||||
}
|
||||
|
||||
private void ShouldBeTrue()
|
||||
{
|
||||
Subject.IsSample(_localEpisode.Series,
|
||||
_localEpisode.Quality,
|
||||
_localEpisode.Path,
|
||||
_localEpisode.Size,
|
||||
_localEpisode.IsSpecial).Should().BeTrue();
|
||||
}
|
||||
|
||||
private void ShouldBeFalse()
|
||||
{
|
||||
Subject.IsSample(_localEpisode.Series,
|
||||
_localEpisode.Quality,
|
||||
_localEpisode.Path,
|
||||
_localEpisode.Size,
|
||||
_localEpisode.IsSpecial).Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,27 +1,27 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.Test.MetadataSource
|
||||
{
|
||||
[TestFixture]
|
||||
public class SearchSeriesComparerFixture : CoreTest
|
||||
public class SearchArtistComparerFixture : CoreTest
|
||||
{
|
||||
private List<Series> _series;
|
||||
private List<Artist> _artist;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_series = new List<Series>();
|
||||
_artist = new List<Artist>();
|
||||
}
|
||||
|
||||
private void WithSeries(string title)
|
||||
private void WithSeries(string name)
|
||||
{
|
||||
_series.Add(new Series { Title = title });
|
||||
_artist.Add(new Artist { Name = name });
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -30,9 +30,9 @@ namespace NzbDrone.Core.Test.MetadataSource
|
|||
WithSeries("Talking Dead");
|
||||
WithSeries("The Walking Dead");
|
||||
|
||||
_series.Sort(new SearchSeriesComparer("the walking dead"));
|
||||
_artist.Sort(new SearchArtistComparer("the walking dead"));
|
||||
|
||||
_series.First().Title.Should().Be("The Walking Dead");
|
||||
_artist.First().Name.Should().Be("The Walking Dead");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -41,9 +41,9 @@ namespace NzbDrone.Core.Test.MetadataSource
|
|||
WithSeries("Talking Dead");
|
||||
WithSeries("The Walking Dead");
|
||||
|
||||
_series.Sort(new SearchSeriesComparer("walking dead"));
|
||||
_artist.Sort(new SearchArtistComparer("walking dead"));
|
||||
|
||||
_series.First().Title.Should().Be("The Walking Dead");
|
||||
_artist.First().Name.Should().Be("The Walking Dead");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -52,9 +52,9 @@ namespace NzbDrone.Core.Test.MetadataSource
|
|||
WithSeries("The Blacklist");
|
||||
WithSeries("Blacklist");
|
||||
|
||||
_series.Sort(new SearchSeriesComparer("blacklist"));
|
||||
_artist.Sort(new SearchArtistComparer("blacklist"));
|
||||
|
||||
_series.First().Title.Should().Be("Blacklist");
|
||||
_artist.First().Name.Should().Be("Blacklist");
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -63,9 +63,9 @@ namespace NzbDrone.Core.Test.MetadataSource
|
|||
WithSeries("Blacklist");
|
||||
WithSeries("The Blacklist");
|
||||
|
||||
_series.Sort(new SearchSeriesComparer("the blacklist"));
|
||||
_artist.Sort(new SearchArtistComparer("the blacklist"));
|
||||
|
||||
_series.First().Title.Should().Be("The Blacklist");
|
||||
_artist.First().Name.Should().Be("The Blacklist");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -104,7 +104,6 @@
|
|||
<Compile Include="BulkImport\BulkImportFixture.cs" />
|
||||
<Compile Include="Configuration\ConfigCachingFixture.cs" />
|
||||
<Compile Include="Configuration\ConfigServiceFixture.cs" />
|
||||
<Compile Include="DataAugmentation\SceneNumbering\XemServiceFixture.cs" />
|
||||
<Compile Include="DataAugmentation\Scene\SceneMappingProxyFixture.cs" />
|
||||
<Compile Include="DataAugmentation\Scene\SceneMappingServiceFixture.cs" />
|
||||
<Compile Include="DataAugmentation\DailySeries\DailySeriesDataProxyFixture.cs" />
|
||||
|
@ -155,7 +154,6 @@
|
|||
<Compile Include="DecisionEngineTests\RssSync\DeletedTrackFileSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\RssSync\ProperSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\Search\ArtistSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\SameEpisodesSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\RawDiskSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\UpgradeDiskSpecificationFixture.cs" />
|
||||
<Compile Include="DiskSpace\DiskSpaceServiceFixture.cs" />
|
||||
|
@ -274,7 +272,6 @@
|
|||
<Compile Include="MediaFiles\MediaInfo\MediaInfoFormatterTests\FormatAudioCodecFixture.cs" />
|
||||
<Compile Include="MediaFiles\TrackFileMovingServiceTests\MoveTrackFileFixture.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\ImportDecisionMakerFixture.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\SampleServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\Specifications\FreeSpaceSpecificationFixture.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\Specifications\NotUnpackingSpecificationFixture.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\Specifications\UpgradeSpecificationFixture.cs" />
|
||||
|
@ -282,7 +279,7 @@
|
|||
<Compile Include="MediaFiles\MediaFileRepositoryFixture.cs" />
|
||||
<Compile Include="Messaging\Commands\CommandQueueManagerFixture.cs" />
|
||||
<Compile Include="MetadataSource\SkyHook\SkyHookProxySearchFixture.cs" />
|
||||
<Compile Include="MetadataSource\SearchSeriesComparerFixture.cs" />
|
||||
<Compile Include="MetadataSource\SearchArtistComparerFixture.cs" />
|
||||
<Compile Include="MetadataSource\SkyHook\SkyHookProxyFixture.cs" />
|
||||
<Compile Include="MusicTests\AddArtistFixture.cs" />
|
||||
<Compile Include="MusicTests\ArtistNameSlugValidatorFixture.cs" />
|
||||
|
@ -290,7 +287,6 @@
|
|||
<Compile Include="NotificationTests\SynologyIndexerFixture.cs" />
|
||||
<Compile Include="OrganizerTests\FileNameBuilderTests\CleanTitleFixture.cs" />
|
||||
<Compile Include="OrganizerTests\FileNameBuilderTests\TitleTheFixture.cs" />
|
||||
<Compile Include="ParserTests\MiniSeriesEpisodeParserFixture.cs" />
|
||||
<Compile Include="ParserTests\MusicParserFixture.cs" />
|
||||
<Compile Include="Qualities\RevisionComparableFixture.cs" />
|
||||
<Compile Include="QueueTests\QueueServiceFixture.cs" />
|
||||
|
@ -320,15 +316,10 @@
|
|||
<Compile Include="OrganizerTests\GetAlbumFolderFixture.cs" />
|
||||
<Compile Include="OrganizerTests\FileNameBuilderTests\FileNameBuilderFixture.cs" />
|
||||
<Compile Include="OrganizerTests\GetArtistFolderFixture.cs" />
|
||||
<Compile Include="ParserTests\AbsoluteEpisodeNumberParserFixture.cs" />
|
||||
<Compile Include="ParserTests\AnimeMetadataParserFixture.cs" />
|
||||
<Compile Include="ParserTests\ExtendedQualityParserRegex.cs" />
|
||||
<Compile Include="ParserTests\CrapParserFixture.cs" />
|
||||
<Compile Include="ParserTests\DailyEpisodeParserFixture.cs" />
|
||||
<Compile Include="ParserTests\HashedReleaseFixture.cs" />
|
||||
<Compile Include="ParserTests\IsPossibleSpecialEpisodeFixture.cs" />
|
||||
<Compile Include="ParserTests\LanguageParserFixture.cs" />
|
||||
<Compile Include="ParserTests\MultiEpisodeParserFixture.cs" />
|
||||
<Compile Include="ParserTests\NormalizeTitleFixture.cs" />
|
||||
<Compile Include="ParserTests\ParserFixture.cs" />
|
||||
<Compile Include="ParserTests\ParsingServiceTests\GetArtistFixture.cs" />
|
||||
|
@ -336,13 +327,12 @@
|
|||
<Compile Include="ParserTests\QualityParserFixture.cs" />
|
||||
<Compile Include="ParserTests\ReleaseGroupParserFixture.cs" />
|
||||
<Compile Include="ParserTests\SeasonParserFixture.cs" />
|
||||
<Compile Include="ParserTests\SeriesTitleInfoFixture.cs" />
|
||||
<Compile Include="ParserTests\ArtistTitleInfoFixture.cs" />
|
||||
<Compile Include="ParserTests\SingleEpisodeParserFixture.cs" />
|
||||
<Compile Include="ParserTests\SceneCheckerFixture.cs" />
|
||||
<Compile Include="Profiles\ProfileRepositoryFixture.cs" />
|
||||
<Compile Include="Profiles\ProfileServiceFixture.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Providers\XemProxyFixture.cs" />
|
||||
<Compile Include="ProviderTests\DiskProviderTests\ArchiveProviderFixture.cs" />
|
||||
<Compile Include="ProviderTests\DiskScanProviderTests\GetAudioFilesFixture.cs" />
|
||||
<Compile Include="ProviderTests\RecycleBinProviderTests\CleanupFixture.cs" />
|
||||
|
@ -355,23 +345,8 @@
|
|||
<Compile Include="RootFolderTests\RootFolderServiceFixture.cs" />
|
||||
<Compile Include="ThingiProvider\ProviderBaseFixture.cs" />
|
||||
<Compile Include="ThingiProviderTests\NullConfigFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeServiceTests\FindEpisodeByTitleFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeServiceTests\HandleEpisodeFileDeletedFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeRepositoryTests\ByAirDateFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesBetweenDatesFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesRepositoryReadFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesWhereCutoffUnmetFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesWithFilesFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesWithoutFilesFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeRepositoryTests\FindEpisodeFixture.cs" />
|
||||
<Compile Include="MusicTests\MoveArtistServiceFixture.cs" />
|
||||
<Compile Include="TvTests\RefreshEpisodeServiceFixture.cs" />
|
||||
<Compile Include="MusicTests\RefreshArtistServiceFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeMonitoredServiceTests\SetEpisodeMontitoredFixture.cs" />
|
||||
<Compile Include="TvTests\SeriesRepositoryTests\SeriesRepositoryFixture.cs" />
|
||||
<Compile Include="TvTests\SeriesServiceTests\UpdateMultipleSeriesFixture.cs" />
|
||||
<Compile Include="TvTests\SeriesServiceTests\UpdateSeriesFixture.cs" />
|
||||
<Compile Include="TvTests\SeriesTitleNormalizerFixture.cs" />
|
||||
<Compile Include="MusicTests\ShouldRefreshArtistFixture.cs" />
|
||||
<Compile Include="UpdateTests\UpdatePackageProviderFixture.cs" />
|
||||
<Compile Include="UpdateTests\UpdateServiceFixture.cs" />
|
||||
|
@ -563,6 +538,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="InstrumentationTests\" />
|
||||
<Folder Include="Providers\" />
|
||||
<Folder Include="ProviderTests\UpdateProviderTests\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,131 +0,0 @@
|
|||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.ParserTests
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class AbsoluteEpisodeNumberParserFixture : CoreTest
|
||||
{
|
||||
[TestCase("[SubDESU]_High_School_DxD_07_(1280x720_x264-AAC)_[6B7FD717]", "High School DxD", 7, 0, 0)]
|
||||
[TestCase("[Chihiro]_Working!!_-_06_[848x480_H.264_AAC][859EEAFA]", "Working!!", 6, 0, 0)]
|
||||
[TestCase("[Commie]_Senki_Zesshou_Symphogear_-_11_[65F220B4]", "Senki Zesshou Symphogear", 11, 0, 0)]
|
||||
[TestCase("[Underwater]_Rinne_no_Lagrange_-_12_(720p)_[5C7BC4F9]", "Rinne no Lagrange", 12, 0, 0)]
|
||||
[TestCase("[Commie]_Rinne_no_Lagrange_-_15_[E76552EA]", "Rinne no Lagrange", 15, 0, 0)]
|
||||
[TestCase("[HorribleSubs]_Hunter_X_Hunter_-_33_[720p]", "Hunter X Hunter", 33, 0, 0)]
|
||||
[TestCase("[HorribleSubs]_Fairy_Tail_-_145_[720p]", "Fairy Tail", 145, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Tonari no Kaibutsu-kun - 13 [1080p].mkv", "Tonari no Kaibutsu-kun", 13, 0, 0)]
|
||||
[TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].[C65D4B1F].mkv", "Yes Pretty Cure 5 Go Go!", 31, 0, 0)]
|
||||
[TestCase("[K-F] One Piece 214", "One Piece", 214, 0, 0)]
|
||||
[TestCase("[K-F] One Piece S10E14 214", "One Piece", 214, 10, 14)]
|
||||
[TestCase("[K-F] One Piece 10x14 214", "One Piece", 214, 10, 14)]
|
||||
[TestCase("[K-F] One Piece 214 10x14", "One Piece", 214, 10, 14)]
|
||||
// [TestCase("One Piece S10E14 214", "One Piece", 214, 10, 14)]
|
||||
// [TestCase("One Piece 10x14 214", "One Piece", 214, 10, 14)]
|
||||
// [TestCase("One Piece 214 10x14", "One Piece", 214, 10, 14)]
|
||||
// [TestCase("214 One Piece 10x14", "One Piece", 214, 10, 14)]
|
||||
[TestCase("Bleach - 031 - The Resolution to Kill [Lunar].avi", "Bleach", 31, 0, 0)]
|
||||
[TestCase("Bleach - 031 - The Resolution to Kill [Lunar]", "Bleach", 31, 0, 0)]
|
||||
[TestCase("[ACX]Hack Sign 01 Role Play [Kosaka] [9C57891E].mkv", "Hack Sign", 1, 0, 0)]
|
||||
[TestCase("[SFW-sage] Bakuman S3 - 12 [720p][D07C91FC]", "Bakuman S3", 12, 0, 0)]
|
||||
[TestCase("ducktales_e66_time_is_money_part_one_marking_time", "ducktales", 66, 0, 0)]
|
||||
[TestCase("[Underwater-FFF] No Game No Life - 01 (720p) [27AAA0A0].mkv", "No Game No Life", 1, 0, 0)]
|
||||
[TestCase("[FroZen] Miyuki - 23 [DVD][7F6170E6]", "Miyuki", 23, 0, 0)]
|
||||
[TestCase("[Commie] Yowamushi Pedal - 32 [0BA19D5B]", "Yowamushi Pedal", 32, 0, 0)]
|
||||
[TestCase("[Doki] Mahouka Koukou no Rettousei - 07 (1280x720 Hi10P AAC) [80AF7DDE]", "Mahouka Koukou no Rettousei", 7, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Yowamushi Pedal - 32 [480p]", "Yowamushi Pedal", 32, 0, 0)]
|
||||
[TestCase("[CR] Sailor Moon - 004 [480p][48CE2D0F]", "Sailor Moon", 4, 0, 0)]
|
||||
[TestCase("[Chibiki] Puchimas!! - 42 [360p][7A4FC77B]", "Puchimas!!", 42, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Yowamushi Pedal - 32 [1080p]", "Yowamushi Pedal", 32, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Love Live! S2 - 07 [720p]", "Love Live! S2", 7, 0, 0)]
|
||||
[TestCase("[DeadFish] Onee-chan ga Kita - 09v2 [720p][AAC]", "Onee-chan ga Kita", 9, 0, 0)]
|
||||
[TestCase("[Underwater-FFF] No Game No Life - 01 (720p) [27AAA0A0]", "No Game No Life", 1, 0, 0)]
|
||||
[TestCase("[S-T-D] Soul Eater Not! - 06 (1280x720 10bit AAC) [59B3F2EA].mkv", "Soul Eater Not!", 6, 0, 0)]
|
||||
[TestCase("No Game No Life - 010 (720p) [27AAA0A0].mkv", "No Game No Life", 10, 0, 0)]
|
||||
[TestCase("Initial D Fifth Stage - 01 DVD - Central Anime", "Initial D Fifth Stage", 1, 0, 0)]
|
||||
[TestCase("Initial_D_Fifth_Stage_-_01(DVD)_-_(Central_Anime)[5AF6F1E4].mkv", "Initial D Fifth Stage", 1, 0, 0)]
|
||||
[TestCase("Initial_D_Fifth_Stage_-_02(DVD)_-_(Central_Anime)[0CA65F00].mkv", "Initial D Fifth Stage", 2, 0, 0)]
|
||||
[TestCase("Initial D Fifth Stage - 03 DVD - Central Anime", "Initial D Fifth Stage", 3, 0, 0)]
|
||||
[TestCase("Initial_D_Fifth_Stage_-_03(DVD)_-_(Central_Anime)[629BD592].mkv", "Initial D Fifth Stage", 3, 0, 0)]
|
||||
[TestCase("Initial D Fifth Stage - 14 DVD - Central Anime", "Initial D Fifth Stage", 14, 0, 0)]
|
||||
[TestCase("Initial_D_Fifth_Stage_-_14(DVD)_-_(Central_Anime)[0183D922].mkv", "Initial D Fifth Stage", 14, 0, 0)]
|
||||
// [TestCase("Initial D - 4th Stage Ep 01.mkv", "Initial D - 4th Stage", 1, 0, 0)]
|
||||
[TestCase("[ChihiroDesuYo].No.Game.No.Life.-.09.1280x720.10bit.AAC.[24CCE81D]", "No Game No Life", 9, 0, 0)]
|
||||
[TestCase("Fairy Tail - 001 - Fairy Tail", "Fairy Tail", 001, 0, 0)]
|
||||
[TestCase("Fairy Tail - 049 - The Day of Fated Meeting", "Fairy Tail", 049, 0, 0)]
|
||||
[TestCase("Fairy Tail - 050 - Special Request Watch Out for the Guy You Like!", "Fairy Tail", 050, 0, 0)]
|
||||
[TestCase("Fairy Tail - 099 - Natsu vs. Gildarts", "Fairy Tail", 099, 0, 0)]
|
||||
[TestCase("Fairy Tail - 100 - Mest", "Fairy Tail", 100, 0, 0)]
|
||||
// [TestCase("Fairy Tail - 101 - Mest", "Fairy Tail", 101, 0, 0)] //This gets caught up in the 'see' numbering
|
||||
[TestCase("[Exiled-Destiny] Angel Beats Ep01 (D2201EC5).mkv", "Angel Beats", 1, 0, 0)]
|
||||
[TestCase("[Commie] Nobunaga the Fool - 23 [5396CA24].mkv", "Nobunaga the Fool", 23, 0, 0)]
|
||||
[TestCase("[FFF] Seikoku no Dragonar - 01 [1FB538B5].mkv", "Seikoku no Dragonar", 1, 0, 0)]
|
||||
[TestCase("[Hatsuyuki]Fate_Zero-01[1280x720][122E6EF8]", "Fate Zero", 1, 0, 0)]
|
||||
[TestCase("[CBM]_Monster_-_11_-_511_Kinderheim_[6C70C4E4].mkv", "Monster", 11, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Log Horizon 2 - 05 [720p].mkv", "Log Horizon 2", 5, 0, 0)]
|
||||
[TestCase("[Commie] Log Horizon 2 - 05 [FCE4D070].mkv", "Log Horizon 2", 5, 0, 0)]
|
||||
[TestCase("[DRONE]Series.Title.100", "Series Title", 100, 0, 0)]
|
||||
[TestCase("[RlsGrp]Series.Title.2010.S01E01.001.HDTV-720p.x264-DTS", "Series Title 2010", 1, 1, 1)]
|
||||
[TestCase("Dragon Ball Kai - 130 - Found You, Gohan! Harsh Training in the Kaioshin Realm! [Baaro][720p][5A1AD35B].mkv", "Dragon Ball Kai", 130, 0, 0)]
|
||||
[TestCase("Dragon Ball Kai - 131 - A Merged Super-Warrior Is Born, His Name Is Gotenks!! [Baaro][720p][32E03F96].mkv", "Dragon Ball Kai", 131, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Magic Kaito 1412 - 01 [1080p]", "Magic Kaito 1412", 1, 0, 0)]
|
||||
[TestCase("[Jumonji-Giri]_[F-B]_Kagihime_Monogatari_Eikyuu_Alice_Rondo_Ep04_(0b0e2c10).mkv", "Kagihime Monogatari Eikyuu Alice Rondo", 4, 0, 0)]
|
||||
[TestCase("[Jumonji-Giri]_[F-B]_Kagihime_Monogatari_Eikyuu_Alice_Rondo_Ep08_(8246e542).mkv", "Kagihime Monogatari Eikyuu Alice Rondo", 8, 0, 0)]
|
||||
[TestCase("Knights of Sidonia - 01 [1080p 10b DTSHD-MA eng sub].mkv", "Knights of Sidonia", 1, 0, 0)]
|
||||
[TestCase("Series Title (2010) {01} Episode Title (1).hdtv-720p", "Series Title (2010)", 1, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Shirobako - 20 [720p].mkv", "Shirobako", 20, 0, 0)]
|
||||
[TestCase("[Hatsuyuki] Dragon Ball Kai (2014) - 017 (115) [1280x720][B2CFBC0F]", "Dragon Ball Kai (2014)", 17, 0, 0)]
|
||||
[TestCase("[Hatsuyuki] Dragon Ball Kai (2014) - 018 (116) [1280x720][C4A3B16E]", "Dragon Ball Kai (2014)", 18, 0, 0)]
|
||||
[TestCase("Dragon Ball Kai (2014) - 39 (137) [v2][720p.HDTV][Unison Fansub]", "Dragon Ball Kai (2014)", 39, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Eyeshield 21 - 101 [480p].mkv", "Eyeshield 21", 101, 0, 0)]
|
||||
[TestCase("[Cthuyuu].Taimadou.Gakuen.35.Shiken.Shoutai.-.03.[720p.H264.AAC][8AD82C3A]", "Taimadou Gakuen 35 Shiken Shoutai", 3, 0, 0)]
|
||||
//[TestCase("Taimadou.Gakuen.35.Shiken.Shoutai.-.03.(1280x720.HEVC.AAC)", "Taimadou Gakuen 35 Shiken Shoutai", 3, 0, 0)]
|
||||
[TestCase("[Cthuyuu] Taimadou Gakuen 35 Shiken Shoutai - 03 [720p H264 AAC][8AD82C3A]", "Taimadou Gakuen 35 Shiken Shoutai", 3, 0, 0)]
|
||||
[TestCase("Dragon Ball Super Episode 56 [VOSTFR V2][720p][AAC]-Mystic Z-Team", "Dragon Ball Super", 56, 0, 0)]
|
||||
[TestCase("[Mystic Z-Team] Dragon Ball Super Episode 69 [VOSTFR_Finale][1080p][AAC].mp4", "Dragon Ball Super", 69, 0, 0)]
|
||||
//[TestCase("", "", 0, 0, 0)]
|
||||
public void should_parse_absolute_numbers(string postTitle, string title, int absoluteEpisodeNumber, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
result.Should().NotBeNull();
|
||||
result.AbsoluteEpisodeNumbers.Single().Should().Be(absoluteEpisodeNumber);
|
||||
result.SeasonNumber.Should().Be(seasonNumber);
|
||||
result.EpisodeNumbers.SingleOrDefault().Should().Be(episodeNumber);
|
||||
result.SeriesTitle.Should().Be(title);
|
||||
result.FullSeason.Should().BeFalse();
|
||||
}
|
||||
|
||||
[TestCase("[DeadFish] Kenzen Robo Daimidaler - 01 - Special [BD][720p][AAC]", "Kenzen Robo Daimidaler", 1)]
|
||||
[TestCase("[DeadFish] Kenzen Robo Daimidaler - 01 - OVA [BD][720p][AAC]", "Kenzen Robo Daimidaler", 1)]
|
||||
[TestCase("[DeadFish] Kenzen Robo Daimidaler - 01 - OVD [BD][720p][AAC]", "Kenzen Robo Daimidaler", 1)]
|
||||
public void should_parse_absolute_specials(string postTitle, string title, int absoluteEpisodeNumber)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
result.Should().NotBeNull();
|
||||
result.AbsoluteEpisodeNumbers.Single().Should().Be(absoluteEpisodeNumber);
|
||||
result.SeasonNumber.Should().Be(0);
|
||||
result.EpisodeNumbers.SingleOrDefault().Should().Be(0);
|
||||
result.SeriesTitle.Should().Be(title);
|
||||
result.FullSeason.Should().BeFalse();
|
||||
result.Special.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestCase("[ANBU-AonE]_Naruto_26-27_[F224EF26].avi", "Naruto", new[] { 26, 27 })]
|
||||
[TestCase("[Doutei] Recently, My Sister is Unusual - 01-12 [BD][720p-AAC]", "Recently, My Sister is Unusual", new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 })]
|
||||
[TestCase("Series Title (2010) - 01-02-03 - Episode Title (1) HDTV-720p", "Series Title (2010)", new [] { 1, 2, 3 })]
|
||||
[TestCase("[RlsGrp] Series Title (2010) - S01E01-02-03 - 001-002-003 - Episode Title HDTV-720p v2", "Series Title (2010)", new[] { 1, 2, 3 })]
|
||||
[TestCase("[RlsGrp] Series Title (2010) - S01E01-02 - 001-002 - Episode Title HDTV-720p v2", "Series Title (2010)", new[] { 1, 2 })]
|
||||
[TestCase("Series Title (2010) - S01E01-02 (001-002) - Episode Title (1) HDTV-720p v2 [RlsGrp]", "Series Title (2010)", new[] { 1, 2 })]
|
||||
[TestCase("[HorribleSubs] Haikyuu!! (01-25) [1080p] (Batch)", "Haikyuu!!", new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 })]
|
||||
public void should_parse_multi_episode_absolute_numbers(string postTitle, string title, int[] absoluteEpisodeNumbers)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
result.Should().NotBeNull();
|
||||
result.AbsoluteEpisodeNumbers.Should().BeEquivalentTo(absoluteEpisodeNumbers);
|
||||
result.SeriesTitle.Should().Be(title);
|
||||
result.FullSeason.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.ParserTests
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class AnimeMetadataParserFixture : CoreTest
|
||||
{
|
||||
[TestCase("[SubDESU]_High_School_DxD_07_(1280x720_x264-AAC)_[6B7FD717]", "SubDESU", "6B7FD717")]
|
||||
[TestCase("[Chihiro]_Working!!_-_06_[848x480_H.264_AAC][859EEAFA]", "Chihiro", "859EEAFA")]
|
||||
[TestCase("[Underwater]_Rinne_no_Lagrange_-_12_(720p)_[5C7BC4F9]", "Underwater", "5C7BC4F9")]
|
||||
[TestCase("[HorribleSubs]_Hunter_X_Hunter_-_33_[720p]", "HorribleSubs", "")]
|
||||
[TestCase("[HorribleSubs] Tonari no Kaibutsu-kun - 13 [1080p].mkv", "HorribleSubs", "")]
|
||||
[TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].[C65D4B1F].mkv", "Doremi", "C65D4B1F")]
|
||||
[TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].[C65D4B1F]", "Doremi", "C65D4B1F")]
|
||||
[TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].mkv", "Doremi", "")]
|
||||
[TestCase("[K-F] One Piece 214", "K-F", "")]
|
||||
[TestCase("[K-F] One Piece S10E14 214", "K-F", "")]
|
||||
[TestCase("[K-F] One Piece 10x14 214", "K-F", "")]
|
||||
[TestCase("[K-F] One Piece 214 10x14", "K-F", "")]
|
||||
[TestCase("Bleach - 031 - The Resolution to Kill [Lunar].avi", "Lunar", "")]
|
||||
[TestCase("[ACX]Hack Sign 01 Role Play [Kosaka] [9C57891E].mkv", "ACX", "9C57891E")]
|
||||
[TestCase("[S-T-D] Soul Eater Not! - 06 (1280x720 10bit AAC) [59B3F2EA].mkv", "S-T-D", "59B3F2EA")]
|
||||
public void should_parse_absolute_numbers(string postTitle, string subGroup, string hash)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
result.Should().NotBeNull();
|
||||
result.ReleaseGroup.Should().Be(subGroup);
|
||||
result.ReleaseHash.Should().Be(hash);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +1,18 @@
|
|||
using FluentAssertions;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.ParserTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SeriesTitleInfoFixture : CoreTest
|
||||
public class ArtistTitleInfoFixture : CoreTest
|
||||
{
|
||||
[Test]
|
||||
public void should_have_year_zero_when_title_doesnt_have_a_year()
|
||||
{
|
||||
const string title = "House.S01E01.pilot.720p.hdtv";
|
||||
|
||||
var result = Parser.Parser.ParseTitle(title).SeriesTitleInfo;
|
||||
var result = Parser.Parser.ParseAlbumTitle(title).ArtistTitleInfo;
|
||||
|
||||
result.Year.Should().Be(0);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
{
|
||||
const string title = "House.S01E01.pilot.720p.hdtv";
|
||||
|
||||
var result = Parser.Parser.ParseTitle(title).SeriesTitleInfo;
|
||||
var result = Parser.Parser.ParseAlbumTitle(title).ArtistTitleInfo;
|
||||
|
||||
result.Title.Should().Be(result.TitleWithoutYear);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
{
|
||||
const string title = "House.2004.S01E01.pilot.720p.hdtv";
|
||||
|
||||
var result = Parser.Parser.ParseTitle(title).SeriesTitleInfo;
|
||||
var result = Parser.Parser.ParseAlbumTitle(title).ArtistTitleInfo;
|
||||
|
||||
result.Year.Should().Be(2004);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
{
|
||||
const string title = "House.2004.S01E01.pilot.720p.hdtv";
|
||||
|
||||
var result = Parser.Parser.ParseTitle(title).SeriesTitleInfo;
|
||||
var result = Parser.Parser.ParseAlbumTitle(title).ArtistTitleInfo;
|
||||
|
||||
result.Title.Should().Be("House 2004");
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
{
|
||||
const string title = "House.2004.S01E01.pilot.720p.hdtv";
|
||||
|
||||
var result = Parser.Parser.ParseTitle(title).SeriesTitleInfo;
|
||||
var result = Parser.Parser.ParseAlbumTitle(title).ArtistTitleInfo;
|
||||
|
||||
result.TitleWithoutYear.Should().Be("House");
|
||||
}
|
|
@ -33,7 +33,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("QZC4HDl7ncmzyUj9amucWe1ddKU1oFMZDd8r0dEDUsTd")]
|
||||
public void should_not_parse_crap(string title)
|
||||
{
|
||||
Parser.Parser.ParseTitle(title).Should().BeNull();
|
||||
Parser.Parser.ParseAlbumTitle(title).Should().BeNull();
|
||||
ExceptionVerification.IgnoreWarns();
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
|
||||
hash = BitConverter.ToString(hashData).Replace("-", "");
|
||||
|
||||
if (Parser.Parser.ParseTitle(hash) == null)
|
||||
if (Parser.Parser.ParseAlbumTitle(hash) == null)
|
||||
success++;
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
hash.Append(charset[hashAlgo.Next() % charset.Length]);
|
||||
}
|
||||
|
||||
if (Parser.Parser.ParseTitle(hash.ToString()) == null)
|
||||
if (Parser.Parser.ParseAlbumTitle(hash.ToString()) == null)
|
||||
success++;
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("thebiggestloser1618finale")]
|
||||
public void should_not_parse_file_name_without_proper_spacing(string fileName)
|
||||
{
|
||||
Parser.Parser.ParseTitle(fileName).Should().BeNull();
|
||||
Parser.Parser.ParseAlbumTitle(fileName).Should().BeNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
using System;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Expansive;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.ParserTests
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class DailyEpisodeParserFixture : CoreTest
|
||||
{
|
||||
[TestCase("Conan 2011 04 18 Emma Roberts HDTV XviD BFF", "Conan", 2011, 04, 18)]
|
||||
[TestCase("The Tonight Show With Jay Leno 2011 04 15 1080i HDTV DD5 1 MPEG2 TrollHD", "The Tonight Show With Jay Leno", 2011, 04, 15)]
|
||||
[TestCase("The.Daily.Show.2010.10.11.Johnny.Knoxville.iTouch-MW", "The Daily Show", 2010, 10, 11)]
|
||||
[TestCase("The Daily Show - 2011-04-12 - Gov. Deval Patrick", "The Daily Show", 2011, 04, 12)]
|
||||
[TestCase("2011.01.10 - Denis Leary - HD TV.mkv", "", 2011, 1, 10)]
|
||||
[TestCase("2011.03.13 - Denis Leary - HD TV.mkv", "", 2011, 3, 13)]
|
||||
[TestCase("The Tonight Show with Jay Leno - 2011-06-16 - Larry David, \"Bachelorette\" Ashley Hebert, Pitbull with Ne-Yo", "The Tonight Show with Jay Leno", 2011, 6, 16)]
|
||||
[TestCase("2020.NZ.2012.16.02.PDTV.XviD-C4TV", "2020 NZ", 2012, 2, 16)]
|
||||
[TestCase("2020.NZ.2012.13.02.PDTV.XviD-C4TV", "2020 NZ", 2012, 2, 13)]
|
||||
[TestCase("2020.NZ.2011.12.02.PDTV.XviD-C4TV", "2020 NZ", 2011, 12, 2)]
|
||||
[TestCase("Series Title - 2013-10-30 - Episode Title (1) [HDTV-720p]", "Series Title", 2013, 10, 30)]
|
||||
[TestCase("The_Voice_US_04.28.2014_hdtv.x264.Poke.mp4", "The Voice US", 2014, 4, 28)]
|
||||
[TestCase("At.Midnight.140722.720p.HDTV.x264-YesTV", "At Midnight", 2014, 07, 22)]
|
||||
[TestCase("At_Midnight_140722_720p_HDTV_x264-YesTV", "At Midnight", 2014, 07, 22)]
|
||||
//[TestCase("Corrie.07.01.15", "Corrie", 2015, 1, 7)]
|
||||
[TestCase("The Nightly Show with Larry Wilmore 2015 02 09 WEBRIP s01e13", "The Nightly Show with Larry Wilmore", 2015, 2, 9)]
|
||||
//[TestCase("", "", 0, 0, 0)]
|
||||
public void should_parse_daily_episode(string postTitle, string title, int year, int month, int day)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var airDate = new DateTime(year, month, day);
|
||||
result.Should().NotBeNull();
|
||||
result.SeriesTitle.Should().Be(title);
|
||||
result.AirDate.Should().Be(airDate.ToString(Episode.AIR_DATE_FORMAT));
|
||||
result.EpisodeNumbers.Should().BeEmpty();
|
||||
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||
result.FullSeason.Should().BeFalse();
|
||||
}
|
||||
|
||||
[TestCase("Conan {year} {month} {day} Emma Roberts HDTV XviD BFF")]
|
||||
[TestCase("The Tonight Show With Jay Leno {year} {month} {day} 1080i HDTV DD5 1 MPEG2 TrollHD")]
|
||||
[TestCase("The.Daily.Show.{year}.{month}.{day}.Johnny.Knoxville.iTouch-MW")]
|
||||
[TestCase("The Daily Show - {year}-{month}-{day} - Gov. Deval Patrick")]
|
||||
[TestCase("{year}.{month}.{day} - Denis Leary - HD TV.mkv")]
|
||||
[TestCase("The Tonight Show with Jay Leno - {year}-{month}-{day} - Larry David, \"Bachelorette\" Ashley Hebert, Pitbull with Ne-Yo")]
|
||||
[TestCase("2020.NZ.{year}.{month}.{day}.PDTV.XviD-C4TV")]
|
||||
public void should_not_accept_ancient_daily_series(string title)
|
||||
{
|
||||
var yearTooLow = title.Expand(new { year = 1950, month = 10, day = 14 });
|
||||
Parser.Parser.ParseTitle(yearTooLow).Should().BeNull();
|
||||
}
|
||||
|
||||
[TestCase("Conan {year} {month} {day} Emma Roberts HDTV XviD BFF")]
|
||||
[TestCase("The Tonight Show With Jay Leno {year} {month} {day} 1080i HDTV DD5 1 MPEG2 TrollHD")]
|
||||
[TestCase("The.Daily.Show.{year}.{month}.{day}.Johnny.Knoxville.iTouch-MW")]
|
||||
[TestCase("The Daily Show - {year}-{month}-{day} - Gov. Deval Patrick")]
|
||||
[TestCase("{year}.{month}.{day} - Denis Leary - HD TV.mkv")]
|
||||
[TestCase("The Tonight Show with Jay Leno - {year}-{month}-{day} - Larry David, \"Bachelorette\" Ashley Hebert, Pitbull with Ne-Yo")]
|
||||
[TestCase("2020.NZ.{year}.{month}.{day}.PDTV.XviD-C4TV")]
|
||||
public void should_not_accept_future_dates(string title)
|
||||
{
|
||||
var twoDaysFromNow = DateTime.Now.AddDays(2);
|
||||
|
||||
var validDate = title.Expand(new { year = twoDaysFromNow.Year, month = twoDaysFromNow.Month.ToString("00"), day = twoDaysFromNow.Day.ToString("00") });
|
||||
|
||||
Parser.Parser.ParseTitle(validDate).Should().BeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_fail_if_episode_is_far_in_future()
|
||||
{
|
||||
var title = string.Format("{0:yyyy.MM.dd} - Denis Leary - HD TV.mkv", DateTime.Now.AddDays(2));
|
||||
|
||||
Parser.Parser.ParseTitle(title).Should().BeNull();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using FluentAssertions;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
@ -86,7 +86,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[Test, TestCaseSource(nameof(HashedReleaseParserCases))]
|
||||
public void should_properly_parse_hashed_releases(string path, string title, Quality quality, string releaseGroup)
|
||||
{
|
||||
var result = Parser.Parser.ParsePath(path);
|
||||
var result = Parser.Parser.ParseMusicPath(path);
|
||||
//result.SeriesTitle.Should().Be(title);
|
||||
result.Quality.Quality.Should().Be(quality);
|
||||
}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Test.ParserTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class IsPossibleSpecialEpisodeFixture
|
||||
{
|
||||
[Test]
|
||||
public void should_not_treat_files_without_a_series_title_as_a_special()
|
||||
{
|
||||
var parsedEpisodeInfo = new ParsedEpisodeInfo
|
||||
{
|
||||
EpisodeNumbers = new[]{ 7 },
|
||||
SeasonNumber = 1,
|
||||
SeriesTitle = ""
|
||||
};
|
||||
|
||||
parsedEpisodeInfo.IsPossibleSpecialEpisode.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_episode_numbers_is_empty()
|
||||
{
|
||||
var parsedEpisodeInfo = new ParsedEpisodeInfo
|
||||
{
|
||||
SeasonNumber = 1,
|
||||
SeriesTitle = ""
|
||||
};
|
||||
|
||||
parsedEpisodeInfo.IsPossibleSpecialEpisode.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestCase("Under.the.Dome.S02.Special-Inside.Chesters.Mill.HDTV.x264-BAJSKORV")]
|
||||
[TestCase("Under.the.Dome.S02.Special-Inside.Chesters.Mill.720p.HDTV.x264-BAJSKORV")]
|
||||
[TestCase("Rookie.Blue.Behind.the.Badge.S05.Special.HDTV.x264-2HD")]
|
||||
public void IsPossibleSpecialEpisode_should_be_true(string title)
|
||||
{
|
||||
Parser.Parser.ParseTitle(title).IsPossibleSpecialEpisode.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,14 +37,14 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Shield,.The.1x13.Tueurs.De.Flics.FR.DVDRip.XviD")]
|
||||
public void should_parse_language_french(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.French.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Spanish.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_spanish(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Spanish.Id);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Elementary - S02E16 - Kampfhaehne - mkv - by Videomann")]
|
||||
public void should_parse_language_german(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.German.Id);
|
||||
}
|
||||
|
||||
|
@ -61,14 +61,14 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("person.of.interest.1x19.ita.720p.bdmux.x264-novarip")]
|
||||
public void should_parse_language_italian(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Italian.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Danish.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_danish(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Danish.Id);
|
||||
}
|
||||
|
||||
|
@ -77,35 +77,35 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Ray Donovan - S01E01.720p.HDtv.x264-Evolve (NLsub)")]
|
||||
public void should_parse_language_dutch(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Dutch.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Japanese.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_japanese(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Japanese.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Cantonese.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_cantonese(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Cantonese.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Mandarin.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_mandarin(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Mandarin.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Korean.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_korean(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Korean.Id);
|
||||
}
|
||||
|
||||
|
@ -113,28 +113,28 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("True.Detective.S01E01.1080p.WEB-DL.Rus.Eng.TVKlondike")]
|
||||
public void should_parse_language_russian(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Russian.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Polish.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_polish(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Polish.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Vietnamese.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_vietnamese(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Vietnamese.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Swedish.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_swedish(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Swedish.Id);
|
||||
}
|
||||
|
||||
|
@ -142,42 +142,42 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Revolution S01E03 No Quarter 2012 WEB-DL 720p Nordic-philipo mkv")]
|
||||
public void should_parse_language_norwegian(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Norwegian.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Finnish.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_finnish(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Finnish.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Turkish.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_turkish(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Turkish.Id);
|
||||
}
|
||||
|
||||
[TestCase("Castle.2009.S01E14.Portuguese.HDTV.XviD-LOL")]
|
||||
public void should_parse_language_portuguese(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Portuguese.Id);
|
||||
}
|
||||
|
||||
[TestCase("Salamander.S01E01.FLEMISH.HDTV.x264-BRiGAND")]
|
||||
public void should_parse_language_flemish(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Flemish.Id);
|
||||
}
|
||||
|
||||
[TestCase("H.Polukatoikia.S03E13.Greek.PDTV.XviD-Ouzo")]
|
||||
public void should_parse_language_greek(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Greek.Id);
|
||||
}
|
||||
|
||||
|
@ -186,14 +186,14 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Castle.2009.S01E14.HDTV.XviD.HUN-LOL")]
|
||||
public void should_parse_language_hungarian(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Hungarian.Id);
|
||||
}
|
||||
|
||||
[TestCase("Avatar.The.Last.Airbender.S01-03.DVDRip.HebDub")]
|
||||
public void should_parse_language_hebrew(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Hebrew.Id);
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Prison.Break.S05E01.WEBRip.x264.AC3.LT.EN-CNN")]
|
||||
public void should_parse_language_lithuanian(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Lithuanian.Id);
|
||||
}
|
||||
|
||||
|
@ -209,7 +209,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("The.Walking.Dead.S07E11.WEB Rip.XviD.Louige-CZ.EN.5.1")]
|
||||
public void should_parse_language_czech(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Language.Id.Should().Be(Language.Czech.Id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.ParserTests
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class MiniSeriesEpisodeParserFixture : CoreTest
|
||||
{
|
||||
[TestCase("The.Kennedys.Part.2.DSR.XviD-SYS", "The Kennedys", 2)]
|
||||
[TestCase("the-pacific-e07-720p", "the-pacific", 7)]
|
||||
[TestCase("Hatfields and McCoys 2012 Part 1 REPACK 720p HDTV x264 2HD", "Hatfields and McCoys 2012", 1)]
|
||||
//[TestCase("Band.Of.Brothers.EP02.Day.Of.Days.DVDRiP.XviD-DEiTY", "Band.Of.Brothers", 2)]
|
||||
//[TestCase("", "", 0, 0)]
|
||||
[TestCase("Mars.2016.E04.Power.720p.WEB-DL.DD5.1.H.264-MARS", "Mars 2016", 4)]
|
||||
public void should_parse_mini_series_episode(string postTitle, string title, int episodeNumber)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
result.Should().NotBeNull();
|
||||
result.EpisodeNumbers.Should().HaveCount(1);
|
||||
result.SeasonNumber.Should().Be(1);
|
||||
result.EpisodeNumbers.First().Should().Be(episodeNumber);
|
||||
result.SeriesTitle.Should().Be(title);
|
||||
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||
result.FullSeason.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.ParserTests
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class MultiEpisodeParserFixture : CoreTest
|
||||
{
|
||||
[TestCase("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", "WEEDS", 3, new[] { 1, 2, 3, 4, 5, 6 })]
|
||||
[TestCase("Two.and.a.Half.Men.103.104.720p.HDTV.X264-DIMENSION", "Two and a Half Men", 1, new[] { 3, 4 })]
|
||||
[TestCase("Weeds.S03E01.S03E02.720p.HDTV.X264-DIMENSION", "Weeds", 3, new[] { 1, 2 })]
|
||||
[TestCase("The Borgias S01e01 e02 ShoHD On Demand 1080i DD5 1 ALANiS", "The Borgias", 1, new[] { 1, 2 })]
|
||||
[TestCase("White.Collar.2x04.2x05.720p.BluRay-FUTV", "White Collar", 2, new[] { 4, 5 })]
|
||||
[TestCase("Desperate.Housewives.S07E22E23.720p.HDTV.X264-DIMENSION", "Desperate Housewives", 7, new[] { 22, 23 })]
|
||||
[TestCase("Desparate Housewives - S07E22 - S07E23 - And Lots of Security.. [HDTV-720p].mkv", "Desparate Housewives", 7, new[] { 22, 23 })]
|
||||
[TestCase("S03E01.S03E02.720p.HDTV.X264-DIMENSION", "", 3, new[] { 1, 2 })]
|
||||
[TestCase("Desparate Housewives - S07E22 - 7x23 - And Lots of Security.. [HDTV-720p].mkv", "Desparate Housewives", 7, new[] { 22, 23 })]
|
||||
[TestCase("S07E22 - 7x23 - And Lots of Security.. [HDTV-720p].mkv", "", 7, new[] { 22, 23 })]
|
||||
[TestCase("2x04x05.720p.BluRay-FUTV", "", 2, new[] { 4, 5 })]
|
||||
[TestCase("S02E04E05.720p.BluRay-FUTV", "", 2, new[] { 4, 5 })]
|
||||
[TestCase("S02E03-04-05.720p.BluRay-FUTV", "", 2, new[] { 3, 4, 5 })]
|
||||
[TestCase("Breakout.Kings.S02E09-E10.HDTV.x264-ASAP", "Breakout Kings", 2, new[] { 9, 10 })]
|
||||
[TestCase("Breakout Kings - 2x9-2x10 - Served Cold [SDTV] ", "Breakout Kings", 2, new[] { 9, 10 })]
|
||||
[TestCase("Breakout Kings - 2x09-2x10 - Served Cold [SDTV] ", "Breakout Kings", 2, new[] { 9, 10 })]
|
||||
[TestCase("Hell on Wheels S02E09 E10 HDTV x264 EVOLVE", "Hell on Wheels", 2, new[] { 9, 10 })]
|
||||
[TestCase("Hell.on.Wheels.S02E09-E10.720p.HDTV.x264-EVOLVE", "Hell on Wheels", 2, new[] { 9, 10 })]
|
||||
[TestCase("Grey's Anatomy - 8x01_02 - Free Falling", "Grey's Anatomy", 8, new [] { 1,2 })]
|
||||
[TestCase("8x01_02 - Free Falling", "", 8, new[] { 1, 2 })]
|
||||
[TestCase("Kaamelott.S01E91-E100", "Kaamelott", 1, new[] { 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 })]
|
||||
[TestCase("Neighbours.S29E161-E165.PDTV.x264-FQM", "Neighbours", 29, new[] { 161, 162, 163, 164, 165 })]
|
||||
[TestCase("Shortland.Street.S22E5363-E5366.HDTV.x264-FiHTV", "Shortland Street", 22, new[] { 5363, 5364, 5365, 5366 })]
|
||||
[TestCase("the.office.101.102.hdtv-lol", "the office", 1, new[] { 1, 2 })]
|
||||
[TestCase("extant.10708.hdtv-lol.mp4", "extant", 1, new[] { 7, 8 })]
|
||||
[TestCase("extant.10910.hdtv-lol.mp4", "extant", 1, new[] { 9, 10 })]
|
||||
[TestCase("E.010910.HDTVx264REPACKLOL.mp4", "E", 1, new[] { 9, 10 })]
|
||||
[TestCase("World Series of Poker - 2013x15 - 2013x16 - HD TV.mkv", "World Series of Poker", 2013, new[] { 15, 16 })]
|
||||
[TestCase("The Librarians US S01E01-E02 720p HDTV x264", "The Librarians US", 1, new [] { 1, 2 })]
|
||||
[TestCase("Series Title Season 01 Episode 05-06 720p", "Series Title", 1,new [] { 5, 6 })]
|
||||
//[TestCase("My Name Is Earl - S03E01-E02 - My Name Is Inmate 28301-016 [SDTV]", "My Name Is Earl", 3, new[] { 1, 2 })]
|
||||
//[TestCase("Adventure Time - 5x01 - x02 - Finn the Human (2) & Jake the Dog (3)", "Adventure Time", 5, new [] { 1, 2 })]
|
||||
[TestCase("The Young And The Restless - S42 Ep10718 - Ep10722", "The Young And The Restless", 42, new[] { 10718, 10719, 10720, 10721, 10722 })]
|
||||
[TestCase("The Young And The Restless - S42 Ep10688 - Ep10692", "The Young And The Restless", 42, new[] { 10688, 10689, 10690, 10691, 10692 })]
|
||||
[TestCase("RWBY.S01E02E03.1080p.BluRay.x264-DeBTViD", "RWBY", 1, new [] { 2, 3 })]
|
||||
[TestCase("grp-zoos01e11e12-1080p", "grp-zoo", 1, new [] { 11, 12 })]
|
||||
[TestCase("grp-zoo-s01e11e12-1080p", "grp-zoo", 1, new [] { 11, 12 })]
|
||||
[TestCase("Series Title.S6.E1.E2.Episode Name.1080p.WEB-DL", "Series Title", 6, new [] { 1, 2 })]
|
||||
[TestCase("Series Title.S6E1-E2.Episode Name.1080p.WEB-DL", "Series Title", 6, new [] { 1, 2 })]
|
||||
[TestCase("Series Title.S6E1-S6E2.Episode Name.1080p.WEB-DL", "Series Title", 6, new [] { 1, 2 })]
|
||||
[TestCase("Series Title.S6E1E2.Episode Name.1080p.WEB-DL", "Series Title", 6, new [] { 1, 2 })]
|
||||
[TestCase("Series Title.S6E1-E2-E3.Episode Name.1080p.WEB-DL", "Series Title", 6, new [] { 1, 2, 3})]
|
||||
[TestCase("Series Title.S6.E1E3.Episode Name.1080p.WEB-DL", "Series Title", 6, new [] { 1, 2, 3 })]
|
||||
[TestCase("Series Title.S6.E1-E2.Episode Name.1080p.WEB-DL", "Series Title", 6, new[] { 1, 2 })]
|
||||
[TestCase("Series Title.S6.E1-S6E2.Episode Name.1080p.WEB-DL", "Series Title", 6, new[] { 1, 2 })]
|
||||
[TestCase("Series Title.S6.E1E2.Episode Name.1080p.WEB-DL", "Series Title", 6, new[] { 1, 2 })]
|
||||
[TestCase("Series Title.S6.E1-E2-E3.Episode Name.1080p.WEB-DL", "Series Title", 6, new[] { 1, 2, 3 })]
|
||||
[TestCase("Mad.Men.S05E01-E02.720p.5.1Ch.BluRay", "Mad Men", 5, new[] { 1, 2 })]
|
||||
[TestCase("Mad.Men.S05E01-02.720p.5.1Ch.BluRay", "Mad Men", 5, new[] { 1, 2 })]
|
||||
//[TestCase("", "", , new [] { })]
|
||||
public void should_parse_multiple_episodes(string postTitle, string title, int season, int[] episodes)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
result.SeasonNumber.Should().Be(season);
|
||||
result.EpisodeNumbers.Should().BeEquivalentTo(episodes);
|
||||
result.SeriesTitle.Should().Be(title);
|
||||
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||
result.FullSeason.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Reno.911.S01.DVDRip.DD2.0.x264-DEEP", "Reno 911")]
|
||||
public void should_parse_series_name(string postTitle, string title)
|
||||
{
|
||||
var result = Parser.Parser.ParseSeriesName(postTitle).CleanSeriesTitle();
|
||||
var result = Parser.Parser.ParseArtistName(postTitle).CleanSeriesTitle();
|
||||
result.Should().Be(title.CleanSeriesTitle());
|
||||
}
|
||||
|
||||
|
@ -55,21 +55,21 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Discovery TV - Gold Rush : 02 Road From Hell [S04].mp4")]
|
||||
public void should_clean_up_invalid_path_characters(string postTitle)
|
||||
{
|
||||
Parser.Parser.ParseTitle(postTitle);
|
||||
Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
}
|
||||
|
||||
[TestCase("[scnzbefnet][509103] 2.Broke.Girls.S03E18.720p.HDTV.X264-DIMENSION", "2 Broke Girls")]
|
||||
public void should_remove_request_info_from_title(string postTitle, string title)
|
||||
{
|
||||
Parser.Parser.ParseTitle(postTitle).SeriesTitle.Should().Be(title);
|
||||
Parser.Parser.ParseAlbumTitle(postTitle).ArtistName.Should().Be(title);
|
||||
}
|
||||
|
||||
[TestCase("Revolution.S01E02.Chained.Heat.mkv")]
|
||||
[TestCase("Dexter - S01E01 - Title.avi")]
|
||||
public void should_parse_quality_from_extension(string title)
|
||||
{
|
||||
Parser.Parser.ParseTitle(title).Quality.Quality.Should().NotBe(Quality.Unknown);
|
||||
Parser.Parser.ParseTitle(title).Quality.QualitySource.Should().Be(QualitySource.Extension);
|
||||
Parser.Parser.ParseAlbumTitle(title).Quality.Quality.Should().NotBe(Quality.Unknown);
|
||||
Parser.Parser.ParseAlbumTitle(title).Quality.QualitySource.Should().Be(QualitySource.Extension);
|
||||
}
|
||||
|
||||
[TestCase("VA - The Best 101 Love Ballads (2017) MP3 [192 kbps]", "The Best 101 Love Ballads")]
|
||||
|
|
|
@ -33,12 +33,12 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
// [TestCase(@"C:\CSI.NY.S02E04.720p.WEB-DL.DD5.1.H.264\73696S02-04.mkv", 2, 4)] //Gets treated as S01E04 (because it gets parsed as anime)
|
||||
public void should_parse_from_path(string path, int season, int episode)
|
||||
{
|
||||
var result = Parser.Parser.ParsePath(path.AsOsAgnostic());
|
||||
result.EpisodeNumbers.Should().HaveCount(1);
|
||||
result.SeasonNumber.Should().Be(season);
|
||||
result.EpisodeNumbers[0].Should().Be(episode);
|
||||
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||
result.FullSeason.Should().BeFalse();
|
||||
var result = Parser.Parser.ParseMusicPath(path.AsOsAgnostic());
|
||||
//result.EpisodeNumbers.Should().HaveCount(1);
|
||||
//result.SeasonNumber.Should().Be(season);
|
||||
//result.EpisodeNumbers[0].Should().Be(episode);
|
||||
//result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||
//result.FullSeason.Should().BeFalse();
|
||||
|
||||
ExceptionVerification.IgnoreWarns();
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
{
|
||||
const string path = @"C:\Test\Doctor.Who.2005.s01e01.internal.bdrip.x264-archivist.mkv";
|
||||
|
||||
Parser.Parser.ParsePath(path).ReleaseGroup.Should().Be("archivist");
|
||||
Parser.Parser.ParseMusicPath(path).ReleaseGroup.Should().Be("archivist");
|
||||
}
|
||||
|
||||
[TestCase("Marvels.Daredevil.S02E04.720p.WEBRip.x264-SKGTV English", "SKGTV")]
|
||||
|
|
|
@ -26,12 +26,12 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("My.Series.S2014.720p.HDTV.x264-ME", "My Series", 2014)]
|
||||
public void should_parse_full_season_release(string postTitle, string title, int season)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
result.SeasonNumber.Should().Be(season);
|
||||
result.SeriesTitle.Should().Be(title);
|
||||
result.EpisodeNumbers.Should().BeEmpty();
|
||||
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||
result.FullSeason.Should().BeTrue();
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
//result.SeasonNumber.Should().Be(season);
|
||||
//result.SeriesTitle.Should().Be(title);
|
||||
//result.EpisodeNumbers.Should().BeEmpty();
|
||||
//result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||
//result.FullSeason.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestCase("Acropolis Now S05 EXTRAS DVDRip XviD RUNNER")]
|
||||
|
@ -39,7 +39,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Instant Star S03 EXTRAS DVDRip XviD OSiTV")]
|
||||
public void should_parse_season_extras(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
|
||||
result.Should().BeNull();
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("CSI.S11.SUBPACK.DVDRip.XviD-REWARD")]
|
||||
public void should_parse_season_subpack(string postTitle)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
|
||||
result.Should().BeNull();
|
||||
}
|
||||
|
|
|
@ -131,14 +131,14 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
//[TestCase("", "", 0, 0)]
|
||||
public void should_parse_single_episode(string postTitle, string title, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
var result = Parser.Parser.ParseAlbumTitle(postTitle);
|
||||
result.Should().NotBeNull();
|
||||
result.EpisodeNumbers.Should().HaveCount(1);
|
||||
result.SeasonNumber.Should().Be(seasonNumber);
|
||||
result.EpisodeNumbers.First().Should().Be(episodeNumber);
|
||||
result.SeriesTitle.Should().Be(title);
|
||||
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||
result.FullSeason.Should().BeFalse();
|
||||
//result.EpisodeNumbers.Should().HaveCount(1);
|
||||
//result.SeasonNumber.Should().Be(seasonNumber);
|
||||
//result.EpisodeNumbers.First().Should().Be(episodeNumber);
|
||||
//result.SeriesTitle.Should().Be(title);
|
||||
//result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||
//result.FullSeason.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DataAugmentation.Xem;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common.Categories;
|
||||
|
||||
namespace NzbDrone.Core.Test.Providers
|
||||
{
|
||||
[TestFixture]
|
||||
[IntegrationTest]
|
||||
public class XemProxyFixture : CoreTest<XemProxy>
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
UseRealHttp();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void get_series_ids()
|
||||
{
|
||||
var ids = Subject.GetXemSeriesIds();
|
||||
|
||||
ids.Should().NotBeEmpty();
|
||||
ids.Should().Contain(i => i == 73141);
|
||||
}
|
||||
|
||||
[TestCase(12345, Description = "invalid id")]
|
||||
[TestCase(279042, Description = "no single connection")]
|
||||
public void should_return_empty_when_known_error(int id)
|
||||
{
|
||||
Subject.GetSceneTvdbMappings(id).Should().BeEmpty();
|
||||
}
|
||||
|
||||
[TestCase(82807)]
|
||||
[TestCase(73141, Description = "American Dad!")]
|
||||
public void should_get_mapping(int seriesId)
|
||||
{
|
||||
var result = Subject.GetSceneTvdbMappings(seriesId);
|
||||
|
||||
result.Should().NotBeEmpty();
|
||||
result.Should().OnlyContain(c => c.Scene != null);
|
||||
result.Should().OnlyContain(c => c.Tvdb != null);
|
||||
}
|
||||
|
||||
[TestCase(78916)]
|
||||
public void should_filter_out_episodes_without_scene_mapping(int seriesId)
|
||||
{
|
||||
var result = Subject.GetSceneTvdbMappings(seriesId);
|
||||
|
||||
result.Should().NotContain(c => c.Tvdb == null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,221 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeMonitoredServiceTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SetEpisodeMontitoredFixture : CoreTest<EpisodeMonitoredService>
|
||||
{
|
||||
private Series _series;
|
||||
private List<Episode> _episodes;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var seasons = 4;
|
||||
|
||||
_series = Builder<Series>.CreateNew()
|
||||
.With(s => s.Seasons = Builder<Season>.CreateListOfSize(seasons)
|
||||
.All()
|
||||
.With(n => n.Monitored = true)
|
||||
.Build()
|
||||
.ToList())
|
||||
.Build();
|
||||
|
||||
_episodes = Builder<Episode>.CreateListOfSize(seasons)
|
||||
.All()
|
||||
.With(e => e.Monitored = true)
|
||||
.With(e => e.AirDateUtc = DateTime.UtcNow.AddDays(-7))
|
||||
//Missing
|
||||
.TheFirst(1)
|
||||
.With(e => e.EpisodeFileId = 0)
|
||||
//Has File
|
||||
.TheNext(1)
|
||||
.With(e => e.EpisodeFileId = 1)
|
||||
//Future
|
||||
.TheNext(1)
|
||||
.With(e => e.EpisodeFileId = 0)
|
||||
.With(e => e.AirDateUtc = DateTime.UtcNow.AddDays(7))
|
||||
//Future/TBA
|
||||
.TheNext(1)
|
||||
.With(e => e.EpisodeFileId = 0)
|
||||
.With(e => e.AirDateUtc = null)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(_episodes);
|
||||
}
|
||||
|
||||
private void GivenSpecials()
|
||||
{
|
||||
foreach (var episode in _episodes)
|
||||
{
|
||||
episode.SeasonNumber = 0;
|
||||
}
|
||||
|
||||
_series.Seasons = new List<Season>{new Season { Monitored = false, SeasonNumber = 0 }};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_monitor_series_without_changing_episodes()
|
||||
{
|
||||
Subject.SetEpisodeMonitoredStatus(_series, null);
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Once());
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.UpdateEpisodes(It.IsAny<List<Episode>>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_monitor_all_episodes()
|
||||
{
|
||||
Subject.SetEpisodeMonitoredStatus(_series, new MonitoringOptions());
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.UpdateEpisodes(It.Is<List<Episode>>(l => l.All(e => e.Monitored))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_monitor_missing_episodes_only()
|
||||
{
|
||||
var monitoringOptions = new MonitoringOptions
|
||||
{
|
||||
IgnoreEpisodesWithFiles = true,
|
||||
IgnoreEpisodesWithoutFiles = false
|
||||
};
|
||||
|
||||
Subject.SetEpisodeMonitoredStatus(_series, monitoringOptions);
|
||||
|
||||
VerifyMonitored(e => !e.HasFile);
|
||||
VerifyNotMonitored(e => e.HasFile);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_monitor_new_episodes_only()
|
||||
{
|
||||
var monitoringOptions = new MonitoringOptions
|
||||
{
|
||||
IgnoreEpisodesWithFiles = true,
|
||||
IgnoreEpisodesWithoutFiles = true
|
||||
};
|
||||
|
||||
Subject.SetEpisodeMonitoredStatus(_series, monitoringOptions);
|
||||
|
||||
VerifyMonitored(e => e.AirDateUtc.HasValue && e.AirDateUtc.Value.After(DateTime.UtcNow));
|
||||
VerifyMonitored(e => !e.AirDateUtc.HasValue);
|
||||
VerifyNotMonitored(e => e.AirDateUtc.HasValue && e.AirDateUtc.Value.Before(DateTime.UtcNow));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_monitor_missing_specials()
|
||||
{
|
||||
GivenSpecials();
|
||||
|
||||
var monitoringOptions = new MonitoringOptions
|
||||
{
|
||||
IgnoreEpisodesWithFiles = true,
|
||||
IgnoreEpisodesWithoutFiles = false
|
||||
};
|
||||
|
||||
Subject.SetEpisodeMonitoredStatus(_series, monitoringOptions);
|
||||
|
||||
VerifyNotMonitored(e => e.SeasonNumber == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_monitor_new_specials()
|
||||
{
|
||||
GivenSpecials();
|
||||
|
||||
var monitoringOptions = new MonitoringOptions
|
||||
{
|
||||
IgnoreEpisodesWithFiles = true,
|
||||
IgnoreEpisodesWithoutFiles = true
|
||||
};
|
||||
|
||||
Subject.SetEpisodeMonitoredStatus(_series, monitoringOptions);
|
||||
|
||||
VerifyNotMonitored(e => e.SeasonNumber == 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_monitor_season_when_all_episodes_are_monitored_except_latest_season()
|
||||
{
|
||||
_series.Seasons = Builder<Season>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(n => n.Monitored = true)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
_episodes = Builder<Episode>.CreateListOfSize(5)
|
||||
.All()
|
||||
.With(e => e.SeasonNumber = 1)
|
||||
.With(e => e.EpisodeFileId = 0)
|
||||
.With(e => e.AirDateUtc = DateTime.UtcNow.AddDays(-5))
|
||||
.TheLast(1)
|
||||
.With(e => e.SeasonNumber = 2)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(_episodes);
|
||||
|
||||
var monitoringOptions = new MonitoringOptions
|
||||
{
|
||||
IgnoreEpisodesWithoutFiles = true
|
||||
};
|
||||
|
||||
Subject.SetEpisodeMonitoredStatus(_series, monitoringOptions);
|
||||
|
||||
VerifySeasonMonitored(n => n.SeasonNumber == 2);
|
||||
VerifySeasonNotMonitored(n => n.SeasonNumber == 1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_ignore_episodes_when_season_is_not_monitored()
|
||||
{
|
||||
_series.Seasons.ForEach(s => s.Monitored = false);
|
||||
|
||||
Subject.SetEpisodeMonitoredStatus(_series, new MonitoringOptions());
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.UpdateEpisodes(It.Is<List<Episode>>(l => l.All(e => !e.Monitored))));
|
||||
}
|
||||
|
||||
private void VerifyMonitored(Func<Episode, bool> predicate)
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.UpdateEpisodes(It.Is<List<Episode>>(l => l.Where(predicate).All(e => e.Monitored))));
|
||||
}
|
||||
|
||||
private void VerifyNotMonitored(Func<Episode, bool> predicate)
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.UpdateEpisodes(It.Is<List<Episode>>(l => l.Where(predicate).All(e => !e.Monitored))));
|
||||
}
|
||||
|
||||
private void VerifySeasonMonitored(Func<Season, bool> predicate)
|
||||
{
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Where(predicate).All(n => n.Monitored))));
|
||||
}
|
||||
|
||||
private void VerifySeasonNotMonitored(Func<Season, bool> predicate)
|
||||
{
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Where(predicate).All(n => !n.Monitored))));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
using System;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ByAirDateFixture : DbTest<EpisodeRepository, Episode>
|
||||
{
|
||||
private const int SERIES_ID = 1;
|
||||
private const string AIR_DATE = "2014-04-02";
|
||||
|
||||
private void GivenEpisode(int seasonNumber)
|
||||
{
|
||||
var episode = Builder<Episode>.CreateNew()
|
||||
.With(e => e.SeriesId = 1)
|
||||
.With(e => e.SeasonNumber = seasonNumber)
|
||||
.With(e => e.AirDate = AIR_DATE)
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(episode);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_multiple_regular_episodes_are_found()
|
||||
{
|
||||
GivenEpisode(1);
|
||||
GivenEpisode(2);
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => Subject.Get(SERIES_ID, AIR_DATE));
|
||||
Assert.Throws<InvalidOperationException>(() => Subject.Find(SERIES_ID, AIR_DATE));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_throw_when_get_finds_no_episode()
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => Subject.Get(SERIES_ID, AIR_DATE));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_episode_when_single_episode_exists_for_air_date()
|
||||
{
|
||||
GivenEpisode(1);
|
||||
|
||||
Subject.Get(SERIES_ID, AIR_DATE).Should().NotBeNull();
|
||||
Subject.Find(SERIES_ID, AIR_DATE).Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_episode_when_regular_episode_and_special_share_the_same_air_date()
|
||||
{
|
||||
GivenEpisode(1);
|
||||
GivenEpisode(0);
|
||||
|
||||
Subject.Get(SERIES_ID, AIR_DATE).Should().NotBeNull();
|
||||
Subject.Find(SERIES_ID, AIR_DATE).Should().NotBeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_special_when_its_the_only_episode_for_the_date_provided()
|
||||
{
|
||||
GivenEpisode(0);
|
||||
|
||||
Subject.Get(SERIES_ID, AIR_DATE).Should().NotBeNull();
|
||||
Subject.Find(SERIES_ID, AIR_DATE).Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
using System;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class EpisodesBetweenDatesFixture : DbTest<EpisodeRepository, Episode>
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var series = Builder<Series>.CreateNew()
|
||||
.With(s => s.Id = 0)
|
||||
.With(s => s.Runtime = 30)
|
||||
.With(s => s.Monitored = true)
|
||||
.Build();
|
||||
|
||||
series.Id = Db.Insert(series).Id;
|
||||
|
||||
var episode = Builder<Episode>.CreateNew()
|
||||
.With(e => e.Id = 0)
|
||||
.With(e => e.SeriesId = series.Id)
|
||||
.With(e => e.Monitored = true)
|
||||
.Build();
|
||||
|
||||
Db.Insert(episode);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_episodes()
|
||||
{
|
||||
var episodes = Subject.EpisodesBetweenDates(DateTime.Today.AddDays(-1), DateTime.Today.AddDays(3), false);
|
||||
episodes.Should().HaveCount(1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class EpisodesRepositoryReadFixture : DbTest<EpisodeRepository, Episode>
|
||||
{
|
||||
private Series series;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
series = Builder<Series>.CreateNew()
|
||||
.With(s => s.Runtime = 30)
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(series);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_episodes_by_file()
|
||||
{
|
||||
var episodeFile = Builder<EpisodeFile>.CreateNew()
|
||||
.With(h => h.Quality = new QualityModel())
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(episodeFile);
|
||||
|
||||
var episode = Builder<Episode>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(e => e.SeriesId = series.Id)
|
||||
.With(e => e.EpisodeFileId = episodeFile.Id)
|
||||
.BuildListOfNew();
|
||||
|
||||
Db.InsertMany(episode);
|
||||
|
||||
var episodes = Subject.GetEpisodeByFileId(episodeFile.Id);
|
||||
episodes.Should().HaveCount(2);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class EpisodesWhereCutoffUnmetFixture : DbTest<EpisodeRepository, Episode>
|
||||
{
|
||||
private Series _monitoredSeries;
|
||||
private Series _unmonitoredSeries;
|
||||
private PagingSpec<Episode> _pagingSpec;
|
||||
private List<QualitiesBelowCutoff> _qualitiesBelowCutoff;
|
||||
private List<LanguagesBelowCutoff> _languagesBelowCutoff;
|
||||
private List<Episode> _unairedEpisodes;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var profile = new Profile
|
||||
{
|
||||
Id = 1,
|
||||
Cutoff = Quality.MP3_256,
|
||||
Items = new List<ProfileQualityItem>
|
||||
{
|
||||
new ProfileQualityItem { Allowed = true, Quality = Quality.MP3_192 },
|
||||
new ProfileQualityItem { Allowed = true, Quality = Quality.MP3_256 },
|
||||
new ProfileQualityItem { Allowed = true, Quality = Quality.FLAC }
|
||||
}
|
||||
};
|
||||
|
||||
var langProfile = new LanguageProfile
|
||||
{
|
||||
Id = 1,
|
||||
Languages = Languages.LanguageFixture.GetDefaultLanguages(),
|
||||
Cutoff = Language.Spanish
|
||||
};
|
||||
|
||||
_monitoredSeries = Builder<Series>.CreateNew()
|
||||
.With(s => s.TvRageId = RandomNumber)
|
||||
.With(s => s.Runtime = 30)
|
||||
.With(s => s.Monitored = true)
|
||||
.With(s => s.TitleSlug = "Title3")
|
||||
.With(s => s.ProfileId = profile.Id)
|
||||
.With(s => s.LanguageProfileId = langProfile.Id)
|
||||
.BuildNew();
|
||||
|
||||
_unmonitoredSeries = Builder<Series>.CreateNew()
|
||||
.With(s => s.TvdbId = RandomNumber)
|
||||
.With(s => s.Runtime = 30)
|
||||
.With(s => s.Monitored = false)
|
||||
.With(s => s.TitleSlug = "Title2")
|
||||
.With(s => s.ProfileId = profile.Id)
|
||||
.With(s => s.LanguageProfileId = langProfile.Id)
|
||||
.BuildNew();
|
||||
|
||||
_monitoredSeries.Id = Db.Insert(_monitoredSeries).Id;
|
||||
_unmonitoredSeries.Id = Db.Insert(_unmonitoredSeries).Id;
|
||||
|
||||
_pagingSpec = new PagingSpec<Episode>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 10,
|
||||
SortKey = "AirDate",
|
||||
SortDirection = SortDirection.Ascending
|
||||
};
|
||||
|
||||
_qualitiesBelowCutoff = new List<QualitiesBelowCutoff>
|
||||
{
|
||||
new QualitiesBelowCutoff(profile.Id, new[] {Quality.MP3_192.Id})
|
||||
};
|
||||
|
||||
_languagesBelowCutoff = new List<LanguagesBelowCutoff>
|
||||
|
||||
{
|
||||
new LanguagesBelowCutoff(profile.Id, new[] { Language.English.Id })
|
||||
};
|
||||
|
||||
var qualityMetLanguageUnmet = new TrackFile { RelativePath = "a", Quality = new QualityModel { Quality = Quality.MP3_256 }, Language = Language.English };
|
||||
var qualityMetLanguageMet = new TrackFile { RelativePath = "b", Quality = new QualityModel { Quality = Quality.MP3_256 }, Language = Language.Spanish };
|
||||
var qualityMetLanguageExceed = new TrackFile { RelativePath = "c", Quality = new QualityModel { Quality = Quality.MP3_256 }, Language = Language.French };
|
||||
var qualityUnmetLanguageUnmet = new TrackFile { RelativePath = "d", Quality = new QualityModel { Quality = Quality.MP3_192 }, Language = Language.English };
|
||||
var qualityUnmetLanguageMet = new TrackFile { RelativePath = "e", Quality = new QualityModel { Quality = Quality.MP3_192 }, Language = Language.Spanish };
|
||||
var qualityUnmetLanguageExceed = new TrackFile { RelativePath = "f", Quality = new QualityModel { Quality = Quality.MP3_192 }, Language = Language.French };
|
||||
var qualityRawHDLanguageUnmet = new TrackFile { RelativePath = "g", Quality = new QualityModel { Quality = Quality.FLAC }, Language = Language.English };
|
||||
var qualityRawHDLanguageMet = new TrackFile { RelativePath = "h", Quality = new QualityModel { Quality = Quality.FLAC }, Language = Language.Spanish };
|
||||
var qualityRawHDLanguageExceed = new TrackFile { RelativePath = "i", Quality = new QualityModel { Quality = Quality.FLAC }, Language = Language.French };
|
||||
MediaFileRepository fileRepository = Mocker.Resolve<MediaFileRepository>();
|
||||
|
||||
qualityMetLanguageUnmet = fileRepository.Insert(qualityMetLanguageUnmet);
|
||||
qualityMetLanguageMet = fileRepository.Insert(qualityMetLanguageMet);
|
||||
qualityMetLanguageExceed = fileRepository.Insert(qualityMetLanguageExceed);
|
||||
qualityUnmetLanguageUnmet = fileRepository.Insert(qualityUnmetLanguageUnmet);
|
||||
qualityUnmetLanguageMet = fileRepository.Insert(qualityUnmetLanguageMet);
|
||||
qualityUnmetLanguageExceed = fileRepository.Insert(qualityUnmetLanguageExceed);
|
||||
qualityRawHDLanguageUnmet = fileRepository.Insert(qualityRawHDLanguageUnmet);
|
||||
qualityRawHDLanguageMet = fileRepository.Insert(qualityRawHDLanguageMet);
|
||||
qualityRawHDLanguageExceed = fileRepository.Insert(qualityRawHDLanguageExceed);
|
||||
|
||||
var monitoredSeriesEpisodes = Builder<Episode>.CreateListOfSize(4)
|
||||
.All()
|
||||
.With(e => e.Id = 0)
|
||||
.With(e => e.SeriesId = _monitoredSeries.Id)
|
||||
.With(e => e.AirDateUtc = DateTime.Now.AddDays(-5))
|
||||
.With(e => e.Monitored = true)
|
||||
.With(e => e.EpisodeFileId = qualityUnmetLanguageUnmet.Id)
|
||||
.TheFirst(1)
|
||||
.With(e => e.Monitored = false)
|
||||
.With(e => e.EpisodeFileId = qualityMetLanguageMet.Id)
|
||||
.TheNext(1)
|
||||
.With(e => e.EpisodeFileId = qualityRawHDLanguageExceed.Id)
|
||||
.TheLast(1)
|
||||
.With(e => e.SeasonNumber = 0)
|
||||
.Build();
|
||||
|
||||
var unmonitoredSeriesEpisodes = Builder<Episode>.CreateListOfSize(3)
|
||||
.All()
|
||||
.With(e => e.Id = 0)
|
||||
.With(e => e.SeriesId = _unmonitoredSeries.Id)
|
||||
.With(e => e.AirDateUtc = DateTime.Now.AddDays(-5))
|
||||
.With(e => e.Monitored = true)
|
||||
.With(e => e.EpisodeFileId = qualityRawHDLanguageUnmet.Id)
|
||||
.TheFirst(1)
|
||||
.With(e => e.Monitored = false)
|
||||
.With(e => e.EpisodeFileId = qualityMetLanguageMet.Id)
|
||||
.TheLast(1)
|
||||
.With(e => e.SeasonNumber = 0)
|
||||
.Build();
|
||||
|
||||
|
||||
_unairedEpisodes = Builder<Episode>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.Id = 0)
|
||||
.With(e => e.SeriesId = _monitoredSeries.Id)
|
||||
.With(e => e.AirDateUtc = DateTime.Now.AddDays(5))
|
||||
.With(e => e.Monitored = true)
|
||||
.With(e => e.EpisodeFileId = qualityUnmetLanguageUnmet.Id)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Db.InsertMany(monitoredSeriesEpisodes);
|
||||
Db.InsertMany(unmonitoredSeriesEpisodes);
|
||||
}
|
||||
|
||||
private void GivenMonitoredFilterExpression()
|
||||
{
|
||||
_pagingSpec.FilterExpression = e => e.Monitored == true && e.Series.Monitored == true;
|
||||
}
|
||||
|
||||
private void GivenUnmonitoredFilterExpression()
|
||||
{
|
||||
_pagingSpec.FilterExpression = e => e.Monitored == false || e.Series.Monitored == false;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_include_episodes_where_cutoff_has_not_be_met()
|
||||
{
|
||||
GivenMonitoredFilterExpression();
|
||||
|
||||
var spec = Subject.EpisodesWhereCutoffUnmet(_pagingSpec, _qualitiesBelowCutoff, _languagesBelowCutoff, false);
|
||||
|
||||
spec.Records.Should().HaveCount(1);
|
||||
spec.Records.Should().OnlyContain(e => e.EpisodeFile.Value.Quality.Quality == Quality.MP3_192);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_only_contain_monitored_episodes()
|
||||
{
|
||||
GivenMonitoredFilterExpression();
|
||||
|
||||
var spec = Subject.EpisodesWhereCutoffUnmet(_pagingSpec, _qualitiesBelowCutoff, _languagesBelowCutoff, false);
|
||||
|
||||
spec.Records.Should().HaveCount(1);
|
||||
spec.Records.Should().OnlyContain(e => e.Monitored);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_only_contain_episode_with_monitored_series()
|
||||
{
|
||||
GivenMonitoredFilterExpression();
|
||||
|
||||
var spec = Subject.EpisodesWhereCutoffUnmet(_pagingSpec, _qualitiesBelowCutoff, _languagesBelowCutoff, false);
|
||||
|
||||
spec.Records.Should().HaveCount(1);
|
||||
spec.Records.Should().OnlyContain(e => e.Series.Monitored);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_contain_unaired_episodes_if_file_does_not_meet_cutoff()
|
||||
{
|
||||
Db.InsertMany(_unairedEpisodes);
|
||||
|
||||
GivenMonitoredFilterExpression();
|
||||
|
||||
var spec = Subject.EpisodesWhereCutoffUnmet(_pagingSpec, _qualitiesBelowCutoff, _languagesBelowCutoff, false);
|
||||
|
||||
spec.Records.Should().HaveCount(2);
|
||||
spec.Records.Should().OnlyContain(e => e.Series.Monitored);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class EpisodesWithFilesFixture : DbTest<EpisodeRepository, Episode>
|
||||
{
|
||||
private const int SERIES_ID = 1;
|
||||
private List<Episode> _episodes;
|
||||
private List<EpisodeFile> _episodeFiles;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_episodeFiles = Builder<EpisodeFile>.CreateListOfSize(5)
|
||||
.All()
|
||||
.With(c => c.Quality = new QualityModel())
|
||||
.BuildListOfNew();
|
||||
|
||||
Db.InsertMany(_episodeFiles);
|
||||
|
||||
_episodes = Builder<Episode>.CreateListOfSize(10)
|
||||
.All()
|
||||
.With(e => e.EpisodeFileId = 0)
|
||||
.With(e => e.SeriesId = SERIES_ID)
|
||||
.BuildListOfNew()
|
||||
.ToList();
|
||||
|
||||
for (int i = 0; i < _episodeFiles.Count; i++)
|
||||
{
|
||||
_episodes[i].EpisodeFileId = _episodeFiles[i].Id;
|
||||
}
|
||||
|
||||
Db.InsertMany(_episodes);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_only_get_files_that_have_episode_files()
|
||||
{
|
||||
var result = Subject.EpisodesWithFiles(SERIES_ID);
|
||||
|
||||
result.Should().OnlyContain(e => e.EpisodeFileId > 0);
|
||||
result.Should().HaveCount(_episodeFiles.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_only_contain_episodes_for_the_given_series()
|
||||
{
|
||||
var episodeFile = Builder<EpisodeFile>.CreateNew()
|
||||
.With(f => f.RelativePath = "another path")
|
||||
.With(c => c.Quality = new QualityModel())
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(episodeFile);
|
||||
|
||||
var episode = Builder<Episode>.CreateNew()
|
||||
.With(e => e.SeriesId = SERIES_ID + 10)
|
||||
.With(e => e.EpisodeFileId = episodeFile.Id)
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(episode);
|
||||
|
||||
Subject.EpisodesWithFiles(episode.SeriesId).Should().OnlyContain(e => e.SeriesId == episode.SeriesId);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_have_episode_file_loaded()
|
||||
{
|
||||
Subject.EpisodesWithFiles(SERIES_ID).Should().OnlyContain(e => e.EpisodeFile.IsLoaded);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class EpisodesWithoutFilesFixture : DbTest<EpisodeRepository, Episode>
|
||||
{
|
||||
private Series _monitoredSeries;
|
||||
private Series _unmonitoredSeries;
|
||||
private PagingSpec<Episode> _pagingSpec;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_monitoredSeries = Builder<Series>.CreateNew()
|
||||
.With(s => s.Id = 0)
|
||||
.With(s => s.TvRageId = RandomNumber)
|
||||
.With(s => s.Runtime = 30)
|
||||
.With(s => s.Monitored = true)
|
||||
.With(s => s.TitleSlug = "Title3")
|
||||
.Build();
|
||||
|
||||
_unmonitoredSeries = Builder<Series>.CreateNew()
|
||||
.With(s => s.Id = 0)
|
||||
.With(s => s.TvdbId = RandomNumber)
|
||||
.With(s => s.Runtime = 30)
|
||||
.With(s => s.Monitored = false)
|
||||
.With(s => s.TitleSlug = "Title2")
|
||||
.Build();
|
||||
|
||||
_monitoredSeries.Id = Db.Insert(_monitoredSeries).Id;
|
||||
_unmonitoredSeries.Id = Db.Insert(_unmonitoredSeries).Id;
|
||||
|
||||
_pagingSpec = new PagingSpec<Episode>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 10,
|
||||
SortKey = "AirDate",
|
||||
SortDirection = SortDirection.Ascending
|
||||
};
|
||||
|
||||
var monitoredSeriesEpisodes = Builder<Episode>.CreateListOfSize(3)
|
||||
.All()
|
||||
.With(e => e.Id = 0)
|
||||
.With(e => e.SeriesId = _monitoredSeries.Id)
|
||||
.With(e => e.EpisodeFileId = 0)
|
||||
.With(e => e.AirDateUtc = DateTime.Now.AddDays(-5))
|
||||
.With(e => e.Monitored = true)
|
||||
.TheFirst(1)
|
||||
.With(e => e.Monitored = false)
|
||||
.TheLast(1)
|
||||
.With(e => e.SeasonNumber = 0)
|
||||
.Build();
|
||||
|
||||
var unmonitoredSeriesEpisodes = Builder<Episode>.CreateListOfSize(3)
|
||||
.All()
|
||||
.With(e => e.Id = 0)
|
||||
.With(e => e.SeriesId = _unmonitoredSeries.Id)
|
||||
.With(e => e.EpisodeFileId = 0)
|
||||
.With(e => e.AirDateUtc = DateTime.Now.AddDays(-5))
|
||||
.With(e => e.Monitored = true)
|
||||
.TheFirst(1)
|
||||
.With(e => e.Monitored = false)
|
||||
.TheLast(1)
|
||||
.With(e => e.SeasonNumber = 0)
|
||||
.Build();
|
||||
|
||||
|
||||
var unairedEpisodes = Builder<Episode>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.Id = 0)
|
||||
.With(e => e.SeriesId = _monitoredSeries.Id)
|
||||
.With(e => e.EpisodeFileId = 0)
|
||||
.With(e => e.AirDateUtc = DateTime.Now.AddDays(5))
|
||||
.With(e => e.Monitored = true)
|
||||
.Build();
|
||||
|
||||
|
||||
Db.InsertMany(monitoredSeriesEpisodes);
|
||||
Db.InsertMany(unmonitoredSeriesEpisodes);
|
||||
Db.InsertMany(unairedEpisodes);
|
||||
}
|
||||
|
||||
private void GivenMonitoredFilterExpression()
|
||||
{
|
||||
_pagingSpec.FilterExpression = e => e.Monitored == true && e.Series.Monitored == true;
|
||||
}
|
||||
|
||||
private void GivenUnmonitoredFilterExpression()
|
||||
{
|
||||
_pagingSpec.FilterExpression = e => e.Monitored == false || e.Series.Monitored == false;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_monitored_episodes()
|
||||
{
|
||||
GivenMonitoredFilterExpression();
|
||||
|
||||
var episodes = Subject.EpisodesWithoutFiles(_pagingSpec, false);
|
||||
|
||||
episodes.Records.Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("Specials not implemented")]
|
||||
public void should_get_episode_including_specials()
|
||||
{
|
||||
var episodes = Subject.EpisodesWithoutFiles(_pagingSpec, true);
|
||||
|
||||
episodes.Records.Should().HaveCount(2);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_include_unmonitored_episodes()
|
||||
{
|
||||
GivenMonitoredFilterExpression();
|
||||
|
||||
var episodes = Subject.EpisodesWithoutFiles(_pagingSpec, false);
|
||||
|
||||
episodes.Records.Should().NotContain(e => e.Monitored == false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_contain_unmonitored_series()
|
||||
{
|
||||
GivenMonitoredFilterExpression();
|
||||
|
||||
var episodes = Subject.EpisodesWithoutFiles(_pagingSpec, false);
|
||||
|
||||
episodes.Records.Should().NotContain(e => e.SeriesId == _unmonitoredSeries.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_return_unaired()
|
||||
{
|
||||
var episodes = Subject.EpisodesWithoutFiles(_pagingSpec, false);
|
||||
|
||||
episodes.TotalRecords.Should().Be(4);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_return_episodes_on_air()
|
||||
{
|
||||
var onAirEpisode = Builder<Episode>.CreateNew()
|
||||
.With(e => e.Id = 0)
|
||||
.With(e => e.SeriesId = _monitoredSeries.Id)
|
||||
.With(e => e.EpisodeFileId = 0)
|
||||
.With(e => e.AirDateUtc = DateTime.Now.AddMinutes(-15))
|
||||
.With(e => e.Monitored = true)
|
||||
.Build();
|
||||
|
||||
Db.Insert(onAirEpisode);
|
||||
|
||||
var episodes = Subject.EpisodesWithoutFiles(_pagingSpec, false);
|
||||
|
||||
episodes.TotalRecords.Should().Be(4);
|
||||
episodes.Records.Where(e => e.Id == onAirEpisode.Id).Should().BeEmpty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class FindEpisodeFixture : DbTest<EpisodeRepository, Episode>
|
||||
{
|
||||
private Episode _episode1;
|
||||
private Episode _episode2;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_episode1 = Builder<Episode>.CreateNew()
|
||||
.With(e => e.SeriesId = 1)
|
||||
.With(e => e.SeasonNumber = 1)
|
||||
.With(e => e.SceneSeasonNumber = 2)
|
||||
.With(e => e.EpisodeNumber = 3)
|
||||
.With(e => e.AbsoluteEpisodeNumber = 3)
|
||||
.With(e => e.SceneEpisodeNumber = 4)
|
||||
.BuildNew();
|
||||
|
||||
_episode2 = Builder<Episode>.CreateNew()
|
||||
.With(e => e.SeriesId = 1)
|
||||
.With(e => e.SeasonNumber = 1)
|
||||
.With(e => e.SceneSeasonNumber = 2)
|
||||
.With(e => e.EpisodeNumber = 4)
|
||||
.With(e => e.SceneEpisodeNumber = 4)
|
||||
.BuildNew();
|
||||
|
||||
_episode1 = Db.Insert(_episode1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_find_episode_by_scene_numbering()
|
||||
{
|
||||
Subject.FindEpisodesBySceneNumbering(_episode1.SeriesId, _episode1.SceneSeasonNumber.Value, _episode1.SceneEpisodeNumber.Value)
|
||||
.First()
|
||||
.Id
|
||||
.Should()
|
||||
.Be(_episode1.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_find_episode_by_standard_numbering()
|
||||
{
|
||||
Subject.Find(_episode1.SeriesId, _episode1.SeasonNumber, _episode1.EpisodeNumber)
|
||||
.Id
|
||||
.Should()
|
||||
.Be(_episode1.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_find_episode_that_does_not_exist()
|
||||
{
|
||||
Subject.Find(_episode1.SeriesId, _episode1.SeasonNumber + 1, _episode1.EpisodeNumber)
|
||||
.Should()
|
||||
.BeNull();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_find_episode_by_absolute_numbering()
|
||||
{
|
||||
Subject.Find(_episode1.SeriesId, _episode1.AbsoluteEpisodeNumber.Value)
|
||||
.Id
|
||||
.Should()
|
||||
.Be(_episode1.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_multiple_episode_if_multiple_match_by_scene_numbering()
|
||||
{
|
||||
_episode2 = Db.Insert(_episode2);
|
||||
|
||||
Subject.FindEpisodesBySceneNumbering(_episode1.SeriesId, _episode1.SceneSeasonNumber.Value, _episode1.SceneEpisodeNumber.Value)
|
||||
.Should()
|
||||
.HaveCount(2);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class FindEpisodeByTitleFixture : CoreTest<EpisodeService>
|
||||
{
|
||||
private List<Episode> _episodes;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_episodes = Builder<Episode>.CreateListOfSize(5)
|
||||
.Build()
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private void GivenEpisodesWithTitles(params string[] titles)
|
||||
{
|
||||
for (int i = 0; i < titles.Count(); i++)
|
||||
{
|
||||
_episodes[i].Title = titles[i];
|
||||
}
|
||||
|
||||
Mocker.GetMock<IEpisodeRepository>()
|
||||
.Setup(s => s.GetEpisodes(It.IsAny<int>(), It.IsAny<int>()))
|
||||
.Returns(_episodes);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_find_episode_by_title()
|
||||
{
|
||||
const string expectedTitle = "A Journey to the Highlands";
|
||||
GivenEpisodesWithTitles(expectedTitle);
|
||||
|
||||
Subject.FindEpisodeByTitle(1, 1, "Downton.Abbey.A.Journey.To.The.Highlands.720p.BluRay.x264-aAF")
|
||||
.Title
|
||||
.Should()
|
||||
.Be(expectedTitle);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_prefer_longer_match()
|
||||
{
|
||||
const string expectedTitle = "Inside The Walking Dead: Walker University";
|
||||
GivenEpisodesWithTitles("Inside The Walking Dead", expectedTitle);
|
||||
|
||||
Subject.FindEpisodeByTitle(1, 1, "The.Walking.Dead.S04.Special.Inside.The.Walking.Dead.Walker.University.720p.HDTV.x264-W4F")
|
||||
.Title
|
||||
.Should()
|
||||
.Be(expectedTitle);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_null_when_no_match_is_found()
|
||||
{
|
||||
GivenEpisodesWithTitles();
|
||||
|
||||
Subject.FindEpisodeByTitle(1, 1, "The.Walking.Dead.S04.Special.Inside.The.Walking.Dead.Walker.University.720p.HDTV.x264-W4F")
|
||||
.Should()
|
||||
.BeNull();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.EpisodeServiceTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class HandleEpisodeFileDeletedFixture : CoreTest<EpisodeService>
|
||||
{
|
||||
private EpisodeFile _episodeFile;
|
||||
private List<Episode> _episodes;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_episodeFile = Builder<EpisodeFile>
|
||||
.CreateNew()
|
||||
.Build();
|
||||
}
|
||||
|
||||
private void GivenSingleEpisodeFile()
|
||||
{
|
||||
_episodes = Builder<Episode>
|
||||
.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.Monitored = true)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Mocker.GetMock<IEpisodeRepository>()
|
||||
.Setup(s => s.GetEpisodeByFileId(_episodeFile.Id))
|
||||
.Returns(_episodes);
|
||||
}
|
||||
|
||||
private void GivenMultiEpisodeFile()
|
||||
{
|
||||
_episodes = Builder<Episode>
|
||||
.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(e => e.Monitored = true)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Mocker.GetMock<IEpisodeRepository>()
|
||||
.Setup(s => s.GetEpisodeByFileId(_episodeFile.Id))
|
||||
.Returns(_episodes);
|
||||
}
|
||||
|
||||
//[Test]
|
||||
//public void should_set_EpisodeFileId_to_zero()
|
||||
//{
|
||||
// GivenSingleEpisodeFile();
|
||||
|
||||
// Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
||||
|
||||
// Mocker.GetMock<IEpisodeRepository>()
|
||||
// .Verify(v => v.Update(It.Is<Episode>(e => e.EpisodeFileId == 0)), Times.Once());
|
||||
//}
|
||||
|
||||
//[Test]
|
||||
//public void should_update_each_episode_for_file()
|
||||
//{
|
||||
// GivenMultiEpisodeFile();
|
||||
|
||||
// Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
||||
|
||||
// Mocker.GetMock<IEpisodeRepository>()
|
||||
// .Verify(v => v.Update(It.Is<Episode>(e => e.EpisodeFileId == 0)), Times.Exactly(2));
|
||||
//}
|
||||
|
||||
//[Test]
|
||||
//public void should_set_monitored_to_false_if_autoUnmonitor_is_true_and_is_not_for_an_upgrade()
|
||||
//{
|
||||
// GivenSingleEpisodeFile();
|
||||
|
||||
// Mocker.GetMock<IConfigService>()
|
||||
// .SetupGet(s => s.AutoUnmonitorPreviouslyDownloadedTracks)
|
||||
// .Returns(true);
|
||||
|
||||
// Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.MissingFromDisk));
|
||||
|
||||
// Mocker.GetMock<IEpisodeRepository>()
|
||||
// .Verify(v => v.Update(It.Is<Episode>(e => e.Monitored == false)), Times.Once());
|
||||
//}
|
||||
|
||||
//[Test]
|
||||
//public void should_leave_monitored_to_true_if_autoUnmonitor_is_false()
|
||||
//{
|
||||
// GivenSingleEpisodeFile();
|
||||
|
||||
// Mocker.GetMock<IConfigService>()
|
||||
// .SetupGet(s => s.AutoUnmonitorPreviouslyDownloadedTracks)
|
||||
// .Returns(false);
|
||||
|
||||
// Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.Upgrade));
|
||||
|
||||
// Mocker.GetMock<IEpisodeRepository>()
|
||||
// .Verify(v => v.Update(It.Is<Episode>(e => e.Monitored == true)), Times.Once());
|
||||
//}
|
||||
|
||||
//[Test]
|
||||
//public void should_leave_monitored_to_true_if_autoUnmonitor_is_true_and_is_for_an_upgrade()
|
||||
//{
|
||||
// GivenSingleEpisodeFile();
|
||||
|
||||
// Mocker.GetMock<IConfigService>()
|
||||
// .SetupGet(s => s.AutoUnmonitorPreviouslyDownloadedTracks)
|
||||
// .Returns(true);
|
||||
|
||||
// Subject.Handle(new EpisodeFileDeletedEvent(_episodeFile, DeleteMediaFileReason.Upgrade));
|
||||
|
||||
// Mocker.GetMock<IEpisodeRepository>()
|
||||
// .Verify(v => v.Update(It.Is<Episode>(e => e.Monitored == true)), Times.Once());
|
||||
//}
|
||||
}
|
||||
}
|
|
@ -1,397 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MetadataSource.SkyHook;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class RefreshEpisodeServiceFixture : CoreTest<RefreshEpisodeService>
|
||||
{
|
||||
private List<Episode> _insertedEpisodes;
|
||||
private List<Episode> _updatedEpisodes;
|
||||
private List<Episode> _deletedEpisodes;
|
||||
private Tuple<Series, List<Episode>> _gameOfThrones;
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void TestFixture()
|
||||
{
|
||||
UseRealHttp();
|
||||
|
||||
// _gameOfThrones = Mocker.Resolve<SkyHookProxy>().GetSeriesInfo(121361);//Game of thrones
|
||||
|
||||
// Remove specials.
|
||||
_gameOfThrones.Item2.RemoveAll(v => v.SeasonNumber == 0);
|
||||
}
|
||||
|
||||
private List<Episode> GetEpisodes()
|
||||
{
|
||||
return _gameOfThrones.Item2.JsonClone();
|
||||
}
|
||||
|
||||
private Series GetSeries()
|
||||
{
|
||||
var series = _gameOfThrones.Item1.JsonClone();
|
||||
series.Seasons = new List<Season>();
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
private Series GetAnimeSeries()
|
||||
{
|
||||
var series = Builder<Series>.CreateNew().Build();
|
||||
series.SeriesType = SeriesTypes.Anime;
|
||||
series.Seasons = new List<Season>();
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_insertedEpisodes = new List<Episode>();
|
||||
_updatedEpisodes = new List<Episode>();
|
||||
_deletedEpisodes = new List<Episode>();
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.InsertMany(It.IsAny<List<Episode>>()))
|
||||
.Callback<List<Episode>>(e => _insertedEpisodes = e);
|
||||
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.UpdateMany(It.IsAny<List<Episode>>()))
|
||||
.Callback<List<Episode>>(e => _updatedEpisodes = e);
|
||||
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.DeleteMany(It.IsAny<List<Episode>>()))
|
||||
.Callback<List<Episode>>(e => _deletedEpisodes = e);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_create_all_when_no_existing_episodes()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), GetEpisodes());
|
||||
|
||||
_insertedEpisodes.Should().HaveSameCount(GetEpisodes());
|
||||
_updatedEpisodes.Should().BeEmpty();
|
||||
_deletedEpisodes.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_all_when_all_existing_episodes()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(GetEpisodes());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), GetEpisodes());
|
||||
|
||||
_insertedEpisodes.Should().BeEmpty();
|
||||
_updatedEpisodes.Should().HaveSameCount(GetEpisodes());
|
||||
_deletedEpisodes.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_delete_all_when_all_existing_episodes_are_gone_from_datasource()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(GetEpisodes());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), new List<Episode>());
|
||||
|
||||
_insertedEpisodes.Should().BeEmpty();
|
||||
_updatedEpisodes.Should().BeEmpty();
|
||||
_deletedEpisodes.Should().HaveSameCount(GetEpisodes());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_delete_duplicated_episodes_based_on_season_episode_number()
|
||||
{
|
||||
var duplicateEpisodes = GetEpisodes().Skip(5).Take(2).ToList();
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(GetEpisodes().Union(duplicateEpisodes).ToList());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), GetEpisodes());
|
||||
|
||||
_insertedEpisodes.Should().BeEmpty();
|
||||
_updatedEpisodes.Should().HaveSameCount(GetEpisodes());
|
||||
_deletedEpisodes.Should().HaveSameCount(duplicateEpisodes);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_change_monitored_status_for_existing_episodes()
|
||||
{
|
||||
var series = GetSeries();
|
||||
series.Seasons = new List<Season>();
|
||||
series.Seasons.Add(new Season { SeasonNumber = 1, Monitored = false });
|
||||
|
||||
var episodes = GetEpisodes();
|
||||
|
||||
episodes.ForEach(e => e.Monitored = true);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(episodes);
|
||||
|
||||
Subject.RefreshEpisodeInfo(series, GetEpisodes());
|
||||
|
||||
_updatedEpisodes.Should().HaveSameCount(GetEpisodes());
|
||||
_updatedEpisodes.Should().OnlyContain(e => e.Monitored == true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remove_duplicate_remote_episodes_before_processing()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(5)
|
||||
.TheFirst(2)
|
||||
.With(e => e.SeasonNumber = 1)
|
||||
.With(e => e.EpisodeNumber = 1)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), episodes);
|
||||
|
||||
_insertedEpisodes.Should().HaveCount(episodes.Count - 1);
|
||||
_updatedEpisodes.Should().BeEmpty();
|
||||
_deletedEpisodes.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_set_absolute_episode_number_for_anime()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(3).Build().ToList();
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes);
|
||||
|
||||
_insertedEpisodes.All(e => e.AbsoluteEpisodeNumber.HasValue).Should().BeTrue();
|
||||
_updatedEpisodes.Should().BeEmpty();
|
||||
_deletedEpisodes.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_set_absolute_episode_number_even_if_not_previously_set_for_anime()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(3).Build().ToList();
|
||||
|
||||
var existingEpisodes = episodes.JsonClone();
|
||||
existingEpisodes.ForEach(e => e.AbsoluteEpisodeNumber = null);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(existingEpisodes);
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes);
|
||||
|
||||
_insertedEpisodes.Should().BeEmpty();
|
||||
_updatedEpisodes.All(e => e.AbsoluteEpisodeNumber.HasValue).Should().BeTrue();
|
||||
_deletedEpisodes.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_new_season_and_episode_numbers_when_absolute_episode_number_match_found()
|
||||
{
|
||||
const int expectedSeasonNumber = 10;
|
||||
const int expectedEpisodeNumber = 5;
|
||||
const int expectedAbsoluteNumber = 3;
|
||||
|
||||
var episode = Builder<Episode>.CreateNew()
|
||||
.With(e => e.SeasonNumber = expectedSeasonNumber)
|
||||
.With(e => e.EpisodeNumber = expectedEpisodeNumber)
|
||||
.With(e => e.AbsoluteEpisodeNumber = expectedAbsoluteNumber)
|
||||
.Build();
|
||||
|
||||
var existingEpisode = episode.JsonClone();
|
||||
existingEpisode.SeasonNumber = 1;
|
||||
existingEpisode.EpisodeNumber = 1;
|
||||
existingEpisode.AbsoluteEpisodeNumber = expectedAbsoluteNumber;
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>{ existingEpisode });
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), new List<Episode> { episode });
|
||||
|
||||
_insertedEpisodes.Should().BeEmpty();
|
||||
_deletedEpisodes.Should().BeEmpty();
|
||||
|
||||
_updatedEpisodes.First().SeasonNumber.Should().Be(expectedSeasonNumber);
|
||||
_updatedEpisodes.First().EpisodeNumber.Should().Be(expectedEpisodeNumber);
|
||||
_updatedEpisodes.First().AbsoluteEpisodeNumber.Should().Be(expectedAbsoluteNumber);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_prefer_absolute_match_over_season_and_epsiode_match()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
episodes[0].AbsoluteEpisodeNumber = null;
|
||||
episodes[0].SeasonNumber.Should().NotBe(episodes[1].SeasonNumber);
|
||||
episodes[0].EpisodeNumber.Should().NotBe(episodes[1].EpisodeNumber);
|
||||
|
||||
var existingEpisode = new Episode
|
||||
{
|
||||
SeasonNumber = episodes[0].SeasonNumber,
|
||||
EpisodeNumber = episodes[0].EpisodeNumber,
|
||||
AbsoluteEpisodeNumber = episodes[1].AbsoluteEpisodeNumber
|
||||
};
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode> { existingEpisode });
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes);
|
||||
|
||||
_updatedEpisodes.First().SeasonNumber.Should().Be(episodes[1].SeasonNumber);
|
||||
_updatedEpisodes.First().EpisodeNumber.Should().Be(episodes[1].EpisodeNumber);
|
||||
_updatedEpisodes.First().AbsoluteEpisodeNumber.Should().Be(episodes[1].AbsoluteEpisodeNumber);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_ignore_episodes_with_no_absolute_episode_in_distinct_by_absolute()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(10)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
episodes[0].AbsoluteEpisodeNumber = null;
|
||||
episodes[1].AbsoluteEpisodeNumber = null;
|
||||
episodes[2].AbsoluteEpisodeNumber = null;
|
||||
episodes[3].AbsoluteEpisodeNumber = null;
|
||||
episodes[4].AbsoluteEpisodeNumber = null;
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes);
|
||||
|
||||
_insertedEpisodes.Should().HaveCount(episodes.Count);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_override_empty_airdate_for_direct_to_dvd()
|
||||
{
|
||||
var series = GetSeries();
|
||||
series.Status = SeriesStatusType.Ended;
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(10)
|
||||
.All()
|
||||
.With(v => v.AirDateUtc = null)
|
||||
.BuildListOfNew();
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
List<Episode> updateEpisodes = null;
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.InsertMany(It.IsAny<List<Episode>>()))
|
||||
.Callback<List<Episode>>(c => updateEpisodes = c);
|
||||
|
||||
Subject.RefreshEpisodeInfo(series, episodes);
|
||||
|
||||
updateEpisodes.Should().NotBeNull();
|
||||
updateEpisodes.Should().NotBeEmpty();
|
||||
updateEpisodes.All(v => v.AirDateUtc.HasValue).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_tba_for_episode_title_when_null()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(1)
|
||||
.All()
|
||||
.With(e => e.Title = null)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), episodes);
|
||||
|
||||
_insertedEpisodes.First().Title.Should().Be("TBA");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_air_date_when_multiple_episodes_air_on_the_same_day()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
var series = GetSeries();
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(e => e.SeasonNumber = 1)
|
||||
.With(e => e.AirDate = DateTime.Now.ToShortDateString())
|
||||
.With(e => e.AirDateUtc = DateTime.UtcNow)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.RefreshEpisodeInfo(series, episodes);
|
||||
|
||||
_insertedEpisodes.First().AirDateUtc.Value.ToString("s").Should().Be(episodes.First().AirDateUtc.Value.ToString("s"));
|
||||
_insertedEpisodes.Last().AirDateUtc.Value.ToString("s").Should().Be(episodes.First().AirDateUtc.Value.AddMinutes(series.Runtime).ToString("s"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_air_date_when_multiple_episodes_air_on_the_same_day_for_netflix()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
var series = GetSeries();
|
||||
series.Network = "Netflix";
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(e => e.SeasonNumber = 1)
|
||||
.With(e => e.AirDate = DateTime.Now.ToShortDateString())
|
||||
.With(e => e.AirDateUtc = DateTime.UtcNow)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
Subject.RefreshEpisodeInfo(series, episodes);
|
||||
|
||||
_insertedEpisodes.Should().OnlyContain(e => e.AirDateUtc.Value.ToString("s") == episodes.First().AirDateUtc.Value.ToString("s"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_prefer_regular_season_when_absolute_numbers_conflict()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
episodes[0].AbsoluteEpisodeNumber = episodes[1].AbsoluteEpisodeNumber;
|
||||
episodes[0].SeasonNumber = 0;
|
||||
episodes[0].EpisodeNumber.Should().NotBe(episodes[1].EpisodeNumber);
|
||||
|
||||
var existingEpisode = new Episode
|
||||
{
|
||||
SeasonNumber = episodes[0].SeasonNumber,
|
||||
EpisodeNumber = episodes[0].EpisodeNumber,
|
||||
AbsoluteEpisodeNumber = episodes[1].AbsoluteEpisodeNumber
|
||||
};
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode> { existingEpisode });
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes);
|
||||
|
||||
_updatedEpisodes.First().SeasonNumber.Should().Be(episodes[1].SeasonNumber);
|
||||
_updatedEpisodes.First().EpisodeNumber.Should().Be(episodes[1].EpisodeNumber);
|
||||
_updatedEpisodes.First().AbsoluteEpisodeNumber.Should().Be(episodes[1].AbsoluteEpisodeNumber);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
using NzbDrone.Core.Languages;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.SeriesRepositoryTests
|
||||
{
|
||||
[TestFixture]
|
||||
|
||||
public class SeriesRepositoryFixture : DbTest<SeriesRepository, Series>
|
||||
{
|
||||
[Test]
|
||||
public void should_lazyload_quality_profile()
|
||||
{
|
||||
var profile = new Profile
|
||||
{
|
||||
Items = Qualities.QualityFixture.GetDefaultQualities(Quality.MP3_320, Quality.MP3_256, Quality.MP3_192),
|
||||
|
||||
Cutoff = Quality.MP3_320,
|
||||
Name = "TestProfile"
|
||||
};
|
||||
|
||||
var langProfile = new LanguageProfile
|
||||
{
|
||||
Name = "TestProfile",
|
||||
Languages = Languages.LanguageFixture.GetDefaultLanguages(Language.English),
|
||||
Cutoff = Language.English
|
||||
};
|
||||
|
||||
|
||||
|
||||
Mocker.Resolve<ProfileRepository>().Insert(profile);
|
||||
Mocker.Resolve<LanguageProfileRepository>().Insert(langProfile);
|
||||
|
||||
var series = Builder<Series>.CreateNew().BuildNew();
|
||||
series.ProfileId = profile.Id;
|
||||
series.LanguageProfileId = langProfile.Id;
|
||||
|
||||
Subject.Insert(series);
|
||||
|
||||
|
||||
StoredModel.Profile.Should().NotBeNull();
|
||||
StoredModel.LanguageProfile.Should().NotBeNull();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.SeriesServiceTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class AddSeriesFixture : CoreTest<SeriesService>
|
||||
{
|
||||
private Series fakeSeries;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
fakeSeries = Builder<Series>.CreateNew().Build();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void series_added_event_should_have_proper_path()
|
||||
{
|
||||
fakeSeries.Path = null;
|
||||
fakeSeries.RootFolderPath = @"C:\Test\TV";
|
||||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.GetSeriesFolder(fakeSeries, null))
|
||||
.Returns(fakeSeries.Title);
|
||||
|
||||
var series = Subject.AddSeries(fakeSeries);
|
||||
|
||||
series.Path.Should().NotBeNull();
|
||||
|
||||
VerifyEventPublished<SeriesAddedEvent>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.SeriesServiceTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class UpdateMultipleSeriesFixture : CoreTest<SeriesService>
|
||||
{
|
||||
private List<Series> _series;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_series = Builder<Series>.CreateListOfSize(5)
|
||||
.All()
|
||||
.With(s => s.ProfileId = 1)
|
||||
.With(s => s.Monitored)
|
||||
.With(s => s.SeasonFolder)
|
||||
.With(s => s.Path = @"C:\Test\name".AsOsAgnostic())
|
||||
.With(s => s.RootFolderPath = "")
|
||||
.Build().ToList();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_call_repo_updateMany()
|
||||
{
|
||||
Subject.UpdateSeries(_series);
|
||||
|
||||
Mocker.GetMock<ISeriesRepository>().Verify(v => v.UpdateMany(_series), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_path_when_rootFolderPath_is_supplied()
|
||||
{
|
||||
var newRoot = @"C:\Test\TV2".AsOsAgnostic();
|
||||
_series.ForEach(s => s.RootFolderPath = newRoot);
|
||||
|
||||
Subject.UpdateSeries(_series).ForEach(s => s.Path.Should().StartWith(newRoot));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_path_when_rootFolderPath_is_empty()
|
||||
{
|
||||
Subject.UpdateSeries(_series).ForEach(s =>
|
||||
{
|
||||
var expectedPath = _series.Single(ser => ser.Id == s.Id).Path;
|
||||
s.Path.Should().Be(expectedPath);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_update_many_series()
|
||||
{
|
||||
var series = Builder<Series>.CreateListOfSize(50)
|
||||
.All()
|
||||
.With(s => s.Path = (@"C:\Test\TV\" + s.Path).AsOsAgnostic())
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
var newRoot = @"C:\Test\TV2".AsOsAgnostic();
|
||||
series.ForEach(s => s.RootFolderPath = newRoot);
|
||||
|
||||
Subject.UpdateSeries(series);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests.SeriesServiceTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class UpdateSeriesFixture : CoreTest<SeriesService>
|
||||
{
|
||||
private Series _fakeSeries;
|
||||
private Series _existingSeries;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_fakeSeries = Builder<Series>.CreateNew().Build();
|
||||
_existingSeries = Builder<Series>.CreateNew().Build();
|
||||
|
||||
_fakeSeries.Seasons = new List<Season>
|
||||
{
|
||||
new Season{ SeasonNumber = 1, Monitored = true },
|
||||
new Season{ SeasonNumber = 2, Monitored = true }
|
||||
};
|
||||
|
||||
_existingSeries.Seasons = new List<Season>
|
||||
{
|
||||
new Season{ SeasonNumber = 1, Monitored = true },
|
||||
new Season{ SeasonNumber = 2, Monitored = true }
|
||||
};
|
||||
}
|
||||
|
||||
private void GivenExistingSeries()
|
||||
{
|
||||
Mocker.GetMock<ISeriesRepository>()
|
||||
.Setup(s => s.Get(It.IsAny<int>()))
|
||||
.Returns(_existingSeries);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_episodes_if_season_hasnt_changed()
|
||||
{
|
||||
GivenExistingSeries();
|
||||
|
||||
Subject.UpdateSeries(_fakeSeries);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.SetEpisodeMonitoredBySeason(_fakeSeries.Id, It.IsAny<int>(), It.IsAny<bool>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_series_when_it_changes()
|
||||
{
|
||||
GivenExistingSeries();
|
||||
var seasonNumber = 1;
|
||||
var monitored = false;
|
||||
|
||||
_fakeSeries.Seasons.Single(s => s.SeasonNumber == seasonNumber).Monitored = monitored;
|
||||
|
||||
Subject.UpdateSeries(_fakeSeries);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.SetEpisodeMonitoredBySeason(_fakeSeries.Id, seasonNumber, monitored), Times.Once());
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Verify(v => v.SetEpisodeMonitoredBySeason(_fakeSeries.Id, It.IsAny<int>(), It.IsAny<bool>()), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class SeriesTitleNormalizerFixture
|
||||
{
|
||||
[TestCase("A to Z", 281588, "a to z")]
|
||||
[TestCase("A. D. - The Trials & Triumph of the Early Church", 266757, "ad trials triumph early church")]
|
||||
public void should_use_precomputed_title(string title, int tvdbId, string expected)
|
||||
{
|
||||
SeriesTitleNormalizer.Normalize(title, tvdbId).Should().Be(expected);
|
||||
}
|
||||
|
||||
[TestCase("2 Broke Girls", "2 broke girls")]
|
||||
[TestCase("Archer (2009)", "archer 2009")]
|
||||
[TestCase("The Office (US)", "office us")]
|
||||
[TestCase("The Mentalist", "mentalist")]
|
||||
[TestCase("The Good Wife", "good wife")]
|
||||
[TestCase("The Newsroom (2012)", "newsroom 2012")]
|
||||
[TestCase("Special Agent Oso", "special agent oso")]
|
||||
public void should_normalize_title(string title, string expected)
|
||||
{
|
||||
SeriesTitleNormalizer.Normalize(title, 0).Should().Be(expected);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,6 @@ using NzbDrone.Core.Messaging.Commands;
|
|||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.DataAugmentation.Scene
|
||||
{
|
||||
|
@ -23,7 +22,7 @@ namespace NzbDrone.Core.DataAugmentation.Scene
|
|||
}
|
||||
|
||||
public class SceneMappingService : ISceneMappingService,
|
||||
IHandle<SeriesRefreshStartingEvent>,
|
||||
// IHandle<SeriesRefreshStartingEvent>,
|
||||
IExecute<UpdateSceneMappingCommand>
|
||||
{
|
||||
private readonly ISceneMappingRepository _repository;
|
||||
|
@ -237,13 +236,13 @@ namespace NzbDrone.Core.DataAugmentation.Scene
|
|||
return titles.Where(title => title.All(c => c <= 255)).ToList();
|
||||
}
|
||||
|
||||
public void Handle(SeriesRefreshStartingEvent message)
|
||||
{
|
||||
if (message.ManualTrigger && _findByTvdbIdCache.IsExpired(TimeSpan.FromMinutes(1)))
|
||||
{
|
||||
UpdateMappings();
|
||||
}
|
||||
}
|
||||
//public void Handle(SeriesRefreshStartingEvent message)
|
||||
//{
|
||||
// if (message.ManualTrigger && _findByTvdbIdCache.IsExpired(TimeSpan.FromMinutes(1)))
|
||||
// {
|
||||
// UpdateMappings();
|
||||
// }
|
||||
//}
|
||||
|
||||
public void Execute(UpdateSceneMappingCommand message)
|
||||
{
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
namespace NzbDrone.Core.DataAugmentation.Xem.Model
|
||||
{
|
||||
public class XemResult<T>
|
||||
{
|
||||
public string Result { get; set; }
|
||||
public T Data { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace NzbDrone.Core.DataAugmentation.Xem.Model
|
||||
{
|
||||
public class XemSceneTvdbMapping
|
||||
{
|
||||
public XemValues Scene { get; set; }
|
||||
public XemValues Tvdb { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace NzbDrone.Core.DataAugmentation.Xem.Model
|
||||
{
|
||||
public class XemValues
|
||||
{
|
||||
public int Season { get; set; }
|
||||
public int Episode { get; set; }
|
||||
public int Absolute { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using NzbDrone.Core.DataAugmentation.Xem.Model;
|
||||
|
||||
namespace NzbDrone.Core.DataAugmentation.Xem
|
||||
{
|
||||
public interface IXemProxy
|
||||
{
|
||||
List<int> GetXemSeriesIds();
|
||||
List<XemSceneTvdbMapping> GetSceneTvdbMappings(int id);
|
||||
List<SceneMapping> GetSceneTvdbNames();
|
||||
}
|
||||
|
||||
public class XemProxy : IXemProxy
|
||||
{
|
||||
private const string ROOT_URL = "http://thexem.de.broken/map/";
|
||||
|
||||
private readonly Logger _logger;
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IHttpRequestBuilderFactory _xemRequestBuilder;
|
||||
|
||||
private static readonly string[] IgnoredErrors = { "no single connection", "no show with the tvdb_id" };
|
||||
|
||||
public XemProxy(IHttpClient httpClient, Logger logger)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
|
||||
_xemRequestBuilder = new HttpRequestBuilder(ROOT_URL)
|
||||
.AddSuffixQueryParam("origin", "tvdb")
|
||||
.CreateFactory();
|
||||
}
|
||||
|
||||
public List<int> GetXemSeriesIds()
|
||||
{
|
||||
_logger.Debug("Fetching Series IDs from");
|
||||
|
||||
var request = _xemRequestBuilder.Create()
|
||||
.Resource("/havemap")
|
||||
.Build();
|
||||
|
||||
var response = _httpClient.Get<XemResult<List<string>>>(request).Resource;
|
||||
CheckForFailureResult(response);
|
||||
|
||||
return response.Data.Select(d =>
|
||||
{
|
||||
int tvdbId = 0;
|
||||
int.TryParse(d, out tvdbId);
|
||||
|
||||
return tvdbId;
|
||||
}).Where(t => t > 0).ToList();
|
||||
}
|
||||
|
||||
public List<XemSceneTvdbMapping> GetSceneTvdbMappings(int id)
|
||||
{
|
||||
_logger.Debug("Fetching Mappings for: {0}", id);
|
||||
|
||||
var request = _xemRequestBuilder.Create()
|
||||
.Resource("/all")
|
||||
.AddQueryParam("id", id)
|
||||
.Build();
|
||||
|
||||
var response = _httpClient.Get<XemResult<List<XemSceneTvdbMapping>>>(request).Resource;
|
||||
|
||||
return response.Data.Where(c => c.Scene != null).ToList();
|
||||
}
|
||||
|
||||
public List<SceneMapping> GetSceneTvdbNames()
|
||||
{
|
||||
_logger.Debug("Fetching alternate names");
|
||||
|
||||
var request = _xemRequestBuilder.Create()
|
||||
.Resource("/allNames")
|
||||
.AddQueryParam("seasonNumbers", true)
|
||||
.Build();
|
||||
|
||||
var response = _httpClient.Get<XemResult<Dictionary<int, List<JObject>>>>(request).Resource;
|
||||
|
||||
var result = new List<SceneMapping>();
|
||||
|
||||
foreach (var series in response.Data)
|
||||
{
|
||||
foreach (var name in series.Value)
|
||||
{
|
||||
foreach (var n in name)
|
||||
{
|
||||
int seasonNumber;
|
||||
if (!int.TryParse(n.Value.ToString(), out seasonNumber))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//hack to deal with Fate/Zero
|
||||
if (series.Key == 79151 && seasonNumber > 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Add(new SceneMapping
|
||||
{
|
||||
Title = n.Key,
|
||||
SearchTerm = n.Key,
|
||||
SceneSeasonNumber = seasonNumber,
|
||||
TvdbId = series.Key
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void CheckForFailureResult<T>(XemResult<T> response)
|
||||
{
|
||||
if (response.Result.Equals("failure", StringComparison.InvariantCultureIgnoreCase) &&
|
||||
!IgnoredErrors.Any(knowError => response.Message.Contains(knowError)))
|
||||
{
|
||||
throw new Exception("Error response received from Xem: " + response.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.DataAugmentation.Xem
|
||||
{
|
||||
public class XemService : ISceneMappingProvider, IHandle<SeriesUpdatedEvent>, IHandle<SeriesRefreshStartingEvent>
|
||||
{
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly IXemProxy _xemProxy;
|
||||
private readonly ISeriesService _seriesService;
|
||||
private readonly Logger _logger;
|
||||
private readonly ICachedDictionary<bool> _cache;
|
||||
|
||||
public XemService(IEpisodeService episodeService,
|
||||
IXemProxy xemProxy,
|
||||
ISeriesService seriesService, ICacheManager cacheManager, Logger logger)
|
||||
{
|
||||
_episodeService = episodeService;
|
||||
_xemProxy = xemProxy;
|
||||
_seriesService = seriesService;
|
||||
_logger = logger;
|
||||
_cache = cacheManager.GetCacheDictionary<bool>(GetType(), "mappedTvdbid");
|
||||
}
|
||||
|
||||
private void PerformUpdate(Series series)
|
||||
{
|
||||
_logger.Debug("Updating scene numbering mapping for: {0}", series);
|
||||
|
||||
//try
|
||||
//{
|
||||
// var mappings = _xemProxy.GetSceneTvdbMappings(series.TvdbId);
|
||||
|
||||
// if (!mappings.Any() && !series.UseSceneNumbering)
|
||||
// {
|
||||
// _logger.Debug("Mappings for: {0} are empty, skipping", series);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var episodes = _episodeService.GetEpisodeBySeries(series.Id);
|
||||
|
||||
// foreach (var episode in episodes)
|
||||
// {
|
||||
// episode.SceneAbsoluteEpisodeNumber = null;
|
||||
// episode.SceneSeasonNumber = null;
|
||||
// episode.SceneEpisodeNumber = null;
|
||||
// episode.UnverifiedSceneNumbering = false;
|
||||
// }
|
||||
|
||||
// foreach (var mapping in mappings)
|
||||
// {
|
||||
// _logger.Debug("Setting scene numbering mappings for {0} S{1:00}E{2:00}", series, mapping.Tvdb.Season, mapping.Tvdb.Episode);
|
||||
|
||||
// var episode = episodes.SingleOrDefault(e => e.SeasonNumber == mapping.Tvdb.Season && e.EpisodeNumber == mapping.Tvdb.Episode);
|
||||
|
||||
// if (episode == null)
|
||||
// {
|
||||
// _logger.Debug("Information hasn't been added to TheTVDB yet, skipping.");
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// episode.SceneAbsoluteEpisodeNumber = mapping.Scene.Absolute;
|
||||
// episode.SceneSeasonNumber = mapping.Scene.Season;
|
||||
// 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);
|
||||
|
||||
// _logger.Debug("XEM mapping updated for {0}", series);
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// _logger.Error(ex, "Error updating scene numbering mappings for {0}", 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 sceneEpisodeMappings = mappings.ToLookup(v => v.Scene.Season)
|
||||
.ToDictionary(v => v.Key, e => new HashSet<int>(e.Select(v => v.Scene.Episode)));
|
||||
|
||||
var firstTvdbEpisodeBySeason = mappings.ToLookup(v => v.Tvdb.Season)
|
||||
.ToDictionary(v => v.Key, e => e.Min(v => v.Tvdb.Episode));
|
||||
|
||||
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))
|
||||
{
|
||||
// Mark if a mapping exists for an earlier episode in this season.
|
||||
if (firstTvdbEpisodeBySeason[episode.SeasonNumber] <= episode.EpisodeNumber)
|
||||
{
|
||||
episode.UnverifiedSceneNumbering = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mark if a mapping exists with a scene number to this episode.
|
||||
if (sceneEpisodeMappings.ContainsKey(episode.SeasonNumber) &&
|
||||
sceneEpisodeMappings[episode.SeasonNumber].Contains(episode.EpisodeNumber))
|
||||
{
|
||||
episode.UnverifiedSceneNumbering = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else 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 UpdateXemSeriesIds()
|
||||
{
|
||||
try
|
||||
{
|
||||
var ids = _xemProxy.GetXemSeriesIds();
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
_cache.Update(ids.ToDictionary(v => v.ToString(), v => true));
|
||||
return;
|
||||
}
|
||||
|
||||
_cache.ExtendTTL();
|
||||
_logger.Warn("Failed to update Xem series list.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_cache.ExtendTTL();
|
||||
_logger.Warn(ex, "Failed to update Xem series list.");
|
||||
}
|
||||
}
|
||||
|
||||
public List<SceneMapping> GetSceneMappings()
|
||||
{
|
||||
var mappings = _xemProxy.GetSceneTvdbNames();
|
||||
|
||||
return mappings.Where(m =>
|
||||
{
|
||||
int id;
|
||||
|
||||
if (int.TryParse(m.Title, out id))
|
||||
{
|
||||
_logger.Debug("Skipping all numeric name: {0} for {1}", m.Title, m.TvdbId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public void Handle(SeriesUpdatedEvent message)
|
||||
{
|
||||
//if (_cache.IsExpired(TimeSpan.FromHours(3)))
|
||||
//{
|
||||
// UpdateXemSeriesIds();
|
||||
//}
|
||||
|
||||
//if (_cache.Count == 0)
|
||||
//{
|
||||
// _logger.Debug("Scene numbering is not available");
|
||||
// return;
|
||||
//}
|
||||
|
||||
//if (!_cache.Find(message.Series.TvdbId.ToString()) && !message.Series.UseSceneNumbering)
|
||||
//{
|
||||
// _logger.Debug("Scene numbering is not available for {0} [{1}]", message.Series.Title, message.Series.TvdbId);
|
||||
// return;
|
||||
//}
|
||||
|
||||
//PerformUpdate(message.Series);
|
||||
}
|
||||
|
||||
public void Handle(SeriesRefreshStartingEvent message)
|
||||
{
|
||||
//if (message.ManualTrigger && _cache.IsExpired(TimeSpan.FromMinutes(1)))
|
||||
//{
|
||||
// UpdateXemSeriesIds();
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -114,7 +114,7 @@ namespace NzbDrone.Core.Datastore
|
|||
Mapper.Entity<OtherExtraFile>().RegisterModel("ExtraFiles");
|
||||
|
||||
Mapper.Entity<PendingRelease>().RegisterModel("PendingReleases")
|
||||
.Ignore(e => e.RemoteEpisode);
|
||||
.Ignore(e => e.RemoteAlbum);
|
||||
|
||||
Mapper.Entity<RemotePathMapping>().RegisterModel("RemotePathMappings");
|
||||
Mapper.Entity<Tag>().RegisterModel("Tags");
|
||||
|
@ -146,7 +146,8 @@ namespace NzbDrone.Core.Datastore
|
|||
MapRepository.Instance.RegisterTypeConverter(typeof(Language), new LanguageIntConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<string>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(List<ProfileLanguageItem>), new EmbeddedDocumentConverter(new LanguageIntConverter()));
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(ParsedEpisodeInfo), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(ParsedAlbumInfo), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(ParsedTrackInfo), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(ReleaseInfo), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(HashSet<int>), new EmbeddedDocumentConverter());
|
||||
MapRepository.Instance.RegisterTypeConverter(typeof(OsPath), new OsPathConverter());
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine
|
||||
{
|
||||
public class SameEpisodesSpecification
|
||||
{
|
||||
private readonly IEpisodeService _episodeService;
|
||||
|
||||
public SameEpisodesSpecification(IEpisodeService episodeService)
|
||||
{
|
||||
_episodeService = episodeService;
|
||||
}
|
||||
|
||||
public bool IsSatisfiedBy(List<Episode> episodes)
|
||||
{
|
||||
var episodeIds = episodes.SelectList(e => e.Id);
|
||||
var episodeFileIds = episodes.Where(c => c.EpisodeFileId != 0).Select(c => c.EpisodeFileId).Distinct();
|
||||
|
||||
foreach (var episodeFileId in episodeFileIds)
|
||||
{
|
||||
var episodesInFile = _episodeService.GetEpisodesByFileId(episodeFileId);
|
||||
|
||||
if (episodesInFile.Select(e => e.Id).Except(episodeIds).Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
using NzbDrone.Common.Messaging;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
public class EpisodeGrabbedEvent : IEvent
|
||||
{
|
||||
public RemoteEpisode Episode { get; private set; }
|
||||
public string DownloadClient { get; set; }
|
||||
public string DownloadId { get; set; }
|
||||
|
||||
public EpisodeGrabbedEvent(RemoteEpisode episode)
|
||||
{
|
||||
Episode = episode;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
|
@ -13,7 +13,6 @@ namespace NzbDrone.Core.Download.Pending
|
|||
public ReleaseInfo Release { get; set; }
|
||||
|
||||
//Not persisted
|
||||
public RemoteEpisode RemoteEpisode { get; set; }
|
||||
public RemoteAlbum RemoteAlbum { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,10 +94,9 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
|||
return metadata;
|
||||
}
|
||||
|
||||
var parseResult = Parser.Parser.ParseTitle(filename);
|
||||
var parseResult = Parser.Parser.ParseMusicTitle(filename);
|
||||
|
||||
if (parseResult != null &&
|
||||
!parseResult.FullSeason)
|
||||
if (parseResult != null)
|
||||
{
|
||||
var extension = Path.GetExtension(filename).ToLowerInvariant();
|
||||
|
||||
|
|
|
@ -93,10 +93,9 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
|||
return metadata;
|
||||
}
|
||||
|
||||
var parseResult = Parser.Parser.ParseTitle(filename);
|
||||
var parseResult = Parser.Parser.ParseMusicTitle(filename);
|
||||
|
||||
if (parseResult != null &&
|
||||
!parseResult.FullSeason)
|
||||
if (parseResult != null)
|
||||
{
|
||||
switch (Path.GetExtension(filename).ToLowerInvariant())
|
||||
{
|
||||
|
|
|
@ -115,10 +115,9 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
|||
return metadata;
|
||||
}
|
||||
|
||||
var parseResult = Parser.Parser.ParseTitle(filename);
|
||||
var parseResult = Parser.Parser.ParseMusicTitle(filename);
|
||||
|
||||
if (parseResult != null &&
|
||||
!parseResult.FullSeason &&
|
||||
Path.GetExtension(filename) == ".nfo")
|
||||
{
|
||||
metadata.Type = MetadataType.TrackMetadata;
|
||||
|
|
|
@ -27,7 +27,6 @@ namespace NzbDrone.Core.MediaFiles
|
|||
private readonly IParsingService _parsingService;
|
||||
private readonly IMakeImportDecision _importDecisionMaker;
|
||||
private readonly IImportApprovedTracks _importApprovedTracks;
|
||||
private readonly IDetectSample _detectSample;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public DownloadedTracksImportService(IDiskProvider diskProvider,
|
||||
|
@ -36,7 +35,6 @@ namespace NzbDrone.Core.MediaFiles
|
|||
IParsingService parsingService,
|
||||
IMakeImportDecision importDecisionMaker,
|
||||
IImportApprovedTracks importApprovedTracks,
|
||||
IDetectSample detectSample,
|
||||
Logger logger)
|
||||
{
|
||||
_diskProvider = diskProvider;
|
||||
|
@ -45,7 +43,6 @@ namespace NzbDrone.Core.MediaFiles
|
|||
_parsingService = parsingService;
|
||||
_importDecisionMaker = importDecisionMaker;
|
||||
_importApprovedTracks = importApprovedTracks;
|
||||
_detectSample = detectSample;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Marr.Data;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public class EpisodeFile : ModelBase
|
||||
{
|
||||
public int SeriesId { get; set; }
|
||||
public int SeasonNumber { get; set; }
|
||||
public string RelativePath { get; set; }
|
||||
public string Path { get; set; }
|
||||
public long Size { get; set; }
|
||||
public DateTime DateAdded { get; set; }
|
||||
public string SceneName { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public MediaInfoModel MediaInfo { get; set; }
|
||||
public LazyLoaded<List<Episode>> Episodes { get; set; }
|
||||
public LazyLoaded<Series> Series { get; set; }
|
||||
public Language Language { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[{0}] {1}", Id, RelativePath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport
|
||||
{
|
||||
public interface IDetectSample
|
||||
{
|
||||
bool IsSample(Series series, QualityModel quality, string path, long size, bool isSpecial);
|
||||
}
|
||||
|
||||
public class DetectSample : IDetectSample
|
||||
{
|
||||
private readonly IVideoFileInfoReader _videoFileInfoReader;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private static List<Quality> _largeSampleSizeQualities = new List<Quality> { Quality.FLAC };
|
||||
|
||||
public DetectSample(IVideoFileInfoReader videoFileInfoReader, Logger logger)
|
||||
{
|
||||
_videoFileInfoReader = videoFileInfoReader;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public static long SampleSizeLimit => 70.Megabytes();
|
||||
|
||||
public bool IsSample(Series series, QualityModel quality, string path, long size, bool isSpecial)
|
||||
{
|
||||
if (isSpecial)
|
||||
{
|
||||
_logger.Debug("Special, skipping sample check");
|
||||
return false;
|
||||
}
|
||||
|
||||
var extension = Path.GetExtension(path);
|
||||
|
||||
if (extension != null && extension.Equals(".flv", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.Debug("Skipping sample check for .flv file");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extension != null && extension.Equals(".strm", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
_logger.Debug("Skipping sample check for .strm file");
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var runTime = _videoFileInfoReader.GetRunTime(path);
|
||||
var minimumRuntime = GetMinimumAllowedRuntime(series);
|
||||
|
||||
if (runTime.TotalMinutes.Equals(0))
|
||||
{
|
||||
_logger.Error("[{0}] has a runtime of 0, is it a valid video file?", path);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (runTime.TotalSeconds < minimumRuntime)
|
||||
{
|
||||
_logger.Debug("[{0}] appears to be a sample. Runtime: {1} seconds. Expected at least: {2} seconds", path, runTime, minimumRuntime);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
_logger.Debug("Falling back to file size detection");
|
||||
|
||||
return CheckSize(size, quality);
|
||||
}
|
||||
|
||||
_logger.Debug("Runtime is over 90 seconds");
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CheckSize(long size, QualityModel quality)
|
||||
{
|
||||
{
|
||||
if (size < SampleSizeLimit * 2)
|
||||
{
|
||||
_logger.Debug("1080p file is less than sample limit");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (size < SampleSizeLimit)
|
||||
{
|
||||
_logger.Debug("File is less than sample limit");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int GetMinimumAllowedRuntime(Series series)
|
||||
{
|
||||
//Webisodes - 90 seconds
|
||||
if (series.Runtime <= 10)
|
||||
{
|
||||
return 90;
|
||||
}
|
||||
|
||||
//30 minute episodes - 5 minutes
|
||||
if (series.Runtime <= 30)
|
||||
{
|
||||
return 300;
|
||||
}
|
||||
|
||||
//60 minute episodes - 10 minutes
|
||||
return 600;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Extras;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport
|
||||
{
|
||||
[Obsolete("Used by Sonarr, not by Lidarr")]
|
||||
public interface IImportApprovedEpisodes
|
||||
{
|
||||
List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto);
|
||||
}
|
||||
|
||||
public class ImportApprovedEpisodes : IImportApprovedEpisodes
|
||||
{
|
||||
private readonly IUpgradeMediaFiles _episodeFileUpgrader;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IExtraService _extraService;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ImportApprovedEpisodes(IUpgradeMediaFiles episodeFileUpgrader,
|
||||
IMediaFileService mediaFileService,
|
||||
IExtraService extraService,
|
||||
IDiskProvider diskProvider,
|
||||
IEventAggregator eventAggregator,
|
||||
Logger logger)
|
||||
{
|
||||
_episodeFileUpgrader = episodeFileUpgrader;
|
||||
_mediaFileService = mediaFileService;
|
||||
_extraService = extraService;
|
||||
_diskProvider = diskProvider;
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto)
|
||||
{
|
||||
throw new NotImplementedException("This will be removed");
|
||||
}
|
||||
|
||||
private string GetSceneName(DownloadClientItem downloadClientItem, LocalEpisode localEpisode)
|
||||
{
|
||||
if (downloadClientItem != null)
|
||||
{
|
||||
var title = Parser.Parser.RemoveFileExtension(downloadClientItem.Title);
|
||||
|
||||
var parsedTitle = Parser.Parser.ParseTitle(title);
|
||||
|
||||
if (parsedTitle != null && !parsedTitle.FullSeason)
|
||||
{
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
||||
var fileName = Path.GetFileNameWithoutExtension(localEpisode.Path.CleanFilePath());
|
||||
|
||||
if (SceneChecker.IsSceneTitle(fileName))
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IVideoFileInfoReader _videoFileInfoReader;
|
||||
private readonly IDetectSample _detectSample;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ImportDecisionMaker(IEnumerable<IImportDecisionEngineSpecification> specifications,
|
||||
|
@ -36,7 +35,6 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
IMediaFileService mediaFileService,
|
||||
IDiskProvider diskProvider,
|
||||
IVideoFileInfoReader videoFileInfoReader,
|
||||
IDetectSample detectSample,
|
||||
Logger logger)
|
||||
{
|
||||
_specifications = specifications;
|
||||
|
@ -44,7 +42,6 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
_mediaFileService = mediaFileService;
|
||||
_diskProvider = diskProvider;
|
||||
_videoFileInfoReader = videoFileInfoReader;
|
||||
_detectSample = detectSample;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.MetadataSource
|
||||
{
|
||||
public class SearchSeriesComparer : IComparer<Series>
|
||||
public class SearchArtistComparer : IComparer<Artist>
|
||||
{
|
||||
private static readonly Regex RegexCleanPunctuation = new Regex("[-._:]", RegexOptions.Compiled);
|
||||
private static readonly Regex RegexCleanCountryYearPostfix = new Regex(@"(?<=.+)( \([A-Z]{2}\)| \(\d{4}\)| \([A-Z]{2}\) \(\d{4}\))$", RegexOptions.Compiled);
|
||||
|
@ -17,7 +17,7 @@ namespace NzbDrone.Core.MetadataSource
|
|||
private readonly string _searchQueryWithoutYear;
|
||||
private int? _year;
|
||||
|
||||
public SearchSeriesComparer(string searchQuery)
|
||||
public SearchArtistComparer(string searchQuery)
|
||||
{
|
||||
SearchQuery = searchQuery;
|
||||
|
||||
|
@ -33,34 +33,26 @@ namespace NzbDrone.Core.MetadataSource
|
|||
}
|
||||
}
|
||||
|
||||
public int Compare(Series x, Series y)
|
||||
public int Compare(Artist x, Artist y)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
// Prefer exact matches
|
||||
result = Compare(x, y, s => CleanPunctuation(s.Title).Equals(CleanPunctuation(SearchQuery)));
|
||||
result = Compare(x, y, s => CleanPunctuation(s.Name).Equals(CleanPunctuation(SearchQuery)));
|
||||
if (result != 0) return -result;
|
||||
|
||||
// Remove Articles (a/an/the)
|
||||
result = Compare(x, y, s => CleanArticles(s.Title).Equals(CleanArticles(SearchQuery)));
|
||||
result = Compare(x, y, s => CleanArticles(s.Name).Equals(CleanArticles(SearchQuery)));
|
||||
if (result != 0) return -result;
|
||||
|
||||
// Prefer close matches
|
||||
result = Compare(x, y, s => CleanPunctuation(s.Title).LevenshteinDistance(CleanPunctuation(SearchQuery)) <= 1);
|
||||
result = Compare(x, y, s => CleanPunctuation(s.Name).LevenshteinDistance(CleanPunctuation(SearchQuery)) <= 1);
|
||||
if (result != 0) return -result;
|
||||
|
||||
// Compare clean matches by year "Battlestar Galactica 1978"
|
||||
result = CompareWithYear(x, y, s => CleanTitle(s.Title).LevenshteinDistance(_searchQueryWithoutYear) <= 1);
|
||||
if (result != 0) return -result;
|
||||
|
||||
// Compare prefix matches by year "(CSI: ..."
|
||||
result = CompareWithYear(x, y, s => s.Title.ToLowerInvariant().StartsWith(_searchQueryWithoutYear + ":"));
|
||||
if (result != 0) return -result;
|
||||
|
||||
return Compare(x, y, s => SearchQuery.LevenshteinDistanceClean(s.Title) - GetYearFactor(s));
|
||||
return Compare(x, y, s => SearchQuery.LevenshteinDistanceClean(s.Name));
|
||||
}
|
||||
|
||||
public int Compare<T>(Series x, Series y, Func<Series,T> keySelector)
|
||||
public int Compare<T>(Artist x, Artist y, Func<Artist, T> keySelector)
|
||||
where T : IComparable<T>
|
||||
{
|
||||
var keyX = keySelector(x);
|
||||
|
@ -69,25 +61,6 @@ namespace NzbDrone.Core.MetadataSource
|
|||
return keyX.CompareTo(keyY);
|
||||
}
|
||||
|
||||
public int CompareWithYear(Series x, Series y, Predicate<Series> canMatch)
|
||||
{
|
||||
var matchX = canMatch(x);
|
||||
var matchY = canMatch(y);
|
||||
|
||||
if (matchX && matchY)
|
||||
{
|
||||
if (_year.HasValue)
|
||||
{
|
||||
var result = Compare(x, y, s => s.Year == _year.Value);
|
||||
if (result != 0) return result;
|
||||
}
|
||||
|
||||
return Compare(x, y, s => s.Year);
|
||||
}
|
||||
|
||||
return matchX.CompareTo(matchY);
|
||||
}
|
||||
|
||||
private string CleanPunctuation(string title)
|
||||
{
|
||||
title = RegexCleanPunctuation.Replace(title, "");
|
||||
|
@ -110,18 +83,5 @@ namespace NzbDrone.Core.MetadataSource
|
|||
return title.Trim().ToLowerInvariant();
|
||||
}
|
||||
|
||||
private int GetYearFactor(Series series)
|
||||
{
|
||||
if (_year.HasValue)
|
||||
{
|
||||
var offset = Math.Abs(series.Year - _year.Value);
|
||||
if (offset <= 1)
|
||||
{
|
||||
return 20 - 10 * offset;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -151,11 +151,6 @@
|
|||
<Compile Include="DataAugmentation\Scene\SceneMappingsUpdatedEvent.cs" />
|
||||
<Compile Include="DataAugmentation\Scene\ServicesProvider.cs" />
|
||||
<Compile Include="DataAugmentation\Scene\UpdateSceneMappingCommand.cs" />
|
||||
<Compile Include="DataAugmentation\Xem\Model\XemResult.cs" />
|
||||
<Compile Include="DataAugmentation\Xem\Model\XemSceneTvdbMapping.cs" />
|
||||
<Compile Include="DataAugmentation\Xem\Model\XemValues.cs" />
|
||||
<Compile Include="DataAugmentation\Xem\XemProxy.cs" />
|
||||
<Compile Include="DataAugmentation\Xem\XemService.cs" />
|
||||
<Compile Include="Datastore\BasicRepository.cs" />
|
||||
<Compile Include="Datastore\ConnectionStringFactory.cs" />
|
||||
<Compile Include="Datastore\Converters\BooleanIntConverter.cs" />
|
||||
|
@ -331,7 +326,6 @@
|
|||
<Compile Include="DecisionEngine\IRejectWithReason.cs" />
|
||||
<Compile Include="DecisionEngine\Rejection.cs" />
|
||||
<Compile Include="DecisionEngine\RejectionType.cs" />
|
||||
<Compile Include="DecisionEngine\SameEpisodesSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\SameTracksSpecification.cs" />
|
||||
<Compile Include="DecisionEngine\SpecificationPriority.cs" />
|
||||
<Compile Include="DecisionEngine\Specifications\AcceptableSizeSpecification.cs" />
|
||||
|
@ -529,7 +523,6 @@
|
|||
<Compile Include="Download\DownloadFailedEvent.cs" />
|
||||
<Compile Include="Download\DownloadItemStatus.cs" />
|
||||
<Compile Include="Download\DownloadService.cs" />
|
||||
<Compile Include="Download\EpisodeGrabbedEvent.cs" />
|
||||
<Compile Include="Download\FailedDownloadService.cs" />
|
||||
<Compile Include="Download\IDownloadClient.cs" />
|
||||
<Compile Include="Download\Pending\PendingRelease.cs" />
|
||||
|
@ -760,16 +753,13 @@
|
|||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MediaFiles\DownloadedAlbumsCommandService.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeFile.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\IImportDecisionEngineSpecification.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\ImportApprovedEpisodes.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\ImportDecisionMaker.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\ImportResultType.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\Manual\ManualImportFile.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\Manual\ManualImportCommand.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\Manual\ManualImportItem.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\Manual\ManualImportService.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\DetectSample.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\Manual\ManuallyImportedFile.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\Specifications\FreeSpaceSpecification.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\Specifications\NotUnpackingSpecification.cs" />
|
||||
|
@ -836,7 +826,7 @@
|
|||
<Compile Include="MetadataSource\SkyHook\Resource\TimeOfDayResource.cs" />
|
||||
<Compile Include="MetadataSource\SkyHook\Resource\TrackResource.cs" />
|
||||
<Compile Include="MetadataSource\SkyHook\SkyHookProxy.cs" />
|
||||
<Compile Include="MetadataSource\SearchSeriesComparer.cs" />
|
||||
<Compile Include="MetadataSource\SearchArtistComparer.cs" />
|
||||
<Compile Include="MetadataSource\SkyHook\SkyHookException.cs" />
|
||||
<Compile Include="Extras\Metadata\Consumers\MediaBrowser\MediaBrowserMetadata.cs" />
|
||||
<Compile Include="Extras\Metadata\Consumers\MediaBrowser\MediaBrowserMetadataSettings.cs" />
|
||||
|
@ -1079,11 +1069,7 @@
|
|||
<Compile Include="Organizer\NamingConfigService.cs" />
|
||||
<Compile Include="Organizer\SampleResult.cs" />
|
||||
<Compile Include="Parser\InvalidDateException.cs" />
|
||||
<Compile Include="Parser\Model\LocalEpisode.cs" />
|
||||
<Compile Include="Parser\Model\ParsedEpisodeInfo.cs" />
|
||||
<Compile Include="Parser\Model\ReleaseInfo.cs" />
|
||||
<Compile Include="Parser\Model\RemoteEpisode.cs" />
|
||||
<Compile Include="Parser\Model\SeriesTitleInfo.cs" />
|
||||
<Compile Include="Parser\Model\TorrentInfo.cs" />
|
||||
<Compile Include="Parser\Parser.cs" />
|
||||
<Compile Include="Parser\ParsingService.cs" />
|
||||
|
@ -1145,42 +1131,6 @@
|
|||
<Compile Include="ThingiProvider\ProviderMessage.cs" />
|
||||
<Compile Include="ThingiProvider\ProviderRepository.cs" />
|
||||
<Compile Include="TinyTwitter.cs" />
|
||||
<Compile Include="Tv\Actor.cs" />
|
||||
<Compile Include="Tv\AddSeriesOptions.cs" />
|
||||
<Compile Include="Tv\AddSeriesService.cs" />
|
||||
<Compile Include="Tv\AddSeriesValidator.cs" />
|
||||
<Compile Include="Tv\Commands\RefreshSeriesCommand.cs" />
|
||||
<Compile Include="Tv\Episode.cs" />
|
||||
<Compile Include="Tv\EpisodeAddedService.cs" />
|
||||
<Compile Include="Tv\EpisodeCutoffService.cs" />
|
||||
<Compile Include="Tv\EpisodeMonitoredService.cs" />
|
||||
<Compile Include="Tv\EpisodeRepository.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Tv\EpisodeService.cs" />
|
||||
<Compile Include="Tv\Events\EpisodeInfoRefreshedEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesAddedEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesDeletedEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesEditedEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesImportedEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesRefreshStartingEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesUpdatedEvent.cs" />
|
||||
<Compile Include="Tv\MonitoringOptions.cs" />
|
||||
<Compile Include="Tv\Ratings.cs" />
|
||||
<Compile Include="Tv\RefreshEpisodeService.cs" />
|
||||
<Compile Include="Tv\RefreshSeriesService.cs" />
|
||||
<Compile Include="Tv\Season.cs" />
|
||||
<Compile Include="Tv\Series.cs" />
|
||||
<Compile Include="Tv\SeriesAddedHandler.cs" />
|
||||
<Compile Include="Tv\SeriesEditedService.cs" />
|
||||
<Compile Include="Tv\SeriesRepository.cs" />
|
||||
<Compile Include="Tv\SeriesService.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Tv\SeriesStatusType.cs" />
|
||||
<Compile Include="Tv\SeriesTitleNormalizer.cs" />
|
||||
<Compile Include="Tv\SeriesTitleSlugValidator.cs" />
|
||||
<Compile Include="Tv\SeriesTypes.cs" />
|
||||
<Compile Include="Update\Commands\ApplicationUpdateCommand.cs" />
|
||||
<Compile Include="Update\InstallUpdateService.cs" />
|
||||
<Compile Include="Update\RecentUpdateProvider.cs" />
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
namespace NzbDrone.Core.Parser.Model
|
||||
{
|
||||
public class LocalEpisode
|
||||
{
|
||||
public LocalEpisode()
|
||||
{
|
||||
Episodes = new List<Episode>();
|
||||
}
|
||||
|
||||
public string Path { get; set; }
|
||||
public long Size { get; set; }
|
||||
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; }
|
||||
public Series Series { get; set; }
|
||||
public List<Episode> Episodes { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public Language Language { get; set; }
|
||||
public MediaInfoModel MediaInfo { get; set; }
|
||||
public bool ExistingFile { get; set; }
|
||||
|
||||
public int SeasonNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
return Episodes.Select(c => c.SeasonNumber).Distinct().Single();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSpecial => SeasonNumber == 0;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Path;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
namespace NzbDrone.Core.Parser.Model
|
||||
{
|
||||
// TODO: This model needs to module music, not TV series
|
||||
public class ParsedEpisodeInfo
|
||||
{
|
||||
public string SeriesTitle { get; set; }
|
||||
public SeriesTitleInfo SeriesTitleInfo { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public int SeasonNumber { get; set; }
|
||||
public int[] EpisodeNumbers { get; set; }
|
||||
public int[] AbsoluteEpisodeNumbers { get; set; }
|
||||
public string AirDate { get; set; }
|
||||
public Language Language { get; set; }
|
||||
public bool FullSeason { get; set; }
|
||||
public bool Special { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
public string ReleaseHash { get; set; }
|
||||
|
||||
public ParsedEpisodeInfo()
|
||||
{
|
||||
EpisodeNumbers = new int[0];
|
||||
AbsoluteEpisodeNumbers = new int[0];
|
||||
}
|
||||
|
||||
public bool IsDaily
|
||||
{
|
||||
get
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(AirDate);
|
||||
}
|
||||
|
||||
//This prevents manually downloading a release from blowing up in mono
|
||||
//TODO: Is there a better way?
|
||||
private set { }
|
||||
}
|
||||
|
||||
public bool IsAbsoluteNumbering
|
||||
{
|
||||
get
|
||||
{
|
||||
return AbsoluteEpisodeNumbers.Any();
|
||||
}
|
||||
|
||||
//This prevents manually downloading a release from blowing up in mono
|
||||
//TODO: Is there a better way?
|
||||
private set { }
|
||||
}
|
||||
|
||||
public bool IsPossibleSpecialEpisode
|
||||
{
|
||||
get
|
||||
{
|
||||
// if we don't have eny episode numbers we are likely a special episode and need to do a search by episode title
|
||||
return (AirDate.IsNullOrWhiteSpace() &&
|
||||
SeriesTitle.IsNullOrWhiteSpace() &&
|
||||
(EpisodeNumbers.Length == 0 || SeasonNumber == 0) ||
|
||||
!SeriesTitle.IsNullOrWhiteSpace() && Special);
|
||||
}
|
||||
|
||||
//This prevents manually downloading a release from blowing up in mono
|
||||
//TODO: Is there a better way?
|
||||
private set {}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string episodeString = "[Unknown Episode]";
|
||||
|
||||
if (IsDaily && EpisodeNumbers.Empty())
|
||||
{
|
||||
episodeString = string.Format("{0}", AirDate);
|
||||
}
|
||||
else if (FullSeason)
|
||||
{
|
||||
episodeString = string.Format("Season {0:00}", SeasonNumber);
|
||||
}
|
||||
else if (EpisodeNumbers != null && EpisodeNumbers.Any())
|
||||
{
|
||||
episodeString = string.Format("S{0:00}E{1}", SeasonNumber, string.Join("-", EpisodeNumbers.Select(c => c.ToString("00"))));
|
||||
}
|
||||
else if (AbsoluteEpisodeNumbers != null && AbsoluteEpisodeNumbers.Any())
|
||||
{
|
||||
episodeString = string.Format("{0}", string.Join("-", AbsoluteEpisodeNumbers.Select(c => c.ToString("000"))));
|
||||
}
|
||||
|
||||
return string.Format("{0} - {1} {2}", SeriesTitle, episodeString, Quality);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Parser.Model
|
||||
{
|
||||
public class RemoteEpisode
|
||||
{
|
||||
public ReleaseInfo Release { get; set; }
|
||||
public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; }
|
||||
public Series Series { get; set; }
|
||||
public List<Episode> Episodes { get; set; }
|
||||
public bool DownloadAllowed { get; set; }
|
||||
|
||||
public bool IsRecentEpisode()
|
||||
{
|
||||
return Episodes.Any(e => e.AirDateUtc >= DateTime.UtcNow.Date.AddDays(-14));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Release.Title;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace NzbDrone.Core.Parser.Model
|
||||
{
|
||||
public class SeriesTitleInfo
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string TitleWithoutYear { get; set; }
|
||||
public int Year { get; set; }
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ using NzbDrone.Common.Extensions;
|
|||
using NzbDrone.Common.Instrumentation;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Languages;
|
||||
|
||||
namespace NzbDrone.Core.Parser
|
||||
|
@ -418,27 +417,6 @@ namespace NzbDrone.Core.Parser
|
|||
return result;
|
||||
}
|
||||
|
||||
public static ParsedEpisodeInfo ParsePath(string path)
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
|
||||
var result = ParseTitle(fileInfo.Name);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
Logger.Debug("Attempting to parse episode info using directory and file names. {0}", fileInfo.Directory.Name);
|
||||
result = ParseTitle(fileInfo.Directory.Name + " " + fileInfo.Name);
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
Logger.Debug("Attempting to parse episode info using directory name. {0}", fileInfo.Directory.Name);
|
||||
result = ParseTitle(fileInfo.Directory.Name + fileInfo.Extension);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ParsedTrackInfo ParseMusicTitle(string title)
|
||||
{
|
||||
try
|
||||
|
@ -654,130 +632,6 @@ namespace NzbDrone.Core.Parser
|
|||
return null;
|
||||
}
|
||||
|
||||
public static ParsedEpisodeInfo ParseTitle(string title)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!ValidateBeforeParsing(title)) return null;
|
||||
|
||||
Logger.Debug("Parsing string '{0}'", title);
|
||||
|
||||
if (ReversedTitleRegex.IsMatch(title))
|
||||
{
|
||||
var titleWithoutExtension = RemoveFileExtension(title).ToCharArray();
|
||||
Array.Reverse(titleWithoutExtension);
|
||||
|
||||
title = new string(titleWithoutExtension) + title.Substring(titleWithoutExtension.Length);
|
||||
|
||||
Logger.Debug("Reversed name detected. Converted to '{0}'", title);
|
||||
}
|
||||
|
||||
var simpleTitle = SimpleTitleRegex.Replace(title, string.Empty);
|
||||
|
||||
simpleTitle = RemoveFileExtension(simpleTitle);
|
||||
|
||||
// TODO: Quick fix stripping [url] - prefixes.
|
||||
simpleTitle = WebsitePrefixRegex.Replace(simpleTitle, string.Empty);
|
||||
|
||||
simpleTitle = CleanTorrentSuffixRegex.Replace(simpleTitle, string.Empty);
|
||||
|
||||
var airDateMatch = AirDateRegex.Match(simpleTitle);
|
||||
if (airDateMatch.Success)
|
||||
{
|
||||
simpleTitle = airDateMatch.Groups[1].Value + airDateMatch.Groups["airyear"].Value + "." + airDateMatch.Groups["airmonth"].Value + "." + airDateMatch.Groups["airday"].Value;
|
||||
}
|
||||
|
||||
var sixDigitAirDateMatch = SixDigitAirDateRegex.Match(simpleTitle);
|
||||
if (sixDigitAirDateMatch.Success)
|
||||
{
|
||||
var airYear = sixDigitAirDateMatch.Groups["airyear"].Value;
|
||||
var airMonth = sixDigitAirDateMatch.Groups["airmonth"].Value;
|
||||
var airDay = sixDigitAirDateMatch.Groups["airday"].Value;
|
||||
|
||||
if (airMonth != "00" || airDay != "00")
|
||||
{
|
||||
var fixedDate = string.Format("20{0}.{1}.{2}", airYear, airMonth, airDay);
|
||||
|
||||
simpleTitle = simpleTitle.Replace(sixDigitAirDateMatch.Groups["airdate"].Value, fixedDate);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var regex in ReportTitleRegex)
|
||||
{
|
||||
var match = regex.Matches(simpleTitle);
|
||||
|
||||
if (match.Count != 0)
|
||||
{
|
||||
Logger.Trace(regex);
|
||||
try
|
||||
{
|
||||
var result = ParseMatchCollection(match);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
if (result.FullSeason && title.ContainsIgnoreCase("Special"))
|
||||
{
|
||||
result.FullSeason = false;
|
||||
result.Special = true;
|
||||
}
|
||||
|
||||
result.Language = LanguageParser.ParseLanguage(title);
|
||||
Logger.Debug("Language parsed: {0}", result.Language);
|
||||
|
||||
result.Quality = QualityParser.ParseQuality(title);
|
||||
Logger.Debug("Quality parsed: {0}", result.Quality);
|
||||
|
||||
result.ReleaseGroup = ParseReleaseGroup(title);
|
||||
|
||||
var subGroup = GetSubGroup(match);
|
||||
if (!subGroup.IsNullOrWhiteSpace())
|
||||
{
|
||||
result.ReleaseGroup = subGroup;
|
||||
}
|
||||
|
||||
Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup);
|
||||
|
||||
result.ReleaseHash = GetReleaseHash(match);
|
||||
if (!result.ReleaseHash.IsNullOrWhiteSpace())
|
||||
{
|
||||
Logger.Debug("Release Hash parsed: {0}", result.ReleaseHash);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (InvalidDateException ex)
|
||||
{
|
||||
Logger.Debug(ex, ex.Message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!title.ToLower().Contains("password") && !title.ToLower().Contains("yenc"))
|
||||
Logger.Error(e, "An error has occurred while trying to parse {0}", title);
|
||||
}
|
||||
|
||||
Logger.Debug("Unable to parse {0}", title);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string ParseSeriesName(string title)
|
||||
{
|
||||
Logger.Debug("Parsing string '{0}'", title);
|
||||
|
||||
var parseResult = ParseTitle(title);
|
||||
|
||||
if (parseResult == null)
|
||||
{
|
||||
return CleanSeriesTitle(title);
|
||||
}
|
||||
|
||||
return parseResult.SeriesTitle;
|
||||
}
|
||||
|
||||
public static string CleanSeriesTitle(this string title)
|
||||
{
|
||||
long number = 0;
|
||||
|
@ -961,27 +815,6 @@ namespace NzbDrone.Core.Parser
|
|||
return Language.English;
|
||||
}
|
||||
|
||||
private static SeriesTitleInfo GetSeriesTitleInfo(string title)
|
||||
{
|
||||
var seriesTitleInfo = new SeriesTitleInfo();
|
||||
seriesTitleInfo.Title = title;
|
||||
|
||||
var match = YearInTitleRegex.Match(title);
|
||||
|
||||
if (!match.Success)
|
||||
{
|
||||
seriesTitleInfo.TitleWithoutYear = title;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
seriesTitleInfo.TitleWithoutYear = match.Groups["title"].Value;
|
||||
seriesTitleInfo.Year = Convert.ToInt32(match.Groups["year"].Value);
|
||||
}
|
||||
|
||||
return seriesTitleInfo;
|
||||
}
|
||||
|
||||
private static ParsedTrackInfo ParseMatchMusicCollection(MatchCollection matchCollection)
|
||||
{
|
||||
var artistName = matchCollection[0].Groups["artist"].Value./*Removed for cases like Will.I.Am Replace('.', ' ').*/Replace('_', ' ');
|
||||
|
@ -1057,6 +890,20 @@ namespace NzbDrone.Core.Parser
|
|||
return artistTitleInfo;
|
||||
}
|
||||
|
||||
public static string ParseArtistName(string title)
|
||||
{
|
||||
Logger.Debug("Parsing string '{0}'", title);
|
||||
|
||||
var parseResult = ParseAlbumTitle(title);
|
||||
|
||||
if (parseResult == null)
|
||||
{
|
||||
return CleanSeriesTitle(title);
|
||||
}
|
||||
|
||||
return parseResult.ArtistName;
|
||||
}
|
||||
|
||||
private static ParsedAlbumInfo ParseAlbumMatchCollection(MatchCollection matchCollection)
|
||||
{
|
||||
var artistName = matchCollection[0].Groups["artist"].Value.Replace('.', ' ').Replace('_', ' ');
|
||||
|
@ -1080,141 +927,6 @@ namespace NzbDrone.Core.Parser
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchCollection)
|
||||
{
|
||||
var seriesName = matchCollection[0].Groups["title"].Value.Replace('.', ' ').Replace('_', ' ');
|
||||
seriesName = RequestInfoRegex.Replace(seriesName, "").Trim(' ');
|
||||
|
||||
int airYear;
|
||||
int.TryParse(matchCollection[0].Groups["airyear"].Value, out airYear);
|
||||
|
||||
ParsedEpisodeInfo result;
|
||||
|
||||
if (airYear < 1900)
|
||||
{
|
||||
var seasons = new List<int>();
|
||||
|
||||
foreach (Capture seasonCapture in matchCollection[0].Groups["season"].Captures)
|
||||
{
|
||||
int parsedSeason;
|
||||
if (int.TryParse(seasonCapture.Value, out parsedSeason))
|
||||
seasons.Add(parsedSeason);
|
||||
}
|
||||
|
||||
//If no season was found it should be treated as a mini series and season 1
|
||||
if (seasons.Count == 0) seasons.Add(1);
|
||||
|
||||
//If more than 1 season was parsed go to the next REGEX (A multi-season release is unlikely)
|
||||
if (seasons.Distinct().Count() > 1) return null;
|
||||
|
||||
result = new ParsedEpisodeInfo
|
||||
{
|
||||
SeasonNumber = seasons.First(),
|
||||
EpisodeNumbers = new int[0],
|
||||
AbsoluteEpisodeNumbers = new int[0]
|
||||
};
|
||||
|
||||
foreach (Match matchGroup in matchCollection)
|
||||
{
|
||||
var episodeCaptures = matchGroup.Groups["episode"].Captures.Cast<Capture>().ToList();
|
||||
var absoluteEpisodeCaptures = matchGroup.Groups["absoluteepisode"].Captures.Cast<Capture>().ToList();
|
||||
|
||||
//Allows use to return a list of 0 episodes (We can handle that as a full season release)
|
||||
if (episodeCaptures.Any())
|
||||
{
|
||||
var first = ParseNumber(episodeCaptures.First().Value);
|
||||
var last = ParseNumber(episodeCaptures.Last().Value);
|
||||
|
||||
if (first > last)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var count = last - first + 1;
|
||||
result.EpisodeNumbers = Enumerable.Range(first, count).ToArray();
|
||||
}
|
||||
|
||||
if (absoluteEpisodeCaptures.Any())
|
||||
{
|
||||
var first = Convert.ToInt32(absoluteEpisodeCaptures.First().Value);
|
||||
var last = Convert.ToInt32(absoluteEpisodeCaptures.Last().Value);
|
||||
|
||||
if (first > last)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var count = last - first + 1;
|
||||
result.AbsoluteEpisodeNumbers = Enumerable.Range(first, count).ToArray();
|
||||
|
||||
if (matchGroup.Groups["special"].Success)
|
||||
{
|
||||
result.Special = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!episodeCaptures.Any() && !absoluteEpisodeCaptures.Any())
|
||||
{
|
||||
//Check to see if this is an "Extras" or "SUBPACK" release, if it is, return NULL
|
||||
//Todo: Set a "Extras" flag in EpisodeParseResult if we want to download them ever
|
||||
if (!matchCollection[0].Groups["extras"].Value.IsNullOrWhiteSpace()) return null;
|
||||
|
||||
result.FullSeason = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.AbsoluteEpisodeNumbers.Any() && !result.EpisodeNumbers.Any())
|
||||
{
|
||||
result.SeasonNumber = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//Try to Parse as a daily show
|
||||
var airmonth = Convert.ToInt32(matchCollection[0].Groups["airmonth"].Value);
|
||||
var airday = Convert.ToInt32(matchCollection[0].Groups["airday"].Value);
|
||||
|
||||
//Swap day and month if month is bigger than 12 (scene fail)
|
||||
if (airmonth > 12)
|
||||
{
|
||||
var tempDay = airday;
|
||||
airday = airmonth;
|
||||
airmonth = tempDay;
|
||||
}
|
||||
|
||||
DateTime airDate;
|
||||
|
||||
try
|
||||
{
|
||||
airDate = new DateTime(airYear, airmonth, airday);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new InvalidDateException("Invalid date found: {0}-{1}-{2}", airYear, airmonth, airday);
|
||||
}
|
||||
|
||||
//Check if episode is in the future (most likely a parse error)
|
||||
if (airDate > DateTime.Now.AddDays(1).Date || airDate < new DateTime(1970, 1, 1))
|
||||
{
|
||||
throw new InvalidDateException("Invalid date found: {0}", airDate);
|
||||
}
|
||||
|
||||
result = new ParsedEpisodeInfo
|
||||
{
|
||||
AirDate = airDate.ToString(Episode.AIR_DATE_FORMAT),
|
||||
};
|
||||
}
|
||||
|
||||
result.SeriesTitle = seriesName;
|
||||
result.SeriesTitleInfo = GetSeriesTitleInfo(result.SeriesTitle);
|
||||
|
||||
Logger.Debug("Episode Parsed. {0}", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool ValidateBeforeParsing(string title)
|
||||
{
|
||||
if (title.ToLower().Contains("password") && title.ToLower().Contains("yenc"))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace NzbDrone.Core.Parser
|
||||
namespace NzbDrone.Core.Parser
|
||||
{
|
||||
public static class SceneChecker
|
||||
{
|
||||
|
@ -9,12 +9,12 @@
|
|||
if (!title.Contains(".")) return false;
|
||||
if (title.Contains(" ")) return false;
|
||||
|
||||
var parsedTitle = Parser.ParseTitle(title);
|
||||
var parsedTitle = Parser.ParseMusicTitle(title);
|
||||
|
||||
if (parsedTitle == null ||
|
||||
parsedTitle.ReleaseGroup == null ||
|
||||
parsedTitle.Quality.Quality == Qualities.Quality.Unknown ||
|
||||
string.IsNullOrWhiteSpace(parsedTitle.SeriesTitle))
|
||||
string.IsNullOrWhiteSpace(parsedTitle.ArtistTitle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class Actor : IEmbeddedDocument
|
||||
{
|
||||
public Actor()
|
||||
{
|
||||
Images = new List<MediaCover.MediaCover>();
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Character { get; set; }
|
||||
public List<MediaCover.MediaCover> Images { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class AddSeriesOptions : MonitoringOptions
|
||||
{
|
||||
public bool SearchForMissingEpisodes { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using NLog;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public interface IAddSeriesService
|
||||
{
|
||||
Series AddSeries(Series newSeries);
|
||||
}
|
||||
|
||||
public class AddSeriesService : IAddSeriesService
|
||||
{
|
||||
private readonly ISeriesService _seriesService;
|
||||
private readonly IBuildFileNames _fileNameBuilder;
|
||||
private readonly IAddSeriesValidator _addSeriesValidator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public AddSeriesService(ISeriesService seriesService,
|
||||
IBuildFileNames fileNameBuilder,
|
||||
IAddSeriesValidator addSeriesValidator,
|
||||
Logger logger)
|
||||
{
|
||||
_seriesService = seriesService;
|
||||
_fileNameBuilder = fileNameBuilder;
|
||||
_addSeriesValidator = addSeriesValidator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Series AddSeries(Series newSeries)
|
||||
{
|
||||
Ensure.That(newSeries, () => newSeries).IsNotNull();
|
||||
|
||||
newSeries = SetPropertiesAndValidate(newSeries);
|
||||
|
||||
_logger.Info("Adding Series {0} Path: [{1}]", newSeries, newSeries.Path);
|
||||
_seriesService.AddSeries(newSeries);
|
||||
|
||||
return newSeries;
|
||||
}
|
||||
|
||||
private Series SetPropertiesAndValidate(Series newSeries)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(newSeries.Path))
|
||||
{
|
||||
//var folderName = _fileNameBuilder.GetSeriesFolder(newSeries);
|
||||
//newSeries.Path = Path.Combine(newSeries.RootFolderPath, folderName);
|
||||
}
|
||||
|
||||
newSeries.CleanTitle = newSeries.Title.CleanSeriesTitle();
|
||||
newSeries.SortTitle = SeriesTitleNormalizer.Normalize(newSeries.Title, newSeries.TvdbId);
|
||||
newSeries.Added = DateTime.UtcNow;
|
||||
|
||||
var validationResult = _addSeriesValidator.Validate(newSeries);
|
||||
|
||||
if (!validationResult.IsValid)
|
||||
{
|
||||
throw new ValidationException(validationResult.Errors);
|
||||
}
|
||||
|
||||
return newSeries;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
using FluentValidation;
|
||||
using FluentValidation.Results;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public interface IAddSeriesValidator
|
||||
{
|
||||
ValidationResult Validate(Series instance);
|
||||
}
|
||||
|
||||
public class AddSeriesValidator : AbstractValidator<Series>, IAddSeriesValidator
|
||||
{
|
||||
public AddSeriesValidator(RootFolderValidator rootFolderValidator,
|
||||
SeriesTitleSlugValidator seriesTitleSlugValidator)
|
||||
{
|
||||
RuleFor(c => c.Path).Cascade(CascadeMode.StopOnFirstFailure)
|
||||
.IsValidPath()
|
||||
.SetValidator(rootFolderValidator);
|
||||
|
||||
RuleFor(c => c.TitleSlug).SetValidator(seriesTitleSlugValidator);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Tv.Commands
|
||||
{
|
||||
public class RefreshSeriesCommand : Command
|
||||
{
|
||||
public int? SeriesId { get; set; }
|
||||
|
||||
public RefreshSeriesCommand()
|
||||
{
|
||||
}
|
||||
|
||||
public RefreshSeriesCommand(int? seriesId)
|
||||
{
|
||||
SeriesId = seriesId;
|
||||
}
|
||||
|
||||
public override bool SendUpdatesToClient => true;
|
||||
|
||||
public override bool UpdateScheduledTask => !SeriesId.HasValue;
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Marr.Data;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class Episode : ModelBase, IComparable
|
||||
{
|
||||
public Episode()
|
||||
{
|
||||
Images = new List<MediaCover.MediaCover>();
|
||||
}
|
||||
|
||||
public const string AIR_DATE_FORMAT = "yyyy-MM-dd";
|
||||
|
||||
public int SeriesId { get; set; }
|
||||
public int EpisodeFileId { get; set; }
|
||||
public int SeasonNumber { get; set; }
|
||||
public int EpisodeNumber { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string AirDate { get; set; }
|
||||
public DateTime? AirDateUtc { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public int? AbsoluteEpisodeNumber { get; set; }
|
||||
public int? SceneAbsoluteEpisodeNumber { get; set; }
|
||||
public int? SceneSeasonNumber { get; set; }
|
||||
public int? SceneEpisodeNumber { get; set; }
|
||||
public bool UnverifiedSceneNumbering { get; set; }
|
||||
public Ratings Ratings { get; set; }
|
||||
public List<MediaCover.MediaCover> Images { get; set; }
|
||||
|
||||
public string SeriesTitle { get; private set; }
|
||||
|
||||
public LazyLoaded<EpisodeFile> EpisodeFile { get; set; }
|
||||
|
||||
public Series Series { get; set; }
|
||||
|
||||
public bool HasFile => EpisodeFileId > 0;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[{0}]{1}", Id, Title.NullSafe());
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
var other = (Episode)obj;
|
||||
|
||||
if (SeasonNumber > other.SeasonNumber)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (SeasonNumber < other.SeasonNumber)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EpisodeNumber > other.EpisodeNumber)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (EpisodeNumber < other.EpisodeNumber)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.IndexerSearch;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public interface IEpisodeAddedService
|
||||
{
|
||||
void SearchForRecentlyAdded(int seriesId);
|
||||
}
|
||||
|
||||
public class EpisodeAddedService : IHandle<EpisodeInfoRefreshedEvent>, IEpisodeAddedService
|
||||
{
|
||||
private readonly IManageCommandQueue _commandQueueManager;
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly Logger _logger;
|
||||
private readonly ICached<List<int>> _addedEpisodesCache;
|
||||
|
||||
public EpisodeAddedService(ICacheManager cacheManager,
|
||||
IManageCommandQueue commandQueueManager,
|
||||
IEpisodeService episodeService,
|
||||
Logger logger)
|
||||
{
|
||||
_commandQueueManager = commandQueueManager;
|
||||
_episodeService = episodeService;
|
||||
_logger = logger;
|
||||
_addedEpisodesCache = cacheManager.GetCache<List<int>>(GetType());
|
||||
}
|
||||
|
||||
public void SearchForRecentlyAdded(int seriesId)
|
||||
{
|
||||
var previouslyAired = _addedEpisodesCache.Find(seriesId.ToString());
|
||||
|
||||
if (previouslyAired != null && previouslyAired.Any())
|
||||
{
|
||||
var missing = previouslyAired.Select(e => _episodeService.GetEpisode(e)).Where(e => !e.HasFile).ToList();
|
||||
|
||||
if (missing.Any())
|
||||
{
|
||||
//_commandQueueManager.Push(new EpisodeSearchCommand(missing.Select(e => e.Id).ToList()));
|
||||
}
|
||||
}
|
||||
|
||||
_addedEpisodesCache.Remove(seriesId.ToString());
|
||||
}
|
||||
|
||||
public void Handle(EpisodeInfoRefreshedEvent message)
|
||||
{
|
||||
if (message.Series.AddOptions == null)
|
||||
{
|
||||
if (!message.Series.Monitored)
|
||||
{
|
||||
_logger.Debug("Series is not monitored");
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.Added.Empty())
|
||||
{
|
||||
_logger.Debug("No new episodes, skipping search");
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.Added.None(a => a.AirDateUtc.HasValue))
|
||||
{
|
||||
_logger.Debug("No new episodes have an air date");
|
||||
return;
|
||||
}
|
||||
|
||||
var previouslyAired = message.Added.Where(a => a.AirDateUtc.HasValue && a.AirDateUtc.Value.Before(DateTime.UtcNow.AddDays(1)) && a.Monitored).ToList();
|
||||
|
||||
if (previouslyAired.Empty())
|
||||
{
|
||||
_logger.Debug("Newly added episodes all air in the future");
|
||||
return;
|
||||
}
|
||||
|
||||
_addedEpisodesCache.Set(message.Series.Id.ToString(), previouslyAired.Select(e => e.Id).ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public interface IEpisodeCutoffService
|
||||
{
|
||||
PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec);
|
||||
}
|
||||
|
||||
public class EpisodeCutoffService : IEpisodeCutoffService
|
||||
{
|
||||
private readonly IEpisodeRepository _episodeRepository;
|
||||
private readonly IProfileService _profileService;
|
||||
private readonly ILanguageProfileService _languageProfileService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public EpisodeCutoffService(IEpisodeRepository episodeRepository, IProfileService profileService, ILanguageProfileService languageProfileService, Logger logger)
|
||||
{
|
||||
_episodeRepository = episodeRepository;
|
||||
_profileService = profileService;
|
||||
_languageProfileService = languageProfileService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec)
|
||||
{
|
||||
var qualitiesBelowCutoff = new List<QualitiesBelowCutoff>();
|
||||
var languagesBelowCutoff = new List<LanguagesBelowCutoff>();
|
||||
var profiles = _profileService.All();
|
||||
var languageProfiles = _languageProfileService.All();
|
||||
|
||||
//Get all items less than the cutoff
|
||||
foreach (var profile in profiles)
|
||||
{
|
||||
var cutoffIndex = profile.Items.FindIndex(v => v.Quality == profile.Cutoff);
|
||||
var belowCutoff = profile.Items.Take(cutoffIndex).ToList();
|
||||
|
||||
if (belowCutoff.Any())
|
||||
{
|
||||
qualitiesBelowCutoff.Add(new QualitiesBelowCutoff(profile.Id, belowCutoff.Select(i => i.Quality.Id)));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var profile in languageProfiles)
|
||||
{
|
||||
var languageCutoffIndex = profile.Languages.FindIndex(v => v.Language == profile.Cutoff);
|
||||
var belowLanguageCutoff = profile.Languages.Take(languageCutoffIndex).ToList();
|
||||
|
||||
if (belowLanguageCutoff.Any())
|
||||
{
|
||||
languagesBelowCutoff.Add(new LanguagesBelowCutoff(profile.Id, belowLanguageCutoff.Select(l => l.Language.Id)));
|
||||
}
|
||||
}
|
||||
|
||||
return _episodeRepository.EpisodesWhereCutoffUnmet(pagingSpec, qualitiesBelowCutoff, languagesBelowCutoff, false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public interface IEpisodeMonitoredService
|
||||
{
|
||||
void SetEpisodeMonitoredStatus(Series series, MonitoringOptions monitoringOptions);
|
||||
}
|
||||
|
||||
public class EpisodeMonitoredService : IEpisodeMonitoredService
|
||||
{
|
||||
private readonly ISeriesService _seriesService;
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public EpisodeMonitoredService(ISeriesService seriesService, IEpisodeService episodeService, Logger logger)
|
||||
{
|
||||
_seriesService = seriesService;
|
||||
_episodeService = episodeService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void SetEpisodeMonitoredStatus(Series series, MonitoringOptions monitoringOptions)
|
||||
{
|
||||
if (monitoringOptions != null)
|
||||
{
|
||||
_logger.Debug("[{0}] Setting episode monitored status.", series.Title);
|
||||
|
||||
var episodes = _episodeService.GetEpisodeBySeries(series.Id);
|
||||
|
||||
if (monitoringOptions.IgnoreEpisodesWithFiles)
|
||||
{
|
||||
_logger.Debug("Ignoring Episodes with Files");
|
||||
ToggleEpisodesMonitoredState(episodes.Where(e => e.HasFile), false);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
_logger.Debug("Monitoring Episodes with Files");
|
||||
ToggleEpisodesMonitoredState(episodes.Where(e => e.HasFile), true);
|
||||
}
|
||||
|
||||
if (monitoringOptions.IgnoreEpisodesWithoutFiles)
|
||||
{
|
||||
_logger.Debug("Ignoring Episodes without Files");
|
||||
ToggleEpisodesMonitoredState(episodes.Where(e => !e.HasFile && e.AirDateUtc.HasValue && e.AirDateUtc.Value.Before(DateTime.UtcNow)), false);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
_logger.Debug("Monitoring Episodes without Files");
|
||||
ToggleEpisodesMonitoredState(episodes.Where(e => !e.HasFile && e.AirDateUtc.HasValue && e.AirDateUtc.Value.Before(DateTime.UtcNow)), true);
|
||||
}
|
||||
|
||||
var lastSeason = series.Seasons.Select(s => s.SeasonNumber).MaxOrDefault();
|
||||
|
||||
foreach (var s in series.Seasons)
|
||||
{
|
||||
var season = s;
|
||||
|
||||
if (season.Monitored)
|
||||
{
|
||||
if (!monitoringOptions.IgnoreEpisodesWithFiles && !monitoringOptions.IgnoreEpisodesWithoutFiles)
|
||||
{
|
||||
ToggleEpisodesMonitoredState(episodes.Where(e => e.SeasonNumber == season.SeasonNumber), true);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (!monitoringOptions.IgnoreEpisodesWithFiles && !monitoringOptions.IgnoreEpisodesWithoutFiles)
|
||||
{
|
||||
ToggleEpisodesMonitoredState(episodes.Where(e => e.SeasonNumber == season.SeasonNumber), false);
|
||||
}
|
||||
|
||||
else if (season.SeasonNumber == 0)
|
||||
{
|
||||
ToggleEpisodesMonitoredState(episodes.Where(e => e.SeasonNumber == season.SeasonNumber), false);
|
||||
}
|
||||
}
|
||||
|
||||
if (season.SeasonNumber < lastSeason)
|
||||
{
|
||||
if (episodes.Where(e => e.SeasonNumber == season.SeasonNumber).All(e => !e.Monitored))
|
||||
{
|
||||
season.Monitored = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_episodeService.UpdateEpisodes(episodes);
|
||||
}
|
||||
|
||||
_seriesService.UpdateSeries(series);
|
||||
}
|
||||
|
||||
private void ToggleEpisodesMonitoredState(IEnumerable<Episode> episodes, bool monitored)
|
||||
{
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.Monitored = monitored;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,298 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Marr.Data.QGen;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Datastore.Extensions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public interface IEpisodeRepository : IBasicRepository<Episode>
|
||||
{
|
||||
Episode Find(int seriesId, int season, int episodeNumber);
|
||||
Episode Find(int seriesId, int absoluteEpisodeNumber);
|
||||
Episode Get(int seriesId, string date);
|
||||
Episode Find(int seriesId, string date);
|
||||
List<Episode> GetEpisodes(int seriesId);
|
||||
List<Episode> GetEpisodes(int seriesId, int seasonNumber);
|
||||
List<Episode> GetEpisodeByFileId(int fileId);
|
||||
List<Episode> EpisodesWithFiles(int seriesId);
|
||||
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials);
|
||||
PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, List<LanguagesBelowCutoff> languagesBelowCutoff, bool includeSpecials);
|
||||
List<Episode> FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber);
|
||||
Episode FindEpisodeBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber);
|
||||
List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate, bool includeUnmonitored);
|
||||
void SetMonitoredFlat(Episode episode, bool monitored);
|
||||
void SetMonitoredBySeason(int seriesId, int seasonNumber, bool monitored);
|
||||
void SetMonitored(IEnumerable<int> ids, bool monitored);
|
||||
void SetFileId(int episodeId, int fileId);
|
||||
}
|
||||
|
||||
public class EpisodeRepository : BasicRepository<Episode>, IEpisodeRepository
|
||||
{
|
||||
private readonly IMainDatabase _database;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public EpisodeRepository(IMainDatabase database, IEventAggregator eventAggregator, Logger logger)
|
||||
: base(database, eventAggregator)
|
||||
{
|
||||
_database = database;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Episode Find(int seriesId, int season, int episodeNumber)
|
||||
{
|
||||
return Query.Where(s => s.SeriesId == seriesId)
|
||||
.AndWhere(s => s.SeasonNumber == season)
|
||||
.AndWhere(s => s.EpisodeNumber == episodeNumber)
|
||||
.SingleOrDefault();
|
||||
}
|
||||
|
||||
public Episode Find(int seriesId, int absoluteEpisodeNumber)
|
||||
{
|
||||
return Query.Where(s => s.SeriesId == seriesId)
|
||||
.AndWhere(s => s.AbsoluteEpisodeNumber == absoluteEpisodeNumber)
|
||||
.SingleOrDefault();
|
||||
}
|
||||
|
||||
public Episode Get(int seriesId, string date)
|
||||
{
|
||||
var episode = FindOneByAirDate(seriesId, date);
|
||||
|
||||
if (episode == null)
|
||||
{
|
||||
throw new InvalidOperationException("Expected at one episode");
|
||||
}
|
||||
|
||||
return episode;
|
||||
}
|
||||
|
||||
public Episode Find(int seriesId, string date)
|
||||
{
|
||||
return FindOneByAirDate(seriesId, date);
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodes(int seriesId)
|
||||
{
|
||||
return Query.Where(s => s.SeriesId == seriesId).ToList();
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodes(int seriesId, int seasonNumber)
|
||||
{
|
||||
return Query.Where(s => s.SeriesId == seriesId)
|
||||
.AndWhere(s => s.SeasonNumber == seasonNumber)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodeByFileId(int fileId)
|
||||
{
|
||||
return Query.Where(e => e.EpisodeFileId == fileId).ToList();
|
||||
}
|
||||
|
||||
public List<Episode> EpisodesWithFiles(int seriesId)
|
||||
{
|
||||
return Query.Join<Episode, EpisodeFile>(JoinType.Inner, e => e.EpisodeFile, (e, ef) => e.EpisodeFileId == ef.Id)
|
||||
.Where(e => e.SeriesId == seriesId);
|
||||
}
|
||||
|
||||
public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials)
|
||||
{
|
||||
var currentTime = DateTime.UtcNow;
|
||||
var startingSeasonNumber = 1;
|
||||
|
||||
if (includeSpecials)
|
||||
{
|
||||
startingSeasonNumber = 0;
|
||||
}
|
||||
|
||||
pagingSpec.TotalRecords = GetMissingEpisodesQuery(pagingSpec, currentTime, startingSeasonNumber).GetRowCount();
|
||||
pagingSpec.Records = GetMissingEpisodesQuery(pagingSpec, currentTime, startingSeasonNumber).ToList();
|
||||
|
||||
return pagingSpec;
|
||||
}
|
||||
|
||||
public PagingSpec<Episode> EpisodesWhereCutoffUnmet(PagingSpec<Episode> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, List<LanguagesBelowCutoff> languagesBelowCutoff, bool includeSpecials)
|
||||
{
|
||||
var startingSeasonNumber = 1;
|
||||
|
||||
if (includeSpecials)
|
||||
{
|
||||
startingSeasonNumber = 0;
|
||||
}
|
||||
|
||||
pagingSpec.TotalRecords = EpisodesWhereCutoffUnmetQuery(pagingSpec, qualitiesBelowCutoff, languagesBelowCutoff, startingSeasonNumber).GetRowCount();
|
||||
pagingSpec.Records = EpisodesWhereCutoffUnmetQuery(pagingSpec, qualitiesBelowCutoff, languagesBelowCutoff, startingSeasonNumber).ToList();
|
||||
return pagingSpec;
|
||||
}
|
||||
|
||||
public List<Episode> FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return Query.Where(s => s.SeriesId == seriesId)
|
||||
.AndWhere(s => s.SceneSeasonNumber == seasonNumber)
|
||||
.AndWhere(s => s.SceneEpisodeNumber == episodeNumber);
|
||||
}
|
||||
|
||||
public Episode FindEpisodeBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber)
|
||||
{
|
||||
var episodes = Query.Where(s => s.SeriesId == seriesId)
|
||||
.AndWhere(s => s.SceneAbsoluteEpisodeNumber == sceneAbsoluteEpisodeNumber)
|
||||
.ToList();
|
||||
|
||||
if (episodes.Empty() || episodes.Count > 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return episodes.Single();
|
||||
}
|
||||
|
||||
public List<Episode> EpisodesBetweenDates(DateTime startDate, DateTime endDate, bool includeUnmonitored)
|
||||
{
|
||||
var query = Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id)
|
||||
.Where<Episode>(e => e.AirDateUtc >= startDate)
|
||||
.AndWhere(e => e.AirDateUtc <= endDate);
|
||||
|
||||
|
||||
if (!includeUnmonitored)
|
||||
{
|
||||
query.AndWhere(e => e.Monitored)
|
||||
.AndWhere(e => e.Series.Monitored);
|
||||
}
|
||||
|
||||
return query.ToList();
|
||||
}
|
||||
|
||||
public void SetMonitoredFlat(Episode episode, bool monitored)
|
||||
{
|
||||
episode.Monitored = monitored;
|
||||
SetFields(episode, p => p.Monitored);
|
||||
}
|
||||
|
||||
public void SetMonitoredBySeason(int seriesId, int seasonNumber, bool monitored)
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
|
||||
mapper.AddParameter("seriesId", seriesId);
|
||||
mapper.AddParameter("seasonNumber", seasonNumber);
|
||||
mapper.AddParameter("monitored", monitored);
|
||||
|
||||
const string sql = "UPDATE Episodes " +
|
||||
"SET Monitored = @monitored " +
|
||||
"WHERE SeriesId = @seriesId " +
|
||||
"AND SeasonNumber = @seasonNumber";
|
||||
|
||||
mapper.ExecuteNonQuery(sql);
|
||||
}
|
||||
|
||||
public void SetMonitored(IEnumerable<int> ids, bool monitored)
|
||||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
|
||||
mapper.AddParameter("monitored", monitored);
|
||||
|
||||
var sql = "UPDATE Episodes " +
|
||||
"SET Monitored = @monitored " +
|
||||
$"WHERE Id IN ({string.Join(", ", ids)})";
|
||||
|
||||
mapper.ExecuteNonQuery(sql);
|
||||
}
|
||||
|
||||
public void SetFileId(int episodeId, int fileId)
|
||||
{
|
||||
SetFields(new Episode { Id = episodeId, EpisodeFileId = fileId }, episode => episode.EpisodeFileId);
|
||||
}
|
||||
|
||||
private SortBuilder<Episode> GetMissingEpisodesQuery(PagingSpec<Episode> pagingSpec, DateTime currentTime, int startingSeasonNumber)
|
||||
{
|
||||
return Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id)
|
||||
.Where(pagingSpec.FilterExpression)
|
||||
.AndWhere(e => e.EpisodeFileId == 0)
|
||||
.AndWhere(e => e.SeasonNumber >= startingSeasonNumber)
|
||||
.AndWhere(BuildAirDateUtcCutoffWhereClause(currentTime))
|
||||
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||
.Skip(pagingSpec.PagingOffset())
|
||||
.Take(pagingSpec.PageSize);
|
||||
}
|
||||
|
||||
private SortBuilder<Episode> EpisodesWhereCutoffUnmetQuery(PagingSpec<Episode> pagingSpec, List<QualitiesBelowCutoff> qualitiesBelowCutoff, List<LanguagesBelowCutoff> languagesBelowCutoff, int startingSeasonNumber)
|
||||
{
|
||||
return Query.Join<Episode, Series>(JoinType.Inner, e => e.Series, (e, s) => e.SeriesId == s.Id)
|
||||
.Join<Episode, EpisodeFile>(JoinType.Left, e => e.EpisodeFile, (e, s) => e.EpisodeFileId == s.Id)
|
||||
.Where(pagingSpec.FilterExpression)
|
||||
.AndWhere(e => e.EpisodeFileId != 0)
|
||||
.AndWhere(e => e.SeasonNumber >= startingSeasonNumber)
|
||||
.AndWhere(
|
||||
String.Format("({0} OR {1})",
|
||||
BuildLanguageCutoffWhereClause(languagesBelowCutoff),
|
||||
BuildQualityCutoffWhereClause(qualitiesBelowCutoff)))
|
||||
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
|
||||
.Skip(pagingSpec.PagingOffset())
|
||||
.Take(pagingSpec.PageSize);
|
||||
}
|
||||
|
||||
private string BuildAirDateUtcCutoffWhereClause(DateTime currentTime)
|
||||
{
|
||||
return string.Format("WHERE datetime(strftime('%s', [t0].[AirDateUtc]) + [t1].[RunTime] * 60, 'unixepoch') <= '{0}'",
|
||||
currentTime.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||
}
|
||||
|
||||
private string BuildLanguageCutoffWhereClause(List<LanguagesBelowCutoff> languagesBelowCutoff)
|
||||
{
|
||||
var clauses = new List<String>();
|
||||
|
||||
foreach (var language in languagesBelowCutoff)
|
||||
{
|
||||
foreach (var belowCutoff in language.LanguageIds)
|
||||
{
|
||||
clauses.Add(String.Format("([t1].[LanguageProfileId] = {0} AND [t2].[Language] = {1})", language.ProfileId, belowCutoff));
|
||||
}
|
||||
}
|
||||
|
||||
return String.Format("({0})", String.Join(" OR ", clauses));
|
||||
}
|
||||
|
||||
private string BuildQualityCutoffWhereClause(List<QualitiesBelowCutoff> qualitiesBelowCutoff)
|
||||
{
|
||||
var clauses = new List<string>();
|
||||
|
||||
foreach (var profile in qualitiesBelowCutoff)
|
||||
{
|
||||
foreach (var belowCutoff in profile.QualityIds)
|
||||
{
|
||||
clauses.Add(string.Format("([t1].[ProfileId] = {0} AND [t2].[Quality] LIKE '%_quality_: {1},%')", profile.ProfileId, belowCutoff));
|
||||
}
|
||||
}
|
||||
|
||||
return string.Format("({0})", string.Join(" OR ", clauses));
|
||||
}
|
||||
|
||||
private Episode FindOneByAirDate(int seriesId, string date)
|
||||
{
|
||||
var episodes = Query.Where(s => s.SeriesId == seriesId)
|
||||
.AndWhere(s => s.AirDate == date)
|
||||
.ToList();
|
||||
|
||||
if (!episodes.Any()) return null;
|
||||
|
||||
if (episodes.Count == 1) return episodes.First();
|
||||
|
||||
_logger.Debug("Multiple episodes with the same air date were found, will exclude specials");
|
||||
|
||||
var regularEpisodes = episodes.Where(e => e.SeasonNumber > 0).ToList();
|
||||
|
||||
if (regularEpisodes.Count == 1)
|
||||
{
|
||||
_logger.Debug("Left with one episode after excluding specials");
|
||||
return regularEpisodes.First();
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("Multiple episodes with the same air date found");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,231 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public interface IEpisodeService
|
||||
{
|
||||
Episode GetEpisode(int id);
|
||||
List<Episode> GetEpisodes(IEnumerable<int> ids);
|
||||
Episode FindEpisode(int seriesId, int seasonNumber, int episodeNumber);
|
||||
Episode FindEpisode(int seriesId, int absoluteEpisodeNumber);
|
||||
Episode FindEpisodeByTitle(int seriesId, int seasonNumber, string releaseTitle);
|
||||
List<Episode> FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber);
|
||||
Episode FindEpisodeBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber);
|
||||
Episode GetEpisode(int seriesId, string date);
|
||||
Episode FindEpisode(int seriesId, string date);
|
||||
List<Episode> GetEpisodeBySeries(int seriesId);
|
||||
List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber);
|
||||
List<Episode> EpisodesWithFiles(int seriesId);
|
||||
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec);
|
||||
List<Episode> GetEpisodesByFileId(int episodeFileId);
|
||||
void UpdateEpisode(Episode episode);
|
||||
void SetEpisodeMonitored(int episodeId, bool monitored);
|
||||
void SetMonitored(IEnumerable<int> ids, bool monitored);
|
||||
void UpdateEpisodes(List<Episode> episodes);
|
||||
List<Episode> EpisodesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored);
|
||||
void InsertMany(List<Episode> episodes);
|
||||
void UpdateMany(List<Episode> episodes);
|
||||
void DeleteMany(List<Episode> episodes);
|
||||
void SetEpisodeMonitoredBySeason(int seriesId, int seasonNumber, bool monitored);
|
||||
}
|
||||
|
||||
public class EpisodeService : IEpisodeService,
|
||||
//IHandle<EpisodeFileDeletedEvent>,
|
||||
//IHandle<EpisodeFileAddedEvent>,
|
||||
IHandleAsync<SeriesDeletedEvent>
|
||||
{
|
||||
private readonly IEpisodeRepository _episodeRepository;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public EpisodeService(IEpisodeRepository episodeRepository, IConfigService configService, Logger logger)
|
||||
{
|
||||
_episodeRepository = episodeRepository;
|
||||
_configService = configService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Episode GetEpisode(int id)
|
||||
{
|
||||
return _episodeRepository.Get(id);
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodes(IEnumerable<int> ids)
|
||||
{
|
||||
return _episodeRepository.Get(ids).ToList();
|
||||
}
|
||||
|
||||
public Episode FindEpisode(int seriesId, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return _episodeRepository.Find(seriesId, seasonNumber, episodeNumber);
|
||||
}
|
||||
|
||||
public Episode FindEpisode(int seriesId, int absoluteEpisodeNumber)
|
||||
{
|
||||
return _episodeRepository.Find(seriesId, absoluteEpisodeNumber);
|
||||
}
|
||||
|
||||
public List<Episode> FindEpisodesBySceneNumbering(int seriesId, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return _episodeRepository.FindEpisodesBySceneNumbering(seriesId, seasonNumber, episodeNumber);
|
||||
}
|
||||
|
||||
public Episode FindEpisodeBySceneNumbering(int seriesId, int sceneAbsoluteEpisodeNumber)
|
||||
{
|
||||
return _episodeRepository.FindEpisodeBySceneNumbering(seriesId, sceneAbsoluteEpisodeNumber);
|
||||
}
|
||||
|
||||
public Episode GetEpisode(int seriesId, string date)
|
||||
{
|
||||
return _episodeRepository.Get(seriesId, date);
|
||||
}
|
||||
|
||||
public Episode FindEpisode(int seriesId, string date)
|
||||
{
|
||||
return _episodeRepository.Find(seriesId, date);
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodeBySeries(int seriesId)
|
||||
{
|
||||
return _episodeRepository.GetEpisodes(seriesId).ToList();
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber)
|
||||
{
|
||||
return _episodeRepository.GetEpisodes(seriesId, seasonNumber);
|
||||
}
|
||||
|
||||
public Episode FindEpisodeByTitle(int seriesId, int seasonNumber, string releaseTitle)
|
||||
{
|
||||
// TODO: can replace this search mechanism with something smarter/faster/better
|
||||
var normalizedReleaseTitle = Parser.Parser.NormalizeEpisodeTitle(releaseTitle).Replace(".", " ");
|
||||
var episodes = _episodeRepository.GetEpisodes(seriesId, seasonNumber);
|
||||
|
||||
var matches = episodes.Select(
|
||||
episode => new
|
||||
{
|
||||
Position = normalizedReleaseTitle.IndexOf(Parser.Parser.NormalizeEpisodeTitle(episode.Title), StringComparison.CurrentCultureIgnoreCase),
|
||||
Length = Parser.Parser.NormalizeEpisodeTitle(episode.Title).Length,
|
||||
Episode = episode
|
||||
})
|
||||
.Where(e => e.Episode.Title.Length > 0 && e.Position >= 0)
|
||||
.OrderBy(e => e.Position)
|
||||
.ThenByDescending(e => e.Length)
|
||||
.ToList();
|
||||
|
||||
if (matches.Any())
|
||||
{
|
||||
return matches.First().Episode;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Episode> EpisodesWithFiles(int seriesId)
|
||||
{
|
||||
return _episodeRepository.EpisodesWithFiles(seriesId);
|
||||
}
|
||||
|
||||
public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec)
|
||||
{
|
||||
var episodeResult = _episodeRepository.EpisodesWithoutFiles(pagingSpec, true);
|
||||
|
||||
return episodeResult;
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodesByFileId(int episodeFileId)
|
||||
{
|
||||
return _episodeRepository.GetEpisodeByFileId(episodeFileId);
|
||||
}
|
||||
|
||||
public void UpdateEpisode(Episode episode)
|
||||
{
|
||||
_episodeRepository.Update(episode);
|
||||
}
|
||||
|
||||
public void SetEpisodeMonitored(int episodeId, bool monitored)
|
||||
{
|
||||
var episode = _episodeRepository.Get(episodeId);
|
||||
_episodeRepository.SetMonitoredFlat(episode, monitored);
|
||||
|
||||
_logger.Debug("Monitored flag for Episode:{0} was set to {1}", episodeId, monitored);
|
||||
}
|
||||
|
||||
public void SetMonitored(IEnumerable<int> ids, bool monitored)
|
||||
{
|
||||
_episodeRepository.SetMonitored(ids, monitored);
|
||||
}
|
||||
|
||||
public void SetEpisodeMonitoredBySeason(int seriesId, int seasonNumber, bool monitored)
|
||||
{
|
||||
_episodeRepository.SetMonitoredBySeason(seriesId, seasonNumber, monitored);
|
||||
}
|
||||
|
||||
public void UpdateEpisodes(List<Episode> episodes)
|
||||
{
|
||||
_episodeRepository.UpdateMany(episodes);
|
||||
}
|
||||
|
||||
public List<Episode> EpisodesBetweenDates(DateTime start, DateTime end, bool includeUnmonitored)
|
||||
{
|
||||
var episodes = _episodeRepository.EpisodesBetweenDates(start.ToUniversalTime(), end.ToUniversalTime(), includeUnmonitored);
|
||||
|
||||
return episodes;
|
||||
}
|
||||
|
||||
public void InsertMany(List<Episode> episodes)
|
||||
{
|
||||
_episodeRepository.InsertMany(episodes);
|
||||
}
|
||||
|
||||
public void UpdateMany(List<Episode> episodes)
|
||||
{
|
||||
_episodeRepository.UpdateMany(episodes);
|
||||
}
|
||||
|
||||
public void DeleteMany(List<Episode> episodes)
|
||||
{
|
||||
_episodeRepository.DeleteMany(episodes);
|
||||
}
|
||||
|
||||
public void HandleAsync(SeriesDeletedEvent message)
|
||||
{
|
||||
var episodes = GetEpisodeBySeries(message.Series.Id);
|
||||
_episodeRepository.DeleteMany(episodes);
|
||||
}
|
||||
|
||||
//public void Handle(EpisodeFileDeletedEvent message)
|
||||
//{
|
||||
// foreach (var episode in GetEpisodesByFileId(message.EpisodeFile.Id))
|
||||
// {
|
||||
// _logger.Debug("Detaching episode {0} from file.", episode.Id);
|
||||
// episode.EpisodeFileId = 0;
|
||||
|
||||
// if (message.Reason != DeleteMediaFileReason.Upgrade && _configService.AutoUnmonitorPreviouslyDownloadedTracks)
|
||||
// {
|
||||
// episode.Monitored = false;
|
||||
// }
|
||||
|
||||
// UpdateEpisode(episode);
|
||||
// }
|
||||
//}
|
||||
|
||||
//public void Handle(EpisodeFileAddedEvent message)
|
||||
//{
|
||||
// foreach (var episode in message.EpisodeFile.Episodes.Value)
|
||||
// {
|
||||
// _episodeRepository.SetFileId(episode.Id, message.EpisodeFile.Id);
|
||||
// _logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.RelativePath, episode);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using NzbDrone.Common.Messaging;
|
||||
|
||||
namespace NzbDrone.Core.Tv.Events
|
||||
{
|
||||
public class EpisodeInfoRefreshedEvent : IEvent
|
||||
{
|
||||
public Series Series { get; set; }
|
||||
public ReadOnlyCollection<Episode> Added { get; private set; }
|
||||
public ReadOnlyCollection<Episode> Updated { get; private set; }
|
||||
|
||||
public EpisodeInfoRefreshedEvent(Series series, IList<Episode> added, IList<Episode> updated)
|
||||
{
|
||||
Series = series;
|
||||
Added = new ReadOnlyCollection<Episode>(added);
|
||||
Updated = new ReadOnlyCollection<Episode>(updated);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using NzbDrone.Common.Messaging;
|
||||
|
||||
namespace NzbDrone.Core.Tv.Events
|
||||
{
|
||||
public class SeriesAddedEvent : IEvent
|
||||
{
|
||||
public Series Series { get; private set; }
|
||||
|
||||
public SeriesAddedEvent(Series series)
|
||||
{
|
||||
Series = series;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using NzbDrone.Common.Messaging;
|
||||
|
||||
namespace NzbDrone.Core.Tv.Events
|
||||
{
|
||||
public class SeriesDeletedEvent : IEvent
|
||||
{
|
||||
public Series Series { get; private set; }
|
||||
public bool DeleteFiles { get; private set; }
|
||||
|
||||
public SeriesDeletedEvent(Series series, bool deleteFiles)
|
||||
{
|
||||
Series = series;
|
||||
DeleteFiles = deleteFiles;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
using NzbDrone.Common.Messaging;
|
||||
|
||||
namespace NzbDrone.Core.Tv.Events
|
||||
{
|
||||
public class SeriesEditedEvent : IEvent
|
||||
{
|
||||
public Series Series { get; private set; }
|
||||
public Series OldSeries { get; private set; }
|
||||
|
||||
public SeriesEditedEvent(Series series, Series oldSeries)
|
||||
{
|
||||
Series = series;
|
||||
OldSeries = oldSeries;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Common.Messaging;
|
||||
|
||||
namespace NzbDrone.Core.Tv.Events
|
||||
{
|
||||
public class SeriesImportedEvent : IEvent
|
||||
{
|
||||
public List<int> SeriesIds { get; private set; }
|
||||
|
||||
public SeriesImportedEvent(List<int> seriesIds)
|
||||
{
|
||||
SeriesIds = seriesIds;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using NzbDrone.Common.Messaging;
|
||||
|
||||
namespace NzbDrone.Core.Tv.Events
|
||||
{
|
||||
public class SeriesRefreshStartingEvent : IEvent
|
||||
{
|
||||
public bool ManualTrigger { get; set; }
|
||||
|
||||
public SeriesRefreshStartingEvent(bool manualTrigger)
|
||||
{
|
||||
ManualTrigger = manualTrigger;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
using NzbDrone.Common.Messaging;
|
||||
|
||||
namespace NzbDrone.Core.Tv.Events
|
||||
{
|
||||
public class SeriesUpdatedEvent : IEvent
|
||||
{
|
||||
public Series Series { get; private set; }
|
||||
|
||||
public SeriesUpdatedEvent(Series series)
|
||||
{
|
||||
Series = series;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class MonitoringOptions : IEmbeddedDocument
|
||||
{
|
||||
public bool IgnoreEpisodesWithFiles { get; set; }
|
||||
public bool IgnoreEpisodesWithoutFiles { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class Ratings : IEmbeddedDocument
|
||||
{
|
||||
public int Votes { get; set; }
|
||||
public decimal Value { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public interface IRefreshEpisodeService
|
||||
{
|
||||
void RefreshEpisodeInfo(Series series, IEnumerable<Episode> remoteEpisodes);
|
||||
}
|
||||
|
||||
public class RefreshEpisodeService : IRefreshEpisodeService
|
||||
{
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public RefreshEpisodeService(IEpisodeService episodeService, IEventAggregator eventAggregator, Logger logger)
|
||||
{
|
||||
_episodeService = episodeService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void RefreshEpisodeInfo(Series series, IEnumerable<Episode> remoteEpisodes)
|
||||
{
|
||||
_logger.Info("Starting episode info refresh for: {0}", series);
|
||||
var successCount = 0;
|
||||
var failCount = 0;
|
||||
|
||||
var existingEpisodes = _episodeService.GetEpisodeBySeries(series.Id);
|
||||
var seasons = series.Seasons;
|
||||
|
||||
var updateList = new List<Episode>();
|
||||
var newList = new List<Episode>();
|
||||
var dupeFreeRemoteEpisodes = remoteEpisodes.DistinctBy(m => new { m.SeasonNumber, m.EpisodeNumber }).ToList();
|
||||
|
||||
if (series.SeriesType == SeriesTypes.Anime)
|
||||
{
|
||||
dupeFreeRemoteEpisodes = MapAbsoluteEpisodeNumbers(dupeFreeRemoteEpisodes);
|
||||
}
|
||||
|
||||
foreach (var episode in OrderEpisodes(series, dupeFreeRemoteEpisodes))
|
||||
{
|
||||
try
|
||||
{
|
||||
var episodeToUpdate = GetEpisodeToUpdate(series, episode, existingEpisodes);
|
||||
|
||||
if (episodeToUpdate != null)
|
||||
{
|
||||
existingEpisodes.Remove(episodeToUpdate);
|
||||
updateList.Add(episodeToUpdate);
|
||||
}
|
||||
else
|
||||
{
|
||||
episodeToUpdate = new Episode();
|
||||
episodeToUpdate.Monitored = GetMonitoredStatus(episode, seasons);
|
||||
newList.Add(episodeToUpdate);
|
||||
}
|
||||
|
||||
episodeToUpdate.SeriesId = series.Id;
|
||||
episodeToUpdate.EpisodeNumber = episode.EpisodeNumber;
|
||||
episodeToUpdate.SeasonNumber = episode.SeasonNumber;
|
||||
episodeToUpdate.AbsoluteEpisodeNumber = episode.AbsoluteEpisodeNumber;
|
||||
episodeToUpdate.Title = episode.Title ?? "TBA";
|
||||
episodeToUpdate.Overview = episode.Overview;
|
||||
episodeToUpdate.AirDate = episode.AirDate;
|
||||
episodeToUpdate.AirDateUtc = episode.AirDateUtc;
|
||||
episodeToUpdate.Ratings = episode.Ratings;
|
||||
episodeToUpdate.Images = episode.Images;
|
||||
|
||||
successCount++;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Fatal(e, "An error has occurred while updating episode info for series {0}. {1}", series, episode);
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
var allEpisodes = new List<Episode>();
|
||||
allEpisodes.AddRange(newList);
|
||||
allEpisodes.AddRange(updateList);
|
||||
|
||||
AdjustMultiEpisodeAirTime(series, allEpisodes);
|
||||
AdjustDirectToDvdAirDate(series, allEpisodes);
|
||||
|
||||
_episodeService.DeleteMany(existingEpisodes);
|
||||
_episodeService.UpdateMany(updateList);
|
||||
_episodeService.InsertMany(newList);
|
||||
|
||||
_eventAggregator.PublishEvent(new EpisodeInfoRefreshedEvent(series, newList, updateList));
|
||||
|
||||
if (failCount != 0)
|
||||
{
|
||||
_logger.Info("Finished episode refresh for series: {0}. Successful: {1} - Failed: {2} ",
|
||||
series.Title, successCount, failCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Info("Finished episode refresh for series: {0}.", series);
|
||||
}
|
||||
}
|
||||
|
||||
private bool GetMonitoredStatus(Episode episode, IEnumerable<Season> seasons)
|
||||
{
|
||||
if (episode.EpisodeNumber == 0 && episode.SeasonNumber != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var season = seasons.SingleOrDefault(c => c.SeasonNumber == episode.SeasonNumber);
|
||||
return season == null || season.Monitored;
|
||||
}
|
||||
|
||||
private void AdjustMultiEpisodeAirTime(Series series, IEnumerable<Episode> allEpisodes)
|
||||
{
|
||||
if (series.Network == "Netflix")
|
||||
{
|
||||
_logger.Debug("Not adjusting episode air times for Netflix series {0}", series.Title);
|
||||
return;
|
||||
}
|
||||
|
||||
var groups = allEpisodes.Where(c => c.AirDateUtc.HasValue)
|
||||
.GroupBy(e => new { e.SeasonNumber, e.AirDate })
|
||||
.Where(g => g.Count() > 1)
|
||||
.ToList();
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var episodeCount = 0;
|
||||
|
||||
foreach (var episode in group.OrderBy(e => e.SeasonNumber).ThenBy(e => e.EpisodeNumber))
|
||||
{
|
||||
episode.AirDateUtc = episode.AirDateUtc.Value.AddMinutes(series.Runtime * episodeCount);
|
||||
episodeCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AdjustDirectToDvdAirDate(Series series, IEnumerable<Episode> allEpisodes)
|
||||
{
|
||||
if (series.Status == SeriesStatusType.Ended && allEpisodes.All(v => !v.AirDateUtc.HasValue) && series.FirstAired.HasValue)
|
||||
{
|
||||
foreach (var episode in allEpisodes)
|
||||
{
|
||||
episode.AirDateUtc = series.FirstAired;
|
||||
episode.AirDate = series.FirstAired.Value.ToString("yyyy-MM-dd");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Episode> MapAbsoluteEpisodeNumbers(List<Episode> remoteEpisodes)
|
||||
{
|
||||
//Return all episodes with no abs number, but distinct for those with abs number
|
||||
return remoteEpisodes.Where(e => e.AbsoluteEpisodeNumber.HasValue)
|
||||
.OrderByDescending(e => e.SeasonNumber)
|
||||
.DistinctBy(e => e.AbsoluteEpisodeNumber.Value)
|
||||
.Concat(remoteEpisodes.Where(e => !e.AbsoluteEpisodeNumber.HasValue))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private Episode GetEpisodeToUpdate(Series series, Episode episode, List<Episode> existingEpisodes)
|
||||
{
|
||||
if (series.SeriesType == SeriesTypes.Anime)
|
||||
{
|
||||
if (episode.AbsoluteEpisodeNumber.HasValue)
|
||||
{
|
||||
var matchingEpisode = existingEpisodes.FirstOrDefault(e => e.AbsoluteEpisodeNumber == episode.AbsoluteEpisodeNumber);
|
||||
|
||||
if (matchingEpisode != null) return matchingEpisode;
|
||||
}
|
||||
}
|
||||
|
||||
return existingEpisodes.FirstOrDefault(e => e.SeasonNumber == episode.SeasonNumber && e.EpisodeNumber == episode.EpisodeNumber);
|
||||
}
|
||||
|
||||
private IEnumerable<Episode> OrderEpisodes(Series series, List<Episode> episodes)
|
||||
{
|
||||
if (series.SeriesType == SeriesTypes.Anime)
|
||||
{
|
||||
var withAbs = episodes.Where(e => e.AbsoluteEpisodeNumber.HasValue)
|
||||
.OrderBy(e => e.AbsoluteEpisodeNumber);
|
||||
|
||||
var withoutAbs = episodes.Where(e => !e.AbsoluteEpisodeNumber.HasValue)
|
||||
.OrderBy(e => e.SeasonNumber)
|
||||
.ThenBy(e => e.EpisodeNumber);
|
||||
|
||||
return withAbs.Concat(withoutAbs);
|
||||
}
|
||||
|
||||
return episodes.OrderBy(e => e.SeasonNumber).ThenBy(e => e.EpisodeNumber);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.DataAugmentation.DailySeries;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Tv.Commands;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class RefreshSeriesService : IExecute<RefreshSeriesCommand>
|
||||
{
|
||||
private readonly ISeriesService _seriesService;
|
||||
private readonly IRefreshEpisodeService _refreshEpisodeService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IDailySeriesService _dailySeriesService;
|
||||
private readonly IDiskScanService _diskScanService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public RefreshSeriesService(ISeriesService seriesService,
|
||||
IRefreshEpisodeService refreshEpisodeService,
|
||||
IEventAggregator eventAggregator,
|
||||
IDailySeriesService dailySeriesService,
|
||||
IDiskScanService diskScanService,
|
||||
Logger logger)
|
||||
{
|
||||
_seriesService = seriesService;
|
||||
_refreshEpisodeService = refreshEpisodeService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_dailySeriesService = dailySeriesService;
|
||||
_diskScanService = diskScanService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
||||
private List<Season> UpdateSeasons(Series series, Series seriesInfo)
|
||||
{
|
||||
var seasons = seriesInfo.Seasons.DistinctBy(s => s.SeasonNumber).ToList();
|
||||
|
||||
foreach (var season in seasons)
|
||||
{
|
||||
var existingSeason = series.Seasons.FirstOrDefault(s => s.SeasonNumber == season.SeasonNumber);
|
||||
|
||||
//Todo: Should this should use the previous season's monitored state?
|
||||
if (existingSeason == null)
|
||||
{
|
||||
if (season.SeasonNumber == 0)
|
||||
{
|
||||
season.Monitored = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.Debug("New season ({0}) for series: [{1}] {2}, setting monitored to true", season.SeasonNumber, series.TvdbId, series.Title);
|
||||
season.Monitored = true;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
season.Monitored = existingSeason.Monitored;
|
||||
}
|
||||
}
|
||||
|
||||
return seasons;
|
||||
}
|
||||
|
||||
public void Execute(RefreshSeriesCommand message)
|
||||
{
|
||||
_eventAggregator.PublishEvent(new SeriesRefreshStartingEvent(message.Trigger == CommandTrigger.Manual));
|
||||
|
||||
if (message.SeriesId.HasValue)
|
||||
{
|
||||
var series = _seriesService.GetSeries(message.SeriesId.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
var allSeries = _seriesService.GetAllSeries().OrderBy(c => c.SortTitle).ToList();
|
||||
|
||||
foreach (var series in allSeries)
|
||||
{
|
||||
if (message.Trigger == CommandTrigger.Manual)
|
||||
{
|
||||
try
|
||||
{
|
||||
//RefreshSeriesInfo(series);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(e, "Couldn't refresh info for {0}", series);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.Info("Skipping refresh of series: {0}", series.Title);
|
||||
//_diskScanService.Scan(series);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(e, "Couldn't rescan series {0}", series);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class Season : IEmbeddedDocument
|
||||
{
|
||||
public Season()
|
||||
{
|
||||
Images = new List<MediaCover.MediaCover>();
|
||||
}
|
||||
|
||||
public int SeasonNumber { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public List<MediaCover.MediaCover> Images { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Marr.Data;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class Series : ModelBase
|
||||
{
|
||||
public Series()
|
||||
{
|
||||
Images = new List<MediaCover.MediaCover>();
|
||||
Genres = new List<string>();
|
||||
Actors = new List<Actor>();
|
||||
Seasons = new List<Season>();
|
||||
Tags = new HashSet<int>();
|
||||
}
|
||||
|
||||
public int TvdbId { get; set; }
|
||||
public int TvRageId { get; set; }
|
||||
public int TvMazeId { get; set; }
|
||||
public string ImdbId { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string CleanTitle { get; set; }
|
||||
public string SortTitle { get; set; }
|
||||
public SeriesStatusType Status { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public string AirTime { get; set; }
|
||||
public bool Monitored { get; set; }
|
||||
public int ProfileId { get; set; }
|
||||
public int LanguageProfileId { get; set; }
|
||||
public bool SeasonFolder { get; set; }
|
||||
public DateTime? LastInfoSync { get; set; }
|
||||
public int Runtime { get; set; }
|
||||
public List<MediaCover.MediaCover> Images { get; set; }
|
||||
public SeriesTypes SeriesType { get; set; }
|
||||
public string Network { get; set; }
|
||||
public bool UseSceneNumbering { get; set; }
|
||||
public string TitleSlug { get; set; }
|
||||
public string Path { get; set; }
|
||||
public int Year { get; set; }
|
||||
public Ratings Ratings { get; set; }
|
||||
public List<string> Genres { get; set; }
|
||||
public List<Actor> Actors { get; set; }
|
||||
public string Certification { get; set; }
|
||||
public string RootFolderPath { get; set; }
|
||||
public DateTime Added { get; set; }
|
||||
public DateTime? FirstAired { get; set; }
|
||||
public LazyLoaded<Profile> Profile { get; set; }
|
||||
public LazyLoaded<LanguageProfile> LanguageProfile { get; set; }
|
||||
|
||||
public List<Season> Seasons { get; set; }
|
||||
public HashSet<int> Tags { get; set; }
|
||||
public AddSeriesOptions AddOptions { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[{0}][{1}]", TvdbId, Title.NullSafe());
|
||||
}
|
||||
|
||||
public void ApplyChanges(Series otherSeries)
|
||||
{
|
||||
TvdbId = otherSeries.TvdbId;
|
||||
|
||||
Seasons = otherSeries.Seasons;
|
||||
Path = otherSeries.Path;
|
||||
ProfileId = otherSeries.ProfileId;
|
||||
LanguageProfileId = otherSeries.LanguageProfileId;
|
||||
|
||||
SeasonFolder = otherSeries.SeasonFolder;
|
||||
Monitored = otherSeries.Monitored;
|
||||
|
||||
SeriesType = otherSeries.SeriesType;
|
||||
RootFolderPath = otherSeries.RootFolderPath;
|
||||
Tags = otherSeries.Tags;
|
||||
AddOptions = otherSeries.AddOptions;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
using System.Linq;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv.Commands;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class SeriesAddedHandler : IHandle<SeriesAddedEvent>,
|
||||
IHandle<SeriesImportedEvent>
|
||||
{
|
||||
private readonly IManageCommandQueue _commandQueueManager;
|
||||
|
||||
public SeriesAddedHandler(IManageCommandQueue commandQueueManager)
|
||||
{
|
||||
_commandQueueManager = commandQueueManager;
|
||||
}
|
||||
|
||||
public void Handle(SeriesAddedEvent message)
|
||||
{
|
||||
_commandQueueManager.Push(new RefreshSeriesCommand(message.Series.Id));
|
||||
}
|
||||
|
||||
public void Handle(SeriesImportedEvent message)
|
||||
{
|
||||
_commandQueueManager.PushMany(message.SeriesIds.Select(s => new RefreshSeriesCommand(s)).ToList());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv.Commands;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class SeriesEditedService : IHandle<SeriesEditedEvent>
|
||||
{
|
||||
private readonly IManageCommandQueue _commandQueueManager;
|
||||
|
||||
public SeriesEditedService(IManageCommandQueue commandQueueManager)
|
||||
{
|
||||
_commandQueueManager = commandQueueManager;
|
||||
}
|
||||
|
||||
public void Handle(SeriesEditedEvent message)
|
||||
{
|
||||
if (message.Series.SeriesType != message.OldSeries.SeriesType)
|
||||
{
|
||||
_commandQueueManager.Push(new RefreshSeriesCommand(message.Series.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
using System.Linq;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public interface ISeriesRepository : IBasicRepository<Series>
|
||||
{
|
||||
bool SeriesPathExists(string path);
|
||||
Series FindByTitle(string cleanTitle);
|
||||
Series FindByTitle(string cleanTitle, int year);
|
||||
Series FindByTvdbId(int tvdbId);
|
||||
Series FindByTvRageId(int tvRageId);
|
||||
}
|
||||
|
||||
public class SeriesRepository : BasicRepository<Series>, ISeriesRepository
|
||||
{
|
||||
public SeriesRepository(IMainDatabase database, IEventAggregator eventAggregator)
|
||||
: base(database, eventAggregator)
|
||||
{
|
||||
}
|
||||
|
||||
public bool SeriesPathExists(string path)
|
||||
{
|
||||
return Query.Where(c => c.Path == path).Any();
|
||||
}
|
||||
|
||||
public Series FindByTitle(string cleanTitle)
|
||||
{
|
||||
cleanTitle = cleanTitle.ToLowerInvariant();
|
||||
|
||||
return Query.Where(s => s.CleanTitle == cleanTitle)
|
||||
.SingleOrDefault();
|
||||
}
|
||||
|
||||
public Series FindByTitle(string cleanTitle, int year)
|
||||
{
|
||||
cleanTitle = cleanTitle.ToLowerInvariant();
|
||||
|
||||
return Query.Where(s => s.CleanTitle == cleanTitle)
|
||||
.AndWhere(s => s.Year == year)
|
||||
.SingleOrDefault();
|
||||
}
|
||||
|
||||
public Series FindByTvdbId(int tvdbId)
|
||||
{
|
||||
return Query.Where(s => s.TvdbId == tvdbId).SingleOrDefault();
|
||||
}
|
||||
|
||||
public Series FindByTvRageId(int tvRageId)
|
||||
{
|
||||
return Query.Where(s => s.TvRageId == tvRageId).SingleOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,229 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public interface ISeriesService
|
||||
{
|
||||
Series GetSeries(int seriesId);
|
||||
List<Series> GetSeries(IEnumerable<int> seriesIds);
|
||||
Series AddSeries(Series newSeries);
|
||||
List<Series> AddSeries(List<Series> newSeries);
|
||||
Series FindByTvdbId(int tvdbId);
|
||||
Series FindByTvRageId(int tvRageId);
|
||||
Series FindByTitle(string title);
|
||||
Series FindByTitle(string title, int year);
|
||||
Series FindByTitleInexact(string title);
|
||||
void DeleteSeries(int seriesId, bool deleteFiles);
|
||||
List<Series> GetAllSeries();
|
||||
List<Series> AllForTag(int tagId);
|
||||
Series UpdateSeries(Series series);
|
||||
List<Series> UpdateSeries(List<Series> series);
|
||||
bool SeriesPathExists(string folder);
|
||||
void RemoveAddOptions(Series series);
|
||||
}
|
||||
|
||||
public class SeriesService : ISeriesService
|
||||
{
|
||||
private readonly ISeriesRepository _seriesRepository;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
// private readonly ISceneMappingService _sceneMappingService;
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly IBuildFileNames _fileNameBuilder;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public SeriesService(ISeriesRepository seriesRepository,
|
||||
IEventAggregator eventAggregator,
|
||||
// ISceneMappingService sceneMappingService,
|
||||
IEpisodeService episodeService,
|
||||
IBuildFileNames fileNameBuilder,
|
||||
Logger logger)
|
||||
{
|
||||
_seriesRepository = seriesRepository;
|
||||
_eventAggregator = eventAggregator;
|
||||
//_sceneMappingService = sceneMappingService;
|
||||
_episodeService = episodeService;
|
||||
_fileNameBuilder = fileNameBuilder;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Series GetSeries(int seriesId)
|
||||
{
|
||||
return _seriesRepository.Get(seriesId);
|
||||
}
|
||||
|
||||
public List<Series> GetSeries(IEnumerable<int> seriesIds)
|
||||
{
|
||||
return _seriesRepository.Get(seriesIds).ToList();
|
||||
}
|
||||
|
||||
public Series AddSeries(Series newSeries)
|
||||
{
|
||||
_seriesRepository.Insert(newSeries);
|
||||
_eventAggregator.PublishEvent(new SeriesAddedEvent(GetSeries(newSeries.Id)));
|
||||
|
||||
return newSeries;
|
||||
}
|
||||
|
||||
public List<Series> AddSeries(List<Series> newSeries)
|
||||
{
|
||||
_seriesRepository.InsertMany(newSeries);
|
||||
_eventAggregator.PublishEvent(new SeriesImportedEvent(newSeries.Select(s => s.Id).ToList()));
|
||||
|
||||
return newSeries;
|
||||
}
|
||||
|
||||
public Series FindByTvdbId(int tvRageId)
|
||||
{
|
||||
return _seriesRepository.FindByTvdbId(tvRageId);
|
||||
}
|
||||
|
||||
public Series FindByTvRageId(int tvRageId)
|
||||
{
|
||||
return _seriesRepository.FindByTvRageId(tvRageId);
|
||||
}
|
||||
|
||||
public Series FindByTitle(string title)
|
||||
{
|
||||
//var tvdbId = _sceneMappingService.FindTvdbId(title);
|
||||
|
||||
//if (tvdbId.HasValue)
|
||||
//{
|
||||
// return _seriesRepository.FindByTvdbId(tvdbId.Value);
|
||||
//}
|
||||
|
||||
return _seriesRepository.FindByTitle(title.CleanSeriesTitle());
|
||||
}
|
||||
|
||||
public Series FindByTitleInexact(string title)
|
||||
{
|
||||
// find any series clean title within the provided release title
|
||||
string cleanTitle = title.CleanSeriesTitle();
|
||||
var list = _seriesRepository.All().Where(s => cleanTitle.Contains(s.CleanTitle)).ToList();
|
||||
if (!list.Any())
|
||||
{
|
||||
// no series matched
|
||||
return null;
|
||||
}
|
||||
if (list.Count == 1)
|
||||
{
|
||||
// return the first series if there is only one
|
||||
return list.Single();
|
||||
}
|
||||
// build ordered list of series by position in the search string
|
||||
var query =
|
||||
list.Select(series => new
|
||||
{
|
||||
position = cleanTitle.IndexOf(series.CleanTitle),
|
||||
length = series.CleanTitle.Length,
|
||||
series = series
|
||||
})
|
||||
.Where(s => (s.position>=0))
|
||||
.ToList()
|
||||
.OrderBy(s => s.position)
|
||||
.ThenByDescending(s => s.length)
|
||||
.ToList();
|
||||
|
||||
// get the leftmost series that is the longest
|
||||
// series are usually the first thing in release title, so we select the leftmost and longest match
|
||||
var match = query.First().series;
|
||||
|
||||
_logger.Debug("Multiple series matched {0} from title {1}", match.Title, title);
|
||||
foreach (var entry in list)
|
||||
{
|
||||
_logger.Debug("Multiple series match candidate: {0} cleantitle: {1}", entry.Title, entry.CleanTitle);
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
public Series FindByTitle(string title, int year)
|
||||
{
|
||||
return _seriesRepository.FindByTitle(title.CleanSeriesTitle(), year);
|
||||
}
|
||||
|
||||
public void DeleteSeries(int seriesId, bool deleteFiles)
|
||||
{
|
||||
var series = _seriesRepository.Get(seriesId);
|
||||
_seriesRepository.Delete(seriesId);
|
||||
_eventAggregator.PublishEvent(new SeriesDeletedEvent(series, deleteFiles));
|
||||
}
|
||||
|
||||
public List<Series> GetAllSeries()
|
||||
{
|
||||
return _seriesRepository.All().ToList();
|
||||
}
|
||||
|
||||
public List<Series> AllForTag(int tagId)
|
||||
{
|
||||
return GetAllSeries().Where(s => s.Tags.Contains(tagId))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
public Series UpdateSeries(Series series)
|
||||
{
|
||||
var storedSeries = GetSeries(series.Id);
|
||||
|
||||
foreach (var season in series.Seasons)
|
||||
{
|
||||
var storedSeason = storedSeries.Seasons.SingleOrDefault(s => s.SeasonNumber == season.SeasonNumber);
|
||||
|
||||
if (storedSeason != null && season.Monitored != storedSeason.Monitored)
|
||||
{
|
||||
_episodeService.SetEpisodeMonitoredBySeason(series.Id, season.SeasonNumber, season.Monitored);
|
||||
}
|
||||
}
|
||||
|
||||
var updatedSeries = _seriesRepository.Update(series);
|
||||
_eventAggregator.PublishEvent(new SeriesEditedEvent(updatedSeries, storedSeries));
|
||||
|
||||
return updatedSeries;
|
||||
}
|
||||
|
||||
public List<Series> UpdateSeries(List<Series> series)
|
||||
{
|
||||
_logger.Debug("Updating {0} series", series.Count);
|
||||
foreach (var s in series)
|
||||
{
|
||||
_logger.Trace("Updating: {0}", s.Title);
|
||||
if (!s.RootFolderPath.IsNullOrWhiteSpace())
|
||||
{
|
||||
var folderName = new DirectoryInfo(s.Path).Name;
|
||||
s.Path = Path.Combine(s.RootFolderPath, folderName);
|
||||
_logger.Trace("Changing path for {0} to {1}", s.Title, s.Path);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
_logger.Trace("Not changing path for: {0}", s.Title);
|
||||
}
|
||||
}
|
||||
|
||||
_seriesRepository.UpdateMany(series);
|
||||
_logger.Debug("{0} series updated", series.Count);
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
public bool SeriesPathExists(string folder)
|
||||
{
|
||||
return _seriesRepository.SeriesPathExists(folder);
|
||||
}
|
||||
|
||||
public void RemoveAddOptions(Series series)
|
||||
{
|
||||
_seriesRepository.SetFields(series, s => s.AddOptions);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public enum SeriesStatusType
|
||||
{
|
||||
Continuing = 0,
|
||||
Ended = 1
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public static class SeriesTitleNormalizer
|
||||
{
|
||||
private readonly static Dictionary<int, string> PreComputedTitles = new Dictionary<int, string>
|
||||
{
|
||||
{ 281588, "a to z" },
|
||||
{ 266757, "ad trials triumph early church" },
|
||||
{ 289260, "ad bible continues"}
|
||||
};
|
||||
|
||||
public static string Normalize(string title, int tvdbId)
|
||||
{
|
||||
if (PreComputedTitles.ContainsKey(tvdbId))
|
||||
{
|
||||
return PreComputedTitles[tvdbId];
|
||||
}
|
||||
|
||||
return Parser.Parser.NormalizeTitle(title).ToLower();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
using FluentValidation.Validators;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class SeriesTitleSlugValidator : PropertyValidator
|
||||
{
|
||||
private readonly ISeriesService _seriesService;
|
||||
|
||||
public SeriesTitleSlugValidator(ISeriesService seriesService)
|
||||
: base("Title slug is in use by another series with a similar name")
|
||||
{
|
||||
_seriesService = seriesService;
|
||||
}
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
if (context.PropertyValue == null) return true;
|
||||
|
||||
dynamic instance = context.ParentContext.InstanceToValidate;
|
||||
var instanceId = (int)instance.Id;
|
||||
|
||||
return !_seriesService.GetAllSeries().Exists(s => s.TitleSlug.Equals(context.PropertyValue.ToString()) && s.Id != instanceId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public enum SeriesTypes
|
||||
{
|
||||
Standard = 0,
|
||||
Daily = 1,
|
||||
Anime = 2,
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue