mirror of https://github.com/Sonarr/Sonarr
250 lines
9.6 KiB
C#
250 lines
9.6 KiB
C#
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.Configuration;
|
|
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 IProvideSeriesInfo _seriesInfo;
|
|
private readonly ISeriesService _seriesService;
|
|
private readonly IRefreshEpisodeService _refreshEpisodeService;
|
|
private readonly IEventAggregator _eventAggregator;
|
|
private readonly IDiskScanService _diskScanService;
|
|
private readonly ICheckIfSeriesShouldBeRefreshed _checkIfSeriesShouldBeRefreshed;
|
|
private readonly IConfigService _configService;
|
|
private readonly Logger _logger;
|
|
|
|
public RefreshSeriesService(IProvideSeriesInfo seriesInfo,
|
|
ISeriesService seriesService,
|
|
IRefreshEpisodeService refreshEpisodeService,
|
|
IEventAggregator eventAggregator,
|
|
|
|
IDiskScanService diskScanService,
|
|
ICheckIfSeriesShouldBeRefreshed checkIfSeriesShouldBeRefreshed,
|
|
IConfigService configService,
|
|
Logger logger)
|
|
{
|
|
_seriesInfo = seriesInfo;
|
|
_seriesService = seriesService;
|
|
_refreshEpisodeService = refreshEpisodeService;
|
|
_eventAggregator = eventAggregator;
|
|
_diskScanService = diskScanService;
|
|
_checkIfSeriesShouldBeRefreshed = checkIfSeriesShouldBeRefreshed;
|
|
_configService = configService;
|
|
_logger = logger;
|
|
}
|
|
|
|
private void RefreshSeriesInfo(Series series)
|
|
{
|
|
_logger.ProgressInfo("Updating {0}", series.Title);
|
|
|
|
Series seriesInfo;
|
|
List<Episode> episodes;
|
|
|
|
try
|
|
{
|
|
var tuple = _seriesInfo.GetSeriesInfo(series.TvdbId);
|
|
seriesInfo = tuple.Item1;
|
|
episodes = tuple.Item2;
|
|
}
|
|
catch (SeriesNotFoundException)
|
|
{
|
|
if (series.Status != SeriesStatusType.Deleted)
|
|
{
|
|
series.Status = SeriesStatusType.Deleted;
|
|
_seriesService.UpdateSeries(series);
|
|
_logger.Debug("Series marked as deleted on tvdb for {0}", series.Title);
|
|
_eventAggregator.PublishEvent(new SeriesUpdatedEvent(series));
|
|
}
|
|
throw;
|
|
}
|
|
|
|
if (series.TvdbId != seriesInfo.TvdbId)
|
|
{
|
|
_logger.Warn("Series '{0}' (tvdbid {1}) was replaced with '{2}' (tvdbid {3}), because the original was a duplicate.", series.Title, series.TvdbId, seriesInfo.Title, seriesInfo.TvdbId);
|
|
series.TvdbId = seriesInfo.TvdbId;
|
|
}
|
|
|
|
series.Title = seriesInfo.Title;
|
|
series.TitleSlug = seriesInfo.TitleSlug;
|
|
series.TvRageId = seriesInfo.TvRageId;
|
|
series.TvMazeId = seriesInfo.TvMazeId;
|
|
series.ImdbId = seriesInfo.ImdbId;
|
|
series.AirTime = seriesInfo.AirTime;
|
|
series.Overview = seriesInfo.Overview;
|
|
series.Status = seriesInfo.Status;
|
|
series.CleanTitle = seriesInfo.CleanTitle;
|
|
series.SortTitle = seriesInfo.SortTitle;
|
|
series.LastInfoSync = DateTime.UtcNow;
|
|
series.Runtime = seriesInfo.Runtime;
|
|
series.Images = seriesInfo.Images;
|
|
series.Network = seriesInfo.Network;
|
|
series.FirstAired = seriesInfo.FirstAired;
|
|
series.Ratings = seriesInfo.Ratings;
|
|
series.Actors = seriesInfo.Actors;
|
|
series.Genres = seriesInfo.Genres;
|
|
series.Certification = seriesInfo.Certification;
|
|
|
|
try
|
|
{
|
|
series.Path = new DirectoryInfo(series.Path).FullName;
|
|
series.Path = series.Path.GetActualCasing();
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_logger.Warn(e, "Couldn't update series path for " + series.Path);
|
|
}
|
|
|
|
series.Seasons = UpdateSeasons(series, seriesInfo);
|
|
|
|
_seriesService.UpdateSeries(series);
|
|
_refreshEpisodeService.RefreshEpisodeInfo(series, episodes);
|
|
|
|
_logger.Debug("Finished series refresh for {0}", series.Title);
|
|
_eventAggregator.PublishEvent(new SeriesUpdatedEvent(series));
|
|
}
|
|
|
|
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)
|
|
{
|
|
_logger.Debug("Ignoring season 0 for series [{0}] {1} by default", series.TvdbId, series.Title);
|
|
season.Monitored = false;
|
|
continue;
|
|
}
|
|
|
|
_logger.Debug("New season ({0}) for series: [{1}] {2}, setting monitored to {3}", season.SeasonNumber, series.TvdbId, series.Title, series.Monitored.ToString().ToLowerInvariant());
|
|
season.Monitored = series.Monitored;
|
|
}
|
|
|
|
else
|
|
{
|
|
season.Monitored = existingSeason.Monitored;
|
|
}
|
|
}
|
|
|
|
return seasons;
|
|
}
|
|
|
|
private void RescanSeries(Series series, bool isNew, CommandTrigger trigger)
|
|
{
|
|
var rescanAfterRefresh = _configService.RescanAfterRefresh;
|
|
var shouldRescan = true;
|
|
|
|
if (isNew)
|
|
{
|
|
_logger.Trace("Forcing rescan of {0}. Reason: New series", series);
|
|
shouldRescan = true;
|
|
}
|
|
else if (rescanAfterRefresh == RescanAfterRefreshType.Never)
|
|
{
|
|
_logger.Trace("Skipping rescan of {0}. Reason: never rescan after refresh", series);
|
|
shouldRescan = false;
|
|
}
|
|
else if (rescanAfterRefresh == RescanAfterRefreshType.AfterManual && trigger != CommandTrigger.Manual)
|
|
{
|
|
_logger.Trace("Skipping rescan of {0}. Reason: not after automatic scans", series);
|
|
shouldRescan = false;
|
|
}
|
|
|
|
if (!shouldRescan)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
_diskScanService.Scan(series);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_logger.Error(e, "Couldn't rescan series {0}", series);
|
|
}
|
|
}
|
|
|
|
public void Execute(RefreshSeriesCommand message)
|
|
{
|
|
var trigger = message.Trigger;
|
|
var isNew = message.IsNewSeries;
|
|
_eventAggregator.PublishEvent(new SeriesRefreshStartingEvent(trigger == CommandTrigger.Manual));
|
|
|
|
if (message.SeriesId.HasValue)
|
|
{
|
|
var series = _seriesService.GetSeries(message.SeriesId.Value);
|
|
|
|
try
|
|
{
|
|
RefreshSeriesInfo(series);
|
|
RescanSeries(series, isNew, trigger);
|
|
}
|
|
catch (SeriesNotFoundException)
|
|
{
|
|
_logger.Error("Series '{0}' (tvdbid {1}) was not found, it may have been removed from TheTVDB.", series.Title, series.TvdbId);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_logger.Error(e, "Couldn't refresh info for {0}", series);
|
|
RescanSeries(series, isNew, trigger);
|
|
throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var allSeries = _seriesService.GetAllSeries().OrderBy(c => c.SortTitle).ToList();
|
|
|
|
foreach (var series in allSeries)
|
|
{
|
|
if (trigger == CommandTrigger.Manual || _checkIfSeriesShouldBeRefreshed.ShouldRefresh(series))
|
|
{
|
|
try
|
|
{
|
|
RefreshSeriesInfo(series);
|
|
}
|
|
catch (SeriesNotFoundException)
|
|
{
|
|
_logger.Error("Series '{0}' (tvdbid {1}) was not found, it may have been removed from TheTVDB.", series.Title, series.TvdbId);
|
|
continue;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
_logger.Error(e, "Couldn't refresh info for {0}", series);
|
|
}
|
|
|
|
RescanSeries(series, false, trigger);
|
|
}
|
|
|
|
else
|
|
{
|
|
_logger.Info("Skipping refresh of series: {0}", series.Title);
|
|
RescanSeries(series, false, trigger);
|
|
}
|
|
}
|
|
}
|
|
|
|
_eventAggregator.PublishEvent(new SeriesRefreshCompleteEvent());
|
|
}
|
|
}
|
|
}
|