You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Sonarr/src/NzbDrone.Core/Tv/AddSeriesService.cs

170 lines
6.2 KiB

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.Common.Extensions;
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);
List<Series> AddSeries(List<Series> newSeries, bool ignoreErrors = false);
}
public class AddSeriesService : IAddSeriesService
{
private readonly ISeriesService _seriesService;
private readonly IProvideSeriesInfo _seriesInfo;
private readonly IBuildFileNames _fileNameBuilder;
private readonly IAddSeriesValidator _addSeriesValidator;
private readonly Logger _logger;
public AddSeriesService(ISeriesService seriesService,
IProvideSeriesInfo seriesInfo,
IBuildFileNames fileNameBuilder,
IAddSeriesValidator addSeriesValidator,
Logger logger)
{
_seriesService = seriesService;
_seriesInfo = seriesInfo;
_fileNameBuilder = fileNameBuilder;
_addSeriesValidator = addSeriesValidator;
_logger = logger;
}
public Series AddSeries(Series newSeries)
{
Ensure.That(newSeries, () => newSeries).IsNotNull();
newSeries = AddSkyhookData(newSeries);
newSeries = SetPropertiesAndValidate(newSeries);
_logger.Info("Adding Series {0} Path: [{1}]", newSeries, newSeries.Path);
_seriesService.AddSeries(newSeries);
return newSeries;
}
public List<Series> AddSeries(List<Series> newSeries, bool ignoreErrors = false)
{
var added = DateTime.UtcNow;
var seriesToAdd = new List<Series>();
var existingSeriesTvdbIds = _seriesService.AllSeriesTvdbIds();
foreach (var s in newSeries)
{
if (s.Path.IsNullOrWhiteSpace())
{
_logger.Info("Adding Series {0} Root Folder Path: [{1}]", s, s.RootFolderPath);
}
else
{
_logger.Info("Adding Series {0} Path: [{1}]", s, s.Path);
}
try
{
var series = AddSkyhookData(s);
series = SetPropertiesAndValidate(series);
series.Added = added;
if (existingSeriesTvdbIds.Any(f => f == series.TvdbId))
{
_logger.Debug("TVDB ID {0} was not added due to validation failure: Series {1} already exists in database", s.TvdbId, s);
continue;
}
if (seriesToAdd.Any(f => f.TvdbId == series.TvdbId))
{
_logger.Trace("TVDB ID {0} was already added from another import list, not adding series {1} again", s.TvdbId, s);
continue;
}
var duplicateSlug = seriesToAdd.FirstOrDefault(f => f.TitleSlug == series.TitleSlug);
if (duplicateSlug != null)
{
_logger.Debug("TVDB ID {0} was not added due to validation failure: Duplicate Slug {1} used by series {2}", s.TvdbId, s.TitleSlug, duplicateSlug.TvdbId);
continue;
}
seriesToAdd.Add(series);
}
catch (ValidationException ex)
{
if (!ignoreErrors)
{
throw;
}
_logger.Debug("Series {0} with TVDB ID {1} was not added due to validation failures. {2}", s, s.TvdbId, ex.Message);
}
}
return _seriesService.AddSeries(seriesToAdd);
}
private Series AddSkyhookData(Series newSeries)
{
Tuple<Series, List<Episode>> tuple;
try
{
tuple = _seriesInfo.GetSeriesInfo(newSeries.TvdbId);
}
catch (SeriesNotFoundException)
{
_logger.Error("Series {0} with TVDB ID {1} was not found, it may have been removed from TheTVDB. Path: {2}", newSeries, newSeries.TvdbId, newSeries.Path);
throw new ValidationException(new List<ValidationFailure>
{
new ValidationFailure("TvdbId", $"A series with this ID was not found. Path: {newSeries.Path}", newSeries.TvdbId)
});
}
var series = tuple.Item1;
// If seasons were passed in on the new series use them, otherwise use the seasons from Skyhook
newSeries.Seasons = newSeries.Seasons != null && newSeries.Seasons.Any() ? newSeries.Seasons : series.Seasons;
series.ApplyChanges(newSeries);
return series;
}
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;
if (newSeries.AddOptions != null && newSeries.AddOptions.Monitor == MonitorTypes.None)
{
newSeries.Monitored = false;
}
var validationResult = _addSeriesValidator.Validate(newSeries);
if (!validationResult.IsValid)
{
throw new ValidationException(validationResult.Errors);
}
return newSeries;
}
}
}