Merge branch 'develop'

This commit is contained in:
Mark McDowall 2014-02-23 14:57:02 -08:00
commit e7c2eda995
249 changed files with 4351 additions and 3175 deletions
Logo
src
NzbDrone.Api
NzbDrone.Common
NzbDrone.Core.Test
NzbDrone.Core

Binary file not shown.

Before

(image error) Size: 1.5 KiB

After

(image error) Size: 3.5 KiB

Binary file not shown.

Before

(image error) Size: 79 KiB

Binary file not shown.

Before

(image error) Size: 65 KiB

Binary file not shown.

Before

(image error) Size: 92 KiB

View File

@ -0,0 +1,21 @@
using System;
using FluentValidation;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Api.Config
{
public class DownloadClientConfigModule : NzbDroneConfigModule<DownloadClientConfigResource>
{
public DownloadClientConfigModule(IConfigService configService, RootFolderValidator rootFolderValidator, PathExistsValidator pathExistsValidator)
: base(configService)
{
SharedValidator.RuleFor(c => c.DownloadedEpisodesFolder)
.Cascade(CascadeMode.StopOnFirstFailure)
.IsValidPath()
.SetValidator(rootFolderValidator)
.SetValidator(pathExistsValidator)
.When(c => !String.IsNullOrWhiteSpace(c.DownloadedEpisodesFolder));
}
}
}

View File

@ -0,0 +1,15 @@
using System;
using NzbDrone.Api.REST;
namespace NzbDrone.Api.Config
{
public class DownloadClientConfigResource : RestResource
{
public String DownloadedEpisodesFolder { get; set; }
public String DownloadClientWorkingFolders { get; set; }
public Boolean AutoRedownloadFailed { get; set; }
public Boolean RemoveFailedDownloads { get; set; }
public Boolean EnableFailedDownloadHandling { get; set; }
}
}

View File

@ -0,0 +1,55 @@
using System.Linq;
using System.Reflection;
using FluentValidation;
using NzbDrone.Core.Configuration;
using Omu.ValueInjecter;
namespace NzbDrone.Api.Config
{
public class HostConfigModule : NzbDroneRestModule<HostConfigResource>
{
private readonly IConfigFileProvider _configFileProvider;
public HostConfigModule(ConfigFileProvider configFileProvider)
: base("/config/host")
{
_configFileProvider = configFileProvider;
GetResourceSingle = GetHostConfig;
GetResourceById = GetHostConfig;
UpdateResource = SaveHostConfig;
SharedValidator.RuleFor(c => c.Branch).NotEmpty().WithMessage("Branch name is required, 'master' is the default");
SharedValidator.RuleFor(c => c.Port).InclusiveBetween(1, 65535);
SharedValidator.RuleFor(c => c.Username).NotEmpty().When(c => c.AuthenticationEnabled);
SharedValidator.RuleFor(c => c.Password).NotEmpty().When(c => c.AuthenticationEnabled);
SharedValidator.RuleFor(c => c.SslPort).InclusiveBetween(1, 65535).When(c => c.EnableSsl);
SharedValidator.RuleFor(c => c.SslCertHash).NotEmpty().When(c => c.EnableSsl);
}
private HostConfigResource GetHostConfig()
{
var resource = new HostConfigResource();
resource.InjectFrom(_configFileProvider);
resource.Id = 1;
return resource;
}
private HostConfigResource GetHostConfig(int id)
{
return GetHostConfig();
}
private void SaveHostConfig(HostConfigResource resource)
{
var dictionary = resource.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null));
_configFileProvider.SaveConfigDictionary(dictionary);
}
}
}

View File

@ -0,0 +1,22 @@
using System;
using NzbDrone.Api.REST;
namespace NzbDrone.Api.Config
{
public class HostConfigResource : RestResource
{
public Int32 Port { get; set; }
public Int32 SslPort { get; set; }
public Boolean EnableSsl { get; set; }
public Boolean LaunchBrowser { get; set; }
public Boolean AuthenticationEnabled { get; set; }
public String Username { get; set; }
public String Password { get; set; }
public String LogLevel { get; set; }
public String Branch { get; set; }
public String ApiKey { get; set; }
public Boolean Torrent { get; set; }
public String SslCertHash { get; set; }
public String UrlBase { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using FluentValidation;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Api.Config
{
public class IndexerConfigModule : NzbDroneConfigModule<IndexerConfigResource>
{
public IndexerConfigModule(IConfigService configService)
: base(configService)
{
SharedValidator.RuleFor(c => c.RssSyncInterval).InclusiveBetween(10, 120);
}
}
}

View File

@ -0,0 +1,12 @@
using System;
using NzbDrone.Api.REST;
namespace NzbDrone.Api.Config
{
public class IndexerConfigResource : RestResource
{
public Int32 Retention { get; set; }
public Int32 RssSyncInterval { get; set; }
public String ReleaseRestrictions { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
using FluentValidation;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Api.Config
{
public class MediaManagementConfigModule : NzbDroneConfigModule<MediaManagementConfigResource>
{
public MediaManagementConfigModule(IConfigService configService, PathExistsValidator pathExistsValidator)
: base(configService)
{
SharedValidator.RuleFor(c => c.FileChmod).NotEmpty();
SharedValidator.RuleFor(c => c.FolderChmod).NotEmpty();
SharedValidator.RuleFor(c => c.RecycleBin).IsValidPath().SetValidator(pathExistsValidator).When(c => !String.IsNullOrWhiteSpace(c.RecycleBin));
}
}
}

View File

@ -0,0 +1,19 @@
using System;
using NzbDrone.Api.REST;
namespace NzbDrone.Api.Config
{
public class MediaManagementConfigResource : RestResource
{
public Boolean AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; }
public String RecycleBin { get; set; }
public Boolean AutoDownloadPropers { get; set; }
public Boolean CreateEmptySeriesFolders { get; set; }
public Boolean SetPermissionsLinux { get; set; }
public String FileChmod { get; set; }
public String FolderChmod { get; set; }
public String ChownUser { get; set; }
public String ChownGroup { get; set; }
}
}

View File

@ -12,14 +12,14 @@ using Omu.ValueInjecter;
namespace NzbDrone.Api.Config
{
public class NamingModule : NzbDroneRestModule<NamingConfigResource>
public class NamingConfigModule : NzbDroneRestModule<NamingConfigResource>
{
private readonly INamingConfigService _namingConfigService;
private readonly IFilenameSampleService _filenameSampleService;
private readonly IFilenameValidationService _filenameValidationService;
private readonly IBuildFileNames _filenameBuilder;
public NamingModule(INamingConfigService namingConfigService,
public NamingConfigModule(INamingConfigService namingConfigService,
IFilenameSampleService filenameSampleService,
IFilenameValidationService filenameValidationService,
IBuildFileNames filenameBuilder)

View File

@ -0,0 +1,51 @@
using System.Linq;
using System.Reflection;
using NzbDrone.Api.REST;
using NzbDrone.Core.Configuration;
using Omu.ValueInjecter;
namespace NzbDrone.Api.Config
{
public abstract class NzbDroneConfigModule<TResource> : NzbDroneRestModule<TResource> where TResource : RestResource, new()
{
private readonly IConfigService _configService;
protected NzbDroneConfigModule(IConfigService configService)
: this(new TResource().ResourceName.Replace("config", ""), configService)
{
}
protected NzbDroneConfigModule(string resource, IConfigService configService) :
base("config/" + resource.Trim('/'))
{
_configService = configService;
GetResourceSingle = GetConfig;
GetResourceById = GetConfig;
UpdateResource = SaveConfig;
}
private TResource GetConfig()
{
var resource = new TResource();
resource.InjectFrom(_configService);
resource.Id = 1;
return resource;
}
private TResource GetConfig(int id)
{
return GetConfig();
}
private void SaveConfig(TResource resource)
{
var dictionary = resource.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(resource, null));
_configService.SaveConfigDictionary(dictionary);
}
}
}

View File

@ -1,71 +0,0 @@
using System;
using System.Collections.Generic;
using Nancy;
using NzbDrone.Api.Extensions;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Api.Config
{
public class SettingsModule : NzbDroneApiModule
{
private readonly IConfigService _configService;
private readonly IConfigFileProvider _configFileProvider;
public SettingsModule(IConfigService configService, IConfigFileProvider configFileProvider)
: base("/settings")
{
_configService = configService;
_configFileProvider = configFileProvider;
Get["/"] = x => GetGeneralSettings();
Post["/"] = x => SaveGeneralSettings();
Get["/host"] = x => GetHostSettings();
Post["/host"] = x => SaveHostSettings();
Get["/log"] = x => GetLogSettings();
Post["/log"] = x => SaveLogSettings();
}
private Response SaveLogSettings()
{
throw new NotImplementedException();
}
private Response GetLogSettings()
{
throw new NotImplementedException();
}
private Response SaveHostSettings()
{
var request = Request.Body.FromJson<Dictionary<string, object>>();
_configFileProvider.SaveConfigDictionary(request);
return GetHostSettings();
}
private Response GetHostSettings()
{
return _configFileProvider.GetConfigDictionary().AsResponse();
}
private Response GetGeneralSettings()
{
var collection = Request.Query.Collection;
if (collection.HasValue && Boolean.Parse(collection.Value))
return _configService.All().AsResponse();
return _configService.AllWithDefaults().AsResponse();
}
private Response SaveGeneralSettings()
{
var request = Request.Body.FromJson<Dictionary<string, object>>();
_configService.SaveValues(request);
return request.AsResponse();
}
}
}

View File

@ -0,0 +1,18 @@
using NzbDrone.Core.Download;
namespace NzbDrone.Api.DownloadClient
{
public class DownloadClientModule : ProviderModuleBase<DownloadClientResource, IDownloadClient, DownloadClientDefinition>
{
public DownloadClientModule(IDownloadClientFactory downloadClientFactory)
: base(downloadClientFactory, "downloadclient")
{
}
protected override void Validate(DownloadClientDefinition definition)
{
if (!definition.Enable) return;
base.Validate(definition);
}
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace NzbDrone.Api.DownloadClient
{
public class DownloadClientResource : ProviderResource
{
public Boolean Enable { get; set; }
public Int32 Protocol { get; set; }
}
}

View File

@ -0,0 +1,37 @@
using System.Collections.Generic;
using NzbDrone.Api.ClientSchema;
using NzbDrone.Core.Download;
using Omu.ValueInjecter;
namespace NzbDrone.Api.DownloadClient
{
public class DownloadClientSchemaModule : NzbDroneRestModule<DownloadClientResource>
{
private readonly IDownloadClientFactory _notificationFactory;
public DownloadClientSchemaModule(IDownloadClientFactory notificationFactory)
: base("downloadclient/schema")
{
_notificationFactory = notificationFactory;
GetResourceAll = GetSchema;
}
private List<DownloadClientResource> GetSchema()
{
var notifications = _notificationFactory.Templates();
var result = new List<DownloadClientResource>(notifications.Count);
foreach (var notification in notifications)
{
var notificationResource = new DownloadClientResource();
notificationResource.InjectFrom(notification);
notificationResource.Fields = SchemaBuilder.ToSchema(notification.Settings);
result.Add(notificationResource);
}
return result;
}
}
}

View File

@ -92,8 +92,19 @@
<Compile Include="ClientSchema\SelectOption.cs" />
<Compile Include="Commands\CommandModule.cs" />
<Compile Include="Commands\CommandResource.cs" />
<Compile Include="Config\IndexerConfigModule.cs" />
<Compile Include="Config\MediaManagementConfigModule.cs" />
<Compile Include="Config\MediaManagementConfigResource.cs" />
<Compile Include="Config\NzbDroneConfigModule.cs" />
<Compile Include="Config\DownloadClientConfigModule.cs" />
<Compile Include="Config\DownloadClientConfigResource.cs" />
<Compile Include="Config\HostConfigModule.cs" />
<Compile Include="Config\HostConfigResource.cs" />
<Compile Include="Config\NamingConfigResource.cs" />
<Compile Include="Config\NamingModule.cs" />
<Compile Include="Config\NamingConfigModule.cs" />
<Compile Include="Config\IndexerConfigResource.cs" />
<Compile Include="DownloadClient\DownloadClientModule.cs" />
<Compile Include="DownloadClient\DownloadClientResource.cs" />
<Compile Include="DiskSpace\DiskSpaceModule.cs" />
<Compile Include="DiskSpace\DiskSpaceResource.cs" />
<Compile Include="EpisodeFiles\EpisodeFileModule.cs" />
@ -122,6 +133,7 @@
<Compile Include="History\HistoryModule.cs" />
<Compile Include="Metadata\MetadataResource.cs" />
<Compile Include="Metadata\MetadataModule.cs" />
<Compile Include="Notifications\NotificationSchemaModule.cs" />
<Compile Include="ProviderResource.cs" />
<Compile Include="ProviderModuleBase.cs" />
<Compile Include="Indexers\IndexerSchemaModule.cs" />
@ -145,7 +157,7 @@
<Compile Include="Queue\QueueModule.cs" />
<Compile Include="Queue\QueueResource.cs" />
<Compile Include="ResourceChangeMessage.cs" />
<Compile Include="Notifications\NotificationSchemaModule.cs" />
<Compile Include="DownloadClient\DownloadClientSchemaModule.cs" />
<Compile Include="Notifications\NotificationModule.cs" />
<Compile Include="Notifications\NotificationResource.cs" />
<Compile Include="NzbDroneRestModule.cs" />
@ -174,11 +186,9 @@
<Compile Include="Qualities\QualityDefinitionResource.cs" />
<Compile Include="Qualities\QualityDefinitionModule.cs" />
<Compile Include="Extensions\ReqResExtensions.cs" />
<Compile Include="Config\SettingsModule.cs" />
<Compile Include="System\SystemModule.cs" />
<Compile Include="TinyIoCNancyBootstrapper.cs" />
<Compile Include="Update\UpdateModule.cs" />
<Compile Include="Validation\PathValidator.cs" />
<Compile Include="Validation\RuleBuilderExtensions.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -5,7 +5,7 @@ using FluentValidation.Results;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.RootFolders;
using NzbDrone.Api.Mapping;
using NzbDrone.Api.Validation;
using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Api.RootFolders
{
@ -13,7 +13,11 @@ namespace NzbDrone.Api.RootFolders
{
private readonly IRootFolderService _rootFolderService;
public RootFolderModule(IRootFolderService rootFolderService, ICommandExecutor commandExecutor)
public RootFolderModule(IRootFolderService rootFolderService,
ICommandExecutor commandExecutor,
RootFolderValidator rootFolderValidator,
PathExistsValidator pathExistsValidator,
DroneFactoryValidator droneFactoryValidator)
: base(commandExecutor)
{
_rootFolderService = rootFolderService;
@ -23,7 +27,12 @@ namespace NzbDrone.Api.RootFolders
CreateResource = CreateRootFolder;
DeleteResource = DeleteFolder;
SharedValidator.RuleFor(c => c.Path).IsValidPath();
SharedValidator.RuleFor(c => c.Path)
.Cascade(CascadeMode.StopOnFirstFailure)
.IsValidPath()
.SetValidator(rootFolderValidator)
.SetValidator(pathExistsValidator)
.SetValidator(droneFactoryValidator);
}
private RootFolderResource GetRootFolder(int id)
@ -33,15 +42,7 @@ namespace NzbDrone.Api.RootFolders
private int CreateRootFolder(RootFolderResource rootFolderResource)
{
try
{
return GetNewId<RootFolder>(_rootFolderService.Add, rootFolderResource);
}
catch (Exception ex)
{
throw new ValidationException(new [] { new ValidationFailure("Path", ex.Message) });
}
return GetNewId<RootFolder>(_rootFolderService.Add, rootFolderResource);
}
private List<RootFolderResource> GetRootFolders()

View File

@ -12,6 +12,7 @@ using NzbDrone.Core.Tv;
using NzbDrone.Api.Validation;
using NzbDrone.Api.Mapping;
using NzbDrone.Core.Tv.Events;
using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Api.Series
{

View File

@ -1,6 +1,7 @@
using System.Text.RegularExpressions;
using FluentValidation;
using FluentValidation.Validators;
using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Api.Validation
{
@ -21,11 +22,6 @@ namespace NzbDrone.Api.Validation
return ruleBuilder.SetValidator(new RegularExpressionValidator("^http(s)?://", RegexOptions.IgnoreCase)).WithMessage("must start with http:// or https://");
}
public static IRuleBuilderOptions<T, string> IsValidPath<T>(this IRuleBuilder<T, string> ruleBuilder)
{
return ruleBuilder.SetValidator(new PathValidator());
}
public static IRuleBuilderOptions<T, string> NotBlank<T>(this IRuleBuilder<T, string> ruleBuilder)
{
return ruleBuilder.SetValidator(new NotNullValidator()).SetValidator(new NotEmptyValidator(""));

View File

@ -71,7 +71,6 @@ namespace NzbDrone.Common
return false;
}
public static bool ContainsInvalidPathChars(this string text)
{
return text.IndexOfAny(Path.GetInvalidPathChars()) >= 0;

View File

@ -179,9 +179,7 @@ namespace NzbDrone.Common.Processes
public ProcessOutput StartAndCapture(string path, string args = null)
{
var output = new ProcessOutput();
var process = Start(path, args, s => output.Standard.Add(s), error => output.Error.Add(error));
WaitForExit(process);
Start(path, args, s => output.Standard.Add(s), error => output.Error.Add(error)).WaitForExit();
return output;
}
@ -190,10 +188,7 @@ namespace NzbDrone.Common.Processes
{
Logger.Trace("Waiting for process {0} to exit.", process.ProcessName);
if (!process.HasExited)
{
process.WaitForExit();
}
process.WaitForExit();
}
public void SetPriority(int processId, ProcessPriorityClass priority)

View File

@ -105,16 +105,6 @@ namespace NzbDrone.Core.Test.Configuration
Subject.GetValue(key, value2).Should().Be(value2);
}
[Test]
public void updating_a_vakye_should_update_its_value()
{
Subject.SabHost = "Test";
Subject.SabHost.Should().Be("Test");
Subject.SabHost = "Test2";
Subject.SabHost.Should().Be("Test2");
}
[Test]
[Description("This test will use reflection to ensure each config property read/writes to a unique key")]
public void config_properties_should_write_and_read_using_same_key()

View File

@ -15,340 +15,166 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
public class AcceptableSizeSpecificationFixture : CoreTest<AcceptableSizeSpecification>
{
private RemoteEpisode parseResultMultiSet;
private RemoteEpisode parseResultMulti;
private RemoteEpisode parseResultSingle;
private Series series30minutes;
private Series series60minutes;
private Series series;
private QualityDefinition qualityType;
[SetUp]
public void Setup()
{
series = Builder<Series>.CreateNew()
.Build();
parseResultMultiSet = new RemoteEpisode
{
Series = series,
Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.SDTV, true) },
Episodes = new List<Episode> { new Episode(), new Episode(), new Episode(), new Episode(), new Episode(), new Episode() }
};
parseResultMulti = new RemoteEpisode
{
Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.SDTV, true) },
Episodes = new List<Episode> { new Episode(), new Episode() }
};
{
Series = series,
Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.SDTV, true) },
Episodes = new List<Episode> { new Episode(), new Episode() }
};
parseResultSingle = new RemoteEpisode
{
Series = series,
Release = new ReleaseInfo(),
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = new QualityModel(Quality.SDTV, true) },
Episodes = new List<Episode> { new Episode() }
};
series30minutes = Builder<Series>.CreateNew()
.With(c => c.Runtime = 30)
.Build();
series60minutes = Builder<Series>.CreateNew()
.With(c => c.Runtime = 60)
.Build();
qualityType = Builder<QualityDefinition>.CreateNew()
.With(q => q.MinSize = 0)
.With(q => q.MinSize = 2)
.With(q => q.MaxSize = 10)
.With(q => q.Quality = Quality.SDTV)
.Build();
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
}
[Test]
public void IsAcceptableSize_true_single_episode_not_first_or_last_30_minute()
private void GivenLastEpisode()
{
parseResultSingle.Series = series30minutes;
parseResultSingle.Release.Size = 184572800;
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(false);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeTrue();
}
[Test]
public void IsAcceptableSize_true_single_episode_not_first_or_last_60_minute()
{
parseResultSingle.Series = series60minutes;
parseResultSingle.Release.Size = 368572800;
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(false);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeTrue();
}
[Test]
public void IsAcceptableSize_false_single_episode_not_first_or_last_30_minute()
{
parseResultSingle.Series = series30minutes;
parseResultSingle.Release.Size = 1.Gigabytes();
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(false);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeFalse();
}
[Test]
public void IsAcceptableSize_false_single_episode_not_first_or_last_60_minute()
{
parseResultSingle.Series = series60minutes;
parseResultSingle.Release.Size = 1.Gigabytes();
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(false);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeFalse();
}
[Test]
public void IsAcceptableSize_true_multi_episode_not_first_or_last_30_minute()
{
parseResultMulti.Series = series30minutes;
parseResultMulti.Release.Size = 184572800;
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(false);
bool result = Subject.IsSatisfiedBy(parseResultMulti, null);
result.Should().BeTrue();
}
[Test]
public void IsAcceptableSize_true_multi_episode_not_first_or_last_60_minute()
{
parseResultMulti.Series = series60minutes;
parseResultMulti.Release.Size = 368572800;
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(false);
bool result = Subject.IsSatisfiedBy(parseResultMulti, null);
result.Should().BeTrue();
}
[Test]
public void IsAcceptableSize_false_multi_episode_not_first_or_last_30_minute()
{
parseResultMulti.Series = series30minutes;
parseResultMulti.Release.Size = 1.Gigabytes();
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(false);
bool result = Subject.IsSatisfiedBy(parseResultMulti, null);
result.Should().BeFalse();
}
[Test]
public void IsAcceptableSize_false_multi_episode_not_first_or_last_60_minute()
{
parseResultMulti.Series = series60minutes;
parseResultMulti.Release.Size = 10.Gigabytes();
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(false);
bool result = Subject.IsSatisfiedBy(parseResultMulti, null);
result.Should().BeFalse();
}
[Test]
public void IsAcceptableSize_true_single_episode_first_30_minute()
{
parseResultSingle.Series = series30minutes;
parseResultSingle.Release.Size = 184572800;
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(true);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeTrue();
}
[Test]
public void IsAcceptableSize_true_single_episode_first_60_minute()
{
parseResultSingle.Series = series60minutes;
parseResultSingle.Release.Size = 368572800;
[TestCase(30, 50, false)]
[TestCase(30, 250, true)]
[TestCase(30, 500, false)]
[TestCase(60, 100, false)]
[TestCase(60, 500, true)]
[TestCase(60, 1000, false)]
public void single_episode(int runtime, int sizeInMegaBytes, bool expectedResult)
{
series.Runtime = runtime;
parseResultSingle.Series = series;
parseResultSingle.Release.Size = sizeInMegaBytes.Megabytes();
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Subject.IsSatisfiedBy(parseResultSingle, null).Should().Be(expectedResult);
}
[TestCase(30, 500, true)]
[TestCase(30, 1000, false)]
[TestCase(60, 1000, true)]
[TestCase(60, 2000, false)]
public void single_episode_first_or_last(int runtime, int sizeInMegaBytes, bool expectedResult)
{
GivenLastEpisode();
series.Runtime = runtime;
parseResultSingle.Series = series;
parseResultSingle.Release.Size = sizeInMegaBytes.Megabytes();
Subject.IsSatisfiedBy(parseResultSingle, null).Should().Be(expectedResult);
}
[TestCase(30, 50 * 2, false)]
[TestCase(30, 250 * 2, true)]
[TestCase(30, 500 * 2, false)]
[TestCase(60, 100 * 2, false)]
[TestCase(60, 500 * 2, true)]
[TestCase(60, 1000 * 2, false)]
public void multi_episode(int runtime, int sizeInMegaBytes, bool expectedResult)
{
series.Runtime = runtime;
parseResultMulti.Series = series;
parseResultMulti.Release.Size = sizeInMegaBytes.Megabytes();
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(true);
.Returns(false);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeTrue();
Subject.IsSatisfiedBy(parseResultMulti, null).Should().Be(expectedResult);
}
[Test]
public void IsAcceptableSize_false_single_episode_first_30_minute()
[TestCase(30, 50 * 6, false)]
[TestCase(30, 250 * 6, true)]
[TestCase(30, 500 * 6, false)]
[TestCase(60, 100 * 6, false)]
[TestCase(60, 500 * 6, true)]
[TestCase(60, 1000 * 6, false)]
public void multiset_episode(int runtime, int sizeInMegaBytes, bool expectedResult)
{
parseResultSingle.Series = series30minutes;
parseResultSingle.Release.Size = 1.Gigabytes();
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
series.Runtime = runtime;
parseResultMultiSet.Series = series;
parseResultMultiSet.Release.Size = sizeInMegaBytes.Megabytes();
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(true);
.Returns(false);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeFalse();
Subject.IsSatisfiedBy(parseResultMultiSet, null).Should().Be(expectedResult);
}
[Test]
public void IsAcceptableSize_false_single_episode_first_60_minute()
public void should_return_true_if_unlimited_30_minute()
{
GivenLastEpisode();
parseResultSingle.Series = series60minutes;
parseResultSingle.Release.Size = 10.Gigabytes();
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(true);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeFalse();
}
[Test]
public void IsAcceptableSize_true_unlimited_30_minute()
{
parseResultSingle.Series = series30minutes;
series.Runtime = 30;
parseResultSingle.Series = series;
parseResultSingle.Release.Size = 18457280000;
qualityType.MaxSize = 0;
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(true);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeTrue();
Subject.IsSatisfiedBy(parseResultSingle, null).Should().BeTrue();
}
[Test]
public void IsAcceptableSize_true_unlimited_60_minute()
public void should_return_true_if_unlimited_60_minute()
{
GivenLastEpisode();
parseResultSingle.Series = series60minutes;
series.Runtime = 60;
parseResultSingle.Series = series;
parseResultSingle.Release.Size = 36857280000;
qualityType.MaxSize = 0;
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(true);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeTrue();
Subject.IsSatisfiedBy(parseResultSingle, null).Should().BeTrue();;
}
[Test]
public void IsAcceptableSize_should_treat_daily_series_as_single_episode()
public void should_treat_daily_series_as_single_episode()
{
GivenLastEpisode();
parseResultSingle.Series = series60minutes;
series.Runtime = 60;
parseResultSingle.Series = series;
parseResultSingle.Series.SeriesType = SeriesTypes.Daily;
parseResultSingle.Release.Size = 300.Megabytes();
qualityType.MaxSize = (int)600.Megabytes();
qualityType.MaxSize = 10;
Mocker.GetMock<IQualityDefinitionService>().Setup(s => s.Get(Quality.SDTV)).Returns(qualityType);
Mocker.GetMock<IEpisodeService>().Setup(
s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny<int>()))
.Returns(true);
bool result = Subject.IsSatisfiedBy(parseResultSingle, null);
result.Should().BeTrue();
Subject.IsSatisfiedBy(parseResultSingle, null).Should().BeTrue();
}
[Test]
@ -362,9 +188,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Subject.IsSatisfiedBy(parseResult, null).Should().BeTrue();
}
[Test]
public void should_always_return_false_if_unknow()
public void should_always_return_false_if_unknown()
{
var parseResult = new RemoteEpisode
{
@ -373,7 +198,6 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Subject.IsSatisfiedBy(parseResult, null).Should().BeFalse();
Mocker.GetMock<IQualityDefinitionService>().Verify(c => c.Get(It.IsAny<Quality>()), Times.Never());
}
}

View File

@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void GivenSpecifications(params Mock<IDecisionEngineSpecification>[] mocks)
{
Mocker.SetConstant<IEnumerable<IRejectWithReason>>(mocks.Select(c => c.Object));
Mocker.SetConstant<IEnumerable<IDecisionEngineSpecification>>(mocks.Select(c => c.Object));
}
[Test]

View File

@ -83,7 +83,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
private void GivenSabnzbdDownloadClient()
{
Mocker.GetMock<IProvideDownloadClient>()
.Setup(c => c.GetDownloadClient()).Returns(Mocker.Resolve<SabnzbdClient>());
.Setup(c => c.GetDownloadClient()).Returns(Mocker.Resolve<Sabnzbd>());
}
private void GivenMostRecentForEpisode(HistoryEventType eventType)

View File

@ -56,9 +56,6 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
Mocker.GetMock<IProvideDownloadClient>()
.Setup(s => s.GetDownloadClient())
.Returns(_downloadClient.Object);
_downloadClient.SetupGet(s => s.IsConfigured)
.Returns(true);
}
private void GivenEmptyQueue()

View File

@ -20,65 +20,62 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
{
parseResult = new RemoteEpisode
{
Release = new ReleaseInfo
{
PublishDate = DateTime.Now.AddDays(-100)
}
Release = new ReleaseInfo()
};
}
private void WithUnlimitedRetention()
private void WithRetention(int days)
{
Mocker.GetMock<IConfigService>().SetupGet(c => c.Retention).Returns(0);
Mocker.GetMock<IConfigService>().SetupGet(c => c.Retention).Returns(days);
}
private void WithLongRetention()
private void WithAge(int days)
{
Mocker.GetMock<IConfigService>().SetupGet(c => c.Retention).Returns(1000);
}
private void WithShortRetention()
{
Mocker.GetMock<IConfigService>().SetupGet(c => c.Retention).Returns(10);
}
private void WithEqualRetention()
{
Mocker.GetMock<IConfigService>().SetupGet(c => c.Retention).Returns(100);
parseResult.Release.PublishDate = DateTime.Now.AddDays(-days);
}
[Test]
public void unlimited_retention_should_return_true()
public void should_return_true_when_retention_is_set_to_zero()
{
WithUnlimitedRetention();
WithRetention(0);
WithAge(100);
Subject.IsSatisfiedBy(parseResult, null).Should().BeTrue();
}
[Test]
public void longer_retention_should_return_true()
public void should_return_true_when_release_if_younger_than_retention()
{
WithLongRetention();
WithRetention(1000);
WithAge(100);
Subject.IsSatisfiedBy(parseResult, null).Should().BeTrue();
}
[Test]
public void equal_retention_should_return_true()
public void should_return_true_when_release_and_retention_are_the_same()
{
WithEqualRetention();
WithRetention(100);
WithAge(100);
Subject.IsSatisfiedBy(parseResult, null).Should().BeTrue();
}
[Test]
public void shorter_retention_should_return_false()
public void should_return_false_when_old_than_retention()
{
WithShortRetention();
WithRetention(10);
WithAge(100);
Subject.IsSatisfiedBy(parseResult, null).Should().BeFalse();
}
[Test]
public void zeroDay_report_should_return_true()
public void should_return_true_if_release_came_out_today_and_retention_is_zero()
{
WithUnlimitedRetention();
WithRetention(0);
WithAge(100);
Subject.IsSatisfiedBy(parseResult, null).Should().BeTrue();
}
}

View File

@ -4,8 +4,9 @@ using Moq;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.Download.Clients.Blackhole;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
@ -13,7 +14,7 @@ using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download.DownloadClientTests
{
[TestFixture]
public class BlackholeProviderFixture : CoreTest<BlackholeProvider>
public class BlackholeProviderFixture : CoreTest<Blackhole>
{
private const string _nzbUrl = "http://www.nzbs.com/url";
private const string _title = "some_nzb_title";
@ -27,13 +28,16 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
_blackHoleFolder = @"c:\nzb\blackhole\".AsOsAgnostic();
_nzbPath = @"c:\nzb\blackhole\some_nzb_title.nzb".AsOsAgnostic();
Mocker.GetMock<IConfigService>().SetupGet(c => c.BlackholeFolder).Returns(_blackHoleFolder);
_remoteEpisode = new RemoteEpisode();
_remoteEpisode.Release = new ReleaseInfo();
_remoteEpisode.Release.Title = _title;
_remoteEpisode.Release.DownloadUrl = _nzbUrl;
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new FolderSettings
{
Folder = _blackHoleFolder
};
}
private void WithExistingFile()

View File

@ -3,17 +3,15 @@ using System.Linq;
using FizzWare.NBuilder;
using Moq;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.Nzbget;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetProviderTests
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
{
public class DownloadNzbFixture : CoreTest
public class DownloadNzbFixture : CoreTest<Nzbget>
{
private const string _url = "http://www.nzbdrone.com";
private const string _title = "30.Rock.S01E01.Pilot.720p.hdtv";
@ -32,6 +30,17 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetProviderTests
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT))
.Build()
.ToList();
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new NzbgetSettings
{
Host = "localhost",
Port = 6789,
Username = "nzbget",
Password = "pass",
TvCategory = "tv",
RecentTvPriority = (int)NzbgetPriority.High
};
}
[Test]
@ -39,14 +48,14 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetProviderTests
{
var p = new object[] {"30.Rock.S01E01.Pilot.720p.hdtv.nzb", "TV", 50, false, "http://www.nzbdrone.com"};
Mocker.GetMock<INzbGetCommunicationProxy>()
.Setup(s => s.AddNzb(p))
Mocker.GetMock<INzbgetProxy>()
.Setup(s => s.AddNzb(It.IsAny<NzbgetSettings>(), p))
.Returns(true);
Mocker.Resolve<NzbgetClient>().DownloadNzb(_remoteEpisode);
Subject.DownloadNzb(_remoteEpisode);
Mocker.GetMock<INzbGetCommunicationProxy>()
.Verify(v => v.AddNzb(It.IsAny<object []>()), Times.Once());
Mocker.GetMock<INzbgetProxy>()
.Verify(v => v.AddNzb(It.IsAny<NzbgetSettings>(), It.IsAny<object []>()), Times.Once());
}
}
}

View File

@ -5,40 +5,52 @@ using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.Nzbget;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetProviderTests
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
{
public class QueueFixture : CoreTest<NzbgetClient>
public class QueueFixture : CoreTest<Nzbget>
{
private List<NzbGetQueueItem> _queue;
private List<NzbgetQueueItem> _queue;
[SetUp]
public void Setup()
{
_queue = Builder<NzbGetQueueItem>.CreateListOfSize(5)
_queue = Builder<NzbgetQueueItem>.CreateListOfSize(5)
.All()
.With(q => q.NzbName = "30.Rock.S01E01.Pilot.720p.hdtv.nzb")
.Build()
.ToList();
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new NzbgetSettings
{
Host = "localhost",
Port = 6789,
Username = "nzbget",
Password = "pass",
TvCategory = "tv",
RecentTvPriority = (int)NzbgetPriority.High
};
}
private void WithFullQueue()
{
Mocker.GetMock<INzbGetCommunicationProxy>()
.Setup(s => s.GetQueue())
Mocker.GetMock<INzbgetProxy>()
.Setup(s => s.GetQueue(It.IsAny<NzbgetSettings>()))
.Returns(_queue);
}
private void WithEmptyQueue()
{
Mocker.GetMock<INzbGetCommunicationProxy>()
.Setup(s => s.GetQueue())
.Returns(new List<NzbGetQueueItem>());
Mocker.GetMock<INzbgetProxy>()
.Setup(s => s.GetQueue(It.IsAny<NzbgetSettings>()))
.Returns(new List<NzbgetQueueItem>());
}
[Test]

View File

@ -6,7 +6,9 @@ using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients;
using NzbDrone.Core.Download.Clients.Pneumatic;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Test.Common;
@ -14,7 +16,7 @@ using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download.DownloadClientTests
{
[TestFixture]
public class PneumaticProviderFixture : CoreTest<PneumaticClient>
public class PneumaticProviderFixture : CoreTest<Pneumatic>
{
private const string _nzbUrl = "http://www.nzbs.com/url";
private const string _title = "30.Rock.S01E05.hdtv.xvid-LoL";
@ -31,7 +33,6 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
_nzbPath = Path.Combine(_pneumaticFolder, _title + ".nzb").AsOsAgnostic();
_sabDrop = @"d:\unsorted tv\".AsOsAgnostic();
Mocker.GetMock<IConfigService>().SetupGet(c => c.PneumaticFolder).Returns(_pneumaticFolder);
Mocker.GetMock<IConfigService>().SetupGet(c => c.DownloadedEpisodesFolder).Returns(_sabDrop);
_remoteEpisode = new RemoteEpisode();
@ -41,6 +42,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests
_remoteEpisode.ParsedEpisodeInfo = new ParsedEpisodeInfo();
_remoteEpisode.ParsedEpisodeInfo.FullSeason = false;
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new FolderSettings
{
Folder = _pneumaticFolder
};
}
private void WithExistingFile()

View File

@ -1,191 +0,0 @@
using System;
using System.IO;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.Clients.Sabnzbd;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabProviderTests
{
[TestFixture]
public class SabProviderFixture : CoreTest<SabnzbdClient>
{
private const string URL = "http://www.nzbclub.com/nzb_download.aspx?mid=1950232";
private const string TITLE = "My Series Name - 5x2-5x3 - My title [Bluray720p] [Proper]";
private RemoteEpisode _remoteEpisode;
[SetUp]
public void Setup()
{
var fakeConfig = Mocker.GetMock<IConfigService>();
fakeConfig.SetupGet(c => c.SabHost).Returns("192.168.5.55");
fakeConfig.SetupGet(c => c.SabPort).Returns(2222);
fakeConfig.SetupGet(c => c.SabApiKey).Returns("5c770e3197e4fe763423ee7c392c25d1");
fakeConfig.SetupGet(c => c.SabUsername).Returns("admin");
fakeConfig.SetupGet(c => c.SabPassword).Returns("pass");
fakeConfig.SetupGet(c => c.SabTvCategory).Returns("tv");
_remoteEpisode = new RemoteEpisode();
_remoteEpisode.Release = new ReleaseInfo();
_remoteEpisode.Release.Title = TITLE;
_remoteEpisode.Release.DownloadUrl = URL;
_remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
.All()
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT))
.Build()
.ToList();
}
[Test]
public void should_be_able_to_get_categories_when_config_is_passed_in()
{
const string host = "192.168.5.22";
const int port = 1111;
const string apikey = "5c770e3197e4fe763423ee7c392c25d2";
const string username = "admin2";
const string password = "pass2";
Mocker.GetMock<IHttpProvider>(MockBehavior.Strict)
.Setup(s => s.DownloadString("http://192.168.5.22:1111/api?mode=get_cats&output=json&apikey=5c770e3197e4fe763423ee7c392c25d2&ma_username=admin2&ma_password=pass2"))
.Returns(ReadAllText("Files", "Categories_json.txt"));
var result = Subject.GetCategories(host, port, apikey, username, password);
result.Should().NotBeNull();
result.categories.Should().NotBeEmpty();
}
[Test]
public void should_be_able_to_get_categories_using_config()
{
Mocker.GetMock<IHttpProvider>(MockBehavior.Strict)
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=get_cats&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
.Returns(ReadAllText("Files", "Categories_json.txt"));
var result = Subject.GetCategories();
result.Should().NotBeNull();
result.categories.Should().NotBeEmpty();
}
[Test]
public void GetHistory_should_return_a_list_with_items_when_the_history_has_items()
{
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
.Returns(ReadAllText("Files", "History.txt"));
var result = Subject.GetHistory();
result.Should().HaveCount(1);
}
[Test]
public void GetHistory_should_return_an_empty_list_when_the_queue_is_empty()
{
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
.Returns(ReadAllText("Files", "HistoryEmpty.txt"));
var result = Subject.GetHistory();
result.Should().BeEmpty();
}
[Test]
public void GetHistory_should_return_an_empty_list_when_there_is_an_error_getting_the_queue()
{
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=history&output=json&start=0&limit=0&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
.Returns(ReadAllText("Files", "JsonError.txt"));
Assert.Throws<ApplicationException>(() => Subject.GetHistory(), "API Key Incorrect");
}
[Test]
public void GetVersion_should_return_the_version_using_passed_in_values()
{
var response = "{ \"version\": \"0.6.9\" }";
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=version&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
.Returns(response);
var result = Subject.GetVersion("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass");
result.Should().NotBeNull();
result.Version.Should().Be("0.6.9");
}
[Test]
public void GetVersion_should_return_the_version_using_saved_values()
{
var response = "{ \"version\": \"0.6.9\" }";
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=version&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
.Returns(response);
var result = Subject.GetVersion();
result.Should().NotBeNull();
result.Version.Should().Be("0.6.9");
}
[Test]
public void Test_should_return_version_as_a_string()
{
const string response = "{ \"version\": \"0.6.9\" }";
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString("http://192.168.5.55:2222/api?mode=version&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"))
.Returns(response);
var result = Subject.Test("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass");
result.Should().Be("0.6.9");
}
[Test]
public void downloadNzb_should_use_sabRecentTvPriority_when_recentEpisode_is_true()
{
Mocker.GetMock<IConfigService>()
.SetupGet(s => s.SabRecentTvPriority)
.Returns(SabPriorityType.High);
Mocker.GetMock<ISabCommunicationProxy>()
.Setup(s => s.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabPriorityType.High))
.Returns(new SabAddResponse());
Subject.DownloadNzb(_remoteEpisode);
Mocker.GetMock<ISabCommunicationProxy>()
.Verify(v => v.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabPriorityType.High), Times.Once());
}
}
}

View File

@ -0,0 +1,65 @@
using System;
using System.IO;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Common;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.Sabnzbd;
using NzbDrone.Core.Download.Clients.Sabnzbd.Responses;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{
[TestFixture]
public class SabnzbdFixture : CoreTest<Sabnzbd>
{
private const string URL = "http://www.nzbclub.com/nzb_download.aspx?mid=1950232";
private const string TITLE = "My Series Name - 5x2-5x3 - My title [Bluray720p] [Proper]";
private RemoteEpisode _remoteEpisode;
[SetUp]
public void Setup()
{
_remoteEpisode = new RemoteEpisode();
_remoteEpisode.Release = new ReleaseInfo();
_remoteEpisode.Release.Title = TITLE;
_remoteEpisode.Release.DownloadUrl = URL;
_remoteEpisode.Episodes = Builder<Episode>.CreateListOfSize(1)
.All()
.With(e => e.AirDate = DateTime.Today.ToString(Episode.AIR_DATE_FORMAT))
.Build()
.ToList();
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new SabnzbdSettings
{
Host = "192.168.5.55",
Port = 2222,
ApiKey = "5c770e3197e4fe763423ee7c392c25d1",
Username = "admin",
Password = "pass",
TvCategory = "tv",
RecentTvPriority = (int)SabnzbdPriority.High
};
}
[Test]
public void downloadNzb_should_use_sabRecentTvPriority_when_recentEpisode_is_true()
{
Mocker.GetMock<ISabnzbdProxy>()
.Setup(s => s.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabnzbdPriority.High, It.IsAny<SabnzbdSettings>()))
.Returns(new SabnzbdAddResponse());
Subject.DownloadNzb(_remoteEpisode);
Mocker.GetMock<ISabnzbdProxy>()
.Verify(v => v.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabnzbdPriority.High, It.IsAny<SabnzbdSettings>()), Times.Once());
}
}
}

View File

@ -1,3 +1,4 @@
using System;
using System.Linq;
using System.Net;
using FizzWare.NBuilder;
@ -33,9 +34,6 @@ namespace NzbDrone.Core.Test.Download
.With(c => c.Release = Builder<ReleaseInfo>.CreateNew().Build())
.With(c => c.Episodes = episodes)
.Build();
Mocker.GetMock<IDownloadClient>().Setup(c => c.IsConfigured).Returns(true);
}
private void WithSuccessfulAdd()
@ -85,7 +83,8 @@ namespace NzbDrone.Core.Test.Download
[Test]
public void should_not_attempt_download_if_client_isnt_configure()
{
Mocker.GetMock<IDownloadClient>().Setup(c => c.IsConfigured).Returns(false);
Mocker.GetMock<IProvideDownloadClient>()
.Setup(c => c.GetDownloadClient()).Returns((IDownloadClient)null);
Subject.DownloadReport(_parseResult);

View File

@ -1,25 +0,0 @@
{
"categories":[
"*",
"anime",
"apps",
"books",
"consoles",
"ds-games",
"emulation",
"games",
"misc",
"movies",
"music",
"pda",
"resources",
"test",
"tv",
"tv-dvd",
"unknown",
"wii-games",
"xbox-dlc",
"xbox-xbla",
"xxx"
]
}

View File

@ -1,99 +0,0 @@
{
"history":{
"active_lang":"en",
"paused":false,
"session":"5c770e3197e4fe763423ee7c392c25d1",
"restart_req":false,
"power_options":true,
"slots":[
{
"action_line":"",
"show_details":"True",
"script_log":"",
"meta":null,
"fail_message":"",
"loaded":false,
"id":9858,
"size":"970 MB",
"category":"tv",
"pp":"D",
"retry":0,
"completeness":0,
"script":"None",
"nzb_name":"The.Mentalist.S04E12.720p.HDTV.x264-IMMERSE.nzb",
"download_time":524,
"storage":"C:\\ServerPool\\ServerFolders\\Unsorted TV\\The Mentalist - 4x12 - My Bloody Valentine [HDTV-720p]",
"status":"Completed",
"script_line":"",
"completed":1327033479,
"nzo_id":"SABnzbd_nzo_0crgis",
"downloaded":1016942445,
"report":"",
"path":"D:\\SABnzbd\\downloading\\The Mentalist - 4x12 - My Bloody Valentine [HDTV-720p]",
"postproc_time":24,
"name":"The Mentalist - 4x12 - My Bloody Valentine [HDTV-720p]",
"url":"",
"bytes":1016942445,
"url_info":"",
"stage_log":[
{
"name":"Download",
"actions":[
"Downloaded in 8 minutes 44 seconds at an average of 1.8 MB/s"
]
},
{
"name":"Repair",
"actions":[
"[the.mentalist.s04e12.720p.hdtv.x264-immerse] Quick Check OK"
]
},
{
"name":"Unpack",
"actions":[
"[the.mentalist.s04e12.720p.hdtv.x264-immerse] Unpacked 1 files/folders in 23 seconds"
]
}
]
}
],
"speed":"0 ",
"helpuri":"http://wiki.sabnzbd.org/",
"size":"0 B",
"uptime":"1d",
"total_size":"10.2 T",
"month_size":"445.7 G",
"week_size":"46.6 G",
"version":"0.6.9",
"new_rel_url":"http://sourceforge.net/projects/sabnzbdplus/files/sabnzbdplus/sabnzbd-0.6.14",
"diskspacetotal2":"9314.57",
"color_scheme":"gold",
"diskspacetotal1":"871.41",
"nt":true,
"status":"Idle",
"last_warning":"2012-01-19 23:58:01,736\nWARNING:\nAPI Key incorrect, Use the api key from Config->General in your 3rd party program:",
"have_warnings":"3",
"cache_art":"0",
"sizeleft":"0 B",
"finishaction":null,
"paused_all":false,
"cache_size":"0 B",
"new_release":"0.6.14",
"pause_int":"0",
"mbleft":"0.00",
"diskspace1":"869.82",
"darwin":false,
"timeleft":"0:00:00",
"mb":"0.00",
"noofslots":9724,
"day_size":"0 ",
"eta":"unknown",
"nzb_quota":"",
"loadavg":"",
"cache_max":"-1",
"kbpersec":"0.00",
"speedlimit":"",
"webdir":"D:\\SABnzbd\\SABnzbd\\interfaces\\Plush\\templates",
"diskspace2":"1084.96"
}
}

View File

@ -1,50 +0,0 @@
{
"history":{
"active_lang":"en",
"paused":false,
"session":"5c770e3197e4fe763423ee7c392c25d1",
"restart_req":false,
"power_options":true,
"slots":[
],
"speed":"0 ",
"helpuri":"http://wiki.sabnzbd.org/",
"size":"0 B",
"uptime":"1d",
"total_size":"10.2 T",
"month_size":"445.7 G",
"week_size":"46.6 G",
"version":"0.6.9",
"new_rel_url":"http://sourceforge.net/projects/sabnzbdplus/files/sabnzbdplus/sabnzbd-0.6.14",
"diskspacetotal2":"9314.57",
"color_scheme":"gold",
"diskspacetotal1":"871.41",
"nt":true,
"status":"Idle",
"last_warning":"2012-01-19 23:58:01,736\nWARNING:\nAPI Key incorrect, Use the api key from Config->General in your 3rd party program:",
"have_warnings":"3",
"cache_art":"0",
"sizeleft":"0 B",
"finishaction":null,
"paused_all":false,
"cache_size":"0 B",
"new_release":"0.6.14",
"pause_int":"0",
"mbleft":"0.00",
"diskspace1":"869.82",
"darwin":false,
"timeleft":"0:00:00",
"mb":"0.00",
"noofslots":9724,
"day_size":"0 ",
"eta":"unknown",
"nzb_quota":"",
"loadavg":"",
"cache_max":"-1",
"kbpersec":"0.00",
"speedlimit":"",
"webdir":"D:\\SABnzbd\\SABnzbd\\interfaces\\Plush\\templates",
"diskspace2":"1084.96"
}
}

View File

@ -1,4 +0,0 @@
{
"status": false,
"error": "API Key Incorrect"
}

View File

@ -77,7 +77,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
};
Mocker.GetMock<IParsingService>()
.Setup(c => c.GetEpisodes(It.IsAny<String>(), It.IsAny<Series>(), It.IsAny<Boolean>()))
.Setup(c => c.GetLocalEpisode(It.IsAny<String>(), It.IsAny<Series>(), It.IsAny<Boolean>()))
.Returns(_localEpisode);
@ -150,7 +150,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
{
GivenSpecifications(_pass1);
Mocker.GetMock<IParsingService>().Setup(c => c.GetEpisodes(It.IsAny<String>(), It.IsAny<Series>(), It.IsAny<Boolean>()))
Mocker.GetMock<IParsingService>().Setup(c => c.GetLocalEpisode(It.IsAny<String>(), It.IsAny<Series>(), It.IsAny<Boolean>()))
.Throws<TestException>();
_videoFiles = new List<String>
@ -168,7 +168,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
Subject.GetImportDecisions(_videoFiles, _series, false);
Mocker.GetMock<IParsingService>()
.Verify(c => c.GetEpisodes(It.IsAny<String>(), It.IsAny<Series>(), It.IsAny<Boolean>()), Times.Exactly(_videoFiles.Count));
.Verify(c => c.GetLocalEpisode(It.IsAny<String>(), It.IsAny<Series>(), It.IsAny<Boolean>()), Times.Exactly(_videoFiles.Count));
ExceptionVerification.ExpectedErrors(3);
}

View File

@ -21,6 +21,7 @@ namespace NzbDrone.Core.Test.MetadataSourceTests
[TestCase("Franklin & Bash", "Franklin & Bash")]
[TestCase("Mr. D", "Mr. D")]
[TestCase("Rob & Big", "Rob and Big")]
[TestCase("M*A*S*H", "M*A*S*H")]
public void successful_search(string title, string expected)
{
var result = Subject.SearchForNewSeries(title);
@ -38,7 +39,7 @@ namespace NzbDrone.Core.Test.MetadataSourceTests
}
[TestCase(75978)]
[TestCase(79349)]
[TestCase(83462)]
public void should_be_able_to_get_series_detail(int tvdbId)
{
var details = Subject.GetSeriesInfo(tvdbId);

View File

@ -122,10 +122,10 @@
<Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" />
<Compile Include="Download\DownloadApprovedReportsTests\GetQualifiedReportsFixture.cs" />
<Compile Include="Download\DownloadClientTests\BlackholeProviderFixture.cs" />
<Compile Include="Download\DownloadClientTests\NzbgetProviderTests\DownloadNzbFixture.cs" />
<Compile Include="Download\DownloadClientTests\NzbgetProviderTests\QueueFixture.cs" />
<Compile Include="Download\DownloadClientTests\NzbgetTests\DownloadNzbFixture.cs" />
<Compile Include="Download\DownloadClientTests\NzbgetTests\QueueFixture.cs" />
<Compile Include="Download\DownloadClientTests\PneumaticProviderFixture.cs" />
<Compile Include="Download\DownloadClientTests\SabProviderTests\SabProviderFixture.cs" />
<Compile Include="Download\DownloadClientTests\SabnzbdTests\SabnzbdFixture.cs" />
<Compile Include="Download\DownloadServiceFixture.cs" />
<Compile Include="Download\FailedDownloadServiceFixture.cs" />
<Compile Include="Framework\CoreTest.cs" />
@ -180,6 +180,17 @@
<Compile Include="NotificationTests\Xbmc\OnDownloadFixture.cs" />
<Compile Include="OrganizerTests\BuildFilePathFixture.cs" />
<Compile Include="OrganizerTests\GetSeriesFolderFixture.cs" />
<Compile Include="ParserTests\AbsoluteEpisodeNumberParserFixture.cs" />
<Compile Include="ParserTests\IsPossibleSpecialEpisodeFixture.cs" />
<Compile Include="ParserTests\ReleaseGroupParserFixture.cs" />
<Compile Include="ParserTests\LanguageParserFixture.cs" />
<Compile Include="ParserTests\SeasonParserFixture.cs" />
<Compile Include="ParserTests\NormalizeTitleFixture.cs" />
<Compile Include="ParserTests\CrapParserFixture.cs" />
<Compile Include="ParserTests\DailyEpisodeParserFixture.cs" />
<Compile Include="ParserTests\SingleEpisodeParserFixture.cs" />
<Compile Include="ParserTests\PathParserFixture.cs" />
<Compile Include="ParserTests\MultiEpisodeParserFixture.cs" />
<Compile Include="ParserTests\ParsingServiceTests\GetEpisodesFixture.cs" />
<Compile Include="ParserTests\ParsingServiceTests\GetSeriesFixture.cs" />
<Compile Include="ParserTests\ParsingServiceTests\MapFixture.cs" />
@ -287,18 +298,9 @@
<Content Include="Files\LongOverview.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\HistoryEmpty.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\Queue.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\History.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\JsonError.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Include="..\NzbDrone.Test.Common\App.config">
<Link>App.config</Link>
</None>
@ -330,9 +332,6 @@
<Content Include="Files\RSS\newznab.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\Categories_json.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Files\RSS\SizeParsing\newznab.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>

View File

@ -0,0 +1,47 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class AbsoluteEpisodeNumberParserFixture : CoreTest
{
[TestCase("[SubDESU]_High_School_DxD_07_(1280x720_x264-AAC)_[6B7FD717]", "High School DxD", 7, 0, 0)]
[TestCase("[Chihiro]_Working!!_-_06_[848x480_H.264_AAC][859EEAFA]", "Working!!", 6, 0, 0)]
[TestCase("[Commie]_Senki_Zesshou_Symphogear_-_11_[65F220B4]", "Senki_Zesshou_Symphogear", 11, 0, 0)]
[TestCase("[Underwater]_Rinne_no_Lagrange_-_12_(720p)_[5C7BC4F9]", "Rinne_no_Lagrange", 12, 0, 0)]
[TestCase("[Commie]_Rinne_no_Lagrange_-_15_[E76552EA]", "Rinne_no_Lagrange", 15, 0, 0)]
[TestCase("[HorribleSubs]_Hunter_X_Hunter_-_33_[720p]", "Hunter_X_Hunter", 33, 0, 0)]
[TestCase("[HorribleSubs]_Fairy_Tail_-_145_[720p]", "Fairy_Tail", 145, 0, 0)]
[TestCase("[HorribleSubs] Tonari no Kaibutsu-kun - 13 [1080p].mkv", "Tonari no Kaibutsu-kun", 13, 0, 0)]
[TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].[C65D4B1F].mkv", "Yes.Pretty.Cure.5.Go.Go!", 31, 0, 0)]
[TestCase("[K-F] One Piece 214", "One Piece", 214, 0, 0)]
[TestCase("[K-F] One Piece S10E14 214", "One Piece", 214, 10, 14)]
[TestCase("[K-F] One Piece 10x14 214", "One Piece", 214, 10, 14)]
[TestCase("[K-F] One Piece 214 10x14", "One Piece", 214, 10, 14)]
// [TestCase("One Piece S10E14 214", "One Piece", 214, 10, 14)]
// [TestCase("One Piece 10x14 214", "One Piece", 214, 10, 14)]
// [TestCase("One Piece 214 10x14", "One Piece", 214, 10, 14)]
// [TestCase("214 One Piece 10x14", "One Piece", 214, 10, 14)]
[TestCase("Bleach - 031 - The Resolution to Kill [Lunar].avi", "Bleach", 31, 0, 0)]
[TestCase("Bleach - 031 - The Resolution to Kill [Lunar]", "Bleach", 31, 0, 0)]
[TestCase("[ACX]Hack Sign 01 Role Play [Kosaka] [9C57891E].mkv", "Hack Sign", 1, 0, 0)]
[TestCase("[SFW-sage] Bakuman S3 - 12 [720p][D07C91FC]", "Bakuman S3", 12, 0, 0)]
[TestCase("ducktales_e66_time_is_money_part_one_marking_time", "DuckTales", 66, 0, 0)]
public void should_parse_absolute_numbers(string postTitle, string title, int absoluteEpisodeNumber, int seasonNumber, int episodeNumber)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Should().NotBeNull();
result.AbsoluteEpisodeNumbers.First().Should().Be(absoluteEpisodeNumber);
result.SeasonNumber.Should().Be(seasonNumber);
result.EpisodeNumbers.FirstOrDefault().Should().Be(episodeNumber);
result.SeriesTitle.Should().Be(title.CleanSeriesTitle());
result.FullSeason.Should().BeFalse();
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Expansive;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class CrapParserFixture : CoreTest
{
[TestCase("76El6LcgLzqb426WoVFg1vVVVGx4uCYopQkfjmLe")]
[TestCase("Vrq6e1Aba3U amCjuEgV5R2QvdsLEGYF3YQAQkw8")]
[TestCase("TDAsqTea7k4o6iofVx3MQGuDK116FSjPobMuh8oB")]
[TestCase("yp4nFodAAzoeoRc467HRh1mzuT17qeekmuJ3zFnL")]
[TestCase("oxXo8S2272KE1 lfppvxo3iwEJBrBmhlQVK1gqGc")]
[TestCase("dPBAtu681Ycy3A4NpJDH6kNVQooLxqtnsW1Umfiv")]
[TestCase("password - \"bdc435cb-93c4-4902-97ea-ca00568c3887.337\" yEnc")]
[TestCase("185d86a343e39f3341e35c4dad3f9959")]
[TestCase("ba27283b17c00d01193eacc02a8ba98eeb523a76")]
[TestCase("45a55debe3856da318cc35882ad07e43cd32fd15")]
[TestCase("86420f8ee425340d8894bf3bc636b66404b95f18")]
[TestCase("ce39afb7da6cf7c04eba3090f0a309f609883862")]
[TestCase("THIS SHOULD NEVER PARSE")]
public void should_not_parse_crap(string title)
{
Parser.Parser.ParseTitle(title).Should().BeNull();
ExceptionVerification.IgnoreWarns();
}
}
}

View File

@ -0,0 +1,76 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Expansive;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class DailyEpisodeParserFixture : CoreTest
{
[TestCase("Conan 2011 04 18 Emma Roberts HDTV XviD BFF", "Conan", 2011, 04, 18)]
[TestCase("The Tonight Show With Jay Leno 2011 04 15 1080i HDTV DD5 1 MPEG2 TrollHD", "The Tonight Show With Jay Leno", 2011, 04, 15)]
[TestCase("The.Daily.Show.2010.10.11.Johnny.Knoxville.iTouch-MW", "The.Daily.Show", 2010, 10, 11)]
[TestCase("The Daily Show - 2011-04-12 - Gov. Deval Patrick", "The.Daily.Show", 2011, 04, 12)]
[TestCase("2011.01.10 - Denis Leary - HD TV.mkv", "", 2011, 1, 10)]
[TestCase("2011.03.13 - Denis Leary - HD TV.mkv", "", 2011, 3, 13)]
[TestCase("The Tonight Show with Jay Leno - 2011-06-16 - Larry David, \"Bachelorette\" Ashley Hebert, Pitbull with Ne-Yo", "The Tonight Show with Jay Leno", 2011, 6, 16)]
[TestCase("2020.NZ.2012.16.02.PDTV.XviD-C4TV", "2020nz", 2012, 2, 16)]
[TestCase("2020.NZ.2012.13.02.PDTV.XviD-C4TV", "2020nz", 2012, 2, 13)]
[TestCase("2020.NZ.2011.12.02.PDTV.XviD-C4TV", "2020nz", 2011, 12, 2)]
public void should_parse_daily_episode(string postTitle, string title, int year, int month, int day)
{
var result = Parser.Parser.ParseTitle(postTitle);
var airDate = new DateTime(year, month, day);
result.Should().NotBeNull();
result.SeriesTitle.Should().Be(title.CleanSeriesTitle());
result.AirDate.Should().Be(airDate.ToString(Episode.AIR_DATE_FORMAT));
result.EpisodeNumbers.Should().BeEmpty();
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeFalse();
}
[TestCase("Conan {year} {month} {day} Emma Roberts HDTV XviD BFF")]
[TestCase("The Tonight Show With Jay Leno {year} {month} {day} 1080i HDTV DD5 1 MPEG2 TrollHD")]
[TestCase("The.Daily.Show.{year}.{month}.{day}.Johnny.Knoxville.iTouch-MW")]
[TestCase("The Daily Show - {year}-{month}-{day} - Gov. Deval Patrick")]
[TestCase("{year}.{month}.{day} - Denis Leary - HD TV.mkv")]
[TestCase("The Tonight Show with Jay Leno - {year}-{month}-{day} - Larry David, \"Bachelorette\" Ashley Hebert, Pitbull with Ne-Yo")]
[TestCase("2020.NZ.{year}.{month}.{day}.PDTV.XviD-C4TV")]
public void should_not_accept_ancient_daily_series(string title)
{
var yearTooLow = title.Expand(new { year = 1950, month = 10, day = 14 });
Parser.Parser.ParseTitle(yearTooLow).Should().BeNull();
}
[TestCase("Conan {year} {month} {day} Emma Roberts HDTV XviD BFF")]
[TestCase("The Tonight Show With Jay Leno {year} {month} {day} 1080i HDTV DD5 1 MPEG2 TrollHD")]
[TestCase("The.Daily.Show.{year}.{month}.{day}.Johnny.Knoxville.iTouch-MW")]
[TestCase("The Daily Show - {year}-{month}-{day} - Gov. Deval Patrick")]
[TestCase("{year}.{month}.{day} - Denis Leary - HD TV.mkv")]
[TestCase("The Tonight Show with Jay Leno - {year}-{month}-{day} - Larry David, \"Bachelorette\" Ashley Hebert, Pitbull with Ne-Yo")]
[TestCase("2020.NZ.{year}.{month}.{day}.PDTV.XviD-C4TV")]
public void should_not_accept_future_dates(string title)
{
var twoDaysFromNow = DateTime.Now.AddDays(2);
var validDate = title.Expand(new { year = twoDaysFromNow.Year, month = twoDaysFromNow.Month.ToString("00"), day = twoDaysFromNow.Day.ToString("00") });
Parser.Parser.ParseTitle(validDate).Should().BeNull();
}
[Test]
public void should_fail_if_episode_is_far_in_future()
{
var title = string.Format("{0:yyyy.MM.dd} - Denis Leary - HD TV.mkv", DateTime.Now.AddDays(2));
Parser.Parser.ParseTitle(title).Should().BeNull();
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class IsPossibleSpecialEpisodeFixture
{
[Test]
public void should_not_treat_files_without_a_series_title_as_a_special()
{
var parsedEpisodeInfo = new ParsedEpisodeInfo
{
EpisodeNumbers = new[]{ 7 },
SeasonNumber = 1,
SeriesTitle = ""
};
parsedEpisodeInfo.IsPossibleSpecialEpisode().Should().BeFalse();
}
[Test]
public void should_return_true_when_episode_numbers_is_empty()
{
var parsedEpisodeInfo = new ParsedEpisodeInfo
{
SeasonNumber = 1,
SeriesTitle = ""
};
parsedEpisodeInfo.IsPossibleSpecialEpisode().Should().BeTrue();
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class LanguageParserFixture : CoreTest
{
[TestCase("Castle.2009.S01E14.English.HDTV.XviD-LOL", Language.English)]
[TestCase("Castle.2009.S01E14.French.HDTV.XviD-LOL", Language.French)]
[TestCase("Castle.2009.S01E14.Spanish.HDTV.XviD-LOL", Language.Spanish)]
[TestCase("Castle.2009.S01E14.German.HDTV.XviD-LOL", Language.German)]
[TestCase("Castle.2009.S01E14.Germany.HDTV.XviD-LOL", Language.English)]
[TestCase("Castle.2009.S01E14.Italian.HDTV.XviD-LOL", Language.Italian)]
[TestCase("Castle.2009.S01E14.Danish.HDTV.XviD-LOL", Language.Danish)]
[TestCase("Castle.2009.S01E14.Dutch.HDTV.XviD-LOL", Language.Dutch)]
[TestCase("Castle.2009.S01E14.Japanese.HDTV.XviD-LOL", Language.Japanese)]
[TestCase("Castle.2009.S01E14.Cantonese.HDTV.XviD-LOL", Language.Cantonese)]
[TestCase("Castle.2009.S01E14.Mandarin.HDTV.XviD-LOL", Language.Mandarin)]
[TestCase("Castle.2009.S01E14.Korean.HDTV.XviD-LOL", Language.Korean)]
[TestCase("Castle.2009.S01E14.Russian.HDTV.XviD-LOL", Language.Russian)]
[TestCase("Castle.2009.S01E14.Polish.HDTV.XviD-LOL", Language.Polish)]
[TestCase("Castle.2009.S01E14.Vietnamese.HDTV.XviD-LOL", Language.Vietnamese)]
[TestCase("Castle.2009.S01E14.Swedish.HDTV.XviD-LOL", Language.Swedish)]
[TestCase("Castle.2009.S01E14.Norwegian.HDTV.XviD-LOL", Language.Norwegian)]
[TestCase("Castle.2009.S01E14.Finnish.HDTV.XviD-LOL", Language.Finnish)]
[TestCase("Castle.2009.S01E14.Turkish.HDTV.XviD-LOL", Language.Turkish)]
[TestCase("Castle.2009.S01E14.Portuguese.HDTV.XviD-LOL", Language.Portuguese)]
[TestCase("Castle.2009.S01E14.HDTV.XviD-LOL", Language.English)]
[TestCase("person.of.interest.1x19.ita.720p.bdmux.x264-novarip", Language.Italian)]
[TestCase("Salamander.S01E01.FLEMISH.HDTV.x264-BRiGAND", Language.Flemish)]
[TestCase("H.Polukatoikia.S03E13.Greek.PDTV.XviD-Ouzo", Language.Greek)]
[TestCase("Burn.Notice.S04E15.Brotherly.Love.GERMAN.DUBBED.WS.WEBRiP.XviD.REPACK-TVP", Language.German)]
[TestCase("Ray Donovan - S01E01.720p.HDtv.x264-Evolve (NLsub)", Language.Norwegian)]
[TestCase("Shield,.The.1x13.Tueurs.De.Flics.FR.DVDRip.XviD", Language.French)]
[TestCase("True.Detective.S01E01.1080p.WEB-DL.Rus.Eng.TVKlondike", Language.Russian)]
public void should_parse_language(string postTitle, Language language)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Language.Should().Be(language);
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Expansive;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class MultiEpisodeParserFixture : CoreTest
{
[TestCase("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", "WEEDS", 3, new[] { 1, 2, 3, 4, 5, 6 })]
[TestCase("Two.and.a.Half.Men.103.104.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Men", 1, new[] { 3, 4 })]
[TestCase("Weeds.S03E01.S03E02.720p.HDTV.X264-DIMENSION", "Weeds", 3, new[] { 1, 2 })]
[TestCase("The Borgias S01e01 e02 ShoHD On Demand 1080i DD5 1 ALANiS", "The Borgias", 1, new[] { 1, 2 })]
[TestCase("White.Collar.2x04.2x05.720p.BluRay-FUTV", "White.Collar", 2, new[] { 4, 5 })]
[TestCase("Desperate.Housewives.S07E22E23.720p.HDTV.X264-DIMENSION", "Desperate.Housewives", 7, new[] { 22, 23 })]
[TestCase("Desparate Housewives - S07E22 - S07E23 - And Lots of Security.. [HDTV-720p].mkv", "Desparate Housewives", 7, new[] { 22, 23 })]
[TestCase("S03E01.S03E02.720p.HDTV.X264-DIMENSION", "", 3, new[] { 1, 2 })]
[TestCase("Desparate Housewives - S07E22 - 7x23 - And Lots of Security.. [HDTV-720p].mkv", "Desparate Housewives", 7, new[] { 22, 23 })]
[TestCase("S07E22 - 7x23 - And Lots of Security.. [HDTV-720p].mkv", "", 7, new[] { 22, 23 })]
[TestCase("2x04x05.720p.BluRay-FUTV", "", 2, new[] { 4, 5 })]
[TestCase("S02E04E05.720p.BluRay-FUTV", "", 2, new[] { 4, 5 })]
[TestCase("S02E03-04-05.720p.BluRay-FUTV", "", 2, new[] { 3, 4, 5 })]
[TestCase("Breakout.Kings.S02E09-E10.HDTV.x264-ASAP", "Breakout Kings", 2, new[] { 9, 10 })]
[TestCase("Breakout Kings - 2x9-2x10 - Served Cold [SDTV] ", "Breakout Kings", 2, new[] { 9, 10 })]
[TestCase("Breakout Kings - 2x09-2x10 - Served Cold [SDTV] ", "Breakout Kings", 2, new[] { 9, 10 })]
[TestCase("Hell on Wheels S02E09 E10 HDTV x264 EVOLVE", "Hell on Wheels", 2, new[] { 9, 10 })]
[TestCase("Hell.on.Wheels.S02E09-E10.720p.HDTV.x264-EVOLVE", "Hell on Wheels", 2, new[] { 9, 10 })]
[TestCase("Grey's Anatomy - 8x01_02 - Free Falling", "Grey's Anatomy", 8, new [] { 1,2 })]
[TestCase("8x01_02 - Free Falling", "", 8, new[] { 1, 2 })]
[TestCase("Kaamelott.S01E91-E100", "Kaamelott", 1, new[] { 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 })]
[TestCase("Neighbours.S29E161-E165.PDTV.x264-FQM", "Neighbours", 29, new[] { 161, 162, 163, 164, 165 })]
[TestCase("Shortland.Street.S22E5363-E5366.HDTV.x264-FiHTV", "Shortland Street", 22, new[] { 5363, 5364, 5365, 5366 })]
public void should_parse_multiple_episodes(string postTitle, string title, int season, int[] episodes)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.SeasonNumber.Should().Be(season);
result.EpisodeNumbers.Should().BeEquivalentTo(episodes);
result.SeriesTitle.Should().Be(title.CleanSeriesTitle());
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeFalse();
}
}
}

View File

@ -0,0 +1,96 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Expansive;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class NormalizeTitleFixture : CoreTest
{
[TestCase("Conan", "conan")]
[TestCase("The Tonight Show With Jay Leno", "tonightshowwithjayleno")]
[TestCase("The.Daily.Show", "dailyshow")]
[TestCase("Castle (2009)", "castle2009")]
[TestCase("Parenthood.2010", "parenthood2010")]
[TestCase("Law_and_Order_SVU", "lawordersvu")]
public void should_normalize_series_title(string parsedSeriesName, string seriesName)
{
var result = parsedSeriesName.CleanSeriesTitle();
result.Should().Be(seriesName);
}
[TestCase("CaPitAl", "capital")]
[TestCase("peri.od", "period")]
[TestCase("this.^&%^**$%@#$!That", "thisthat")]
[TestCase("test/test", "testtest")]
[TestCase("90210", "90210")]
[TestCase("24", "24")]
public void should_remove_special_characters_and_casing(string dirty, string clean)
{
var result = dirty.CleanSeriesTitle();
result.Should().Be(clean);
}
[TestCase("the")]
[TestCase("and")]
[TestCase("or")]
[TestCase("a")]
[TestCase("an")]
[TestCase("of")]
public void should_remove_common_words(string word)
{
var dirtyFormat = new[]
{
"word.{0}.word",
"word {0} word",
"word-{0}-word",
"{0}.word.word",
"{0}-word-word",
"{0} word word",
"word.word.{0}",
"word-word-{0}",
"word-word {0}",
};
foreach (var s in dirtyFormat)
{
var dirty = String.Format(s, word);
dirty.CleanSeriesTitle().Should().Be("wordword");
}
}
[TestCase("the")]
[TestCase("and")]
[TestCase("or")]
[TestCase("a")]
[TestCase("an")]
[TestCase("of")]
public void should_not_remove_common_words_in_the_middle_of_word(string word)
{
var dirtyFormat = new[]
{
"word.{0}word",
"word {0}word",
"word-{0}word",
"word{0}.word",
"word{0}-word",
"word{0}-word",
};
foreach (var s in dirtyFormat)
{
var dirty = String.Format(s, word);
dirty.CleanSeriesTitle().Should().Be(("word" + word.ToLower() + "word"));
}
}
}
}

View File

@ -2,11 +2,8 @@ using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Expansive;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ParserTests
{
@ -26,179 +23,6 @@ namespace NzbDrone.Core.Test.ParserTests
* Superman.-.The.Man.of.Steel.1994-05.33.hybrid.DreamGirl-Novus-HD
*/
[TestCase("Sonny.With.a.Chance.S02E15", "Sonny.With.a.Chance", 2, 15)]
[TestCase("Two.and.a.Half.Me.103.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Me", 1, 3)]
[TestCase("Two.and.a.Half.Me.113.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Me", 1, 13)]
[TestCase("Two.and.a.Half.Me.1013.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Me", 10, 13)]
[TestCase("Chuck.4x05.HDTV.XviD-LOL", "Chuck", 4, 5)]
[TestCase("The.Girls.Next.Door.S03E06.DVDRip.XviD-WiDE", "The.Girls.Next.Door", 3, 6)]
[TestCase("Degrassi.S10E27.WS.DSR.XviD-2HD", "Degrassi", 10, 27)]
[TestCase("Parenthood.2010.S02E14.HDTV.XviD-LOL", "Parenthood 2010", 2, 14)]
[TestCase("Hawaii Five 0 S01E19 720p WEB DL DD5 1 H 264 NT", "Hawaii Five 0", 1, 19)]
[TestCase("The Event S01E14 A Message Back 720p WEB DL DD5 1 H264 SURFER", "The Event", 1, 14)]
[TestCase("Adam Hills In Gordon St Tonight S01E07 WS PDTV XviD FUtV", "Adam Hills In Gordon St Tonight", 1, 7)]
[TestCase("Adam Hills In Gordon St Tonight S01E07 WS PDTV XviD FUtV", "Adam Hills In Gordon St Tonight", 1, 7)]
[TestCase("Adventure.Inc.S03E19.DVDRip.XviD-OSiTV", "Adventure.Inc", 3, 19)]
[TestCase("S03E09 WS PDTV XviD FUtV", "", 3, 9)]
[TestCase("5x10 WS PDTV XviD FUtV", "", 5, 10)]
[TestCase("Castle.2009.S01E14.HDTV.XviD-LOL", "Castle 2009", 1, 14)]
[TestCase("Pride.and.Prejudice.1995.S03E20.HDTV.XviD-LOL", "Pride and Prejudice 1995", 3, 20)]
[TestCase("The.Office.S03E115.DVDRip.XviD-OSiTV", "The.Office", 3, 115)]
[TestCase(@"Parks and Recreation - S02E21 - 94 Meetings - 720p TV.mkv", "Parks and Recreation", 2, 21)]
[TestCase(@"24-7 Penguins-Capitals- Road to the NHL Winter Classic - S01E03 - Episode 3.mkv", "24-7 Penguins-Capitals- Road to the NHL Winter Classic", 1, 3)]
[TestCase("Adventure.Inc.S03E19.DVDRip.\"XviD\"-OSiTV", "Adventure.Inc", 3, 19)]
[TestCase("Hawaii Five-0 (2010) - 1x05 - Nalowale (Forgotten/Missing)", "Hawaii Five-0 (2010)", 1, 5)]
[TestCase("Hawaii Five-0 (2010) - 1x05 - Title", "Hawaii Five-0 (2010)", 1, 5)]
[TestCase("House - S06E13 - 5 to 9 [DVD]", "House", 6, 13)]
[TestCase("The Mentalist - S02E21 - 18-5-4", "The Mentalist", 2, 21)]
[TestCase("Breaking.In.S01E07.21.0.Jump.Street.720p.WEB-DL.DD5.1.h.264-KiNGS", "Breaking In", 1, 7)]
[TestCase("CSI.525", "CSI", 5, 25)]
[TestCase("King of the Hill - 10x12 - 24 Hour Propane People [SDTV]", "King of the Hill", 10, 12)]
[TestCase("Brew Masters S01E06 3 Beers For Batali DVDRip XviD SPRiNTER", "Brew Masters", 1, 6)]
[TestCase("24 7 Flyers Rangers Road to the NHL Winter Classic Part01 720p HDTV x264 ORENJI", "24 7 Flyers Rangers Road to the NHL Winter Classic", 1, 1)]
[TestCase("24 7 Flyers Rangers Road to the NHL Winter Classic Part 02 720p HDTV x264 ORENJI", "24 7 Flyers Rangers Road to the NHL Winter Classic", 1, 2)]
[TestCase("24-7 Flyers-Rangers- Road to the NHL Winter Classic - S01E01 - Part 1", "24 7 Flyers Rangers Road to the NHL Winter Classic", 1, 1)]
[TestCase("The.Kennedys.Part.2.DSR.XviD-SYS", "The Kennedys", 1, 2)]
[TestCase("the-pacific-e07-720p", "The Pacific", 1, 7)]
[TestCase("S6E02-Unwrapped-(Playing With Food) - [DarkData]", "", 6, 2)]
[TestCase("S06E03-Unwrapped-(Number Ones Unwrapped) - [DarkData]", "", 6, 3)]
[TestCase("The Mentalist S02E21 18 5 4 720p WEB DL DD5 1 h 264 EbP", "The Mentalist", 2, 21)]
[TestCase("01x04 - Halloween, Part 1 - 720p WEB-DL", "", 1, 4)]
[TestCase("extras.s03.e05.ws.dvdrip.xvid-m00tv", "Extras", 3, 5)]
[TestCase("castle.2009.416.hdtv-lol", "Castle 2009", 4, 16)]
[TestCase("hawaii.five-0.2010.217.hdtv-lol", "Hawaii Five-0 (2010)", 2, 17)]
[TestCase("Looney Tunes - S1936E18 - I Love to Singa", "Looney Tunes", 1936, 18)]
[TestCase("American_Dad!_-_7x6_-_The_Scarlett_Getter_[SDTV]", "American Dad!", 7, 6)]
[TestCase("Falling_Skies_-_1x1_-_Live_and_Learn_[HDTV-720p]", "Falling Skies", 1, 1)]
[TestCase("Top Gear - 07x03 - 2005.11.70", "Top Gear", 7, 3)]
[TestCase("Hatfields and McCoys 2012 Part 1 REPACK 720p HDTV x264 2HD", "Hatfields and McCoys 2012", 1, 1)]
[TestCase("Glee.S04E09.Swan.Song.1080p.WEB-DL.DD5.1.H.264-ECI", "Glee", 4, 9)]
[TestCase("S08E20 50-50 Carla [DVD]", "", 8, 20)]
[TestCase("Cheers S08E20 50-50 Carla [DVD]", "Cheers", 8, 20)]
[TestCase("S02E10 6-50 to SLC [SDTV]", "", 2, 10)]
[TestCase("Franklin & Bash S02E10 6-50 to SLC [SDTV]", "Franklin & Bash", 2, 10)]
[TestCase("The_Big_Bang_Theory_-_6x12_-_The_Egg_Salad_Equivalency_[HDTV-720p]", "The Big Bang Theory", 6, 12)]
[TestCase("Top_Gear.19x06.720p_HDTV_x264-FoV", "Top Gear", 19, 6)]
[TestCase("Portlandia.S03E10.Alexandra.720p.WEB-DL.AAC2.0.H.264-CROM.mkv", "Portlandia", 3, 10)]
[TestCase("(Game of Thrones s03 e - \"Game of Thrones Season 3 Episode 10\"", "Game of Thrones", 3, 10)]
[TestCase("House.Hunters.International.S05E607.720p.hdtv.x264", "House.Hunters.International", 5, 607)]
[TestCase("Adventure.Time.With.Finn.And.Jake.S01E20.720p.BluRay.x264-DEiMOS", "Adventure.Time.With.Finn.And.Jake", 1, 20)]
[TestCase("Hostages.S01E04.2-45.PM.[HDTV-720p].mkv", "Hostages", 1, 4)]
[TestCase("S01E04", "", 1, 4)]
[TestCase("1x04", "", 1, 4)]
[TestCase("10.Things.You.Dont.Know.About.S02E04.Prohibition.HDTV.XviD-AFG", "10 Things You Dont Know About", 2, 4)]
[TestCase("30 Rock - S01E01 - Pilot.avi", "30 Rock", 1, 1)]
[TestCase("666 Park Avenue - S01E01", "666 Park Avenue", 1, 1)]
[TestCase("Warehouse 13 - S01E01", "Warehouse 13", 1, 1)]
[TestCase("Don't Trust The B---- in Apartment 23.S01E01", "Don't Trust The B---- in Apartment 23", 1, 1)]
[TestCase("Warehouse.13.S01E01", "Warehouse.13", 1, 1)]
[TestCase("Dont.Trust.The.B----.in.Apartment.23.S01E01", "Dont.Trust.The.B----.in.Apartment.23", 1, 1)]
[TestCase("24 S01E01", "24", 1, 1)]
[TestCase("24.S01E01", "24", 1, 1)]
[TestCase("Homeland - 2x12 - The Choice [HDTV-1080p].mkv", "Homeland", 2, 12)]
[TestCase("Homeland - 2x4 - New Car Smell [HDTV-1080p].mkv", "Homeland", 2, 4)]
public void ParseTitle_single(string postTitle, string title, int seasonNumber, int episodeNumber)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Should().NotBeNull();
result.EpisodeNumbers.Should().HaveCount(1);
result.SeasonNumber.Should().Be(seasonNumber);
result.EpisodeNumbers.First().Should().Be(episodeNumber);
result.SeriesTitle.Should().Be(title.CleanSeriesTitle());
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeFalse();
}
[TestCase(@"z:\tv shows\battlestar galactica (2003)\Season 3\S03E05 - Collaborators.mkv", 3, 5)]
[TestCase(@"z:\tv shows\modern marvels\Season 16\S16E03 - The Potato.mkv", 16, 3)]
[TestCase(@"z:\tv shows\robot chicken\Specials\S00E16 - Dear Consumer - SD TV.avi", 0, 16)]
[TestCase(@"D:\shares\TV Shows\Parks And Recreation\Season 2\S02E21 - 94 Meetings - 720p TV.mkv", 2, 21)]
[TestCase(@"D:\shares\TV Shows\Battlestar Galactica (2003)\Season 2\S02E21.avi", 2, 21)]
[TestCase("C:/Test/TV/Chuck.4x05.HDTV.XviD-LOL", 4, 5)]
[TestCase(@"P:\TV Shows\House\Season 6\S06E13 - 5 to 9 - 720p BluRay.mkv", 6, 13)]
[TestCase(@"S:\TV Drop\House - 10x11 - Title [SDTV]\1011 - Title.avi", 10, 11)]
[TestCase(@"/TV Drop/House - 10x11 - Title [SDTV]/1011 - Title.avi", 10, 11)]
[TestCase(@"S:\TV Drop\King of the Hill - 10x12 - 24 Hour Propane People [SDTV]\1012 - 24 Hour Propane People.avi", 10, 12)]
[TestCase(@"/TV Drop/King of the Hill - 10x12 - 24 Hour Propane People [SDTV]/1012 - 24 Hour Propane People.avi", 10, 12)]
[TestCase(@"S:\TV Drop\King of the Hill - 10x12 - 24 Hour Propane People [SDTV]\Hour Propane People.avi", 10, 12)]
[TestCase(@"/TV Drop/King of the Hill - 10x12 - 24 Hour Propane People [SDTV]/Hour Propane People.avi", 10, 12)]
[TestCase(@"E:\Downloads\tv\The.Big.Bang.Theory.S01E01.720p.HDTV\ajifajjjeaeaeqwer_eppj.avi", 1, 1)]
[TestCase(@"C:\Test\Unsorted\The.Big.Bang.Theory.S01E01.720p.HDTV\tbbt101.avi", 1, 1)]
public void PathParse_tests(string path, int season, int episode)
{
var result = Parser.Parser.ParsePath(path);
result.EpisodeNumbers.Should().HaveCount(1);
result.SeasonNumber.Should().Be(season);
result.EpisodeNumbers[0].Should().Be(episode);
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeFalse();
ExceptionVerification.IgnoreWarns();
}
[TestCase("THIS SHOULD NEVER PARSE")]
public void unparsable_title_should_log_warn_and_return_null(string title)
{
Parser.Parser.ParseTitle(title).Should().BeNull();
}
//[Timeout(1000)]
[TestCase("WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD", "WEEDS", 3, new[] { 1, 2, 3, 4, 5, 6 })]
[TestCase("Two.and.a.Half.Men.103.104.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Men", 1, new[] { 3, 4 })]
[TestCase("Weeds.S03E01.S03E02.720p.HDTV.X264-DIMENSION", "Weeds", 3, new[] { 1, 2 })]
[TestCase("The Borgias S01e01 e02 ShoHD On Demand 1080i DD5 1 ALANiS", "The Borgias", 1, new[] { 1, 2 })]
[TestCase("White.Collar.2x04.2x05.720p.BluRay-FUTV", "White.Collar", 2, new[] { 4, 5 })]
[TestCase("Desperate.Housewives.S07E22E23.720p.HDTV.X264-DIMENSION", "Desperate.Housewives", 7, new[] { 22, 23 })]
[TestCase("Desparate Housewives - S07E22 - S07E23 - And Lots of Security.. [HDTV-720p].mkv", "Desparate Housewives", 7, new[] { 22, 23 })]
[TestCase("S03E01.S03E02.720p.HDTV.X264-DIMENSION", "", 3, new[] { 1, 2 })]
[TestCase("Desparate Housewives - S07E22 - 7x23 - And Lots of Security.. [HDTV-720p].mkv", "Desparate Housewives", 7, new[] { 22, 23 })]
[TestCase("S07E22 - 7x23 - And Lots of Security.. [HDTV-720p].mkv", "", 7, new[] { 22, 23 })]
[TestCase("2x04x05.720p.BluRay-FUTV", "", 2, new[] { 4, 5 })]
[TestCase("S02E04E05.720p.BluRay-FUTV", "", 2, new[] { 4, 5 })]
[TestCase("S02E03-04-05.720p.BluRay-FUTV", "", 2, new[] { 3, 4, 5 })]
[TestCase("Breakout.Kings.S02E09-E10.HDTV.x264-ASAP", "Breakout Kings", 2, new[] { 9, 10 })]
[TestCase("Breakout Kings - 2x9-2x10 - Served Cold [SDTV] ", "Breakout Kings", 2, new[] { 9, 10 })]
[TestCase("Breakout Kings - 2x09-2x10 - Served Cold [SDTV] ", "Breakout Kings", 2, new[] { 9, 10 })]
[TestCase("Hell on Wheels S02E09 E10 HDTV x264 EVOLVE", "Hell on Wheels", 2, new[] { 9, 10 })]
[TestCase("Hell.on.Wheels.S02E09-E10.720p.HDTV.x264-EVOLVE", "Hell on Wheels", 2, new[] { 9, 10 })]
[TestCase("Grey's Anatomy - 8x01_02 - Free Falling", "Grey's Anatomy", 8, new [] { 1,2 })]
[TestCase("8x01_02 - Free Falling", "", 8, new[] { 1, 2 })]
[TestCase("Kaamelott.S01E91-E100", "Kaamelott", 1, new[] { 91, 92, 93, 94, 95, 96, 97, 98, 99, 100 })]
[TestCase("Neighbours.S29E161-E165.PDTV.x264-FQM", "Neighbours", 29, new[] { 161, 162, 163, 164, 165 })]
[TestCase("Shortland.Street.S22E5363-E5366.HDTV.x264-FiHTV", "Shortland Street", 22, new[] { 5363, 5364, 5365, 5366 })]
public void TitleParse_multi(string postTitle, string title, int season, int[] episodes)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.SeasonNumber.Should().Be(season);
result.EpisodeNumbers.Should().BeEquivalentTo(episodes);
result.SeriesTitle.Should().Be(title.CleanSeriesTitle());
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeFalse();
}
[TestCase("Conan 2011 04 18 Emma Roberts HDTV XviD BFF", "Conan", 2011, 04, 18)]
[TestCase("The Tonight Show With Jay Leno 2011 04 15 1080i HDTV DD5 1 MPEG2 TrollHD", "The Tonight Show With Jay Leno", 2011, 04, 15)]
[TestCase("The.Daily.Show.2010.10.11.Johnny.Knoxville.iTouch-MW", "The.Daily.Show", 2010, 10, 11)]
[TestCase("The Daily Show - 2011-04-12 - Gov. Deval Patrick", "The.Daily.Show", 2011, 04, 12)]
[TestCase("2011.01.10 - Denis Leary - HD TV.mkv", "", 2011, 1, 10)]
[TestCase("2011.03.13 - Denis Leary - HD TV.mkv", "", 2011, 3, 13)]
[TestCase("The Tonight Show with Jay Leno - 2011-06-16 - Larry David, \"Bachelorette\" Ashley Hebert, Pitbull with Ne-Yo", "The Tonight Show with Jay Leno", 2011, 6, 16)]
[TestCase("2020.NZ.2012.16.02.PDTV.XviD-C4TV", "2020nz", 2012, 2, 16)]
[TestCase("2020.NZ.2012.13.02.PDTV.XviD-C4TV", "2020nz", 2012, 2, 13)]
[TestCase("2020.NZ.2011.12.02.PDTV.XviD-C4TV", "2020nz", 2011, 12, 2)]
public void parse_daily_episodes(string postTitle, string title, int year, int month, int day)
{
var result = Parser.Parser.ParseTitle(postTitle);
var airDate = new DateTime(year, month, day);
result.Should().NotBeNull();
result.SeriesTitle.Should().Be(title.CleanSeriesTitle());
result.AirDate.Should().Be(airDate.ToString(Episode.AIR_DATE_FORMAT));
result.EpisodeNumbers.Should().BeEmpty();
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeFalse();
}
[TestCase("[SubDESU]_High_School_DxD_07_(1280x720_x264-AAC)_[6B7FD717]", "High School DxD", 7, 0, 0)]
[TestCase("[Chihiro]_Working!!_-_06_[848x480_H.264_AAC][859EEAFA]", "Working!!", 6, 0, 0)]
[TestCase("[Commie]_Senki_Zesshou_Symphogear_-_11_[65F220B4]", "Senki_Zesshou_Symphogear", 11, 0, 0)]
@ -232,138 +56,6 @@ namespace NzbDrone.Core.Test.ParserTests
result.FullSeason.Should().BeFalse();
}
[TestCase("Conan {year} {month} {day} Emma Roberts HDTV XviD BFF")]
[TestCase("The Tonight Show With Jay Leno {year} {month} {day} 1080i HDTV DD5 1 MPEG2 TrollHD")]
[TestCase("The.Daily.Show.{year}.{month}.{day}.Johnny.Knoxville.iTouch-MW")]
[TestCase("The Daily Show - {year}-{month}-{day} - Gov. Deval Patrick")]
[TestCase("{year}.{month}.{day} - Denis Leary - HD TV.mkv")]
[TestCase("The Tonight Show with Jay Leno - {year}-{month}-{day} - Larry David, \"Bachelorette\" Ashley Hebert, Pitbull with Ne-Yo")]
[TestCase("2020.NZ.{year}.{month}.{day}.PDTV.XviD-C4TV")]
public void should_not_accept_ancient_daily_series(string title)
{
var yearTooLow = title.Expand(new { year = 1950, month = 10, day = 14 });
Parser.Parser.ParseTitle(yearTooLow).Should().BeNull();
}
[TestCase("Conan {year} {month} {day} Emma Roberts HDTV XviD BFF")]
[TestCase("The Tonight Show With Jay Leno {year} {month} {day} 1080i HDTV DD5 1 MPEG2 TrollHD")]
[TestCase("The.Daily.Show.{year}.{month}.{day}.Johnny.Knoxville.iTouch-MW")]
[TestCase("The Daily Show - {year}-{month}-{day} - Gov. Deval Patrick")]
[TestCase("{year}.{month}.{day} - Denis Leary - HD TV.mkv")]
[TestCase("The Tonight Show with Jay Leno - {year}-{month}-{day} - Larry David, \"Bachelorette\" Ashley Hebert, Pitbull with Ne-Yo")]
[TestCase("2020.NZ.{year}.{month}.{day}.PDTV.XviD-C4TV")]
public void should_not_accept_future_dates(string title)
{
var twoDaysFromNow = DateTime.Now.AddDays(2);
var validDate = title.Expand(new { year = twoDaysFromNow.Year, month = twoDaysFromNow.Month.ToString("00"), day = twoDaysFromNow.Day.ToString("00") });
Parser.Parser.ParseTitle(validDate).Should().BeNull();
}
[Test]
public void parse_daily_should_fail_if_episode_is_far_in_future()
{
var title = string.Format("{0:yyyy.MM.dd} - Denis Leary - HD TV.mkv", DateTime.Now.AddDays(2));
Parser.Parser.ParseTitle(title).Should().BeNull();
}
[TestCase("30.Rock.Season.04.HDTV.XviD-DIMENSION", "30.Rock", 4)]
[TestCase("Parks.and.Recreation.S02.720p.x264-DIMENSION", "Parks.and.Recreation", 2)]
[TestCase("The.Office.US.S03.720p.x264-DIMENSION", "The.Office.US", 3)]
[TestCase(@"Sons.of.Anarchy.S03.720p.BluRay-CLUE\REWARD", "Sons.of.Anarchy", 3)]
[TestCase("Adventure Time S02 720p HDTV x264 CRON", "Adventure Time", 2)]
[TestCase("Sealab.2021.S04.iNTERNAL.DVDRip.XviD-VCDVaULT", "Sealab 2021", 4)]
public void full_season_release_parse(string postTitle, string title, int season)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.SeasonNumber.Should().Be(season);
result.SeriesTitle.Should().Be(title.CleanSeriesTitle());
result.EpisodeNumbers.Should().BeEmpty();
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeTrue();
}
[TestCase("Conan", "conan")]
[TestCase("The Tonight Show With Jay Leno", "tonightshowwithjayleno")]
[TestCase("The.Daily.Show", "dailyshow")]
[TestCase("Castle (2009)", "castle2009")]
[TestCase("Parenthood.2010", "parenthood2010")]
[TestCase("Law_and_Order_SVU", "lawordersvu")]
public void series_name_normalize(string parsedSeriesName, string seriesName)
{
var result = parsedSeriesName.CleanSeriesTitle();
result.Should().Be(seriesName);
}
[TestCase("CaPitAl", "capital")]
[TestCase("peri.od", "period")]
[TestCase("this.^&%^**$%@#$!That", "thisthat")]
[TestCase("test/test", "testtest")]
[TestCase("90210", "90210")]
[TestCase("24", "24")]
public void Normalize_Title(string dirty, string clean)
{
var result = dirty.CleanSeriesTitle();
result.Should().Be(clean);
}
[TestCase("the")]
[TestCase("and")]
[TestCase("or")]
[TestCase("a")]
[TestCase("an")]
[TestCase("of")]
public void Normalize_removed_common_words(string word)
{
var dirtyFormat = new[]
{
"word.{0}.word",
"word {0} word",
"word-{0}-word",
"{0}.word.word",
"{0}-word-word",
"{0} word word",
"word.word.{0}",
"word-word-{0}",
"word-word {0}",
};
foreach (var s in dirtyFormat)
{
var dirty = String.Format(s, word);
dirty.CleanSeriesTitle().Should().Be("wordword");
}
}
[TestCase("the")]
[TestCase("and")]
[TestCase("or")]
[TestCase("a")]
[TestCase("an")]
[TestCase("of")]
public void Normalize_not_removed_common_words_in_the_middle(string word)
{
var dirtyFormat = new[]
{
"word.{0}word",
"word {0}word",
"word-{0}word",
"word{0}.word",
"word{0}-word",
"word{0}-word",
};
foreach (var s in dirtyFormat)
{
var dirty = String.Format(s, word);
dirty.CleanSeriesTitle().Should().Be(("word" + word.ToLower() + "word"));
}
}
[TestCase("Chuck - 4x05 - Title", "Chuck")]
[TestCase("Law & Order - 4x05 - Title", "laworder")]
[TestCase("Bad Format", "badformat")]
@ -376,115 +68,10 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Hawaii Five 0", "hawaiifive0")]
[TestCase("Match of the Day", "matchday")]
[TestCase("Match of the Day 2", "matchday2")]
public void parse_series_name(string postTitle, string title)
public void should_parse_series_name(string postTitle, string title)
{
var result = Parser.Parser.ParseSeriesName(postTitle);
result.Should().Be(title.CleanSeriesTitle());
}
[TestCase("Castle.2009.S01E14.English.HDTV.XviD-LOL", Language.English)]
[TestCase("Castle.2009.S01E14.French.HDTV.XviD-LOL", Language.French)]
[TestCase("Castle.2009.S01E14.Spanish.HDTV.XviD-LOL", Language.Spanish)]
[TestCase("Castle.2009.S01E14.German.HDTV.XviD-LOL", Language.German)]
[TestCase("Castle.2009.S01E14.Germany.HDTV.XviD-LOL", Language.English)]
[TestCase("Castle.2009.S01E14.Italian.HDTV.XviD-LOL", Language.Italian)]
[TestCase("Castle.2009.S01E14.Danish.HDTV.XviD-LOL", Language.Danish)]
[TestCase("Castle.2009.S01E14.Dutch.HDTV.XviD-LOL", Language.Dutch)]
[TestCase("Castle.2009.S01E14.Japanese.HDTV.XviD-LOL", Language.Japanese)]
[TestCase("Castle.2009.S01E14.Cantonese.HDTV.XviD-LOL", Language.Cantonese)]
[TestCase("Castle.2009.S01E14.Mandarin.HDTV.XviD-LOL", Language.Mandarin)]
[TestCase("Castle.2009.S01E14.Korean.HDTV.XviD-LOL", Language.Korean)]
[TestCase("Castle.2009.S01E14.Russian.HDTV.XviD-LOL", Language.Russian)]
[TestCase("Castle.2009.S01E14.Polish.HDTV.XviD-LOL", Language.Polish)]
[TestCase("Castle.2009.S01E14.Vietnamese.HDTV.XviD-LOL", Language.Vietnamese)]
[TestCase("Castle.2009.S01E14.Swedish.HDTV.XviD-LOL", Language.Swedish)]
[TestCase("Castle.2009.S01E14.Norwegian.HDTV.XviD-LOL", Language.Norwegian)]
[TestCase("Castle.2009.S01E14.Finnish.HDTV.XviD-LOL", Language.Finnish)]
[TestCase("Castle.2009.S01E14.Turkish.HDTV.XviD-LOL", Language.Turkish)]
[TestCase("Castle.2009.S01E14.Portuguese.HDTV.XviD-LOL", Language.Portuguese)]
[TestCase("Castle.2009.S01E14.HDTV.XviD-LOL", Language.English)]
[TestCase("person.of.interest.1x19.ita.720p.bdmux.x264-novarip", Language.Italian)]
[TestCase("Salamander.S01E01.FLEMISH.HDTV.x264-BRiGAND", Language.Flemish)]
[TestCase("H.Polukatoikia.S03E13.Greek.PDTV.XviD-Ouzo", Language.Greek)]
[TestCase("Burn.Notice.S04E15.Brotherly.Love.GERMAN.DUBBED.WS.WEBRiP.XviD.REPACK-TVP", Language.German)]
[TestCase("Ray Donovan - S01E01.720p.HDtv.x264-Evolve (NLsub)", Language.Norwegian)]
[TestCase("Shield,.The.1x13.Tueurs.De.Flics.FR.DVDRip.XviD", Language.French)]
[TestCase("True.Detective.S01E01.1080p.WEB-DL.Rus.Eng.TVKlondike", Language.Russian)]
public void parse_language(string postTitle, Language language)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Language.Should().Be(language);
}
[TestCase("Hawaii Five 0 S01 720p WEB DL DD5 1 H 264 NT", "Hawaii Five 0", 1)]
[TestCase("30 Rock S03 WS PDTV XviD FUtV", "30 Rock", 3)]
[TestCase("The Office Season 4 WS PDTV XviD FUtV", "The Office", 4)]
[TestCase("Eureka Season 1 720p WEB DL DD 5 1 h264 TjHD", "Eureka", 1)]
[TestCase("The Office Season4 WS PDTV XviD FUtV", "The Office", 4)]
[TestCase("Eureka S 01 720p WEB DL DD 5 1 h264 TjHD", "Eureka", 1)]
[TestCase("Doctor Who Confidential Season 3", "Doctor Who Confidential", 3)]
public void parse_season_info(string postTitle, string seriesName, int seasonNumber)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.SeriesTitle.Should().Be(seriesName.CleanSeriesTitle());
result.SeasonNumber.Should().Be(seasonNumber);
result.FullSeason.Should().BeTrue();
}
[TestCase("Acropolis Now S05 EXTRAS DVDRip XviD RUNNER")]
[TestCase("Punky Brewster S01 EXTRAS DVDRip XviD RUNNER")]
[TestCase("Instant Star S03 EXTRAS DVDRip XviD OSiTV")]
public void parse_season_extras(string postTitle)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Should().BeNull();
}
[TestCase("Lie.to.Me.S03.SUBPACK.DVDRip.XviD-REWARD")]
[TestCase("The.Middle.S02.SUBPACK.DVDRip.XviD-REWARD")]
[TestCase("CSI.S11.SUBPACK.DVDRip.XviD-REWARD")]
public void parse_season_subpack(string postTitle)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Should().BeNull();
}
[TestCase("76El6LcgLzqb426WoVFg1vVVVGx4uCYopQkfjmLe")]
[TestCase("Vrq6e1Aba3U amCjuEgV5R2QvdsLEGYF3YQAQkw8")]
[TestCase("TDAsqTea7k4o6iofVx3MQGuDK116FSjPobMuh8oB")]
[TestCase("yp4nFodAAzoeoRc467HRh1mzuT17qeekmuJ3zFnL")]
[TestCase("oxXo8S2272KE1 lfppvxo3iwEJBrBmhlQVK1gqGc")]
[TestCase("dPBAtu681Ycy3A4NpJDH6kNVQooLxqtnsW1Umfiv")]
[TestCase("password - \"bdc435cb-93c4-4902-97ea-ca00568c3887.337\" yEnc")]
public void should_not_parse_crap(string title)
{
Parser.Parser.ParseTitle(title).Should().BeNull();
ExceptionVerification.IgnoreWarns();
}
[TestCase("Castle.2009.S01E14.English.HDTV.XviD-LOL", "LOL")]
[TestCase("Castle 2009 S01E14 English HDTV XviD LOL", "LOL")]
[TestCase("Acropolis Now S05 EXTRAS DVDRip XviD RUNNER", "RUNNER")]
[TestCase("Punky.Brewster.S01.EXTRAS.DVDRip.XviD-RUNNER", "RUNNER")]
[TestCase("2020.NZ.2011.12.02.PDTV.XviD-C4TV", "C4TV")]
[TestCase("The.Office.S03E115.DVDRip.XviD-OSiTV", "OSiTV")]
[TestCase("The Office - S01E01 - Pilot [HTDV-480p]", "DRONE")]
[TestCase("The Office - S01E01 - Pilot [HTDV-720p]", "DRONE")]
[TestCase("The Office - S01E01 - Pilot [HTDV-1080p]", "DRONE")]
public void parse_releaseGroup(string title, string expected)
{
Parser.Parser.ParseReleaseGroup(title).Should().Be(expected);
}
[Test]
public void should_not_include_extension_in_releaseGroup()
{
const string path = @"C:\Test\Doctor.Who.2005.s01e01.internal.bdrip.x264-archivist.mkv";
Parser.Parser.ParsePath(path).ReleaseGroup.Should().Be("archivist");
}
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Expansive;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class PathParserFixture : CoreTest
{
[TestCase(@"z:\tv shows\battlestar galactica (2003)\Season 3\S03E05 - Collaborators.mkv", 3, 5)]
[TestCase(@"z:\tv shows\modern marvels\Season 16\S16E03 - The Potato.mkv", 16, 3)]
[TestCase(@"z:\tv shows\robot chicken\Specials\S00E16 - Dear Consumer - SD TV.avi", 0, 16)]
[TestCase(@"D:\shares\TV Shows\Parks And Recreation\Season 2\S02E21 - 94 Meetings - 720p TV.mkv", 2, 21)]
[TestCase(@"D:\shares\TV Shows\Battlestar Galactica (2003)\Season 2\S02E21.avi", 2, 21)]
[TestCase("C:/Test/TV/Chuck.4x05.HDTV.XviD-LOL", 4, 5)]
[TestCase(@"P:\TV Shows\House\Season 6\S06E13 - 5 to 9 - 720p BluRay.mkv", 6, 13)]
[TestCase(@"S:\TV Drop\House - 10x11 - Title [SDTV]\1011 - Title.avi", 10, 11)]
[TestCase(@"/TV Drop/House - 10x11 - Title [SDTV]/1011 - Title.avi", 10, 11)]
[TestCase(@"S:\TV Drop\King of the Hill - 10x12 - 24 Hour Propane People [SDTV]\1012 - 24 Hour Propane People.avi", 10, 12)]
[TestCase(@"/TV Drop/King of the Hill - 10x12 - 24 Hour Propane People [SDTV]/1012 - 24 Hour Propane People.avi", 10, 12)]
[TestCase(@"S:\TV Drop\King of the Hill - 10x12 - 24 Hour Propane People [SDTV]\Hour Propane People.avi", 10, 12)]
[TestCase(@"/TV Drop/King of the Hill - 10x12 - 24 Hour Propane People [SDTV]/Hour Propane People.avi", 10, 12)]
[TestCase(@"E:\Downloads\tv\The.Big.Bang.Theory.S01E01.720p.HDTV\ajifajjjeaeaeqwer_eppj.avi", 1, 1)]
[TestCase(@"C:\Test\Unsorted\The.Big.Bang.Theory.S01E01.720p.HDTV\tbbt101.avi", 1, 1)]
[TestCase(@"C:\Test\Unsorted\Terminator.The.Sarah.Connor.Chronicles.S02E19.720p.BluRay.x264-SiNNERS-RP\ba27283b17c00d01193eacc02a8ba98eeb523a76.mkv", 2, 19)]
[TestCase(@"C:\Test\Unsorted\Terminator.The.Sarah.Connor.Chronicles.S02E18.720p.BluRay.x264-SiNNERS-RP\45a55debe3856da318cc35882ad07e43cd32fd15.mkv", 2, 18)]
public void should_parse_from_path(string path, int season, int episode)
{
var result = Parser.Parser.ParsePath(path);
result.EpisodeNumbers.Should().HaveCount(1);
result.SeasonNumber.Should().Be(season);
result.EpisodeNumbers[0].Should().Be(episode);
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeFalse();
ExceptionVerification.IgnoreWarns();
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class ReleaseGroupParserFixture : CoreTest
{
[TestCase("Castle.2009.S01E14.English.HDTV.XviD-LOL", "LOL")]
[TestCase("Castle 2009 S01E14 English HDTV XviD LOL", "LOL")]
[TestCase("Acropolis Now S05 EXTRAS DVDRip XviD RUNNER", "RUNNER")]
[TestCase("Punky.Brewster.S01.EXTRAS.DVDRip.XviD-RUNNER", "RUNNER")]
[TestCase("2020.NZ.2011.12.02.PDTV.XviD-C4TV", "C4TV")]
[TestCase("The.Office.S03E115.DVDRip.XviD-OSiTV", "OSiTV")]
[TestCase("The Office - S01E01 - Pilot [HTDV-480p]", "DRONE")]
[TestCase("The Office - S01E01 - Pilot [HTDV-720p]", "DRONE")]
[TestCase("The Office - S01E01 - Pilot [HTDV-1080p]", "DRONE")]
public void should_parse_release_group(string title, string expected)
{
Parser.Parser.ParseReleaseGroup(title).Should().Be(expected);
}
[Test]
public void should_not_include_extension_in_release_roup()
{
const string path = @"C:\Test\Doctor.Who.2005.s01e01.internal.bdrip.x264-archivist.mkv";
Parser.Parser.ParsePath(path).ReleaseGroup.Should().Be("archivist");
}
}
}

View File

@ -0,0 +1,57 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class SeasonParserFixture : CoreTest
{
[TestCase("30.Rock.Season.04.HDTV.XviD-DIMENSION", "30.Rock", 4)]
[TestCase("Parks.and.Recreation.S02.720p.x264-DIMENSION", "Parks.and.Recreation", 2)]
[TestCase("The.Office.US.S03.720p.x264-DIMENSION", "The.Office.US", 3)]
[TestCase(@"Sons.of.Anarchy.S03.720p.BluRay-CLUE\REWARD", "Sons.of.Anarchy", 3)]
[TestCase("Adventure Time S02 720p HDTV x264 CRON", "Adventure Time", 2)]
[TestCase("Sealab.2021.S04.iNTERNAL.DVDRip.XviD-VCDVaULT", "Sealab 2021", 4)]
[TestCase("Hawaii Five 0 S01 720p WEB DL DD5 1 H 264 NT", "Hawaii Five 0", 1)]
[TestCase("30 Rock S03 WS PDTV XviD FUtV", "30 Rock", 3)]
[TestCase("The Office Season 4 WS PDTV XviD FUtV", "The Office", 4)]
[TestCase("Eureka Season 1 720p WEB DL DD 5 1 h264 TjHD", "Eureka", 1)]
[TestCase("The Office Season4 WS PDTV XviD FUtV", "The Office", 4)]
[TestCase("Eureka S 01 720p WEB DL DD 5 1 h264 TjHD", "Eureka", 1)]
[TestCase("Doctor Who Confidential Season 3", "Doctor Who Confidential", 3)]
public void should_parsefull_season_release(string postTitle, string title, int season)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.SeasonNumber.Should().Be(season);
result.SeriesTitle.Should().Be(title.CleanSeriesTitle());
result.EpisodeNumbers.Should().BeEmpty();
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeTrue();
}
[TestCase("Acropolis Now S05 EXTRAS DVDRip XviD RUNNER")]
[TestCase("Punky Brewster S01 EXTRAS DVDRip XviD RUNNER")]
[TestCase("Instant Star S03 EXTRAS DVDRip XviD OSiTV")]
public void should_parse_season_extras(string postTitle)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Should().BeNull();
}
[TestCase("Lie.to.Me.S03.SUBPACK.DVDRip.XviD-REWARD")]
[TestCase("The.Middle.S02.SUBPACK.DVDRip.XviD-REWARD")]
[TestCase("CSI.S11.SUBPACK.DVDRip.XviD-REWARD")]
public void should_parse_season_subpack(string postTitle)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Should().BeNull();
}
}
}

View File

@ -0,0 +1,97 @@
using System;
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.ParserTests
{
[TestFixture]
public class SingleEpisodeParserFixture : CoreTest
{
[TestCase("Sonny.With.a.Chance.S02E15", "Sonny.With.a.Chance", 2, 15)]
[TestCase("Two.and.a.Half.Me.103.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Me", 1, 3)]
[TestCase("Two.and.a.Half.Me.113.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Me", 1, 13)]
[TestCase("Two.and.a.Half.Me.1013.720p.HDTV.X264-DIMENSION", "Two.and.a.Half.Me", 10, 13)]
[TestCase("Chuck.4x05.HDTV.XviD-LOL", "Chuck", 4, 5)]
[TestCase("The.Girls.Next.Door.S03E06.DVDRip.XviD-WiDE", "The.Girls.Next.Door", 3, 6)]
[TestCase("Degrassi.S10E27.WS.DSR.XviD-2HD", "Degrassi", 10, 27)]
[TestCase("Parenthood.2010.S02E14.HDTV.XviD-LOL", "Parenthood 2010", 2, 14)]
[TestCase("Hawaii Five 0 S01E19 720p WEB DL DD5 1 H 264 NT", "Hawaii Five 0", 1, 19)]
[TestCase("The Event S01E14 A Message Back 720p WEB DL DD5 1 H264 SURFER", "The Event", 1, 14)]
[TestCase("Adam Hills In Gordon St Tonight S01E07 WS PDTV XviD FUtV", "Adam Hills In Gordon St Tonight", 1, 7)]
[TestCase("Adam Hills In Gordon St Tonight S01E07 WS PDTV XviD FUtV", "Adam Hills In Gordon St Tonight", 1, 7)]
[TestCase("Adventure.Inc.S03E19.DVDRip.XviD-OSiTV", "Adventure.Inc", 3, 19)]
[TestCase("S03E09 WS PDTV XviD FUtV", "", 3, 9)]
[TestCase("5x10 WS PDTV XviD FUtV", "", 5, 10)]
[TestCase("Castle.2009.S01E14.HDTV.XviD-LOL", "Castle 2009", 1, 14)]
[TestCase("Pride.and.Prejudice.1995.S03E20.HDTV.XviD-LOL", "Pride and Prejudice 1995", 3, 20)]
[TestCase("The.Office.S03E115.DVDRip.XviD-OSiTV", "The.Office", 3, 115)]
[TestCase(@"Parks and Recreation - S02E21 - 94 Meetings - 720p TV.mkv", "Parks and Recreation", 2, 21)]
[TestCase(@"24-7 Penguins-Capitals- Road to the NHL Winter Classic - S01E03 - Episode 3.mkv", "24-7 Penguins-Capitals- Road to the NHL Winter Classic", 1, 3)]
[TestCase("Adventure.Inc.S03E19.DVDRip.\"XviD\"-OSiTV", "Adventure.Inc", 3, 19)]
[TestCase("Hawaii Five-0 (2010) - 1x05 - Nalowale (Forgotten/Missing)", "Hawaii Five-0 (2010)", 1, 5)]
[TestCase("Hawaii Five-0 (2010) - 1x05 - Title", "Hawaii Five-0 (2010)", 1, 5)]
[TestCase("House - S06E13 - 5 to 9 [DVD]", "House", 6, 13)]
[TestCase("The Mentalist - S02E21 - 18-5-4", "The Mentalist", 2, 21)]
[TestCase("Breaking.In.S01E07.21.0.Jump.Street.720p.WEB-DL.DD5.1.h.264-KiNGS", "Breaking In", 1, 7)]
[TestCase("CSI.525", "CSI", 5, 25)]
[TestCase("King of the Hill - 10x12 - 24 Hour Propane People [SDTV]", "King of the Hill", 10, 12)]
[TestCase("Brew Masters S01E06 3 Beers For Batali DVDRip XviD SPRiNTER", "Brew Masters", 1, 6)]
[TestCase("24 7 Flyers Rangers Road to the NHL Winter Classic Part01 720p HDTV x264 ORENJI", "24 7 Flyers Rangers Road to the NHL Winter Classic", 1, 1)]
[TestCase("24 7 Flyers Rangers Road to the NHL Winter Classic Part 02 720p HDTV x264 ORENJI", "24 7 Flyers Rangers Road to the NHL Winter Classic", 1, 2)]
[TestCase("24-7 Flyers-Rangers- Road to the NHL Winter Classic - S01E01 - Part 1", "24 7 Flyers Rangers Road to the NHL Winter Classic", 1, 1)]
[TestCase("The.Kennedys.Part.2.DSR.XviD-SYS", "The Kennedys", 1, 2)]
[TestCase("the-pacific-e07-720p", "The Pacific", 1, 7)]
[TestCase("S6E02-Unwrapped-(Playing With Food) - [DarkData]", "", 6, 2)]
[TestCase("S06E03-Unwrapped-(Number Ones Unwrapped) - [DarkData]", "", 6, 3)]
[TestCase("The Mentalist S02E21 18 5 4 720p WEB DL DD5 1 h 264 EbP", "The Mentalist", 2, 21)]
[TestCase("01x04 - Halloween, Part 1 - 720p WEB-DL", "", 1, 4)]
[TestCase("extras.s03.e05.ws.dvdrip.xvid-m00tv", "Extras", 3, 5)]
[TestCase("castle.2009.416.hdtv-lol", "Castle 2009", 4, 16)]
[TestCase("hawaii.five-0.2010.217.hdtv-lol", "Hawaii Five-0 (2010)", 2, 17)]
[TestCase("Looney Tunes - S1936E18 - I Love to Singa", "Looney Tunes", 1936, 18)]
[TestCase("American_Dad!_-_7x6_-_The_Scarlett_Getter_[SDTV]", "American Dad!", 7, 6)]
[TestCase("Falling_Skies_-_1x1_-_Live_and_Learn_[HDTV-720p]", "Falling Skies", 1, 1)]
[TestCase("Top Gear - 07x03 - 2005.11.70", "Top Gear", 7, 3)]
[TestCase("Hatfields and McCoys 2012 Part 1 REPACK 720p HDTV x264 2HD", "Hatfields and McCoys 2012", 1, 1)]
[TestCase("Glee.S04E09.Swan.Song.1080p.WEB-DL.DD5.1.H.264-ECI", "Glee", 4, 9)]
[TestCase("S08E20 50-50 Carla [DVD]", "", 8, 20)]
[TestCase("Cheers S08E20 50-50 Carla [DVD]", "Cheers", 8, 20)]
[TestCase("S02E10 6-50 to SLC [SDTV]", "", 2, 10)]
[TestCase("Franklin & Bash S02E10 6-50 to SLC [SDTV]", "Franklin & Bash", 2, 10)]
[TestCase("The_Big_Bang_Theory_-_6x12_-_The_Egg_Salad_Equivalency_[HDTV-720p]", "The Big Bang Theory", 6, 12)]
[TestCase("Top_Gear.19x06.720p_HDTV_x264-FoV", "Top Gear", 19, 6)]
[TestCase("Portlandia.S03E10.Alexandra.720p.WEB-DL.AAC2.0.H.264-CROM.mkv", "Portlandia", 3, 10)]
[TestCase("(Game of Thrones s03 e - \"Game of Thrones Season 3 Episode 10\"", "Game of Thrones", 3, 10)]
[TestCase("House.Hunters.International.S05E607.720p.hdtv.x264", "House.Hunters.International", 5, 607)]
[TestCase("Adventure.Time.With.Finn.And.Jake.S01E20.720p.BluRay.x264-DEiMOS", "Adventure.Time.With.Finn.And.Jake", 1, 20)]
[TestCase("Hostages.S01E04.2-45.PM.[HDTV-720p].mkv", "Hostages", 1, 4)]
[TestCase("S01E04", "", 1, 4)]
[TestCase("1x04", "", 1, 4)]
[TestCase("10.Things.You.Dont.Know.About.S02E04.Prohibition.HDTV.XviD-AFG", "10 Things You Dont Know About", 2, 4)]
[TestCase("30 Rock - S01E01 - Pilot.avi", "30 Rock", 1, 1)]
[TestCase("666 Park Avenue - S01E01", "666 Park Avenue", 1, 1)]
[TestCase("Warehouse 13 - S01E01", "Warehouse 13", 1, 1)]
[TestCase("Don't Trust The B---- in Apartment 23.S01E01", "Don't Trust The B---- in Apartment 23", 1, 1)]
[TestCase("Warehouse.13.S01E01", "Warehouse.13", 1, 1)]
[TestCase("Dont.Trust.The.B----.in.Apartment.23.S01E01", "Dont.Trust.The.B----.in.Apartment.23", 1, 1)]
[TestCase("24 S01E01", "24", 1, 1)]
[TestCase("24.S01E01", "24", 1, 1)]
[TestCase("Homeland - 2x12 - The Choice [HDTV-1080p].mkv", "Homeland", 2, 12)]
[TestCase("Homeland - 2x4 - New Car Smell [HDTV-1080p].mkv", "Homeland", 2, 4)]
public void should_parse_single_episode(string postTitle, string title, int seasonNumber, int episodeNumber)
{
var result = Parser.Parser.ParseTitle(postTitle);
result.Should().NotBeNull();
result.EpisodeNumbers.Should().HaveCount(1);
result.SeasonNumber.Should().Be(seasonNumber);
result.EpisodeNumbers.First().Should().Be(episodeNumber);
result.SeriesTitle.Should().Be(title.CleanSeriesTitle());
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
result.FullSeason.Should().BeFalse();
}
}
}

View File

@ -23,6 +23,7 @@ namespace NzbDrone.Core.Annotations
Textbox,
Password,
Checkbox,
Select
Select,
Path
}
}

View File

@ -1,4 +1,7 @@
using NzbDrone.Core.Datastore;
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Datastore;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Blacklisting
@ -6,6 +9,7 @@ namespace NzbDrone.Core.Blacklisting
public interface IBlacklistRepository : IBasicRepository<Blacklist>
{
bool Blacklisted(string sourceTitle);
List<Blacklist> BlacklistedBySeries(int seriesId);
}
public class BlacklistRepository : BasicRepository<Blacklist>, IBlacklistRepository
@ -17,7 +21,12 @@ namespace NzbDrone.Core.Blacklisting
public bool Blacklisted(string sourceTitle)
{
return Query.Any(e => e.SourceTitle.Contains(sourceTitle));
return Query.Where(e => e.SourceTitle.Contains(sourceTitle)).Any();
}
public List<Blacklist> BlacklistedBySeries(int seriesId)
{
return Query.Where(b => b.SeriesId == seriesId);
}
}
}

View File

@ -3,6 +3,7 @@ using NzbDrone.Core.Datastore;
using NzbDrone.Core.Download;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Tv.Events;
namespace NzbDrone.Core.Blacklisting
{
@ -13,7 +14,7 @@ namespace NzbDrone.Core.Blacklisting
void Delete(int id);
}
public class BlacklistService : IBlacklistService, IHandle<DownloadFailedEvent>, IExecute<ClearBlacklistCommand>
public class BlacklistService : IBlacklistService, IExecute<ClearBlacklistCommand>, IHandle<DownloadFailedEvent>, IHandle<SeriesDeletedEvent>
{
private readonly IBlacklistRepository _blacklistRepository;
private readonly IRedownloadFailedDownloads _redownloadFailedDownloadService;
@ -39,6 +40,11 @@ namespace NzbDrone.Core.Blacklisting
_blacklistRepository.Delete(id);
}
public void Execute(ClearBlacklistCommand message)
{
_blacklistRepository.Purge();
}
public void Handle(DownloadFailedEvent message)
{
var blacklist = new Blacklist
@ -55,9 +61,11 @@ namespace NzbDrone.Core.Blacklisting
_redownloadFailedDownloadService.Redownload(message.SeriesId, message.EpisodeIds);
}
public void Execute(ClearBlacklistCommand message)
public void Handle(SeriesDeletedEvent message)
{
_blacklistRepository.Purge();
var blacklisted = _blacklistRepository.BlacklistedBySeries(message.Series.Id);
_blacklistRepository.DeleteMany(blacklisted);
}
}
}

View File

@ -21,9 +21,7 @@ namespace NzbDrone.Core.Configuration
public Config Get(string key)
{
return Query.SingleOrDefault(c => c.Key == key);
return Query.Where(c => c.Key == key).SingleOrDefault();
}
}
}

View File

@ -54,7 +54,7 @@ namespace NzbDrone.Core.Configuration
return dict;
}
public void SaveValues(Dictionary<string, object> configValues)
public void SaveConfigDictionary(Dictionary<string, object> configValues)
{
var allWithDefaults = AllWithDefaults();
@ -73,69 +73,6 @@ namespace NzbDrone.Core.Configuration
_eventAggregator.PublishEvent(new ConfigSavedEvent());
}
public String SabHost
{
get { return GetValue("SabHost", "localhost"); }
set { SetValue("SabHost", value); }
}
public int SabPort
{
get { return GetValueInt("SabPort", 8080); }
set { SetValue("SabPort", value); }
}
public String SabApiKey
{
get { return GetValue("SabApiKey"); }
set { SetValue("SabApiKey", value); }
}
public String SabUsername
{
get { return GetValue("SabUsername"); }
set { SetValue("SabUsername", value); }
}
public String SabPassword
{
get { return GetValue("SabPassword"); }
set { SetValue("SabPassword", value); }
}
public String SabTvCategory
{
get { return GetValue("SabTvCategory", "tv"); }
set { SetValue("SabTvCategory", value); }
}
public SabPriorityType SabRecentTvPriority
{
get { return GetValueEnum("SabRecentTvPriority", SabPriorityType.Default); }
set { SetValue("SabRecentTvPriority", value); }
}
public SabPriorityType SabOlderTvPriority
{
get { return GetValueEnum("SabOlderTvPriority", SabPriorityType.Default); }
set { SetValue("SabOlderTvPriority", value); }
}
public bool SabUseSsl
{
get { return GetValueBoolean("SabUseSsl", false); }
set { SetValue("SabUseSsl", value); }
}
public String DownloadedEpisodesFolder
{
get { return GetValue(ConfigKey.DownloadedEpisodesFolder.ToString()); }
@ -155,80 +92,12 @@ namespace NzbDrone.Core.Configuration
set { SetValue("Retention", value); }
}
public DownloadClientType DownloadClient
{
get { return GetValueEnum("DownloadClient", DownloadClientType.Blackhole); }
set { SetValue("DownloadClient", value); }
}
public string BlackholeFolder
{
get { return GetValue("BlackholeFolder", String.Empty); }
set { SetValue("BlackholeFolder", value); }
}
public string PneumaticFolder
{
get { return GetValue("PneumaticFolder", String.Empty); }
set { SetValue("PneumaticFolder", value); }
}
public string RecycleBin
{
get { return GetValue("RecycleBin", String.Empty); }
set { SetValue("RecycleBin", value); }
}
public String NzbgetUsername
{
get { return GetValue("NzbgetUsername", "nzbget"); }
set { SetValue("NzbgetUsername", value); }
}
public String NzbgetPassword
{
get { return GetValue("NzbgetPassword", ""); }
set { SetValue("NzbgetPassword", value); }
}
public String NzbgetHost
{
get { return GetValue("NzbgetHost", "localhost"); }
set { SetValue("NzbgetHost", value); }
}
public Int32 NzbgetPort
{
get { return GetValueInt("NzbgetPort", 6789); }
set { SetValue("NzbgetPort", value); }
}
public String NzbgetTvCategory
{
get { return GetValue("NzbgetTvCategory", ""); }
set { SetValue("NzbgetTvCategory", value); }
}
public PriorityType NzbgetRecentTvPriority
{
get { return GetValueEnum("NzbgetRecentTvPriority", PriorityType.Normal); }
set { SetValue("NzbgetRecentTvPriority", value); }
}
public PriorityType NzbgetOlderTvPriority
{
get { return GetValueEnum("NzbgetOlderTvPriority", PriorityType.Normal); }
set { SetValue("NzbgetOlderTvPriority", value); }
}
public string ReleaseRestrictions
{
get { return GetValue("ReleaseRestrictions", String.Empty).Trim('\r', '\n'); }

View File

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Clients.Nzbget;
using NzbDrone.Core.Download.Clients.Sabnzbd;
namespace NzbDrone.Core.Configuration
{
@ -10,42 +7,33 @@ namespace NzbDrone.Core.Configuration
{
IEnumerable<Config> All();
Dictionary<String, Object> AllWithDefaults();
String SabHost { get; set; }
int SabPort { get; set; }
String SabApiKey { get; set; }
String SabUsername { get; set; }
String SabPassword { get; set; }
String SabTvCategory { get; set; }
SabPriorityType SabRecentTvPriority { get; set; }
SabPriorityType SabOlderTvPriority { get; set; }
Boolean SabUseSsl { get; set; }
void SaveConfigDictionary(Dictionary<string, object> configValues);
//Download Client
String DownloadedEpisodesFolder { get; set; }
bool AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; }
int Retention { get; set; }
DownloadClientType DownloadClient { get; set; }
string BlackholeFolder { get; set; }
string PneumaticFolder { get; set; }
string RecycleBin { get; set; }
String NzbgetUsername { get; set; }
String NzbgetPassword { get; set; }
String NzbgetHost { get; set; }
Int32 NzbgetPort { get; set; }
String NzbgetTvCategory { get; set; }
PriorityType NzbgetRecentTvPriority { get; set; }
PriorityType NzbgetOlderTvPriority { get; set; }
string ReleaseRestrictions { get; set; }
Int32 RssSyncInterval { get; set; }
Boolean AutoDownloadPropers { get; set; }
String DownloadClientWorkingFolders { get; set; }
//Failed Download Handling (Download client)
Boolean AutoRedownloadFailed { get; set; }
Boolean RemoveFailedDownloads { get; set; }
Boolean EnableFailedDownloadHandling { get; set; }
//Media Management
Boolean AutoUnmonitorPreviouslyDownloadedEpisodes { get; set; }
String RecycleBin { get; set; }
Boolean AutoDownloadPropers { get; set; }
Boolean CreateEmptySeriesFolders { get; set; }
void SaveValues(Dictionary<string, object> configValues);
//Permissions (Media Management)
Boolean SetPermissionsLinux { get; set; }
String FileChmod { get; set; }
String FolderChmod { get; set; }
String ChownUser { get; set; }
String ChownGroup { get; set; }
//Indexers
Int32 Retention { get; set; }
Int32 RssSyncInterval { get; set; }
String ReleaseRestrictions { get; set; }
}
}

View File

@ -1,6 +1,5 @@
using System;
using System.Linq;
using System.Web.UI.WebControls;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Core.Messaging.Events;

View File

@ -73,7 +73,7 @@ namespace NzbDrone.Core.Datastore
public TModel Get(int id)
{
var model = DataMapper.Query<TModel>().SingleOrDefault(c => c.Id == id);
var model = Query.Where(c => c.Id == id).SingleOrDefault();
if (model == null)
{
@ -142,23 +142,44 @@ namespace NzbDrone.Core.Datastore
public void InsertMany(IList<TModel> models)
{
foreach (var model in models)
using (var unitOfWork = new UnitOfWork(() => DataMapper))
{
Insert(model);
unitOfWork.BeginTransaction();
foreach (var model in models)
{
unitOfWork.DB.Insert(model);
}
unitOfWork.Commit();
}
}
public void UpdateMany(IList<TModel> models)
{
foreach (var model in models)
using (var unitOfWork = new UnitOfWork(() => DataMapper))
{
Update(model);
unitOfWork.BeginTransaction();
foreach (var model in models)
{
var localModel = model;
if (model.Id == 0)
{
throw new InvalidOperationException("Can't update model with ID 0");
}
unitOfWork.DB.Update(model, c => c.Id == localModel.Id);
}
unitOfWork.Commit();
}
}
public void DeleteMany(List<TModel> models)
{
models.ForEach(Delete);
DeleteMany(models.Select(m => m.Id));
}
public TModel Upsert(TModel model)
@ -179,7 +200,19 @@ namespace NzbDrone.Core.Datastore
public void DeleteMany(IEnumerable<int> ids)
{
ids.ToList().ForEach(Delete);
using (var unitOfWork = new UnitOfWork(() => DataMapper))
{
unitOfWork.BeginTransaction();
foreach (var id in ids)
{
var localId = id;
unitOfWork.DB.Delete<TModel>(c => c.Id == localId);
}
unitOfWork.Commit();
}
}
public void Purge()

View File

@ -0,0 +1,20 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(42)]
public class add_download_clients_table : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Create.TableForModel("DownloadClients")
.WithColumn("Enable").AsBoolean().NotNullable()
.WithColumn("Name").AsString().NotNullable()
.WithColumn("Implementation").AsString().NotNullable()
.WithColumn("Settings").AsString().NotNullable()
.WithColumn("ConfigContract").AsString().NotNullable()
.WithColumn("Protocol").AsInt32().NotNullable();
}
}
}

View File

@ -0,0 +1,197 @@
using System;
using System.Collections.Generic;
using System.Data;
using FluentMigrator;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(43)]
public class convert_config_to_download_clients : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(ConvertToThingyProvder);
}
private void ConvertToThingyProvder(IDbConnection conn, IDbTransaction tran)
{
var config = new Dictionary<string, string>();
using (IDbCommand configCmd = conn.CreateCommand())
{
configCmd.Transaction = tran;
configCmd.CommandText = @"SELECT * FROM Config";
using (IDataReader configReader = configCmd.ExecuteReader())
{
var keyIndex = configReader.GetOrdinal("Key");
var valueIndex = configReader.GetOrdinal("Value");
while (configReader.Read())
{
var key = configReader.GetString(keyIndex);
var value = configReader.GetString(valueIndex);
config.Add(key.ToLowerInvariant(), value);
}
}
}
var client = GetConfigValue(config, "DownloadClient", "");
if (String.IsNullOrWhiteSpace(client))
{
return;
}
if (client.Equals("sabnzbd", StringComparison.InvariantCultureIgnoreCase))
{
var settings = new ClientSettingsForMigration
{
Host = GetConfigValue(config, "SabHost", "localhost"),
Port = GetConfigValue(config, "SabPort", 8080),
ApiKey = GetConfigValue(config, "SabApiKey", ""),
Username = GetConfigValue(config, "SabUsername", ""),
Password = GetConfigValue(config, "SabPassword", ""),
TvCategory = GetConfigValue(config, "SabTvCategory", "tv"),
RecentTvPriority = GetSabnzbdPriority(GetConfigValue(config, "NzbgetRecentTvPriority", "Default")),
OlderTvPriority = GetSabnzbdPriority(GetConfigValue(config, "NzbgetOlderTvPriority", "Default")),
UseSsl = GetConfigValue(config, "SabUseSsl", false)
};
AddDownloadClient(conn, tran, "Sabnzbd", "Sabnzbd", settings.ToJson(), "SabnzbdSettings", 1);
}
else if (client.Equals("nzbget", StringComparison.InvariantCultureIgnoreCase))
{
var settings = new ClientSettingsForMigration
{
Host = GetConfigValue(config, "NzbGetHost", "localhost"),
Port = GetConfigValue(config, "NzbgetPort", 6789),
Username = GetConfigValue(config, "NzbgetUsername", "nzbget"),
Password = GetConfigValue(config, "NzbgetPassword", ""),
TvCategory = GetConfigValue(config, "NzbgetTvCategory", "tv"),
RecentTvPriority = GetNzbgetPriority(GetConfigValue(config, "NzbgetRecentTvPriority", "Normal")),
OlderTvPriority = GetNzbgetPriority(GetConfigValue(config, "NzbgetOlderTvPriority", "Normal")),
};
AddDownloadClient(conn, tran, "Nzbget", "Nzbget", settings.ToJson(), "NzbgetSettings", 1);
}
else if (client.Equals("pneumatic", StringComparison.InvariantCultureIgnoreCase))
{
var settings = new FolderSettingsForMigration
{
Folder = GetConfigValue(config, "PneumaticFolder", "")
};
AddDownloadClient(conn, tran, "Pneumatic", "Pneumatic", settings.ToJson(), "FolderSettings", 1);
}
else if (client.Equals("blackhole", StringComparison.InvariantCultureIgnoreCase))
{
var settings = new FolderSettingsForMigration
{
Folder = GetConfigValue(config, "BlackholeFolder", "")
};
AddDownloadClient(conn, tran, "Blackhole", "Blackhole", settings.ToJson(), "FolderSettings", 1);
}
DeleteOldConfigValues(conn, tran);
}
private T GetConfigValue<T>(Dictionary<string, string> config, string key, T defaultValue)
{
key = key.ToLowerInvariant();
if (config.ContainsKey(key))
{
return (T) Convert.ChangeType(config[key], typeof (T));
}
return defaultValue;
}
private void AddDownloadClient(IDbConnection conn, IDbTransaction tran, string name, string implementation, string settings,
string configContract, int protocol)
{
using (IDbCommand updateCmd = conn.CreateCommand())
{
var text = String.Format("INSERT INTO DownloadClients (Enable, Name, Implementation, Settings, ConfigContract, Protocol) VALUES (1, ?, ?, ?, ?, ?)");
updateCmd.AddParameter(name);
updateCmd.AddParameter(implementation);
updateCmd.AddParameter(settings);
updateCmd.AddParameter(configContract);
updateCmd.AddParameter(protocol);
updateCmd.Transaction = tran;
updateCmd.CommandText = text;
updateCmd.ExecuteNonQuery();
}
}
private void DeleteOldConfigValues(IDbConnection conn, IDbTransaction tran)
{
using (IDbCommand updateCmd = conn.CreateCommand())
{
var text = "DELETE FROM Config WHERE [KEY] IN ('nzbgetusername', 'nzbgetpassword', 'nzbgethost', 'nzbgetport', " +
"'nzbgettvcategory', 'nzbgetrecenttvpriority', 'nzbgetoldertvpriority', 'sabhost', 'sabport', " +
"'sabapikey', 'sabusername', 'sabpassword', 'sabtvcategory', 'sabrecenttvpriority', " +
"'saboldertvpriority', 'sabusessl', 'downloadclient', 'blackholefolder', 'pneumaticfolder')";
updateCmd.Transaction = tran;
updateCmd.CommandText = text;
updateCmd.ExecuteNonQuery();
}
}
private int GetSabnzbdPriority(string priority)
{
return (int)Enum.Parse(typeof(SabnzbdPriorityForMigration), priority, true);
}
private int GetNzbgetPriority(string priority)
{
return (int)Enum.Parse(typeof(NzbGetPriorityForMigration), priority, true);
}
private class ClientSettingsForMigration
{
public String Host { get; set; }
public Int32 Port { get; set; }
public String ApiKey { get; set; }
public String Username { get; set; }
public String Password { get; set; }
public String TvCategory { get; set; }
public Int32 RecentTvPriority { get; set; }
public Int32 OlderTvPriority { get; set; }
public Boolean UseSsl { get; set; }
}
private class FolderSettingsForMigration
{
public String Folder { get; set; }
}
private enum SabnzbdPriorityForMigration
{
Default = -100,
Paused = -2,
Low = -1,
Normal = 0,
High = 1,
Force = 2
}
private enum NzbGetPriorityForMigration
{
VeryLow = -100,
Low = -50,
Normal = 0,
High = 50,
VeryHigh = 100
}
}
}

View File

@ -0,0 +1,27 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(44)]
public class fix_xbmc_episode_metadata : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
//Convert Episode Metadata to proper type
Execute.Sql("UPDATE MetadataFiles " +
"SET Type = 2 " +
"WHERE Consumer = 'XbmcMetadata' " +
"AND EpisodeFileId IS NOT NULL " +
"AND Type = 4 " +
"AND RelativePath LIKE '%.nfo'");
//Convert Episode Images to proper type
Execute.Sql("UPDATE MetadataFiles " +
"SET Type = 5 " +
"WHERE Consumer = 'XbmcMetadata' " +
"AND EpisodeFileId IS NOT NULL " +
"AND Type = 4");
}
}
}

View File

@ -7,6 +7,7 @@ using NzbDrone.Core.Blacklisting;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.DataAugmentation.Scene;
using NzbDrone.Core.Datastore.Converters;
using NzbDrone.Core.Download;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Instrumentation;
using NzbDrone.Core.Jobs;
@ -39,6 +40,7 @@ namespace NzbDrone.Core.Datastore
Mapper.Entity<ScheduledTask>().RegisterModel("ScheduledTasks");
Mapper.Entity<NotificationDefinition>().RegisterModel("Notifications");
Mapper.Entity<MetadataDefinition>().RegisterModel("Metadata");
Mapper.Entity<DownloadClientDefinition>().RegisterModel("DownloadClients");
Mapper.Entity<SceneMapping>().RegisterModel("SceneMappings");

View File

@ -23,7 +23,7 @@ namespace NzbDrone.Core.DecisionEngine
private readonly IParsingService _parsingService;
private readonly Logger _logger;
public DownloadDecisionMaker(IEnumerable<IRejectWithReason> specifications, IParsingService parsingService, Logger logger)
public DownloadDecisionMaker(IEnumerable<IDecisionEngineSpecification> specifications, IParsingService parsingService, Logger logger)
{
_specifications = specifications;
_parsingService = parsingService;
@ -63,6 +63,15 @@ namespace NzbDrone.Core.DecisionEngine
{
var parsedEpisodeInfo = Parser.Parser.ParseTitle(report.Title);
if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode())
{
var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(report.Title, report.TvRageId, searchCriteria);
if (specialEpisodeInfo != null)
{
parsedEpisodeInfo = specialEpisodeInfo;
}
}
if (parsedEpisodeInfo != null && !string.IsNullOrWhiteSpace(parsedEpisodeInfo.SeriesTitle))
{
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, report.TvRageId, searchCriteria);
@ -91,13 +100,12 @@ namespace NzbDrone.Core.DecisionEngine
yield return decision;
}
}
}
private DownloadDecision GetDecisionForReport(RemoteEpisode remoteEpisode, SearchCriteriaBase searchCriteria = null)
{
var reasons = _specifications.Select(c => EvaluateSpec(c, remoteEpisode, searchCriteria))
.Where(c => !string.IsNullOrWhiteSpace(c));
.Where(c => !string.IsNullOrWhiteSpace(c));
return new DownloadDecision(remoteEpisode, reasons.ToArray());
}

View File

@ -1,6 +1,5 @@
using NLog;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.DecisionEngine
{

View File

@ -27,7 +27,6 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public virtual bool IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{
_logger.Trace("Beginning size check for: {0}", subject);
var quality = subject.ParsedEpisodeInfo.Quality.Quality;
@ -45,34 +44,43 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
}
var qualityDefinition = _qualityDefinitionService.Get(quality);
var minSize = qualityDefinition.MinSize.Megabytes();
//Multiply maxSize by Series.Runtime
minSize = minSize * subject.Series.Runtime * subject.Episodes.Count;
//If the parsed size is smaller than minSize we don't want it
if (subject.Release.Size < minSize)
{
_logger.Trace("Item: {0}, Size: {1} is smaller than minimum allowed size ({2}), rejecting.", subject, subject.Release.Size, minSize);
return false;
}
if (qualityDefinition.MaxSize == 0)
{
_logger.Trace("Max size is 0 (unlimited) - skipping check.");
return true;
}
var maxSize = qualityDefinition.MaxSize.Megabytes();
//Multiply maxSize by Series.Runtime
maxSize = maxSize * subject.Series.Runtime * subject.Episodes.Count;
//Check if there was only one episode parsed and it is the first
if (subject.Episodes.Count == 1 && subject.Episodes.First().EpisodeNumber == 1)
else
{
maxSize = maxSize * 2;
}
var maxSize = qualityDefinition.MaxSize.Megabytes();
//If the parsed size is greater than maxSize we don't want it
if (subject.Release.Size > maxSize)
{
_logger.Trace("Item: {0}, Size: {1} is greater than maximum allowed size ({2}), rejecting.", subject, subject.Release.Size, maxSize);
return false;
}
//Multiply maxSize by Series.Runtime
maxSize = maxSize * subject.Series.Runtime * subject.Episodes.Count;
//Check if there was only one episode parsed and it is the first
if (subject.Episodes.Count == 1 && _episodeService.IsFirstOrLastEpisodeOfSeason(subject.Episodes.First().Id))
{
maxSize = maxSize * 2;
}
//If the parsed size is greater than maxSize we don't want it
if (subject.Release.Size > maxSize)
{
_logger.Trace("Item: {0}, Size: {1} is greater than maximum allowed size ({2}), rejecting.", subject, subject.Release.Size, maxSize);
return false;
}
}
_logger.Trace("Item: {0}, meets size constraints.", subject);
return true;
}
}
}

View File

@ -5,7 +5,6 @@ using NzbDrone.Core.Download;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.DecisionEngine.Specifications
{
@ -32,9 +31,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
{
var downloadClient = _downloadClientProvider.GetDownloadClient();
if (!downloadClient.IsConfigured)
if (downloadClient == null)
{
_logger.Warn("Download client {0} isn't configured yet.", downloadClient.GetType().Name);
_logger.Warn("Download client isn't configured yet.");
return true;
}

View File

@ -28,9 +28,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
public virtual bool IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
{
var age = subject.Release.Age;
var retention = _configService.Retention;
_logger.Trace("Checking if report meets retention requirements. {0}", age);
if (_configService.Retention > 0 && age > _configService.Retention)
if (retention > 0 && age > retention)
{
_logger.Trace("Report age: {0} rejected by user's retention limit", age);
return false;

View File

@ -41,7 +41,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
return true;
}
if (_downloadClientProvider.GetDownloadClient().GetType() == typeof (SabnzbdClient))
if (_downloadClientProvider.GetDownloadClient().GetType() == typeof (Sabnzbd))
{
_logger.Trace("Performing history status check on report");
foreach (var episode in subject.Episodes)

View File

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.IO;
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients.Blackhole
{
public class Blackhole : DownloadClientBase<FolderSettings>, IExecute<TestBlackholeCommand>
{
private readonly IDiskProvider _diskProvider;
private readonly IHttpProvider _httpProvider;
private readonly Logger _logger;
public Blackhole(IDiskProvider diskProvider, IHttpProvider httpProvider, Logger logger)
{
_diskProvider = diskProvider;
_httpProvider = httpProvider;
_logger = logger;
}
public override string DownloadNzb(RemoteEpisode remoteEpisode)
{
var url = remoteEpisode.Release.DownloadUrl;
var title = remoteEpisode.Release.Title;
title = FileNameBuilder.CleanFilename(title);
var filename = Path.Combine(Settings.Folder, title + ".nzb");
_logger.Trace("Downloading NZB from: {0} to: {1}", url, filename);
_httpProvider.DownloadFile(url, filename);
_logger.Trace("NZB Download succeeded, saved to: {0}", filename);
return null;
}
public override IEnumerable<QueueItem> GetQueue()
{
return new QueueItem[0];
}
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 10)
{
return new HistoryItem[0];
}
public override void RemoveFromQueue(string id)
{
}
public override void RemoveFromHistory(string id)
{
}
public void Execute(TestBlackholeCommand message)
{
var testPath = Path.Combine(message.Folder, "drone_test.txt");
_diskProvider.WriteAllText(testPath, DateTime.Now.ToString());
_diskProvider.DeleteFile(testPath);
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.Download.Clients.Blackhole
{
public class TestBlackholeCommand : Command
{
public override bool SendUpdatesToClient
{
get
{
return true;
}
}
public String Folder { get; set; }
}
}

View File

@ -1,68 +0,0 @@
using System.Collections.Generic;
using System.IO;
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients
{
public class BlackholeProvider : IDownloadClient
{
private readonly IConfigService _configService;
private readonly IHttpProvider _httpProvider;
private readonly Logger _logger;
public BlackholeProvider(IConfigService configService, IHttpProvider httpProvider, Logger logger)
{
_configService = configService;
_httpProvider = httpProvider;
_logger = logger;
}
public string DownloadNzb(RemoteEpisode remoteEpisode)
{
var url = remoteEpisode.Release.DownloadUrl;
var title = remoteEpisode.Release.Title;
title = FileNameBuilder.CleanFilename(title);
var filename = Path.Combine(_configService.BlackholeFolder, title + ".nzb");
_logger.Trace("Downloading NZB from: {0} to: {1}", url, filename);
_httpProvider.DownloadFile(url, filename);
_logger.Trace("NZB Download succeeded, saved to: {0}", filename);
return null;
}
public bool IsConfigured
{
get
{
return !string.IsNullOrWhiteSpace(_configService.BlackholeFolder);
}
}
public IEnumerable<QueueItem> GetQueue()
{
return new QueueItem[0];
}
public IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
{
return new HistoryItem[0];
}
public void RemoveFromQueue(string id)
{
}
public void RemoveFromHistory(string id)
{
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using FluentValidation;
using FluentValidation.Results;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation.Paths;
namespace NzbDrone.Core.Download.Clients
{
public class FolderSettingsValidator : AbstractValidator<FolderSettings>
{
public FolderSettingsValidator()
{
//Todo: Validate that the path actually exists
RuleFor(c => c.Folder).IsValidPath();
}
}
public class FolderSettings : IProviderConfig
{
private static readonly FolderSettingsValidator Validator = new FolderSettingsValidator();
[FieldDefinition(0, Label = "Folder", Type = FieldType.Path)]
public String Folder { get; set; }
public ValidationResult Validate()
{
return Validator.Validate(this);
}
}
}

View File

@ -4,11 +4,11 @@ using Newtonsoft.Json;
namespace NzbDrone.Core.Download.Clients.Nzbget
{
public class NzbGetQueue
public class NzbgetQueue
{
public String Version { get; set; }
[JsonProperty(PropertyName = "result")]
public List<NzbGetQueueItem> QueueItems { get; set; }
public List<NzbgetQueueItem> QueueItems { get; set; }
}
}

View File

@ -2,14 +2,11 @@
namespace NzbDrone.Core.Download.Clients.Nzbget
{
public class NzbGetQueueItem
public class NzbgetQueueItem
{
private string _nzbName;
public Int32 NzbId { get; set; }
public string NzbName { get; set; }
public String Category { get; set; }
public Int32 FileSizeMb { get; set; }
public Int32 RemainingSizeMb { get; set; }

View File

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using Omu.ValueInjecter;
namespace NzbDrone.Core.Download.Clients.Nzbget
{
public class Nzbget : DownloadClientBase<NzbgetSettings>, IExecute<TestNzbgetCommand>
{
private readonly INzbgetProxy _proxy;
private readonly IParsingService _parsingService;
private readonly Logger _logger;
public Nzbget(INzbgetProxy proxy,
IParsingService parsingService,
Logger logger)
{
_proxy = proxy;
_parsingService = parsingService;
_logger = logger;
}
public override string DownloadNzb(RemoteEpisode remoteEpisode)
{
var url = remoteEpisode.Release.DownloadUrl;
var title = remoteEpisode.Release.Title + ".nzb";
string cat = Settings.TvCategory;
int priority = remoteEpisode.IsRecentEpisode() ? Settings.RecentTvPriority : Settings.OlderTvPriority;
_logger.Info("Adding report [{0}] to the queue.", title);
var success = _proxy.AddNzb(Settings, title, cat, priority, false, url);
_logger.Debug("Queue Response: [{0}]", success);
return null;
}
public override IEnumerable<QueueItem> GetQueue()
{
var items = _proxy.GetQueue(Settings);
foreach (var nzbGetQueueItem in items)
{
var queueItem = new QueueItem();
queueItem.Id = nzbGetQueueItem.NzbId.ToString();
queueItem.Title = nzbGetQueueItem.NzbName;
queueItem.Size = nzbGetQueueItem.FileSizeMb;
queueItem.Sizeleft = nzbGetQueueItem.RemainingSizeMb;
queueItem.Status = nzbGetQueueItem.FileSizeMb == nzbGetQueueItem.PausedSizeMb ? "paused" : "queued";
var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title);
if (parsedEpisodeInfo == null) continue;
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0);
if (remoteEpisode.Series == null) continue;
queueItem.RemoteEpisode = remoteEpisode;
yield return queueItem;
}
}
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 10)
{
return new HistoryItem[0];
}
public override void RemoveFromQueue(string id)
{
throw new NotImplementedException();
}
public override void RemoveFromHistory(string id)
{
throw new NotImplementedException();
}
public VersionResponse GetVersion(string host = null, int port = 0, string username = null, string password = null)
{
return _proxy.GetVersion(Settings);
}
public void Execute(TestNzbgetCommand message)
{
var settings = new NzbgetSettings();
settings.InjectFrom(message);
_proxy.GetVersion(settings);
}
}
}

View File

@ -1,136 +0,0 @@
using System;
using System.Collections.Generic;
using NLog;
using NzbDrone.Common;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients.Nzbget
{
public class NzbgetClient : IDownloadClient
{
private readonly IConfigService _configService;
private readonly IHttpProvider _httpProvider;
private readonly INzbGetCommunicationProxy _proxy;
private readonly IParsingService _parsingService;
private readonly Logger _logger;
public NzbgetClient(IConfigService configService,
IHttpProvider httpProvider,
INzbGetCommunicationProxy proxy,
IParsingService parsingService,
Logger logger)
{
_configService = configService;
_httpProvider = httpProvider;
_proxy = proxy;
_parsingService = parsingService;
_logger = logger;
}
public string DownloadNzb(RemoteEpisode remoteEpisode)
{
var url = remoteEpisode.Release.DownloadUrl;
var title = remoteEpisode.Release.Title + ".nzb";
string cat = _configService.NzbgetTvCategory;
int priority = remoteEpisode.IsRecentEpisode() ? (int)_configService.NzbgetRecentTvPriority : (int)_configService.NzbgetOlderTvPriority;
_logger.Info("Adding report [{0}] to the queue.", title);
var success = _proxy.AddNzb(title, cat, priority, false, url);
_logger.Debug("Queue Response: [{0}]", success);
return null;
}
public bool IsConfigured
{
get
{
return !string.IsNullOrWhiteSpace(_configService.NzbgetHost) && _configService.NzbgetPort != 0;
}
}
public virtual IEnumerable<QueueItem> GetQueue()
{
var items = _proxy.GetQueue();
foreach (var nzbGetQueueItem in items)
{
var queueItem = new QueueItem();
queueItem.Id = nzbGetQueueItem.NzbId.ToString();
queueItem.Title = nzbGetQueueItem.NzbName;
queueItem.Size = nzbGetQueueItem.FileSizeMb;
queueItem.Sizeleft = nzbGetQueueItem.RemainingSizeMb;
queueItem.Status = nzbGetQueueItem.FileSizeMb == nzbGetQueueItem.PausedSizeMb ? "paused" : "queued";
var parsedEpisodeInfo = Parser.Parser.ParseTitle(queueItem.Title);
if (parsedEpisodeInfo == null) continue;
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0);
if (remoteEpisode.Series == null) continue;
queueItem.RemoteEpisode = remoteEpisode;
yield return queueItem;
}
}
public IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
{
return new HistoryItem[0];
}
public void RemoveFromQueue(string id)
{
throw new NotImplementedException();
}
public void RemoveFromHistory(string id)
{
throw new NotImplementedException();
}
public virtual VersionModel GetVersion(string host = null, int port = 0, string username = null, string password = null)
{
throw new NotImplementedException();
//Get saved values if any of these are defaults
if (host == null)
host = _configService.NzbgetHost;
if (port == 0)
port = _configService.NzbgetPort;
if (username == null)
username = _configService.NzbgetUsername;
if (password == null)
password = _configService.NzbgetPassword;
var response = _proxy.GetVersion();
return Json.Deserialize<VersionModel>(response);
}
public virtual string Test(string host, int port, string username, string password)
{
try
{
var version = GetVersion(host, port, username, password);
return version.Result;
}
catch (Exception ex)
{
_logger.DebugException("Failed to Test Nzbget", ex);
}
return String.Empty;
}
}
}

View File

@ -1,6 +1,6 @@
namespace NzbDrone.Core.Download.Clients.Nzbget
{
public enum PriorityType
public enum NzbgetPriority
{
VeryLow = -100,
Low = -50,

View File

@ -1,57 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NLog;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Rest;
using RestSharp;
namespace NzbDrone.Core.Download.Clients.Nzbget
{
public interface INzbGetCommunicationProxy
public interface INzbgetProxy
{
bool AddNzb(params object[] parameters);
List<NzbGetQueueItem> GetQueue();
string GetVersion();
bool AddNzb(NzbgetSettings settings, params object[] parameters);
List<NzbgetQueueItem> GetQueue(NzbgetSettings settings);
VersionResponse GetVersion(NzbgetSettings settings);
}
public class NzbGetCommunicationProxy : INzbGetCommunicationProxy
public class NzbgetProxy : INzbgetProxy
{
private readonly IConfigService _configService;
private readonly Logger _logger;
public NzbGetCommunicationProxy(IConfigService configService, Logger logger)
public NzbgetProxy(Logger logger)
{
_configService = configService;
_logger = logger;
}
public bool AddNzb(params object[] parameters)
public bool AddNzb(NzbgetSettings settings, params object[] parameters)
{
var request = BuildRequest(new JsonRequest("appendurl", parameters));
return Json.Deserialize<EnqueueResponse>(ProcessRequest(request)).Result;
return Json.Deserialize<EnqueueResponse>(ProcessRequest(request, settings)).Result;
}
public List<NzbGetQueueItem> GetQueue()
public List<NzbgetQueueItem> GetQueue(NzbgetSettings settings)
{
var request = BuildRequest(new JsonRequest("listgroups"));
var request = BuildRequest(new JsonRequest("listgroups"));
return Json.Deserialize<NzbGetQueue>(ProcessRequest(request)).QueueItems;
return Json.Deserialize<NzbgetQueue>(ProcessRequest(request, settings)).QueueItems;
}
public string GetVersion()
public VersionResponse GetVersion(NzbgetSettings settings)
{
var request = BuildRequest(new JsonRequest("version"));
return ProcessRequest(request);
return Json.Deserialize<VersionResponse>(ProcessRequest(request, settings));
}
private string ProcessRequest(IRestRequest restRequest)
private string ProcessRequest(IRestRequest restRequest, NzbgetSettings settings)
{
var client = BuildClient();
var client = BuildClient(settings);
var response = client.Execute(restRequest);
_logger.Trace("Response: {0}", response.Content);
@ -60,14 +55,14 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
return response.Content;
}
private IRestClient BuildClient()
private IRestClient BuildClient(NzbgetSettings settings)
{
var url = String.Format("http://{0}:{1}/jsonrpc",
_configService.NzbgetHost,
_configService.NzbgetPort);
settings.Host,
settings.Port);
var client = new RestClient(url);
client.Authenticator = new HttpBasicAuthenticator(_configService.NzbgetUsername, _configService.NzbgetPassword);
client.Authenticator = new HttpBasicAuthenticator(settings.Username, settings.Password);
return client;
}

View File

@ -0,0 +1,59 @@
using System;
using FluentValidation;
using FluentValidation.Results;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
namespace NzbDrone.Core.Download.Clients.Nzbget
{
public class NzbgetSettingsValidator : AbstractValidator<NzbgetSettings>
{
public NzbgetSettingsValidator()
{
RuleFor(c => c.Host).NotEmpty();
RuleFor(c => c.Port).GreaterThan(0);
RuleFor(c => c.Username).NotEmpty();
RuleFor(c => c.Password).NotEmpty();
}
}
public class NzbgetSettings : IProviderConfig
{
private static readonly NzbgetSettingsValidator Validator = new NzbgetSettingsValidator();
public NzbgetSettings()
{
Host = "localhost";
Port = 6789;
TvCategory = "tv";
RecentTvPriority = (int)NzbgetPriority.Normal;
OlderTvPriority = (int)NzbgetPriority.Normal;
}
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]
public String Host { get; set; }
[FieldDefinition(1, Label = "Port", Type = FieldType.Textbox)]
public Int32 Port { get; set; }
[FieldDefinition(2, Label = "Username", Type = FieldType.Textbox)]
public String Username { get; set; }
[FieldDefinition(3, Label = "Password", Type = FieldType.Password)]
public String Password { get; set; }
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox)]
public String TvCategory { get; set; }
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority))]
public Int32 RecentTvPriority { get; set; }
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority))]
public Int32 OlderTvPriority { get; set; }
public ValidationResult Validate()
{
return Validator.Validate(this);
}
}
}

View File

@ -0,0 +1,21 @@
using System;
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.Download.Clients.Nzbget
{
public class TestNzbgetCommand : Command
{
public override bool SendUpdatesToClient
{
get
{
return true;
}
}
public String Host { get; set; }
public Int32 Port { get; set; }
public String Username { get; set; }
public String Password { get; set; }
}
}

View File

@ -2,7 +2,7 @@
namespace NzbDrone.Core.Download.Clients.Nzbget
{
public class VersionModel
public class VersionResponse
{
public String Version { get; set; }
public String Result { get; set; }

View File

@ -6,12 +6,13 @@ using NzbDrone.Common;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Organizer;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.Download.Clients
namespace NzbDrone.Core.Download.Clients.Pneumatic
{
public class PneumaticClient : IDownloadClient
public class Pneumatic : DownloadClientBase<FolderSettings>, IExecute<TestPneumaticCommand>
{
private readonly IConfigService _configService;
private readonly IHttpProvider _httpProvider;
@ -19,7 +20,7 @@ namespace NzbDrone.Core.Download.Clients
private static readonly Logger logger = NzbDroneLogger.GetLogger();
public PneumaticClient(IConfigService configService, IHttpProvider httpProvider,
public Pneumatic(IConfigService configService, IHttpProvider httpProvider,
IDiskProvider diskProvider)
{
_configService = configService;
@ -27,20 +28,20 @@ namespace NzbDrone.Core.Download.Clients
_diskProvider = diskProvider;
}
public string DownloadNzb(RemoteEpisode remoteEpisode)
public override string DownloadNzb(RemoteEpisode remoteEpisode)
{
var url = remoteEpisode.Release.DownloadUrl;
var title = remoteEpisode.Release.Title;
if (remoteEpisode.ParsedEpisodeInfo.FullSeason)
{
throw new NotImplementedException("Full season Pneumatic releases are not supported.");
throw new NotImplementedException("Full season releases are not supported with Pneumatic.");
}
title = FileNameBuilder.CleanFilename(title);
//Save to the Pneumatic directory (The user will need to ensure its accessible by XBMC)
var filename = Path.Combine(_configService.PneumaticFolder, title + ".nzb");
var filename = Path.Combine(Settings.Folder, title + ".nzb");
logger.Trace("Downloading NZB from: {0} to: {1}", url, filename);
_httpProvider.DownloadFile(url, filename);
@ -57,31 +58,33 @@ namespace NzbDrone.Core.Download.Clients
{
get
{
return !string.IsNullOrWhiteSpace(_configService.PneumaticFolder);
return !string.IsNullOrWhiteSpace(Settings.Folder);
}
}
public IEnumerable<QueueItem> GetQueue()
public override IEnumerable<QueueItem> GetQueue()
{
return new QueueItem[0];
}
public IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 0)
public override IEnumerable<HistoryItem> GetHistory(int start = 0, int limit = 10)
{
return new HistoryItem[0];
}
public void RemoveFromQueue(string id)
public override void RemoveFromQueue(string id)
{
}
public void RemoveFromHistory(string id)
public override void RemoveFromHistory(string id)
{
}
public virtual bool IsInQueue(RemoteEpisode newEpisode)
public void Execute(TestPneumaticCommand message)
{
return false;
var testPath = Path.Combine(message.Folder, "drone_test.txt");
_diskProvider.WriteAllText(testPath, DateTime.Now.ToString());
_diskProvider.DeleteFile(testPath);
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.Download.Clients.Pneumatic
{
public class TestPneumaticCommand : Command
{
public override bool SendUpdatesToClient
{
get
{
return true;
}
}
public String Folder { get; set; }
}
}

View File

@ -1,8 +0,0 @@
namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
public class ConnectionInfoModel
{
public string Address { get; set; }
public int Port { get; set; }
}
}

View File

@ -7,7 +7,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var priorityType = (SabPriorityType)value;
var priorityType = (SabnzbdPriority)value;
writer.WriteValue(priorityType.ToString());
}
@ -15,7 +15,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters
{
var queuePriority = reader.Value.ToString();
SabPriorityType output;
SabnzbdPriority output;
Enum.TryParse(queuePriority, out output);
return output;
@ -23,7 +23,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SabPriorityType);
return objectType == typeof(SabnzbdPriority);
}
}
}

View File

@ -0,0 +1,18 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace NzbDrone.Core.Download.Clients.Sabnzbd.Responses
{
public class SabnzbdAddResponse
{
public SabnzbdAddResponse()
{
Ids = new List<string>();
}
public bool Status { get; set; }
[JsonProperty(PropertyName = "nzo_ids")]
public List<string> Ids { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace NzbDrone.Core.Download.Clients.Sabnzbd.Responses
{
public class SabnzbdCategoryResponse
{
public SabnzbdCategoryResponse()
{
Categories = new List<String>();
}
public List<String> Categories { get; set; }
}
}

View File

@ -0,0 +1,7 @@
namespace NzbDrone.Core.Download.Clients.Sabnzbd.Responses
{
public class SabnzbdVersionResponse
{
public string Version { get; set; }
}
}

View File

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
public class SabAddResponse
{
public SabAddResponse()
{
Ids = new List<String>();
}
public bool Status { get; set; }
[JsonProperty(PropertyName = "nzo_ids")]
public List<String> Ids { get; set; }
}
}

View File

@ -1,100 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Text.RegularExpressions;
using NLog;
using NzbDrone.Common.Instrumentation;
namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
public class SabAutoConfigureService
{
private static readonly Logger Logger = NzbDroneLogger.GetLogger();
public SabModel AutoConfigureSab()
{
var info = GetConnectionList();
return FindApiKey(info);
}
private List<ConnectionInfoModel> GetConnectionList()
{
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
var info =
ipProperties.GetActiveTcpListeners().Select(
p =>
new ConnectionInfoModel { Address = p.Address.ToString().Replace("0.0.0.0", "127.0.0.1"), Port = p.Port }).Distinct().
ToList();
info.RemoveAll(i => i.Port == 135);
info.RemoveAll(i => i.Port == 139);
info.RemoveAll(i => i.Port == 445);
info.RemoveAll(i => i.Port == 3389);
info.RemoveAll(i => i.Port == 5900);
info.RemoveAll(i => i.Address.Contains("::"));
info.Reverse();
return info;
}
private SabModel FindApiKey(List<ConnectionInfoModel> info)
{
foreach (var connection in info)
{
var apiKey = GetApiKey(connection.Address, connection.Port);
if (!String.IsNullOrEmpty(apiKey))
return new SabModel
{
Host = connection.Address,
Port = connection.Port,
ApiKey = apiKey
};
}
return null;
}
private string GetApiKey(string ipAddress, int port)
{
var request = String.Format("http://{0}:{1}/config/general/", ipAddress, port);
var result = DownloadString(request);
Regex regex =
new Regex("\\<input\\Wtype\\=\\\"text\\\"\\Wid\\=\\\"apikey\\\"\\Wvalue\\=\\\"(?<apikey>\\w+)\\W",
RegexOptions.IgnoreCase
| RegexOptions.Compiled);
var match = regex.Match(result);
if (match.Success)
{
return match.Groups["apikey"].Value;
}
return String.Empty;
}
private string DownloadString(string url)
{
try
{
var request = WebRequest.Create(url);
request.Timeout = 2000;
var response = request.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
return reader.ReadToEnd();
}
catch (Exception ex)
{
Logger.Trace("Failed to get response from: {0}", url);
Logger.Trace(ex.Message, ex);
}
return String.Empty;
}
}
}

View File

@ -1,9 +0,0 @@
using System.Collections.Generic;
namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
public class SabCategoryModel
{
public List<string> categories { get; set; }
}
}

View File

@ -1,130 +0,0 @@
using System;
using System.IO;
using NLog;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Configuration;
using RestSharp;
namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
public interface ISabCommunicationProxy
{
SabAddResponse DownloadNzb(Stream nzb, string name, string category, int priority);
void RemoveFrom(string source, string id);
string ProcessRequest(IRestRequest restRequest, string action);
}
public class SabCommunicationProxy : ISabCommunicationProxy
{
private readonly IConfigService _configService;
private readonly Logger _logger;
public SabCommunicationProxy(IConfigService configService, Logger logger)
{
_configService = configService;
_logger = logger;
}
public SabAddResponse DownloadNzb(Stream nzb, string title, string category, int priority)
{
var request = new RestRequest(Method.POST);
var action = String.Format("mode=addfile&cat={0}&priority={1}", category, priority);
request.AddFile("name", ReadFully(nzb), title, "application/x-nzb");
SabAddResponse response;
if (!Json.TryDeserialize<SabAddResponse>(ProcessRequest(request, action), out response))
{
response = new SabAddResponse();
response.Status = true;
}
return response;
}
public void RemoveFrom(string source, string id)
{
var request = new RestRequest();
var action = String.Format("mode={0}&name=delete&del_files=1&value={1}", source, id);
ProcessRequest(request, action);
}
public string ProcessRequest(IRestRequest restRequest, string action)
{
var client = BuildClient(action);
var response = client.Execute(restRequest);
_logger.Trace("Response: {0}", response.Content);
CheckForError(response);
return response.Content;
}
private IRestClient BuildClient(string action)
{
var protocol = _configService.SabUseSsl ? "https" : "http";
var url = string.Format(@"{0}://{1}:{2}/api?{3}&apikey={4}&ma_username={5}&ma_password={6}&output=json",
protocol,
_configService.SabHost,
_configService.SabPort,
action,
_configService.SabApiKey,
_configService.SabUsername,
_configService.SabPassword);
_logger.Trace(url);
return new RestClient(url);
}
private void CheckForError(IRestResponse response)
{
if (response.ResponseStatus != ResponseStatus.Completed)
{
throw new ApplicationException("Unable to connect to SABnzbd, please check your settings");
}
SabJsonError result;
if (!Json.TryDeserialize<SabJsonError>(response.Content, out result))
{
//Handle plain text responses from SAB
result = new SabJsonError();
if (response.Content.StartsWith("error", StringComparison.InvariantCultureIgnoreCase))
{
result.Status = "false";
result.Error = response.Content.Replace("error: ", "");
}
else
{
result.Status = "true";
}
result.Error = response.Content.Replace("error: ", "");
}
if (result.Failed)
throw new ApplicationException(result.Error);
}
//TODO: Find a better home for this
private byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
}
}

View File

@ -1,9 +0,0 @@
namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
public class SabModel
{
public string Host { get; set; }
public int Port { get; set; }
public string ApiKey { get; set; }
}
}

View File

@ -1,7 +0,0 @@
namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
public class SabVersionModel
{
public string Version { get; set; }
}
}

Some files were not shown because too many files have changed in this diff Show More