parent
9b162f2d5e
commit
1dab0aee6a
|
@ -41,7 +41,7 @@ namespace NzbDrone.Api.Series
|
||||||
|
|
||||||
public static List<Season> ToModel(this IEnumerable<SeasonResource> resources)
|
public static List<Season> ToModel(this IEnumerable<SeasonResource> resources)
|
||||||
{
|
{
|
||||||
return resources.Select(ToModel).ToList();
|
return resources?.Select(ToModel).ToList() ?? new List<Season>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,14 @@ namespace NzbDrone.Api.Series
|
||||||
|
|
||||||
{
|
{
|
||||||
private readonly ISeriesService _seriesService;
|
private readonly ISeriesService _seriesService;
|
||||||
|
private readonly IAddSeriesService _addSeriesService;
|
||||||
private readonly ISeriesStatisticsService _seriesStatisticsService;
|
private readonly ISeriesStatisticsService _seriesStatisticsService;
|
||||||
private readonly ISceneMappingService _sceneMappingService;
|
private readonly ISceneMappingService _sceneMappingService;
|
||||||
private readonly IMapCoversToLocal _coverMapper;
|
private readonly IMapCoversToLocal _coverMapper;
|
||||||
|
|
||||||
public SeriesModule(IBroadcastSignalRMessage signalRBroadcaster,
|
public SeriesModule(IBroadcastSignalRMessage signalRBroadcaster,
|
||||||
ISeriesService seriesService,
|
ISeriesService seriesService,
|
||||||
|
IAddSeriesService addSeriesService,
|
||||||
ISeriesStatisticsService seriesStatisticsService,
|
ISeriesStatisticsService seriesStatisticsService,
|
||||||
ISceneMappingService sceneMappingService,
|
ISceneMappingService sceneMappingService,
|
||||||
IMapCoversToLocal coverMapper,
|
IMapCoversToLocal coverMapper,
|
||||||
|
@ -48,6 +50,7 @@ namespace NzbDrone.Api.Series
|
||||||
: base(signalRBroadcaster)
|
: base(signalRBroadcaster)
|
||||||
{
|
{
|
||||||
_seriesService = seriesService;
|
_seriesService = seriesService;
|
||||||
|
_addSeriesService = addSeriesService;
|
||||||
_seriesStatisticsService = seriesStatisticsService;
|
_seriesStatisticsService = seriesStatisticsService;
|
||||||
_sceneMappingService = sceneMappingService;
|
_sceneMappingService = sceneMappingService;
|
||||||
|
|
||||||
|
@ -74,7 +77,6 @@ namespace NzbDrone.Api.Series
|
||||||
|
|
||||||
PostValidator.RuleFor(s => s.Path).IsValidPath().When(s => s.RootFolderPath.IsNullOrWhiteSpace());
|
PostValidator.RuleFor(s => s.Path).IsValidPath().When(s => s.RootFolderPath.IsNullOrWhiteSpace());
|
||||||
PostValidator.RuleFor(s => s.RootFolderPath).IsValidPath().When(s => s.Path.IsNullOrWhiteSpace());
|
PostValidator.RuleFor(s => s.RootFolderPath).IsValidPath().When(s => s.Path.IsNullOrWhiteSpace());
|
||||||
PostValidator.RuleFor(s => s.Title).NotEmpty();
|
|
||||||
PostValidator.RuleFor(s => s.TvdbId).GreaterThan(0).SetValidator(seriesExistsValidator);
|
PostValidator.RuleFor(s => s.TvdbId).GreaterThan(0).SetValidator(seriesExistsValidator);
|
||||||
|
|
||||||
PutValidator.RuleFor(s => s.Path).IsValidPath();
|
PutValidator.RuleFor(s => s.Path).IsValidPath();
|
||||||
|
@ -114,7 +116,7 @@ namespace NzbDrone.Api.Series
|
||||||
{
|
{
|
||||||
var model = seriesResource.ToModel();
|
var model = seriesResource.ToModel();
|
||||||
|
|
||||||
return _seriesService.AddSeries(model).Id;
|
return _addSeriesService.AddSeries(model).Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateSeries(SeriesResource seriesResource)
|
private void UpdateSeries(SeriesResource seriesResource)
|
||||||
|
|
|
@ -207,19 +207,9 @@ namespace NzbDrone.Api.Series
|
||||||
|
|
||||||
public static Core.Tv.Series ToModel(this SeriesResource resource, Core.Tv.Series series)
|
public static Core.Tv.Series ToModel(this SeriesResource resource, Core.Tv.Series series)
|
||||||
{
|
{
|
||||||
series.TvdbId = resource.TvdbId;
|
var updatedSeries = resource.ToModel();
|
||||||
|
|
||||||
series.Seasons = resource.Seasons.ToModel();
|
series.ApplyChanges(updatedSeries);
|
||||||
series.Path = resource.Path;
|
|
||||||
series.ProfileId = resource.ProfileId;
|
|
||||||
|
|
||||||
series.SeasonFolder = resource.SeasonFolder;
|
|
||||||
series.Monitored = resource.Monitored;
|
|
||||||
|
|
||||||
series.SeriesType = resource.SeriesType;
|
|
||||||
series.RootFolderPath = resource.RootFolderPath;
|
|
||||||
series.Tags = resource.Tags;
|
|
||||||
series.AddOptions = resource.AddOptions;
|
|
||||||
|
|
||||||
return series;
|
return series;
|
||||||
}
|
}
|
||||||
|
|
|
@ -380,7 +380,7 @@
|
||||||
<Compile Include="TvTests\RefreshSeriesServiceFixture.cs" />
|
<Compile Include="TvTests\RefreshSeriesServiceFixture.cs" />
|
||||||
<Compile Include="TvTests\EpisodeMonitoredServiceTests\SetEpisodeMontitoredFixture.cs" />
|
<Compile Include="TvTests\EpisodeMonitoredServiceTests\SetEpisodeMontitoredFixture.cs" />
|
||||||
<Compile Include="TvTests\SeriesRepositoryTests\SeriesRepositoryFixture.cs" />
|
<Compile Include="TvTests\SeriesRepositoryTests\SeriesRepositoryFixture.cs" />
|
||||||
<Compile Include="TvTests\SeriesServiceTests\AddSeriesFixture.cs" />
|
<Compile Include="TvTests\AddSeriesFixture.cs" />
|
||||||
<Compile Include="TvTests\SeriesServiceTests\UpdateMultipleSeriesFixture.cs" />
|
<Compile Include="TvTests\SeriesServiceTests\UpdateMultipleSeriesFixture.cs" />
|
||||||
<Compile Include="TvTests\SeriesServiceTests\UpdateSeriesFixture.cs" />
|
<Compile Include="TvTests\SeriesServiceTests\UpdateSeriesFixture.cs" />
|
||||||
<Compile Include="TvTests\SeriesTitleNormalizerFixture.cs" />
|
<Compile Include="TvTests\SeriesTitleNormalizerFixture.cs" />
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using FluentValidation;
|
||||||
|
using FluentValidation.Results;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Exceptions;
|
||||||
|
using NzbDrone.Core.MetadataSource;
|
||||||
|
using NzbDrone.Core.Organizer;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
using NzbDrone.Test.Common;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.TvTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class AddSeriesFixture : CoreTest<AddSeriesService>
|
||||||
|
{
|
||||||
|
private Series _fakeSeries;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_fakeSeries = Builder<Series>
|
||||||
|
.CreateNew()
|
||||||
|
.With(s => s.Path = null)
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenValidSeries(int tvdbId)
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IProvideSeriesInfo>()
|
||||||
|
.Setup(s => s.GetSeriesInfo(tvdbId))
|
||||||
|
.Returns(new Tuple<Series, List<Episode>>(_fakeSeries, new List<Episode>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenValidPath()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IBuildFileNames>()
|
||||||
|
.Setup(s => s.GetSeriesFolder(It.IsAny<Series>(), null))
|
||||||
|
.Returns<Series, NamingConfig>((c, n) => c.Title);
|
||||||
|
|
||||||
|
Mocker.GetMock<IAddSeriesValidator>()
|
||||||
|
.Setup(s => s.Validate(It.IsAny<Series>()))
|
||||||
|
.Returns(new ValidationResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_be_able_to_add_a_series_without_passing_in_title()
|
||||||
|
{
|
||||||
|
var newSeries = new Series
|
||||||
|
{
|
||||||
|
TvdbId = 1,
|
||||||
|
RootFolderPath = @"C:\Test\TV"
|
||||||
|
};
|
||||||
|
|
||||||
|
GivenValidSeries(newSeries.TvdbId);
|
||||||
|
GivenValidPath();
|
||||||
|
|
||||||
|
var series = Subject.AddSeries(newSeries);
|
||||||
|
|
||||||
|
series.Title.Should().Be(_fakeSeries.Title);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_have_proper_path()
|
||||||
|
{
|
||||||
|
var newSeries = new Series
|
||||||
|
{
|
||||||
|
TvdbId = 1,
|
||||||
|
RootFolderPath = @"C:\Test\TV"
|
||||||
|
};
|
||||||
|
|
||||||
|
GivenValidSeries(newSeries.TvdbId);
|
||||||
|
GivenValidPath();
|
||||||
|
|
||||||
|
var series = Subject.AddSeries(newSeries);
|
||||||
|
|
||||||
|
series.Path.Should().Be(Path.Combine(newSeries.RootFolderPath, _fakeSeries.Title));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_throw_if_series_validation_fails()
|
||||||
|
{
|
||||||
|
var newSeries = new Series
|
||||||
|
{
|
||||||
|
TvdbId = 1,
|
||||||
|
Path = @"C:\Test\TV\Title1"
|
||||||
|
};
|
||||||
|
|
||||||
|
GivenValidSeries(newSeries.TvdbId);
|
||||||
|
|
||||||
|
Mocker.GetMock<IAddSeriesValidator>()
|
||||||
|
.Setup(s => s.Validate(It.IsAny<Series>()))
|
||||||
|
.Returns(new ValidationResult(new List<ValidationFailure>
|
||||||
|
{
|
||||||
|
new ValidationFailure("Path", "Test validation failure")
|
||||||
|
}));
|
||||||
|
|
||||||
|
Assert.Throws<ValidationException>(() => Subject.AddSeries(newSeries));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_throw_if_series_cannot_be_found()
|
||||||
|
{
|
||||||
|
var newSeries = new Series
|
||||||
|
{
|
||||||
|
TvdbId = 1,
|
||||||
|
Path = @"C:\Test\TV\Title1"
|
||||||
|
};
|
||||||
|
|
||||||
|
Mocker.GetMock<IProvideSeriesInfo>()
|
||||||
|
.Setup(s => s.GetSeriesInfo(newSeries.TvdbId))
|
||||||
|
.Throws(new SeriesNotFoundException(newSeries.TvdbId));
|
||||||
|
|
||||||
|
Mocker.GetMock<IAddSeriesValidator>()
|
||||||
|
.Setup(s => s.Validate(It.IsAny<Series>()))
|
||||||
|
.Returns(new ValidationResult(new List<ValidationFailure>
|
||||||
|
{
|
||||||
|
new ValidationFailure("Path", "Test validation failure")
|
||||||
|
}));
|
||||||
|
|
||||||
|
Assert.Throws<ValidationException>(() => Subject.AddSeries(newSeries));
|
||||||
|
|
||||||
|
ExceptionVerification.ExpectedErrors(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -157,6 +157,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
series.Actors = show.Actors.Select(MapActors).ToList();
|
series.Actors = show.Actors.Select(MapActors).ToList();
|
||||||
series.Seasons = show.Seasons.Select(MapSeason).ToList();
|
series.Seasons = show.Seasons.Select(MapSeason).ToList();
|
||||||
series.Images = show.Images.Select(MapImage).ToList();
|
series.Images = show.Images.Select(MapImage).ToList();
|
||||||
|
series.Monitored = true;
|
||||||
|
|
||||||
return series;
|
return series;
|
||||||
}
|
}
|
||||||
|
@ -208,7 +209,8 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
||||||
return new Season
|
return new Season
|
||||||
{
|
{
|
||||||
SeasonNumber = seasonResource.SeasonNumber,
|
SeasonNumber = seasonResource.SeasonNumber,
|
||||||
Images = seasonResource.Images.Select(MapImage).ToList()
|
Images = seasonResource.Images.Select(MapImage).ToList(),
|
||||||
|
Monitored = seasonResource.SeasonNumber > 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1066,6 +1066,8 @@
|
||||||
<Compile Include="TinyTwitter.cs" />
|
<Compile Include="TinyTwitter.cs" />
|
||||||
<Compile Include="Tv\Actor.cs" />
|
<Compile Include="Tv\Actor.cs" />
|
||||||
<Compile Include="Tv\AddSeriesOptions.cs" />
|
<Compile Include="Tv\AddSeriesOptions.cs" />
|
||||||
|
<Compile Include="Tv\AddSeriesService.cs" />
|
||||||
|
<Compile Include="Tv\AddSeriesValidator.cs" />
|
||||||
<Compile Include="Tv\Commands\MoveSeriesCommand.cs" />
|
<Compile Include="Tv\Commands\MoveSeriesCommand.cs" />
|
||||||
<Compile Include="Tv\Commands\RefreshSeriesCommand.cs" />
|
<Compile Include="Tv\Commands\RefreshSeriesCommand.cs" />
|
||||||
<Compile Include="Tv\Episode.cs" />
|
<Compile Include="Tv\Episode.cs" />
|
||||||
|
@ -1099,6 +1101,7 @@
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Tv\SeriesStatusType.cs" />
|
<Compile Include="Tv\SeriesStatusType.cs" />
|
||||||
<Compile Include="Tv\SeriesTitleNormalizer.cs" />
|
<Compile Include="Tv\SeriesTitleNormalizer.cs" />
|
||||||
|
<Compile Include="Tv\SeriesTitleSlugValidator.cs" />
|
||||||
<Compile Include="Tv\SeriesTypes.cs" />
|
<Compile Include="Tv\SeriesTypes.cs" />
|
||||||
<Compile Include="Tv\ShouldRefreshSeries.cs" />
|
<Compile Include="Tv\ShouldRefreshSeries.cs" />
|
||||||
<Compile Include="Update\Commands\ApplicationUpdateCommand.cs" />
|
<Compile Include="Update\Commands\ApplicationUpdateCommand.cs" />
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
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 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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Info("Adding Series {0} Path: [{1}]", newSeries, newSeries.Path);
|
||||||
|
_seriesService.AddSeries(newSeries);
|
||||||
|
|
||||||
|
return newSeries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Series AddSkyhookData(Series newSeries)
|
||||||
|
{
|
||||||
|
Tuple<Series, List<Episode>> tuple;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tuple = _seriesInfo.GetSeriesInfo(newSeries.TvdbId);
|
||||||
|
}
|
||||||
|
catch (SeriesNotFoundException)
|
||||||
|
{
|
||||||
|
_logger.Error("tvdbid {1} was not found, it may have been removed from TheTVDB.", newSeries.TvdbId);
|
||||||
|
|
||||||
|
throw new ValidationException(new List<ValidationFailure>
|
||||||
|
{
|
||||||
|
new ValidationFailure("TvdbId", "A series with this ID was not found", 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
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,
|
||||||
|
SeriesPathValidator seriesPathValidator,
|
||||||
|
DroneFactoryValidator droneFactoryValidator,
|
||||||
|
SeriesAncestorValidator seriesAncestorValidator,
|
||||||
|
SeriesTitleSlugValidator seriesTitleSlugValidator)
|
||||||
|
{
|
||||||
|
RuleFor(c => c.Path).Cascade(CascadeMode.StopOnFirstFailure)
|
||||||
|
.IsValidPath()
|
||||||
|
.SetValidator(rootFolderValidator)
|
||||||
|
.SetValidator(seriesPathValidator)
|
||||||
|
.SetValidator(droneFactoryValidator)
|
||||||
|
.SetValidator(seriesAncestorValidator);
|
||||||
|
|
||||||
|
RuleFor(c => c.TitleSlug).SetValidator(seriesTitleSlugValidator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,5 +57,22 @@ namespace NzbDrone.Core.Tv
|
||||||
{
|
{
|
||||||
return string.Format("[{0}][{1}]", TvdbId, Title.NullSafe());
|
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;
|
||||||
|
|
||||||
|
SeasonFolder = otherSeries.SeasonFolder;
|
||||||
|
Monitored = otherSeries.Monitored;
|
||||||
|
|
||||||
|
SeriesType = otherSeries.SeriesType;
|
||||||
|
RootFolderPath = otherSeries.RootFolderPath;
|
||||||
|
Tags = otherSeries.Tags;
|
||||||
|
AddOptions = otherSeries.AddOptions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -67,20 +67,6 @@ namespace NzbDrone.Core.Tv
|
||||||
|
|
||||||
public Series AddSeries(Series newSeries)
|
public Series AddSeries(Series newSeries)
|
||||||
{
|
{
|
||||||
Ensure.That(newSeries, () => newSeries).IsNotNull();
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(newSeries.Path))
|
|
||||||
{
|
|
||||||
var folderName = _fileNameBuilder.GetSeriesFolder(newSeries);
|
|
||||||
newSeries.Path = Path.Combine(newSeries.RootFolderPath, folderName);
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Info("Adding Series {0} Path: [{1}]", newSeries, newSeries.Path);
|
|
||||||
|
|
||||||
newSeries.CleanTitle = newSeries.Title.CleanSeriesTitle();
|
|
||||||
newSeries.SortTitle = SeriesTitleNormalizer.Normalize(newSeries.Title, newSeries.TvdbId);
|
|
||||||
newSeries.Added = DateTime.UtcNow;
|
|
||||||
|
|
||||||
_seriesRepository.Insert(newSeries);
|
_seriesRepository.Insert(newSeries);
|
||||||
_eventAggregator.PublishEvent(new SeriesAddedEvent(GetSeries(newSeries.Id)));
|
_eventAggregator.PublishEvent(new SeriesAddedEvent(GetSeries(newSeries.Id)));
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue