diff --git a/NzbDrone.Core.Test/MetadataSourceTests/TraktProxyFixture.cs b/NzbDrone.Core.Test/MetadataSourceTests/TraktProxyFixture.cs
index 7c7a3e8ce..fea1cfefd 100644
--- a/NzbDrone.Core.Test/MetadataSourceTests/TraktProxyFixture.cs
+++ b/NzbDrone.Core.Test/MetadataSourceTests/TraktProxyFixture.cs
@@ -49,6 +49,7 @@ private void ValidateSeries(Series series)
{
series.Should().NotBeNull();
series.Title.Should().NotBeBlank();
+ series.CleanTitle.Should().Be(Parser.Parser.CleanSeriesTitle(series.Title));
series.Overview.Should().NotBeBlank();
series.AirTime.Should().NotBeBlank();
series.FirstAired.Should().HaveValue();
diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
index 0526a672a..3fd954996 100644
--- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
+++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
@@ -164,6 +164,7 @@
+
diff --git a/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs b/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs
new file mode 100644
index 000000000..6f8488c9f
Binary files /dev/null and b/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs differ
diff --git a/NzbDrone.Core/MetadataSource/TraktProxy.cs b/NzbDrone.Core/MetadataSource/TraktProxy.cs
index 925549615..15cfc87d1 100644
--- a/NzbDrone.Core/MetadataSource/TraktProxy.cs
+++ b/NzbDrone.Core/MetadataSource/TraktProxy.cs
@@ -47,6 +47,7 @@ private static Series MapSeries(Show show)
series.TvRageId = show.tvrage_id;
series.ImdbId = show.imdb_id;
series.Title = show.title;
+ series.CleanTitle = Parser.Parser.CleanSeriesTitle(show.title);
series.FirstAired = FromIso(show.first_aired_iso);
series.Overview = show.overview;
series.Runtime = show.runtime;
diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj
index b4f1263f6..12a437e7e 100644
--- a/NzbDrone.Core/NzbDrone.Core.csproj
+++ b/NzbDrone.Core/NzbDrone.Core.csproj
@@ -343,6 +343,7 @@
+
diff --git a/NzbDrone.Core/Tv/EpisodeService.cs b/NzbDrone.Core/Tv/EpisodeService.cs
index d7cf318bf..1231d1384 100644
--- a/NzbDrone.Core/Tv/EpisodeService.cs
+++ b/NzbDrone.Core/Tv/EpisodeService.cs
@@ -30,6 +30,7 @@ public interface IEpisodeService
List EpisodesBetweenDates(DateTime start, DateTime end);
void InsertMany(List episodes);
void UpdateMany(List episodes);
+ void DeleteMany(List episodes);
}
public class EpisodeService : IEpisodeService,
@@ -170,6 +171,11 @@ public void UpdateMany(List episodes)
_episodeRepository.UpdateMany(episodes);
}
+ public void DeleteMany(List episodes)
+ {
+ _episodeRepository.DeleteMany(episodes);
+ }
+
public void HandleAsync(SeriesDeletedEvent message)
{
var episodes = GetEpisodeBySeries(message.Series.Id);
diff --git a/NzbDrone.Core/Tv/RefreshEpisodeService.cs b/NzbDrone.Core/Tv/RefreshEpisodeService.cs
new file mode 100644
index 000000000..c1f134c71
--- /dev/null
+++ b/NzbDrone.Core/Tv/RefreshEpisodeService.cs
@@ -0,0 +1,154 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NLog;
+using NzbDrone.Common.Messaging;
+using NzbDrone.Core.Tv.Events;
+
+namespace NzbDrone.Core.Tv
+{
+ public interface IRefreshEpisodeService
+ {
+ void RefreshEpisodeInfo(Series series, IEnumerable remoteEpisodes);
+ }
+
+ public class RefreshEpisodeService : IRefreshEpisodeService
+ {
+ private readonly IEpisodeService _episodeService;
+ private readonly ISeasonService _seasonService;
+ private readonly IMessageAggregator _messageAggregator;
+ private readonly Logger _logger;
+
+ public RefreshEpisodeService(IEpisodeService episodeService,
+ ISeasonService seasonService, IMessageAggregator messageAggregator, Logger logger)
+ {
+ _episodeService = episodeService;
+ _seasonService = seasonService;
+ _messageAggregator = messageAggregator;
+ _logger = logger;
+ }
+
+
+ public void RefreshEpisodeInfo(Series series, IEnumerable remoteEpisodes)
+ {
+ _logger.Info("Starting series info refresh for: {0}", series);
+ var successCount = 0;
+ var failCount = 0;
+
+ var existinEpisodes = _episodeService.GetEpisodeBySeries(series.Id);
+ var seasons = _seasonService.GetSeasonsBySeries(series.Id);
+
+ var updateList = new List();
+ var newList = new List();
+
+ foreach (var episode in remoteEpisodes.OrderBy(e => e.SeasonNumber).ThenBy(e => e.EpisodeNumber))
+ {
+ try
+ {
+ var episodeToUpdate = existinEpisodes.SingleOrDefault(e => e.TvDbEpisodeId == episode.TvDbEpisodeId) ??
+ existinEpisodes.SingleOrDefault(e => e.SeasonNumber == episode.SeasonNumber && e.EpisodeNumber == episode.EpisodeNumber);
+
+ if (episodeToUpdate != null)
+ {
+ existinEpisodes.Remove(episodeToUpdate);
+ updateList.Add(episodeToUpdate);
+
+ if ((episodeToUpdate.EpisodeNumber != episode.EpisodeNumber || episodeToUpdate.SeasonNumber != episode.SeasonNumber) && episodeToUpdate.EpisodeFileId != 0)
+ {
+ _logger.Debug("Un-linking episode file because the episode number has changed");
+ episodeToUpdate.EpisodeFileId = 0;
+ }
+ }
+ else
+ {
+ episodeToUpdate = new Episode();
+ episodeToUpdate.Monitored = GetMonitoredStatus(episode, seasons);
+ newList.Add(episodeToUpdate);
+ }
+
+ episodeToUpdate.SeriesId = series.Id;
+ episodeToUpdate.TvDbEpisodeId = episode.TvDbEpisodeId;
+ episodeToUpdate.EpisodeNumber = episode.EpisodeNumber;
+ episodeToUpdate.SeasonNumber = episode.SeasonNumber;
+ episodeToUpdate.Title = episode.Title;
+ episodeToUpdate.Overview = episode.Overview;
+ episodeToUpdate.AirDate = episode.AirDate;
+ episodeToUpdate.AirDateUtc = episode.AirDateUtc;
+
+ successCount++;
+ }
+ catch (Exception e)
+ {
+ _logger.FatalException(String.Format("An error has occurred while updating episode info for series {0}. {1}", series, episode), e);
+ failCount++;
+ }
+ }
+
+ var allEpisodes = new List();
+ allEpisodes.AddRange(newList);
+ allEpisodes.AddRange(updateList);
+
+ AdjustMultiEpisodeAirTime(series, allEpisodes);
+
+ _episodeService.DeleteMany(existinEpisodes);
+ _episodeService.UpdateMany(updateList);
+ _episodeService.InsertMany(newList);
+
+
+ if (newList.Any())
+ {
+ _messageAggregator.PublishEvent(new EpisodeInfoAddedEvent(newList, series));
+ }
+
+ if (updateList.Any())
+ {
+ _messageAggregator.PublishEvent(new EpisodeInfoUpdatedEvent(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 static bool GetMonitoredStatus(Episode episode, IEnumerable seasons)
+ {
+ if (episode.SeasonNumber == 0)
+ {
+ return false;
+ }
+
+ if (episode.EpisodeNumber == 0 && episode.SeasonNumber != 1)
+ {
+ return false;
+ }
+
+ var season = seasons.SingleOrDefault(c => c.SeasonNumber == episode.SeasonNumber);
+ return season == null || season.Monitored;
+ }
+
+ private static void AdjustMultiEpisodeAirTime(Series series, IEnumerable allEpisodes)
+ {
+ var groups =
+ allEpisodes.Where(c => c.AirDateUtc.HasValue)
+ .GroupBy(e => new { e.SeriesId, 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++;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/NzbDrone.Core/Tv/RefreshSeriesService.cs b/NzbDrone.Core/Tv/RefreshSeriesService.cs
index 7ad4c25e5..ac9517463 100644
--- a/NzbDrone.Core/Tv/RefreshSeriesService.cs
+++ b/NzbDrone.Core/Tv/RefreshSeriesService.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Common.Messaging;
@@ -15,19 +14,16 @@ public class RefreshSeriesService : IExecute, IHandleAsync
{
private readonly IProvideSeriesInfo _seriesInfo;
private readonly ISeriesService _seriesService;
- private readonly IEpisodeService _episodeService;
- private readonly ISeasonRepository _seasonRepository;
+ private readonly IRefreshEpisodeService _refreshEpisodeService;
private readonly IMessageAggregator _messageAggregator;
private readonly IDailySeriesService _dailySeriesService;
private readonly Logger _logger;
- public RefreshSeriesService(IProvideSeriesInfo seriesInfo, ISeriesService seriesService, IEpisodeService episodeService,
- ISeasonRepository seasonRepository, IMessageAggregator messageAggregator, IDailySeriesService dailySeriesService, Logger logger)
+ public RefreshSeriesService(IProvideSeriesInfo seriesInfo, ISeriesService seriesService, IRefreshEpisodeService refreshEpisodeService, IMessageAggregator messageAggregator, IDailySeriesService dailySeriesService, Logger logger)
{
_seriesInfo = seriesInfo;
_seriesService = seriesService;
- _episodeService = episodeService;
- _seasonRepository = seasonRepository;
+ _refreshEpisodeService = refreshEpisodeService;
_messageAggregator = messageAggregator;
_dailySeriesService = dailySeriesService;
_logger = logger;
@@ -74,7 +70,7 @@ private void RefreshSeriesInfo(Series series)
series.AirTime = seriesInfo.AirTime;
series.Overview = seriesInfo.Overview;
series.Status = seriesInfo.Status;
- series.CleanTitle = Parser.Parser.CleanSeriesTitle(seriesInfo.Title);
+ series.CleanTitle = seriesInfo.CleanTitle;
series.LastInfoSync = DateTime.UtcNow;
series.Runtime = seriesInfo.Runtime;
series.Images = seriesInfo.Images;
@@ -88,132 +84,11 @@ private void RefreshSeriesInfo(Series series)
_seriesService.UpdateSeries(series);
- RefreshEpisodeInfo(series, tuple.Item2);
+ _refreshEpisodeService.RefreshEpisodeInfo(series, tuple.Item2);
_messageAggregator.PublishEvent(new SeriesUpdatedEvent(series));
}
- private void RefreshEpisodeInfo(Series series, IEnumerable remoteEpisodes)
- {
- _logger.Info("Starting series info refresh for: {0}", series);
- var successCount = 0;
- var failCount = 0;
- var seriesEpisodes = _episodeService.GetEpisodeBySeries(series.Id);
- var seasons = _seasonRepository.GetSeasonBySeries(series.Id);
-
- var updateList = new List();
- var newList = new List();
-
- foreach (var episode in remoteEpisodes.OrderBy(e => e.SeasonNumber).ThenBy(e => e.EpisodeNumber))
- {
- try
- {
- var episodeToUpdate = seriesEpisodes.SingleOrDefault(e => e.TvDbEpisodeId == episode.TvDbEpisodeId) ??
- seriesEpisodes.SingleOrDefault(e => e.SeasonNumber == episode.SeasonNumber && e.EpisodeNumber == episode.EpisodeNumber);
-
- if (episodeToUpdate == null)
- {
- episodeToUpdate = new Episode();
- newList.Add(episodeToUpdate);
-
- //If it is Episode Zero or Season zero ignore it
- if ((episode.EpisodeNumber == 0 && episode.SeasonNumber != 1) || episode.SeasonNumber == 0)
- {
- episodeToUpdate.Monitored = false;
- }
- else
- {
- var season = seasons.FirstOrDefault(c => c.SeasonNumber == episode.SeasonNumber);
- episodeToUpdate.Monitored = season == null || season.Monitored;
- }
- }
- else
- {
- updateList.Add(episodeToUpdate);
- }
-
- if ((episodeToUpdate.EpisodeNumber != episode.EpisodeNumber ||
- episodeToUpdate.SeasonNumber != episode.SeasonNumber) &&
- episodeToUpdate.EpisodeFileId > 0)
- {
- _logger.Debug("Un-linking episode file because the episode number has changed");
- episodeToUpdate.EpisodeFileId = 0;
- }
-
- episodeToUpdate.SeriesId = series.Id;
- episodeToUpdate.TvDbEpisodeId = episode.TvDbEpisodeId;
- episodeToUpdate.EpisodeNumber = episode.EpisodeNumber;
- episodeToUpdate.SeasonNumber = episode.SeasonNumber;
- episodeToUpdate.Title = episode.Title;
- episodeToUpdate.Overview = episode.Overview;
- episodeToUpdate.AirDate = episode.AirDate;
- episodeToUpdate.AirDateUtc = episode.AirDateUtc;
-
- successCount++;
- }
- catch (Exception e)
- {
- _logger.FatalException(String.Format("An error has occurred while updating episode info for series {0}. {1}", series, episode), e);
- failCount++;
- }
- }
-
- var allEpisodes = new List();
- allEpisodes.AddRange(newList);
- allEpisodes.AddRange(updateList);
-
- var groups = allEpisodes.Where(c=>c.AirDateUtc.HasValue).GroupBy(e => new { e.SeriesId, e.AirDate }).Where(g => g.Count() > 1).ToList();
-
- foreach (var group in groups)
- {
- int 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++;
- }
- }
-
- _episodeService.UpdateMany(updateList);
- _episodeService.InsertMany(newList);
-
- if (newList.Any())
- {
- _messageAggregator.PublishEvent(new EpisodeInfoAddedEvent(newList, series));
- }
-
- if (updateList.Any())
- {
- _messageAggregator.PublishEvent(new EpisodeInfoUpdatedEvent(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);
- }
-
- //DeleteEpisodesNotAvailableAnymore(series, remoteEpisodes);
- }
-
-
- /* private void DeleteEpisodesNotAvailableAnymore(Series series, IEnumerable onlineEpisodes)
- {
- //Todo: This will not work as currently implemented - what are we trying to do here?
- //Todo: We were trying to remove episodes that were once on tvdb but were removed, for whatever reason, instead of polluting our DB with them.
- return;
- _logger.Trace("Starting deletion of episodes that no longer exist in TVDB: {0}", series.Title.WithDefault(series.Id));
- foreach (var episode in onlineEpisodes)
- {
- _episodeRepository.Delete(episode.Id);
- }
-
- _logger.Trace("Deleted episodes that no longer exist in TVDB for {0}", series.Id);
- }*/
}
}
\ No newline at end of file
diff --git a/NzbDrone.Test.Common/NzbDrone.Test.Common.csproj b/NzbDrone.Test.Common/NzbDrone.Test.Common.csproj
index abf8ad677..171f9df7d 100644
--- a/NzbDrone.Test.Common/NzbDrone.Test.Common.csproj
+++ b/NzbDrone.Test.Common/NzbDrone.Test.Common.csproj
@@ -51,6 +51,10 @@
..\packages\Moq.4.0.10827\lib\NET40\Moq.dll
+
+ False
+ ..\packages\Newtonsoft.Json.5.0.3\lib\net35\Newtonsoft.Json.dll
+
False
..\packages\NLog.2.0.1.2\lib\net40\NLog.dll
@@ -76,6 +80,7 @@
+
diff --git a/NzbDrone.Test.Common/ObjectExtentions.cs b/NzbDrone.Test.Common/ObjectExtentions.cs
new file mode 100644
index 000000000..e6ea1e49e
--- /dev/null
+++ b/NzbDrone.Test.Common/ObjectExtentions.cs
@@ -0,0 +1,13 @@
+using Newtonsoft.Json;
+
+namespace NzbDrone.Test.Common
+{
+ public static class ObjectExtentions
+ {
+ public static T JsonClone(this T source)
+ {
+ var json = JsonConvert.SerializeObject(source);
+ return JsonConvert.DeserializeObject(json);
+ }
+ }
+}
\ No newline at end of file
diff --git a/NzbDrone.Test.Common/StringExtensions.cs b/NzbDrone.Test.Common/StringExtensions.cs
index 7ec3f4698..7a7a420de 100644
--- a/NzbDrone.Test.Common/StringExtensions.cs
+++ b/NzbDrone.Test.Common/StringExtensions.cs
@@ -1,4 +1,5 @@
using System.IO;
+using Newtonsoft.Json.Serialization;
using NzbDrone.Common.EnvironmentInfo;
namespace NzbDrone.Test.Common
diff --git a/NzbDrone.Test.Common/packages.config b/NzbDrone.Test.Common/packages.config
index df8a9c997..11b24f356 100644
--- a/NzbDrone.Test.Common/packages.config
+++ b/NzbDrone.Test.Common/packages.config
@@ -3,6 +3,7 @@
+
diff --git a/NzbDrone/NzbDrone.csproj b/NzbDrone/NzbDrone.csproj
index d3551c601..2ed8652b8 100644
--- a/NzbDrone/NzbDrone.csproj
+++ b/NzbDrone/NzbDrone.csproj
@@ -106,10 +106,6 @@
False
..\packages\Nancy.Owin.0.16.1\lib\net40\Nancy.Owin.dll
-
- False
- ..\packages\Newtonsoft.Json.4.5.11\lib\net35\Newtonsoft.Json.dll
-
False
..\packages\NLog.2.0.1.2\lib\net40\NLog.dll
diff --git a/NzbDrone/packages.config b/NzbDrone/packages.config
index c6d386832..3ded934ee 100644
--- a/NzbDrone/packages.config
+++ b/NzbDrone/packages.config
@@ -8,7 +8,7 @@
-
+