diff --git a/src/NzbDrone.Api/Episodes/EpisodeResource.cs b/src/NzbDrone.Api/Episodes/EpisodeResource.cs index 6338afaab..844562337 100644 --- a/src/NzbDrone.Api/Episodes/EpisodeResource.cs +++ b/src/NzbDrone.Api/Episodes/EpisodeResource.cs @@ -20,11 +20,11 @@ namespace NzbDrone.Api.Episodes public Boolean HasFile { get; set; } public Boolean Monitored { get; set; } + public Nullable AbsoluteEpisodeNumber { get; set; } public Nullable SceneAbsoluteEpisodeNumber { get; set; } - public Int32 SceneEpisodeNumber { get; set; } - public Int32 SceneSeasonNumber { get; set; } + public Nullable SceneEpisodeNumber { get; set; } + public Nullable SceneSeasonNumber { get; set; } public Int32 TvDbEpisodeId { get; set; } - public Int32? AbsoluteEpisodeNumber { get; set; } public DateTime? EndTime { get; set; } public DateTime? GrabDate { get; set; } public String SeriesTitle { get; set; } diff --git a/src/NzbDrone.Core.Test/IndexerSearchTests/NzbSearchServiceFixture.cs b/src/NzbDrone.Core.Test/IndexerSearchTests/NzbSearchServiceFixture.cs index ffc9f68a1..82e571166 100644 --- a/src/NzbDrone.Core.Test/IndexerSearchTests/NzbSearchServiceFixture.cs +++ b/src/NzbDrone.Core.Test/IndexerSearchTests/NzbSearchServiceFixture.cs @@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests .Returns(new List()); } - private void WithEpisode(int seasonNumber, int episodeNumber, int sceneSeasonNumber, int sceneEpisodeNumber) + private void WithEpisode(Int32 seasonNumber, Int32 episodeNumber, Int32? sceneSeasonNumber, Int32? sceneEpisodeNumber) { var episode = Builder.CreateNew() .With(v => v.SeriesId == _xemSeries.Id) @@ -90,8 +90,8 @@ namespace NzbDrone.Core.Test.IndexerSearchTests WithEpisode(5, 1, 6, 12); // Season 7+ maps normally, so no mapping specified. - WithEpisode(7, 1, 0, 0); - WithEpisode(7, 2, 0, 0); + WithEpisode(7, 1, null, null); + WithEpisode(7, 2, null, null); } private List WatchForSearchCriteria() diff --git a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderFixture.cs b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderFixture.cs index b194c4e70..f12f3808b 100644 --- a/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderFixture.cs +++ b/src/NzbDrone.Core.Test/OrganizerTests/FileNameBuilderFixture.cs @@ -530,10 +530,10 @@ namespace NzbDrone.Core.Test.OrganizerTests } [Test] - public void should_use_standard_naming_when_anime_episode_has_absolute_number_of_zero() + public void should_use_standard_naming_when_anime_episode_has_no_absolute_number() { _series.SeriesType = SeriesTypes.Anime; - _episode1.AbsoluteEpisodeNumber = 0; + _episode1.AbsoluteEpisodeNumber = null; _namingConfig.StandardEpisodeFormat = "{Series Title} - {season:0}x{episode:00} - {Episode Title}"; _namingConfig.AnimeEpisodeFormat = "{Series Title} - {absolute:000} - {Episode Title}"; diff --git a/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs b/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs index 685e995e0..29730bb60 100644 --- a/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs +++ b/src/NzbDrone.Core.Test/TvTests/EpisodeRepositoryTests/FindEpisodeFixture.cs @@ -39,7 +39,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests [Test] public void should_find_episode_by_scene_numbering() { - Subject.FindEpisodesBySceneNumbering(_episode1.SeriesId, _episode1.SceneSeasonNumber, _episode1.SceneEpisodeNumber) + Subject.FindEpisodesBySceneNumbering(_episode1.SeriesId, _episode1.SceneSeasonNumber.Value, _episode1.SceneEpisodeNumber.Value) .First() .Id .Should() @@ -77,7 +77,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests { _episode2 = Db.Insert(_episode2); - Subject.FindEpisodesBySceneNumbering(_episode1.SeriesId, _episode1.SceneSeasonNumber, _episode1.SceneEpisodeNumber) + Subject.FindEpisodesBySceneNumbering(_episode1.SeriesId, _episode1.SceneSeasonNumber.Value, _episode1.SceneEpisodeNumber.Value) .Should() .HaveCount(2); } diff --git a/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs b/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs index bdada91a1..1d1374bfe 100644 --- a/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs +++ b/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs @@ -183,7 +183,7 @@ namespace NzbDrone.Core.Test.TvTests Subject.RefreshEpisodeInfo(GetSeries(), GetEpisodes()); - _insertedEpisodes.All(e => e.AbsoluteEpisodeNumber == 0 || !e.AbsoluteEpisodeNumber.HasValue).Should().BeTrue(); + _insertedEpisodes.All(e => !e.AbsoluteEpisodeNumber.HasValue).Should().BeTrue(); } [Test] @@ -197,7 +197,7 @@ namespace NzbDrone.Core.Test.TvTests Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes); - _insertedEpisodes.All(e => e.AbsoluteEpisodeNumber > 0).Should().BeTrue(); + _insertedEpisodes.All(e => e.AbsoluteEpisodeNumber.HasValue).Should().BeTrue(); _updatedEpisodes.Should().BeEmpty(); _deletedEpisodes.Should().BeEmpty(); } @@ -209,7 +209,7 @@ namespace NzbDrone.Core.Test.TvTests GivenAnimeEpisodes(episodes); var existingEpisodes = episodes.JsonClone(); - existingEpisodes.ForEach(e => e.AbsoluteEpisodeNumber = 0); + existingEpisodes.ForEach(e => e.AbsoluteEpisodeNumber = null); Mocker.GetMock().Setup(c => c.GetEpisodeBySeries(It.IsAny())) .Returns(existingEpisodes); @@ -217,7 +217,7 @@ namespace NzbDrone.Core.Test.TvTests Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes); _insertedEpisodes.Should().BeEmpty(); - _updatedEpisodes.All(e => e.AbsoluteEpisodeNumber > 0).Should().BeTrue(); + _updatedEpisodes.All(e => e.AbsoluteEpisodeNumber.HasValue).Should().BeTrue(); _deletedEpisodes.Should().BeEmpty(); } @@ -261,10 +261,9 @@ namespace NzbDrone.Core.Test.TvTests .Build() .ToList(); - episodes[0].AbsoluteEpisodeNumber = 0; + episodes[0].AbsoluteEpisodeNumber = null; episodes[0].SeasonNumber.Should().NotBe(episodes[1].SeasonNumber); episodes[0].EpisodeNumber.Should().NotBe(episodes[1].EpisodeNumber); - episodes[0].AbsoluteEpisodeNumber.Should().NotBe(episodes[1].AbsoluteEpisodeNumber); GivenAnimeEpisodes(episodes); @@ -286,17 +285,17 @@ namespace NzbDrone.Core.Test.TvTests } [Test] - public void should_ignore_episodes_with_absolute_episode_of_zero_in_distinct_by_absolute() + public void should_ignore_episodes_with_no_absolute_episode_in_distinct_by_absolute() { var episodes = Builder.CreateListOfSize(10) .Build() .ToList(); - episodes[0].AbsoluteEpisodeNumber = 0; - episodes[1].AbsoluteEpisodeNumber = 0; - episodes[2].AbsoluteEpisodeNumber = 0; - episodes[3].AbsoluteEpisodeNumber = 0; - episodes[4].AbsoluteEpisodeNumber = 0; + episodes[0].AbsoluteEpisodeNumber = null; + episodes[1].AbsoluteEpisodeNumber = null; + episodes[2].AbsoluteEpisodeNumber = null; + episodes[3].AbsoluteEpisodeNumber = null; + episodes[4].AbsoluteEpisodeNumber = null; GivenAnimeEpisodes(episodes); diff --git a/src/NzbDrone.Core/DataAugmentation/Xem/XemService.cs b/src/NzbDrone.Core/DataAugmentation/Xem/XemService.cs index 4b9b4e43e..aa76bbd6f 100644 --- a/src/NzbDrone.Core/DataAugmentation/Xem/XemService.cs +++ b/src/NzbDrone.Core/DataAugmentation/Xem/XemService.cs @@ -49,9 +49,9 @@ namespace NzbDrone.Core.DataAugmentation.Xem foreach (var episode in episodes) { - episode.SceneAbsoluteEpisodeNumber = 0; - episode.SceneSeasonNumber = 0; - episode.SceneEpisodeNumber = 0; + episode.SceneAbsoluteEpisodeNumber = null; + episode.SceneSeasonNumber = null; + episode.SceneEpisodeNumber = null; } foreach (var mapping in mappings) diff --git a/src/NzbDrone.Core/Datastore/Migration/065_make_scene_numbering_nullable.cs b/src/NzbDrone.Core/Datastore/Migration/065_make_scene_numbering_nullable.cs new file mode 100644 index 000000000..7936f04dd --- /dev/null +++ b/src/NzbDrone.Core/Datastore/Migration/065_make_scene_numbering_nullable.cs @@ -0,0 +1,16 @@ +using FluentMigrator; +using NzbDrone.Core.Datastore.Migration.Framework; + +namespace NzbDrone.Core.Datastore.Migration +{ + [Migration(65)] + public class make_scene_numbering_nullable : NzbDroneMigrationBase + { + protected override void MainDbUpgrade() + { + Execute.Sql("UPDATE Episodes SET AbsoluteEpisodeNumber = NULL WHERE AbsoluteEpisodeNumber = 0"); + Execute.Sql("UPDATE Episodes SET SceneAbsoluteEpisodeNumber = NULL WHERE SceneAbsoluteEpisodeNumber = 0"); + Execute.Sql("UPDATE Episodes SET SceneSeasonNumber = NULL, SceneEpisodeNumber = NULL WHERE SceneSeasonNumber = 0 AND SceneEpisodeNumber = 0"); + } + } +} diff --git a/src/NzbDrone.Core/Download/DownloadTrackingService.cs b/src/NzbDrone.Core/Download/DownloadTrackingService.cs index 6c75cf476..6038f2f13 100644 --- a/src/NzbDrone.Core/Download/DownloadTrackingService.cs +++ b/src/NzbDrone.Core/Download/DownloadTrackingService.cs @@ -139,32 +139,24 @@ namespace NzbDrone.Core.Download var downloadClientHistory = downloadClient.GetItems().ToList(); foreach (var downloadItem in downloadClientHistory) { - try + var trackingId = String.Format("{0}-{1}", downloadClient.Definition.Id, downloadItem.DownloadClientId); + TrackedDownload trackedDownload; + + if (newTrackedDownloads.ContainsKey(trackingId)) continue; + + if (!oldTrackedDownloads.TryGetValue(trackingId, out trackedDownload)) { - var trackingId = String.Format("{0}-{1}", downloadClient.Definition.Id, downloadItem.DownloadClientId); - TrackedDownload trackedDownload; + trackedDownload = GetTrackedDownload(trackingId, downloadClient.Definition.Id, downloadItem, grabbedHistory); - if (newTrackedDownloads.ContainsKey(trackingId)) continue; + if (trackedDownload == null) continue; - if (!oldTrackedDownloads.TryGetValue(trackingId, out trackedDownload)) - { - trackedDownload = GetTrackedDownload(trackingId, downloadClient.Definition.Id, downloadItem, - grabbedHistory); - - if (trackedDownload == null) continue; - - _logger.Debug("[{0}] Started tracking download with id {1}.", downloadItem.Title, trackingId); - stateChanged = true; - } - - trackedDownload.DownloadItem = downloadItem; - - newTrackedDownloads[trackingId] = trackedDownload; - } - catch (Exception e) - { - _logger.ErrorException("An error occured while tracking download." + downloadItem.Title, e); + _logger.Debug("[{0}] Started tracking download with id {1}.", downloadItem.Title, trackingId); + stateChanged = true; } + + trackedDownload.DownloadItem = downloadItem; + + newTrackedDownloads[trackingId] = trackedDownload; } } @@ -243,34 +235,42 @@ namespace NzbDrone.Core.Download Status = TrackedDownloadStatus.Ok, }; - var historyItems = grabbedHistory.Where(h => - { - var downloadClientId = h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID); - if (downloadClientId == null) return false; - - return downloadClientId.Equals(trackedDownload.DownloadItem.DownloadClientId); - }).ToList(); - - var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); - if (parsedEpisodeInfo == null) return null; - - var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0); - - if (remoteEpisode.Series == null) + try { - if (historyItems.Empty()) return null; + var historyItems = grabbedHistory.Where(h => + { + var downloadClientId = h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID); - trackedDownload.Status = TrackedDownloadStatus.Warning; - trackedDownload.StatusMessages.Add(new TrackedDownloadStatusMessage( - trackedDownload.DownloadItem.Title, - "Series title mismatch, automatic import is not possible") - ); + if (downloadClientId == null) return false; - remoteEpisode = _parsingService.Map(parsedEpisodeInfo, historyItems.First().SeriesId, historyItems.Select(h => h.EpisodeId)); + return downloadClientId.Equals(trackedDownload.DownloadItem.DownloadClientId); + }).ToList(); + + var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); + if (parsedEpisodeInfo == null) return null; + + var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0); + if (remoteEpisode.Series == null) + { + if (historyItems.Empty()) return null; + + trackedDownload.Status = TrackedDownloadStatus.Warning; + trackedDownload.StatusMessages.Add(new TrackedDownloadStatusMessage( + trackedDownload.DownloadItem.Title, + "Series title mismatch, automatic import is not possible") + ); + + remoteEpisode = _parsingService.Map(parsedEpisodeInfo, historyItems.First().SeriesId, historyItems.Select(h => h.EpisodeId)); + } + + trackedDownload.RemoteEpisode = remoteEpisode; + } + catch (Exception e) + { + _logger.DebugException("Failed to find episode for " + downloadItem.Title, e); + return null; } - - trackedDownload.RemoteEpisode = remoteEpisode; return trackedDownload; } diff --git a/src/NzbDrone.Core/Download/FailedDownloadService.cs b/src/NzbDrone.Core/Download/FailedDownloadService.cs index cf1f26081..a0d602c7b 100644 --- a/src/NzbDrone.Core/Download/FailedDownloadService.cs +++ b/src/NzbDrone.Core/Download/FailedDownloadService.cs @@ -103,7 +103,7 @@ namespace NzbDrone.Core.Download } else { - if (FailedDownloadForRecentRelease(downloadClient, trackedDownload, grabbedItems)) + if (FailedDownloadForRecentRelease(downloadClient, trackedDownload, grabbedItems)) { _logger.Debug("[{0}] Recent release Failed, do not blacklist.", trackedDownload.DownloadItem.Title); return; diff --git a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs index 304c37222..2e562939e 100644 --- a/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs +++ b/src/NzbDrone.Core/IndexerSearch/NzbSearchService.cs @@ -102,13 +102,14 @@ namespace NzbDrone.Core.IndexerSearch { var sceneSeasonGroups = episodes.GroupBy(v => { - if (v.SceneSeasonNumber == 0 && v.SceneEpisodeNumber == 0) + if (v.SceneSeasonNumber.HasValue && v.SceneEpisodeNumber.HasValue) + { + return v.SceneSeasonNumber.Value; + } + else { return v.SeasonNumber; } - - return v.SceneSeasonNumber; - }).Distinct(); foreach (var sceneSeasonEpisodes in sceneSeasonGroups) @@ -118,10 +119,10 @@ namespace NzbDrone.Core.IndexerSearch var episode = sceneSeasonEpisodes.First(); var searchSpec = Get(series, sceneSeasonEpisodes.ToList()); searchSpec.SeasonNumber = sceneSeasonEpisodes.Key; - if (episode.SceneSeasonNumber == 0 && episode.SceneEpisodeNumber == 0) - searchSpec.EpisodeNumber = episode.EpisodeNumber; + if (episode.SceneSeasonNumber.HasValue && episode.SceneEpisodeNumber.HasValue) + searchSpec.EpisodeNumber = episode.SceneEpisodeNumber.Value; else - searchSpec.EpisodeNumber = episode.SceneEpisodeNumber; + searchSpec.EpisodeNumber = episode.EpisodeNumber; var decisions = Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec); downloadDecisions.AddRange(decisions); @@ -152,19 +153,10 @@ namespace NzbDrone.Core.IndexerSearch { var searchSpec = Get(series, new List{episode}); - if (series.UseSceneNumbering) + if (series.UseSceneNumbering && episode.SceneSeasonNumber.HasValue && episode.SceneEpisodeNumber.HasValue) { - if (episode.SceneSeasonNumber > 0 && episode.SceneEpisodeNumber > 0) - { - searchSpec.EpisodeNumber = episode.SceneEpisodeNumber; - searchSpec.SeasonNumber = episode.SceneSeasonNumber; - } - - else - { - searchSpec.EpisodeNumber = episode.EpisodeNumber; - searchSpec.SeasonNumber = episode.SeasonNumber; - } + searchSpec.EpisodeNumber = episode.SceneEpisodeNumber.Value; + searchSpec.SeasonNumber = episode.SceneSeasonNumber.Value; } else { @@ -187,16 +179,18 @@ namespace NzbDrone.Core.IndexerSearch private List SearchAnime(Series series, Episode episode) { var searchSpec = Get(series, new List { episode }); - searchSpec.AbsoluteEpisodeNumber = episode.SceneAbsoluteEpisodeNumber.GetValueOrDefault(0); - if (searchSpec.AbsoluteEpisodeNumber == 0) + if (episode.SceneAbsoluteEpisodeNumber.HasValue) { - searchSpec.AbsoluteEpisodeNumber = episode.AbsoluteEpisodeNumber.GetValueOrDefault(0); + searchSpec.AbsoluteEpisodeNumber = episode.SceneAbsoluteEpisodeNumber.Value; } - - if (searchSpec.AbsoluteEpisodeNumber == 0) + else if (episode.AbsoluteEpisodeNumber.HasValue) { - throw new ArgumentOutOfRangeException("AbsoluteEpisodeNumber", "Can not search for an episode absolute episode number of zero"); + searchSpec.AbsoluteEpisodeNumber = episode.AbsoluteEpisodeNumber.Value; + } + else + { + throw new ArgumentOutOfRangeException("AbsoluteEpisodeNumber", "Can not search for an episode without an absolute episode number"); } return Dispatch(indexer => indexer.Fetch(searchSpec), searchSpec); @@ -232,7 +226,7 @@ namespace NzbDrone.Core.IndexerSearch spec.Series = series; spec.SceneTitles = _sceneMapping.GetSceneNames(series.TvdbId, episodes.Select(e => e.SeasonNumber) - .Concat(episodes.Select(e => e.SceneSeasonNumber) + .Concat(episodes.Select(e => e.SceneSeasonNumber.Value) .Distinct())); spec.Episodes = episodes; diff --git a/src/NzbDrone.Core/MetadataSource/Tvdb/TvdbProxy.cs b/src/NzbDrone.Core/MetadataSource/Tvdb/TvdbProxy.cs index 39a5772c7..36cf35f63 100644 --- a/src/NzbDrone.Core/MetadataSource/Tvdb/TvdbProxy.cs +++ b/src/NzbDrone.Core/MetadataSource/Tvdb/TvdbProxy.cs @@ -2,6 +2,7 @@ using System.IO; using System.Linq; using System.Xml.Linq; +using NzbDrone.Common; using NzbDrone.Common.Http; using NzbDrone.Core.Indexers; using NzbDrone.Core.Tv; @@ -39,7 +40,11 @@ namespace NzbDrone.Core.MetadataSource.Tvdb var episode = new Episode(); episode.SeasonNumber = item.TryGetValue("SeasonNumber", 0); episode.EpisodeNumber = item.TryGetValue("EpisodeNumber", 0); - episode.AbsoluteEpisodeNumber = item.TryGetValue("absolute_number", 0); + + if (item.TryGetValue("absolute_number").IsNotNullOrWhiteSpace()) + { + episode.AbsoluteEpisodeNumber = item.TryGetValue("absolute_number", 0); + } return episode; } diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index d617dda58..188ab2a4a 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -229,6 +229,7 @@ + diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index a5886d201..1229267cf 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -111,7 +111,7 @@ namespace NzbDrone.Core.Organizer pattern = namingConfig.DailyEpisodeFormat; } - if (series.SeriesType == SeriesTypes.Anime && episodes.All(e => e.AbsoluteEpisodeNumber > 0)) + if (series.SeriesType == SeriesTypes.Anime && episodes.All(e => e.AbsoluteEpisodeNumber.HasValue)) { pattern = namingConfig.AnimeEpisodeFormat; } diff --git a/src/NzbDrone.Core/Tv/Episode.cs b/src/NzbDrone.Core/Tv/Episode.cs index e564ee519..eeb7bf88b 100644 --- a/src/NzbDrone.Core/Tv/Episode.cs +++ b/src/NzbDrone.Core/Tv/Episode.cs @@ -27,8 +27,8 @@ namespace NzbDrone.Core.Tv public Boolean Monitored { get; set; } public Nullable AbsoluteEpisodeNumber { get; set; } public Nullable SceneAbsoluteEpisodeNumber { get; set; } - public int SceneSeasonNumber { get; set; } - public int SceneEpisodeNumber { get; set; } + public Nullable SceneSeasonNumber { get; set; } + public Nullable SceneEpisodeNumber { get; set; } public Ratings Ratings { get; set; } public List Images { get; set; } diff --git a/src/NzbDrone.Core/Tv/RefreshEpisodeService.cs b/src/NzbDrone.Core/Tv/RefreshEpisodeService.cs index 46b11c0f1..8808d02c5 100644 --- a/src/NzbDrone.Core/Tv/RefreshEpisodeService.cs +++ b/src/NzbDrone.Core/Tv/RefreshEpisodeService.cs @@ -183,10 +183,10 @@ namespace NzbDrone.Core.Tv episode.AbsoluteEpisodeNumber = tvdbEpisode.AbsoluteEpisodeNumber; } - //Return all episodes with abs 0, but distinct by abs for ones greater than 0 - return traktEpisodes.Where(e => e.AbsoluteEpisodeNumber > 0) - .DistinctBy(e => e.AbsoluteEpisodeNumber) - .Concat(traktEpisodes.Where(e => e.AbsoluteEpisodeNumber == 0)) + //Return all episodes with no abs number, but distinct for those with abs number + return traktEpisodes.Where(e => e.AbsoluteEpisodeNumber.HasValue) + .DistinctBy(e => e.AbsoluteEpisodeNumber.Value) + .Concat(traktEpisodes.Where(e => !e.AbsoluteEpisodeNumber.HasValue)) .ToList(); } @@ -194,7 +194,7 @@ namespace NzbDrone.Core.Tv { if (series.SeriesType == SeriesTypes.Anime) { - if (episode.AbsoluteEpisodeNumber > 0) + if (episode.AbsoluteEpisodeNumber.HasValue) { var matchingEpisode = existingEpisodes.FirstOrDefault(e => e.AbsoluteEpisodeNumber == episode.AbsoluteEpisodeNumber); @@ -209,10 +209,10 @@ namespace NzbDrone.Core.Tv { if (series.SeriesType == SeriesTypes.Anime) { - var withAbs = episodes.Where(e => e.AbsoluteEpisodeNumber > 0) + var withAbs = episodes.Where(e => e.AbsoluteEpisodeNumber.HasValue) .OrderBy(e => e.AbsoluteEpisodeNumber); - var withoutAbs = episodes.Where(e => e.AbsoluteEpisodeNumber == 0) + var withoutAbs = episodes.Where(e => !e.AbsoluteEpisodeNumber.HasValue) .OrderBy(e => e.SeasonNumber) .ThenBy(e => e.EpisodeNumber); diff --git a/src/UI/Cells/EpisodeNumberCell.js b/src/UI/Cells/EpisodeNumberCell.js index 7b83b238d..5ed8992bc 100644 --- a/src/UI/Cells/EpisodeNumberCell.js +++ b/src/UI/Cells/EpisodeNumberCell.js @@ -36,7 +36,7 @@ define( episodes = this.cellValue.get(episodeField); } - if (!absoluteEpisodeNumber) { + if (absoluteEpisodeNumber === undefined) { absoluteEpisodeNumber = this.cellValue.get(absoluteEpisodeField); } @@ -62,7 +62,7 @@ define( result = '{0}x{1}'.format(seasonNumber, paddedEpisodes); - if (absoluteEpisodeNumber > 0 && paddedAbsoluteEpisode) { + if (absoluteEpisodeNumber !== undefined && paddedAbsoluteEpisode) { result += ' ({0})'.format(paddedAbsoluteEpisode); } } diff --git a/src/UI/Handlebars/Helpers/Episode.js b/src/UI/Handlebars/Helpers/Episode.js index 6c864b468..1b3e70e4d 100644 --- a/src/UI/Handlebars/Helpers/Episode.js +++ b/src/UI/Handlebars/Helpers/Episode.js @@ -11,7 +11,7 @@ define( return moment(this.airDate).format('L'); } - else if (this.series.seriesType === 'anime' && this.absoluteEpisodeNumber > 0) { + else if (this.series.seriesType === 'anime' && this.absoluteEpisodeNumber !== undefined) { return '{0}x{1} ({2})'.format(this.seasonNumber, FormatHelpers.pad(this.episodeNumber, 2), FormatHelpers.pad(this.absoluteEpisodeNumber, 2)); } diff --git a/src/UI/Series/Details/EpisodeNumberCell.js b/src/UI/Series/Details/EpisodeNumberCell.js index 7a37d2826..8e7616e50 100644 --- a/src/UI/Series/Details/EpisodeNumberCell.js +++ b/src/UI/Series/Details/EpisodeNumberCell.js @@ -42,7 +42,7 @@ define( if (this.model.get('sceneSeasonNumber') > 0 || this.model.get('sceneEpisodeNumber') > 0 || - (this.model.has('sceneAbsoluteEpisodeNumber') && this.model.get('sceneAbsoluteEpisodeNumber') > 0) || + this.model.has('sceneAbsoluteEpisodeNumber') || alternateTitles.length > 0) { this.templateFunction = Marionette.TemplateCache.get(this.template); diff --git a/src/UI/Series/Details/EpisodeWarningCell.js b/src/UI/Series/Details/EpisodeWarningCell.js index ab80a9e4c..f86062fd1 100644 --- a/src/UI/Series/Details/EpisodeWarningCell.js +++ b/src/UI/Series/Details/EpisodeWarningCell.js @@ -15,7 +15,7 @@ define( if (SeriesCollection.get(this.model.get('seriesId')).get('seriesType') === 'anime') { - if (this.model.get('seasonNumber') > 0 && this.model.get('absoluteEpisodeNumber') === 0) { + if (this.model.get('seasonNumber') > 0 && !this.model.has('absoluteEpisodeNumber')) { this.$el.html(''); } }