mirror of
https://github.com/Sonarr/Sonarr.git
synced 2025-01-23 11:04:52 +02:00
parent
e70d92f670
commit
9b617af713
frontend/src/Settings/MediaManagement
src
NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications
NzbDrone.Core
Sonarr.Api.V3/Config
@ -13,6 +13,12 @@ import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import RootFoldersConnector from 'RootFolder/RootFoldersConnector';
|
||||
import NamingConnector from './Naming/NamingConnector';
|
||||
|
||||
const episodeTitleRequiredOptions = [
|
||||
{ key: 'always', value: 'Always' },
|
||||
{ key: 'bulkSeasonReleases', value: 'Only for Bulk Season Releases' },
|
||||
{ key: 'never', value: 'Never' }
|
||||
];
|
||||
|
||||
const rescanAfterRefreshOptions = [
|
||||
{ key: 'always', value: 'Always' },
|
||||
{ key: 'afterManual', value: 'After Manual Refresh' },
|
||||
@ -116,6 +122,23 @@ class MediaManagement extends Component {
|
||||
<FieldSet
|
||||
legend="Importing"
|
||||
>
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
size={sizes.SMALL}
|
||||
>
|
||||
<FormLabel>Episode Title Required</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="episodeTitleRequired"
|
||||
helpText="Prevent importing for up to 24 hours if the episode title is in the naming format and the episode title is TBA"
|
||||
values={episodeTitleRequiredOptions}
|
||||
onChange={onInputChange}
|
||||
{...settings.episodeTitleRequired}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{
|
||||
isMono &&
|
||||
<FormGroup
|
||||
|
64
src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/EpisodeTitleSpecificationFixture.cs
64
src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/EpisodeTitleSpecificationFixture.cs
@ -2,7 +2,10 @@ using System;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
@ -81,5 +84,66 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
||||
|
||||
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_accept_when_episode_title_is_never_required()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.EpisodeTitleRequired)
|
||||
.Returns(EpisodeTitleRequiredType.Never);
|
||||
|
||||
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_accept_if_episode_title_is_required_for_bulk_season_releases_and_not_bulk_season()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.EpisodeTitleRequired)
|
||||
.Returns(EpisodeTitleRequiredType.BulkSeasonReleases);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodesBySeason(It.IsAny<int>(), It.IsAny<int>()))
|
||||
.Returns(Builder<Episode>.CreateListOfSize(5).BuildList());
|
||||
|
||||
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_accept_if_episode_title_is_required_for_bulk_season_releases()
|
||||
{
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.EpisodeTitleRequired)
|
||||
.Returns(EpisodeTitleRequiredType.BulkSeasonReleases);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodesBySeason(It.IsAny<int>(), It.IsAny<int>()))
|
||||
.Returns(Builder<Episode>.CreateListOfSize(5)
|
||||
.All()
|
||||
.With(e => e.AirDateUtc == _localEpisode.Episodes.First().AirDateUtc)
|
||||
.BuildList());
|
||||
|
||||
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_reject_if_episode_title_is_required_for_bulk_season_releases_and_it_is_mising()
|
||||
{
|
||||
_localEpisode.Episodes.First().Title = "TBA";
|
||||
|
||||
Mocker.GetMock<IConfigService>()
|
||||
.Setup(s => s.EpisodeTitleRequired)
|
||||
.Returns(EpisodeTitleRequiredType.BulkSeasonReleases);
|
||||
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(s => s.GetEpisodesBySeason(It.IsAny<int>(), It.IsAny<int>()))
|
||||
.Returns(Builder<Episode>.CreateListOfSize(5)
|
||||
.All()
|
||||
.With(e => e.AirDateUtc = _localEpisode.Episodes.First().AirDateUtc)
|
||||
.BuildList());
|
||||
|
||||
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using NzbDrone.Core.Configuration.Events;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Common.Http.Proxy;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.Security;
|
||||
|
||||
namespace NzbDrone.Core.Configuration
|
||||
@ -223,6 +224,13 @@ namespace NzbDrone.Core.Configuration
|
||||
set { SetValue("RescanAfterRefresh", value); }
|
||||
}
|
||||
|
||||
public EpisodeTitleRequiredType EpisodeTitleRequired
|
||||
{
|
||||
get { return GetValueEnum("EpisodeTitleRequired", EpisodeTitleRequiredType.Always); }
|
||||
|
||||
set { SetValue("EpisodeTitleRequired", value); }
|
||||
}
|
||||
|
||||
public bool SetPermissionsLinux
|
||||
{
|
||||
get { return GetValueBoolean("SetPermissionsLinux", false); }
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Common.Http.Proxy;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.Security;
|
||||
|
||||
namespace NzbDrone.Core.Configuration
|
||||
@ -35,6 +36,8 @@ namespace NzbDrone.Core.Configuration
|
||||
bool ImportExtraFiles { get; set; }
|
||||
string ExtraFileExtensions { get; set; }
|
||||
RescanAfterRefreshType RescanAfterRefresh { get; set; }
|
||||
EpisodeTitleRequiredType EpisodeTitleRequired { get; set; }
|
||||
|
||||
|
||||
//Permissions (Media Management)
|
||||
bool SetPermissionsLinux { get; set; }
|
||||
|
@ -0,0 +1,9 @@
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
{
|
||||
public enum EpisodeTitleRequiredType
|
||||
{
|
||||
Always = 0,
|
||||
BulkSeasonReleases = 1,
|
||||
Never = 2
|
||||
}
|
||||
}
|
@ -1,32 +1,69 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||
{
|
||||
public class EpisodeTitleSpecification : IImportDecisionEngineSpecification
|
||||
{
|
||||
private readonly IConfigService _configService;
|
||||
private readonly IBuildFileNames _buildFileNames;
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public EpisodeTitleSpecification(IBuildFileNames buildFileNames, Logger logger)
|
||||
public EpisodeTitleSpecification(IConfigService configService,
|
||||
IBuildFileNames buildFileNames,
|
||||
IEpisodeService episodeService,
|
||||
Logger logger)
|
||||
{
|
||||
_configService = configService;
|
||||
_buildFileNames = buildFileNames;
|
||||
_episodeService = episodeService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
var episodeTitleRequired = _configService.EpisodeTitleRequired;
|
||||
|
||||
if (episodeTitleRequired == EpisodeTitleRequiredType.Never)
|
||||
{
|
||||
_logger.Debug("Episode titles are never required, skipping check");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
if (!_buildFileNames.RequiresEpisodeTitle(localEpisode.Series, localEpisode.Episodes))
|
||||
{
|
||||
_logger.Debug("File name format does not require episode title, skipping check");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
foreach (var episode in localEpisode.Episodes)
|
||||
var episodes = localEpisode.Episodes;
|
||||
var firstEpisode = episodes.First();
|
||||
var episodesInSeason = _episodeService.GetEpisodesBySeason(firstEpisode.SeriesId, firstEpisode.EpisodeNumber);
|
||||
var allEpisodesOnTheSameDay = firstEpisode.AirDateUtc.HasValue && episodes.All(e =>
|
||||
e.AirDateUtc.HasValue &&
|
||||
e.AirDateUtc.Value == firstEpisode.AirDateUtc.Value);
|
||||
|
||||
if (episodeTitleRequired == EpisodeTitleRequiredType.BulkSeasonReleases &&
|
||||
allEpisodesOnTheSameDay &&
|
||||
episodesInSeason.Count(e => e.AirDateUtc.HasValue &&
|
||||
e.AirDateUtc.Value == firstEpisode.AirDateUtc.Value
|
||||
) < 4
|
||||
)
|
||||
{
|
||||
_logger.Debug("Episode title only required for bulk season releases");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
var airDateUtc = episode.AirDateUtc;
|
||||
var title = episode.Title;
|
||||
|
@ -783,6 +783,7 @@
|
||||
<Compile Include="Languages\LanguageComparer.cs" />
|
||||
<Compile Include="Languages\LanguagesBelowCutoff.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Aggregation\Aggregators\AggregateLanguage.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\EpisodeTitleRequiredType.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\AbsoluteEpisodeNumberSpecification.cs" />
|
||||
<Compile Include="Notifications\Discord\Discord.cs" />
|
||||
<Compile Include="Notifications\Discord\DiscordColors.cs" />
|
||||
|
@ -1,5 +1,6 @@
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using Sonarr.Http.REST;
|
||||
|
||||
namespace Sonarr.Api.V3.Config
|
||||
@ -20,6 +21,7 @@ namespace Sonarr.Api.V3.Config
|
||||
public string ChownUser { get; set; }
|
||||
public string ChownGroup { get; set; }
|
||||
|
||||
public EpisodeTitleRequiredType EpisodeTitleRequired { get; set; }
|
||||
public bool SkipFreeSpaceCheckWhenImporting { get; set; }
|
||||
public bool CopyUsingHardlinks { get; set; }
|
||||
public bool ImportExtraFiles { get; set; }
|
||||
@ -47,6 +49,7 @@ namespace Sonarr.Api.V3.Config
|
||||
ChownUser = model.ChownUser,
|
||||
ChownGroup = model.ChownGroup,
|
||||
|
||||
EpisodeTitleRequired = model.EpisodeTitleRequired,
|
||||
SkipFreeSpaceCheckWhenImporting = model.SkipFreeSpaceCheckWhenImporting,
|
||||
CopyUsingHardlinks = model.CopyUsingHardlinks,
|
||||
ImportExtraFiles = model.ImportExtraFiles,
|
||||
|
Loading…
x
Reference in New Issue
Block a user