Merge branch 'develop'
This commit is contained in:
commit
87497e3b53
|
@ -84,7 +84,6 @@ Generated_Code #added for RIA/Silverlight projects
|
|||
# Backup & report files from converting an old project file to a newer
|
||||
# Visual Studio version. Backup files are not needed, because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
|
||||
# SQL Server files
|
||||
|
|
|
@ -37,6 +37,7 @@ module.exports = function (grunt) {
|
|||
'Content/theme.less',
|
||||
'Content/overrides.less',
|
||||
'Series/series.less',
|
||||
'History/history.less',
|
||||
'AddSeries/addSeries.less',
|
||||
'Calendar/calendar.less',
|
||||
'Cells/cells.less',
|
||||
|
|
|
@ -2,6 +2,4 @@
|
|||
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("1.1.0")]
|
||||
[assembly: AssemblyFileVersion("1.1.0.0")]
|
||||
[assembly: AssemblyInformationalVersion("1.1.3")]
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
|
|
|
@ -22,18 +22,8 @@ using System.Runtime.InteropServices;
|
|||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("a463887e-594f-4733-b227-a79f4ffb2158")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
[assembly: AssemblyFileVersion("10.0.0.*")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Exceptron.Client.Tests")]
|
||||
[assembly: InternalsVisibleTo("Exceptron.Api.v1.Tests")]
|
||||
[assembly: InternalsVisibleTo("Exceptron.Rush")]
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace NzbDrone.Api.Test.MappingTests
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void should_map_lay_loaded_values_should_not_be_inject_if_not_loaded()
|
||||
public void should_map_lazy_loaded_values_should_not_be_inject_if_not_loaded()
|
||||
{
|
||||
var modelWithLazy = new ModelWithLazy()
|
||||
{
|
||||
|
|
|
@ -21,15 +21,4 @@ using System.Runtime.InteropServices;
|
|||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("260b2ff9-d3b7-4d8a-b720-a12c93d045e5")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
[assembly: AssemblyFileVersion("10.0.0.*")]
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace NzbDrone.Api.Blacklist
|
|||
{
|
||||
_blacklistService = blacklistService;
|
||||
GetResourcePaged = GetBlacklist;
|
||||
DeleteResource = Delete;
|
||||
DeleteResource = DeleteBlacklist;
|
||||
}
|
||||
|
||||
private PagingResource<BlacklistResource> GetBlacklist(PagingResource<BlacklistResource> pagingResource)
|
||||
|
@ -25,16 +25,10 @@ namespace NzbDrone.Api.Blacklist
|
|||
SortDirection = pagingResource.SortDirection
|
||||
};
|
||||
|
||||
//This is a hack to deal with backgrid setting the sortKey to the column name instead of sortValue
|
||||
if (pagingSpec.SortKey.Equals("series", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
pagingSpec.SortKey = "series.title";
|
||||
}
|
||||
|
||||
return ApplyToPage(_blacklistService.Paged, pagingSpec);
|
||||
}
|
||||
|
||||
private void Delete(int id)
|
||||
private void DeleteBlacklist(int id)
|
||||
{
|
||||
_blacklistService.Delete(id);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Api.ClientSchema
|
||||
{
|
||||
public class Field
|
||||
{
|
||||
public int Order { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Label { get; set; }
|
||||
public string HelpText { get; set; }
|
||||
public string HelpLink { get; set; }
|
||||
public object Value { get; set; }
|
||||
public string Type { get; set; }
|
||||
public Int32 Order { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String Label { get; set; }
|
||||
public String HelpText { get; set; }
|
||||
public String HelpLink { get; set; }
|
||||
public Object Value { get; set; }
|
||||
public String Type { get; set; }
|
||||
public Boolean Advanced { get; set; }
|
||||
public List<SelectOption> SelectOptions { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Common.Reflection;
|
||||
|
@ -26,13 +28,14 @@ namespace NzbDrone.Api.ClientSchema
|
|||
if (fieldAttribute != null)
|
||||
{
|
||||
|
||||
var field = new Field()
|
||||
var field = new Field
|
||||
{
|
||||
Name = propertyInfo.Name,
|
||||
Label = fieldAttribute.Label,
|
||||
HelpText = fieldAttribute.HelpText,
|
||||
HelpLink = fieldAttribute.HelpLink,
|
||||
Order = fieldAttribute.Order,
|
||||
Advanced = fieldAttribute.Advanced,
|
||||
Type = fieldAttribute.Type.ToString().ToLowerInvariant()
|
||||
};
|
||||
|
||||
|
@ -101,6 +104,23 @@ namespace NzbDrone.Api.ClientSchema
|
|||
propertyInfo.SetValue(target, value, null);
|
||||
}
|
||||
|
||||
else if (propertyInfo.PropertyType == typeof (IEnumerable<Int32>))
|
||||
{
|
||||
IEnumerable<Int32> value;
|
||||
|
||||
if (field.Value.GetType() == typeof (JArray))
|
||||
{
|
||||
value = ((JArray) field.Value).Select(s => s.Value<Int32>());
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
value = field.Value.ToString().Split(new []{','}, StringSplitOptions.RemoveEmptyEntries).Select(s => Convert.ToInt32(s));
|
||||
}
|
||||
|
||||
propertyInfo.SetValue(target, value, null);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
propertyInfo.SetValue(target, field.Value, null);
|
||||
|
|
|
@ -39,6 +39,7 @@ namespace NzbDrone.Api.Config
|
|||
SharedValidator.RuleFor(c => c.MultiEpisodeStyle).InclusiveBetween(0, 3);
|
||||
SharedValidator.RuleFor(c => c.StandardEpisodeFormat).ValidEpisodeFormat();
|
||||
SharedValidator.RuleFor(c => c.DailyEpisodeFormat).ValidDailyEpisodeFormat();
|
||||
SharedValidator.RuleFor(c => c.AnimeEpisodeFormat).ValidAnimeEpisodeFormat();
|
||||
SharedValidator.RuleFor(c => c.SeriesFolderFormat).ValidSeriesFolderFormat();
|
||||
SharedValidator.RuleFor(c => c.SeasonFolderFormat).ValidSeasonFolderFormat();
|
||||
}
|
||||
|
@ -80,6 +81,7 @@ namespace NzbDrone.Api.Config
|
|||
var singleEpisodeSampleResult = _filenameSampleService.GetStandardSample(nameSpec);
|
||||
var multiEpisodeSampleResult = _filenameSampleService.GetMultiEpisodeSample(nameSpec);
|
||||
var dailyEpisodeSampleResult = _filenameSampleService.GetDailySample(nameSpec);
|
||||
var animeEpisodeSampleResult = _filenameSampleService.GetAnimeSample(nameSpec);
|
||||
|
||||
sampleResource.SingleEpisodeExample = _filenameValidationService.ValidateStandardFilename(singleEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
|
@ -93,6 +95,10 @@ namespace NzbDrone.Api.Config
|
|||
? "Invalid format"
|
||||
: dailyEpisodeSampleResult.Filename;
|
||||
|
||||
sampleResource.AnimeEpisodeExample = _filenameValidationService.ValidateAnimeFilename(animeEpisodeSampleResult) != null
|
||||
? "Invalid format"
|
||||
: animeEpisodeSampleResult.Filename;
|
||||
|
||||
sampleResource.SeriesFolderExample = nameSpec.SeriesFolderFormat.IsNullOrWhiteSpace()
|
||||
? "Invalid format"
|
||||
: _filenameSampleService.GetSeriesFolderSample(nameSpec);
|
||||
|
|
|
@ -9,6 +9,7 @@ namespace NzbDrone.Api.Config
|
|||
public Int32 MultiEpisodeStyle { get; set; }
|
||||
public string StandardEpisodeFormat { get; set; }
|
||||
public string DailyEpisodeFormat { get; set; }
|
||||
public string AnimeEpisodeFormat { get; set; }
|
||||
public string SeriesFolderFormat { get; set; }
|
||||
public string SeasonFolderFormat { get; set; }
|
||||
public bool IncludeSeriesTitle { get; set; }
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
public string SingleEpisodeExample { get; set; }
|
||||
public string MultiEpisodeExample { get; set; }
|
||||
public string DailyEpisodeExample { get; set; }
|
||||
public string AnimeEpisodeExample { get; set; }
|
||||
public string SeriesFolderExample { get; set; }
|
||||
public string SeasonFolderExample { get; set; }
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ namespace NzbDrone.Api.Episodes
|
|||
|
||||
GetResourceAll = GetEpisodes;
|
||||
UpdateResource = SetMonitored;
|
||||
GetResourceById = GetEpisode;
|
||||
}
|
||||
|
||||
private List<EpisodeResource> GetEpisodes()
|
||||
|
|
|
@ -26,11 +26,15 @@ namespace NzbDrone.Api.Episodes
|
|||
: base(commandExecutor, resource)
|
||||
{
|
||||
_episodeService = episodeService;
|
||||
|
||||
GetResourceById = GetEpisode;
|
||||
}
|
||||
|
||||
protected EpisodeResource GetEpisode(int id)
|
||||
{
|
||||
return _episodeService.GetEpisode(id).InjectTo<EpisodeResource>();
|
||||
var episode = _episodeService.GetEpisode(id);
|
||||
episode.EpisodeFile.LazyLoad();
|
||||
return episode.InjectTo<EpisodeResource>();
|
||||
}
|
||||
|
||||
public void Handle(EpisodeGrabbedEvent message)
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace NzbDrone.Api.Episodes
|
|||
|
||||
public Boolean HasFile { get; set; }
|
||||
public Boolean Monitored { get; set; }
|
||||
public Nullable<Int32> SceneAbsoluteEpisodeNumber { get; set; }
|
||||
public Int32 SceneEpisodeNumber { get; set; }
|
||||
public Int32 SceneSeasonNumber { get; set; }
|
||||
public Int32 TvDbEpisodeId { get; set; }
|
||||
|
|
|
@ -1,11 +1,18 @@
|
|||
using Nancy;
|
||||
using Nancy.Bootstrapper;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Api.Frontend;
|
||||
|
||||
namespace NzbDrone.Api.Extensions.Pipelines
|
||||
{
|
||||
public class NzbDroneVersionPipeline : IRegisterNancyPipeline
|
||||
public class CacheHeaderPipeline : IRegisterNancyPipeline
|
||||
{
|
||||
private readonly ICacheableSpecification _cacheableSpecification;
|
||||
|
||||
public CacheHeaderPipeline(ICacheableSpecification cacheableSpecification)
|
||||
{
|
||||
_cacheableSpecification = cacheableSpecification;
|
||||
}
|
||||
|
||||
public void Register(IPipelines pipelines)
|
||||
{
|
||||
pipelines.AfterRequest.AddItemToStartOfPipeline(Handle);
|
||||
|
@ -13,9 +20,13 @@ namespace NzbDrone.Api.Extensions.Pipelines
|
|||
|
||||
private void Handle(NancyContext context)
|
||||
{
|
||||
if (!context.Response.Headers.ContainsKey("X-ApplicationVersion"))
|
||||
if (_cacheableSpecification.IsCacheable(context))
|
||||
{
|
||||
context.Response.Headers.Add("X-ApplicationVersion", BuildInfo.Version.ToString());
|
||||
context.Response.Headers.EnableCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.Headers.DisableCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,11 @@
|
|||
using Nancy;
|
||||
using Nancy.Bootstrapper;
|
||||
using NzbDrone.Api.Frontend;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
|
||||
namespace NzbDrone.Api.Extensions.Pipelines
|
||||
{
|
||||
public class CacheHeaderPipeline : IRegisterNancyPipeline
|
||||
public class NzbDroneVersionPipeline : IRegisterNancyPipeline
|
||||
{
|
||||
private readonly ICacheableSpecification _cacheableSpecification;
|
||||
|
||||
public CacheHeaderPipeline(ICacheableSpecification cacheableSpecification)
|
||||
{
|
||||
_cacheableSpecification = cacheableSpecification;
|
||||
}
|
||||
|
||||
public void Register(IPipelines pipelines)
|
||||
{
|
||||
pipelines.AfterRequest.AddItemToStartOfPipeline(Handle);
|
||||
|
@ -20,13 +13,9 @@ namespace NzbDrone.Api.Extensions.Pipelines
|
|||
|
||||
private void Handle(NancyContext context)
|
||||
{
|
||||
if (_cacheableSpecification.IsCacheable(context))
|
||||
if (!context.Response.Headers.ContainsKey("X-ApplicationVersion"))
|
||||
{
|
||||
context.Response.Headers.EnableCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.Headers.DisableCache();
|
||||
context.Response.Headers.Add("X-ApplicationVersion", BuildInfo.Version.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using Nancy;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
|
||||
namespace NzbDrone.Api.Frontend
|
||||
|
@ -20,7 +21,13 @@ namespace NzbDrone.Api.Frontend
|
|||
|
||||
if (context.Request.Query.v == BuildInfo.Version) return true;
|
||||
|
||||
if (context.Request.Path.StartsWith("/api", StringComparison.CurrentCultureIgnoreCase)) return false;
|
||||
if (context.Request.Path.StartsWith("/api", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
if (context.Request.Path.ContainsIgnoreCase("/MediaCover")) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context.Request.Path.StartsWith("/signalr", StringComparison.CurrentCultureIgnoreCase)) return false;
|
||||
if (context.Request.Path.EndsWith("main.js")) return false;
|
||||
if (context.Request.Path.StartsWith("/feed", StringComparison.CurrentCultureIgnoreCase)) return false;
|
|
@ -0,0 +1,31 @@
|
|||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
|
||||
namespace NzbDrone.Api.Frontend.Mappers
|
||||
{
|
||||
public class BackupFileMapper : StaticResourceMapperBase
|
||||
{
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
|
||||
public BackupFileMapper(IAppFolderInfo appFolderInfo, IDiskProvider diskProvider, Logger logger)
|
||||
: base(diskProvider, logger)
|
||||
{
|
||||
_appFolderInfo = appFolderInfo;
|
||||
}
|
||||
|
||||
protected override string Map(string resourceUrl)
|
||||
{
|
||||
var path = resourceUrl.Replace("/backup/", "").Replace('/', Path.DirectorySeparatorChar);
|
||||
|
||||
return Path.Combine(_appFolderInfo.GetBackupFolder(), path);
|
||||
}
|
||||
|
||||
public override bool CanHandle(string resourceUrl)
|
||||
{
|
||||
return resourceUrl.StartsWith("/backup/") && resourceUrl.ContainsIgnoreCase("nzbdrone_backup_") && resourceUrl.EndsWith(".zip");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,12 +10,12 @@ namespace NzbDrone.Api.History
|
|||
public class HistoryModule : NzbDroneRestModule<HistoryResource>
|
||||
{
|
||||
private readonly IHistoryService _historyService;
|
||||
private readonly IFailedDownloadService _failedDownloadService;
|
||||
private readonly IDownloadTrackingService _downloadTrackingService;
|
||||
|
||||
public HistoryModule(IHistoryService historyService, IFailedDownloadService failedDownloadService)
|
||||
public HistoryModule(IHistoryService historyService, IDownloadTrackingService downloadTrackingService)
|
||||
{
|
||||
_historyService = historyService;
|
||||
_failedDownloadService = failedDownloadService;
|
||||
_downloadTrackingService = downloadTrackingService;
|
||||
GetResourcePaged = GetHistory;
|
||||
|
||||
Post["/failed"] = x => MarkAsFailed();
|
||||
|
@ -33,12 +33,6 @@ namespace NzbDrone.Api.History
|
|||
SortDirection = pagingResource.SortDirection
|
||||
};
|
||||
|
||||
//This is a hack to deal with backgrid setting the sortKey to the column name instead of sortValue
|
||||
if (pagingSpec.SortKey.Equals("series", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
pagingSpec.SortKey = "series.title";
|
||||
}
|
||||
|
||||
if (pagingResource.FilterKey == "eventType")
|
||||
{
|
||||
var filterValue = (HistoryEventType)Convert.ToInt32(pagingResource.FilterValue);
|
||||
|
@ -57,7 +51,7 @@ namespace NzbDrone.Api.History
|
|||
private Response MarkAsFailed()
|
||||
{
|
||||
var id = (int)Request.Form.Id;
|
||||
_failedDownloadService.MarkAsFailed(id);
|
||||
_downloadTrackingService.MarkAsFailed(id);
|
||||
return new Object().AsResponse();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FluentValidation;
|
||||
using Nancy;
|
||||
using NLog;
|
||||
using NzbDrone.Api.Mapping;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
|
@ -13,6 +15,7 @@ using Omu.ValueInjecter;
|
|||
using System.Linq;
|
||||
using Nancy.ModelBinding;
|
||||
using NzbDrone.Api.Extensions;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Api.Indexers
|
||||
{
|
||||
|
@ -21,20 +24,26 @@ namespace NzbDrone.Api.Indexers
|
|||
private readonly IFetchAndParseRss _rssFetcherAndParser;
|
||||
private readonly ISearchForNzb _nzbSearchService;
|
||||
private readonly IMakeDownloadDecision _downloadDecisionMaker;
|
||||
private readonly IPrioritizeDownloadDecision _prioritizeDownloadDecision;
|
||||
private readonly IDownloadService _downloadService;
|
||||
private readonly IParsingService _parsingService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ReleaseModule(IFetchAndParseRss rssFetcherAndParser,
|
||||
ISearchForNzb nzbSearchService,
|
||||
IMakeDownloadDecision downloadDecisionMaker,
|
||||
IPrioritizeDownloadDecision prioritizeDownloadDecision,
|
||||
IDownloadService downloadService,
|
||||
IParsingService parsingService)
|
||||
IParsingService parsingService,
|
||||
Logger logger)
|
||||
{
|
||||
_rssFetcherAndParser = rssFetcherAndParser;
|
||||
_nzbSearchService = nzbSearchService;
|
||||
_downloadDecisionMaker = downloadDecisionMaker;
|
||||
_prioritizeDownloadDecision = prioritizeDownloadDecision;
|
||||
_downloadService = downloadService;
|
||||
_parsingService = parsingService;
|
||||
_logger = logger;
|
||||
GetResourceAll = GetReleases;
|
||||
Post["/"] = x=> DownloadRelease(this.Bind<ReleaseResource>());
|
||||
|
||||
|
@ -43,7 +52,7 @@ namespace NzbDrone.Api.Indexers
|
|||
|
||||
private Response DownloadRelease(ReleaseResource release)
|
||||
{
|
||||
var remoteEpisode = _parsingService.Map(release.InjectTo<ParsedEpisodeInfo>(), 0);
|
||||
var remoteEpisode = _parsingService.Map(release.InjectTo<ParsedEpisodeInfo>(), release.TvRageId);
|
||||
remoteEpisode.Release = release.InjectTo<ReleaseInfo>();
|
||||
_downloadService.DownloadReport(remoteEpisode);
|
||||
|
||||
|
@ -62,17 +71,28 @@ namespace NzbDrone.Api.Indexers
|
|||
|
||||
private List<ReleaseResource> GetEpisodeReleases(int episodeId)
|
||||
{
|
||||
var decisions = _nzbSearchService.EpisodeSearch(episodeId);
|
||||
try
|
||||
{
|
||||
var decisions = _nzbSearchService.EpisodeSearch(episodeId);
|
||||
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
|
||||
|
||||
return MapDecisions(decisions);
|
||||
return MapDecisions(prioritizedDecisions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Episode search failed: " + ex.Message, ex);
|
||||
}
|
||||
|
||||
return new List<ReleaseResource>();
|
||||
}
|
||||
|
||||
private List<ReleaseResource> GetRss()
|
||||
{
|
||||
var reports = _rssFetcherAndParser.Fetch();
|
||||
var decisions = _downloadDecisionMaker.GetRssDecision(reports);
|
||||
var prioritizedDecisions = _prioritizeDownloadDecision.PrioritizeDecisions(decisions);
|
||||
|
||||
return MapDecisions(decisions);
|
||||
return MapDecisions(prioritizedDecisions);
|
||||
}
|
||||
|
||||
private static List<ReleaseResource> MapDecisions(IEnumerable<DownloadDecision> decisions)
|
||||
|
@ -89,6 +109,18 @@ namespace NzbDrone.Api.Indexers
|
|||
release.Rejections = downloadDecision.Rejections.ToList();
|
||||
release.DownloadAllowed = downloadDecision.RemoteEpisode.DownloadAllowed;
|
||||
|
||||
release.ReleaseWeight = result.Count;
|
||||
|
||||
if (downloadDecision.RemoteEpisode.Series != null)
|
||||
{
|
||||
release.QualityWeight = downloadDecision.RemoteEpisode.Series.QualityProfile.Value.Items.FindIndex(v => v.Quality == release.Quality.Quality) * 2;
|
||||
}
|
||||
|
||||
if (!release.Quality.Proper)
|
||||
{
|
||||
release.QualityWeight++;
|
||||
}
|
||||
|
||||
result.Add(release);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,11 +10,14 @@ namespace NzbDrone.Api.Indexers
|
|||
public class ReleaseResource : RestResource
|
||||
{
|
||||
public QualityModel Quality { get; set; }
|
||||
public Int32 QualityWeight { get; set; }
|
||||
public Int32 Age { get; set; }
|
||||
public Double AgeHours { get; set; }
|
||||
public Int64 Size { get; set; }
|
||||
public String Indexer { get; set; }
|
||||
public String ReleaseGroup { get; set; }
|
||||
public String SubGroup { get; set; }
|
||||
public String ReleaseHash { get; set; }
|
||||
public String Title { get; set; }
|
||||
public Boolean FullSeason { get; set; }
|
||||
public Boolean SceneSource { get; set; }
|
||||
|
@ -23,14 +26,21 @@ namespace NzbDrone.Api.Indexers
|
|||
public String AirDate { get; set; }
|
||||
public String SeriesTitle { get; set; }
|
||||
public int[] EpisodeNumbers { get; set; }
|
||||
public int[] AbsoluteEpisodeNumbers { get; set; }
|
||||
public Boolean Approved { get; set; }
|
||||
public Int32 TvRageId { get; set; }
|
||||
public List<string> Rejections { get; set; }
|
||||
public IEnumerable<String> Rejections { get; set; }
|
||||
public DateTime PublishDate { get; set; }
|
||||
public String CommentUrl { get; set; }
|
||||
public String DownloadUrl { get; set; }
|
||||
public String InfoUrl { get; set; }
|
||||
public Boolean DownloadAllowed { get; set; }
|
||||
public DownloadProtocol DownloadProtocol { get; set; }
|
||||
public Int32 ReleaseWeight { get; set; }
|
||||
|
||||
public Boolean IsDaily { get; set; }
|
||||
public Boolean IsAbsoluteNumbering { get; set; }
|
||||
public Boolean IsPossibleSpecialEpisode { get; set; }
|
||||
public Boolean Special { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,8 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using Nancy;
|
||||
using Nancy.Responses;
|
||||
using NzbDrone.Common;
|
||||
|
|
|
@ -122,15 +122,16 @@
|
|||
<Compile Include="Episodes\EpisodeResource.cs" />
|
||||
<Compile Include="Episodes\RenameEpisodeModule.cs" />
|
||||
<Compile Include="Episodes\RenameEpisodeResource.cs" />
|
||||
<Compile Include="Extensions\Pipelines\CacheHeaderPipeline.cs" />
|
||||
<Compile Include="Extensions\Pipelines\NzbDroneVersionPipeline.cs" />
|
||||
<Compile Include="Extensions\Pipelines\CacheHeaderPipeline.cs" />
|
||||
<Compile Include="Extensions\Pipelines\GZipPipeline.cs" />
|
||||
<Compile Include="Extensions\Pipelines\IfModifiedPipeline.cs" />
|
||||
<Compile Include="Extensions\Pipelines\IRegisterNancyPipeline.cs" />
|
||||
<Compile Include="Extensions\NancyJsonSerializer.cs" />
|
||||
<Compile Include="Extensions\RequestExtensions.cs" />
|
||||
<Compile Include="Frontend\IsCacheableSpecification.cs" />
|
||||
<Compile Include="Frontend\CacheableSpecification.cs" />
|
||||
<Compile Include="Frontend\Mappers\UpdateLogFileMapper.cs" />
|
||||
<Compile Include="Frontend\Mappers\BackupFileMapper.cs" />
|
||||
<Compile Include="Frontend\Mappers\FaviconMapper.cs" />
|
||||
<Compile Include="Frontend\Mappers\IndexHtmlMapper.cs" />
|
||||
<Compile Include="Frontend\Mappers\LogFileMapper.cs" />
|
||||
|
@ -164,6 +165,10 @@
|
|||
<Compile Include="Mapping\MappingValidation.cs" />
|
||||
<Compile Include="Mapping\ResourceMappingException.cs" />
|
||||
<Compile Include="Mapping\ValueInjectorExtensions.cs" />
|
||||
<Compile Include="Series\AlternateTitleResource.cs" />
|
||||
<Compile Include="Series\SeasonResource.cs" />
|
||||
<Compile Include="System\Backup\BackupModule.cs" />
|
||||
<Compile Include="System\Backup\BackupResource.cs" />
|
||||
<Compile Include="Update\UpdateResource.cs" />
|
||||
<Compile Include="Wanted\CutoffModule.cs" />
|
||||
<Compile Include="Wanted\LegacyMissingModule.cs" />
|
||||
|
|
|
@ -7,6 +7,5 @@ using System.Runtime.InteropServices;
|
|||
[assembly: Guid("4c0922d7-979e-4ff7-b44b-b8ac2100eeb5")]
|
||||
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
[assembly: AssemblyFileVersion("10.0.0.*")]
|
||||
|
||||
[assembly: InternalsVisibleTo("NzbDrone.Core")]
|
||||
|
|
|
@ -23,7 +23,10 @@ namespace NzbDrone.Api
|
|||
: base(resource)
|
||||
{
|
||||
_providerFactory = providerFactory;
|
||||
|
||||
Get["schema"] = x => GetTemplates();
|
||||
Post["test"] = x => Test(ReadResourceFromRequest());
|
||||
|
||||
GetResourceAll = GetAll;
|
||||
GetResourceById = GetProviderById;
|
||||
CreateResource = CreateProvider;
|
||||
|
@ -63,16 +66,26 @@ namespace NzbDrone.Api
|
|||
|
||||
private int CreateProvider(TProviderResource providerResource)
|
||||
{
|
||||
var provider = GetDefinition(providerResource);
|
||||
provider = _providerFactory.Create(provider);
|
||||
return provider.Id;
|
||||
var providerDefinition = GetDefinition(providerResource);
|
||||
|
||||
if (providerDefinition.Enable)
|
||||
{
|
||||
Test(providerDefinition);
|
||||
}
|
||||
|
||||
providerDefinition = _providerFactory.Create(providerDefinition);
|
||||
|
||||
return providerDefinition.Id;
|
||||
}
|
||||
|
||||
private void UpdateProvider(TProviderResource providerResource)
|
||||
{
|
||||
var providerDefinition = GetDefinition(providerResource);
|
||||
|
||||
Validate(providerDefinition);
|
||||
if (providerDefinition.Enable)
|
||||
{
|
||||
Test(providerDefinition);
|
||||
}
|
||||
|
||||
_providerFactory.Update(providerDefinition);
|
||||
}
|
||||
|
@ -133,6 +146,25 @@ namespace NzbDrone.Api
|
|||
return result.AsResponse();
|
||||
}
|
||||
|
||||
private Response Test(TProviderResource providerResource)
|
||||
{
|
||||
var providerDefinition = GetDefinition(providerResource);
|
||||
|
||||
Test(providerDefinition);
|
||||
|
||||
return "{}";
|
||||
}
|
||||
|
||||
private void Test(TProviderDefinition providerDefinition)
|
||||
{
|
||||
var result = _providerFactory.Test(providerDefinition);
|
||||
|
||||
if (!result.IsValid)
|
||||
{
|
||||
throw new ValidationException(result.Errors);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Validate(TProviderDefinition definition)
|
||||
{
|
||||
var validationResult = definition.Settings.Validate();
|
||||
|
@ -143,4 +175,4 @@ namespace NzbDrone.Api
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,5 +17,6 @@ namespace NzbDrone.Api.Queue
|
|||
public Decimal Sizeleft { get; set; }
|
||||
public TimeSpan? Timeleft { get; set; }
|
||||
public String Status { get; set; }
|
||||
public String ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ namespace NzbDrone.Api.REST
|
|||
|
||||
var errors = SharedValidator.Validate(resource).Errors.ToList();
|
||||
|
||||
if (Request.Method.Equals("POST", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (Request.Method.Equals("POST", StringComparison.InvariantCultureIgnoreCase) && !Request.Url.Path.EndsWith("/test", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
errors.AddRange(PostValidator.Validate(resource).Errors);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace NzbDrone.Api.Series
|
||||
{
|
||||
public class AlternateTitleResource
|
||||
{
|
||||
public String Title { get; set; }
|
||||
public Int32 SeasonNumber { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Api.Series
|
||||
{
|
||||
public class SeasonResource
|
||||
{
|
||||
public int SeasonNumber { get; set; }
|
||||
public Boolean Monitored { get; set; }
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ using NzbDrone.Api.Mapping;
|
|||
using NzbDrone.Core.Tv.Events;
|
||||
using NzbDrone.Core.Validation.Paths;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using Omu.ValueInjecter;
|
||||
|
||||
namespace NzbDrone.Api.Series
|
||||
{
|
||||
|
@ -78,21 +79,6 @@ namespace NzbDrone.Api.Series
|
|||
PutValidator.RuleFor(s => s.Path).IsValidPath();
|
||||
}
|
||||
|
||||
private void PopulateAlternativeTitles(List<SeriesResource> resources)
|
||||
{
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
PopulateAlternativeTitles(resource);
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateAlternativeTitles(SeriesResource resource)
|
||||
{
|
||||
var mapping = _sceneMappingService.FindByTvdbid(resource.TvdbId);
|
||||
if (mapping == null) return;
|
||||
resource.AlternativeTitles = mapping.Select(x => x.Title).Distinct().ToList();
|
||||
}
|
||||
|
||||
private SeriesResource GetSeries(int id)
|
||||
{
|
||||
var series = _seriesService.GetSeries(id);
|
||||
|
@ -106,7 +92,7 @@ namespace NzbDrone.Api.Series
|
|||
var resource = series.InjectTo<SeriesResource>();
|
||||
MapCoversToLocal(resource);
|
||||
FetchAndLinkSeriesStatistics(resource);
|
||||
PopulateAlternativeTitles(resource);
|
||||
PopulateAlternateTitles(resource);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
@ -118,7 +104,7 @@ namespace NzbDrone.Api.Series
|
|||
|
||||
MapCoversToLocal(seriesResources.ToArray());
|
||||
LinkSeriesStatistics(seriesResources, seriesStats);
|
||||
PopulateAlternativeTitles(seriesResources);
|
||||
PopulateAlternateTitles(seriesResources);
|
||||
|
||||
return seriesResources;
|
||||
}
|
||||
|
@ -177,6 +163,24 @@ namespace NzbDrone.Api.Series
|
|||
resource.EpisodeCount = seriesStatistics.EpisodeCount;
|
||||
resource.EpisodeFileCount = seriesStatistics.EpisodeFileCount;
|
||||
resource.NextAiring = seriesStatistics.NextAiring;
|
||||
resource.PreviousAiring = seriesStatistics.PreviousAiring;
|
||||
}
|
||||
|
||||
private void PopulateAlternateTitles(List<SeriesResource> resources)
|
||||
{
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
PopulateAlternateTitles(resource);
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateAlternateTitles(SeriesResource resource)
|
||||
{
|
||||
var mappings = _sceneMappingService.FindByTvdbid(resource.TvdbId);
|
||||
|
||||
if (mappings == null) return;
|
||||
|
||||
resource.AlternateTitles = mappings.InjectTo<List<AlternateTitleResource>>();
|
||||
}
|
||||
|
||||
public void Handle(EpisodeImportedEvent message)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
@ -15,7 +16,8 @@ namespace NzbDrone.Api.Series
|
|||
|
||||
//View Only
|
||||
public String Title { get; set; }
|
||||
public List<String> AlternativeTitles { get; set; }
|
||||
public List<AlternateTitleResource> AlternateTitles { get; set; }
|
||||
public String SortTitle { get; set; }
|
||||
|
||||
public Int32 SeasonCount
|
||||
{
|
||||
|
@ -33,12 +35,13 @@ namespace NzbDrone.Api.Series
|
|||
public String QualityProfileName { get; set; }
|
||||
public String Overview { get; set; }
|
||||
public DateTime? NextAiring { get; set; }
|
||||
public DateTime? PreviousAiring { get; set; }
|
||||
public String Network { get; set; }
|
||||
public String AirTime { get; set; }
|
||||
public List<MediaCover> Images { get; set; }
|
||||
|
||||
public String RemotePoster { get; set; }
|
||||
public List<Season> Seasons { get; set; }
|
||||
public List<SeasonResource> Seasons { get; set; }
|
||||
public Int32 Year { get; set; }
|
||||
|
||||
//View & Edit
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Backup;
|
||||
|
||||
namespace NzbDrone.Api.System.Backup
|
||||
{
|
||||
public class BackupModule : NzbDroneRestModule<BackupResource>
|
||||
{
|
||||
private readonly IBackupService _backupService;
|
||||
|
||||
public BackupModule(IBackupService backupService) : base("system/backup")
|
||||
{
|
||||
_backupService = backupService;
|
||||
GetResourceAll = GetBackupFiles;
|
||||
}
|
||||
|
||||
public List<BackupResource> GetBackupFiles()
|
||||
{
|
||||
var backups = _backupService.GetBackups();
|
||||
|
||||
return backups.Select(b => new BackupResource
|
||||
{
|
||||
Id = b.Path.GetHashCode(),
|
||||
Name = Path.GetFileName(b.Path),
|
||||
Path = b.Path,
|
||||
Type = b.Type,
|
||||
Time = b.Time
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.Backup;
|
||||
|
||||
namespace NzbDrone.Api.System.Backup
|
||||
{
|
||||
public class BackupResource : RestResource
|
||||
{
|
||||
public String Name { get; set; }
|
||||
public String Path { get; set; }
|
||||
public BackupType Type { get; set; }
|
||||
public DateTime Time { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
|
|
|
@ -21,15 +21,4 @@ using System.Runtime.InteropServices;
|
|||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("b47d34ef-05e8-4826-8a57-9dd05106c964")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
[assembly: AssemblyFileVersion("10.0.0.*")]
|
||||
|
|
|
@ -21,15 +21,4 @@ using System.Runtime.InteropServices;
|
|||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("6b8945f5-f5b5-4729-865d-f958fbd673d9")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
|
|
|
@ -172,7 +172,7 @@ namespace NzbDrone.Common.Test.DiskProviderTests
|
|||
public void empty_folder_should_return_folder_modified_date()
|
||||
{
|
||||
var tempfolder = new DirectoryInfo(TempFolder);
|
||||
Subject.FolderGetLastWrite(TempFolder).Should().Be(tempfolder.LastWriteTimeUtc);
|
||||
Subject.FolderGetLastWriteUtc(TempFolder).Should().Be(tempfolder.LastWriteTimeUtc);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -189,8 +189,8 @@ namespace NzbDrone.Common.Test.DiskProviderTests
|
|||
|
||||
Subject.WriteAllText(testFile, "Test");
|
||||
|
||||
Subject.FolderGetLastWrite(TempFolder).Should().BeOnOrAfter(DateTime.UtcNow.AddMinutes(-1));
|
||||
Subject.FolderGetLastWrite(TempFolder).Should().BeBefore(DateTime.UtcNow.AddMinutes(1));
|
||||
Subject.FolderGetLastWriteUtc(TempFolder).Should().BeOnOrAfter(DateTime.UtcNow.AddMinutes(-1));
|
||||
Subject.FolderGetLastWriteUtc(TempFolder).Should().BeBefore(DateTime.UtcNow.AddMinutes(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -238,7 +238,7 @@ namespace NzbDrone.Common.Test.DiskProviderTests
|
|||
[Explicit]
|
||||
public void check_last_write()
|
||||
{
|
||||
Console.WriteLine(Subject.FolderGetLastWrite(GetFilledTempFolder().FullName));
|
||||
Console.WriteLine(Subject.FolderGetLastWriteUtc(GetFilledTempFolder().FullName));
|
||||
Console.WriteLine(GetFilledTempFolder().LastWriteTimeUtc);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,14 +26,6 @@ namespace NzbDrone.Common.Test.DiskProviderTests
|
|||
Subject.GetAvailableSpace(Path.Combine(path, "invalidFolder")).Should().NotBe(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_free_space_for_drive_that_doesnt_exist()
|
||||
{
|
||||
WindowsOnly();
|
||||
|
||||
Assert.Throws<DirectoryNotFoundException>(() => Subject.GetAvailableSpace("J:\\").Should().NotBe(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_be_able_to_check_space_on_ramdrive()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Instrumentation;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace NzbDrone.Common.Test.InstrumentationTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class CleanseLogMessageFixture
|
||||
{
|
||||
[TestCase(@"http://127.0.0.1:1234/api/call?vv=1&apikey=mySecret")]
|
||||
[TestCase(@"http://127.0.0.1:1234/api/call?vv=1&ma_username=mySecret&ma_password=mySecret")]
|
||||
// NzbGet
|
||||
[TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")]
|
||||
[TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")]
|
||||
// Sabnzbd
|
||||
[TestCase(@"""config"":{""newzbin"":{""username"":""mySecret"",""password"":""mySecret""}")]
|
||||
[TestCase(@"""nzbxxx"":{""username"":""mySecret"",""apikey"":""mySecret""}")]
|
||||
[TestCase(@"""growl"":{""growl_password"":""mySecret"",""growl_server"":""""}")]
|
||||
[TestCase(@"""nzbmatrix"":{""username"":""mySecret"",""apikey"":""mySecret""}")]
|
||||
[TestCase(@"""misc"":{""username"":""mySecret"",""api_key"":""mySecret"",""password"":""mySecret"",""nzb_key"":""mySecret""}")]
|
||||
[TestCase(@"""servers"":[{""username"":""mySecret"",""password"":""mySecret""}]")]
|
||||
[TestCase(@"""misc"":{""email_account"":""mySecret"",""email_to"":[],""email_from"":"""",""email_pwd"":""mySecret""}")]
|
||||
public void should_clean_message(String message)
|
||||
{
|
||||
var cleansedMessage = CleanseLogMessage.Cleanse(message);
|
||||
|
||||
cleansedMessage.Should().NotContain("mySecret");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -67,6 +67,7 @@
|
|||
<Compile Include="EnsureTest\PathExtensionFixture.cs" />
|
||||
<Compile Include="EnvironmentTests\StartupArgumentsFixture.cs" />
|
||||
<Compile Include="EnvironmentTests\EnvironmentProviderTest.cs" />
|
||||
<Compile Include="InstrumentationTests\CleanseLogMessageFixture.cs" />
|
||||
<Compile Include="LevenshteinDistanceFixture.cs" />
|
||||
<Compile Include="ReflectionExtensions.cs" />
|
||||
<Compile Include="PathExtensionFixture.cs" />
|
||||
|
|
|
@ -136,6 +136,23 @@ namespace NzbDrone.Common.Test
|
|||
parentPath.IsParentPath(childPath).Should().Be(expectedResult);
|
||||
}
|
||||
|
||||
[TestCase(@"C:\Test\mydir", @"C:\Test")]
|
||||
[TestCase(@"C:\Test\", @"C:")]
|
||||
[TestCase(@"C:\", null)]
|
||||
public void path_should_return_parent(string path, string parentPath)
|
||||
{
|
||||
path.GetParentPath().Should().Be(parentPath);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void path_should_return_parent_for_oversized_path()
|
||||
{
|
||||
var path = @"/media/2e168617-f2ae-43fb-b88c-3663af1c8eea/downloads/sabnzbd/nzbdrone/Some.Real.Big.Thing/With.Alot.Of.Nested.Directories/Some.Real.Big.Thing/With.Alot.Of.Nested.Directories/Some.Real.Big.Thing/With.Alot.Of.Nested.Directories/Some.Real.Big.Thing/With.Alot.Of.Nested.Directories/Some.Real.Big.Thing/With.Alot.Of.Nested.Directories";
|
||||
var parentPath = @"/media/2e168617-f2ae-43fb-b88c-3663af1c8eea/downloads/sabnzbd/nzbdrone/Some.Real.Big.Thing/With.Alot.Of.Nested.Directories/Some.Real.Big.Thing/With.Alot.Of.Nested.Directories/Some.Real.Big.Thing/With.Alot.Of.Nested.Directories/Some.Real.Big.Thing/With.Alot.Of.Nested.Directories/Some.Real.Big.Thing";
|
||||
|
||||
path.GetParentPath().Should().Be(parentPath);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore]
|
||||
public void should_not_be_parent_when_it_is_grandparent()
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace NzbDrone.Common
|
|||
public interface IArchiveService
|
||||
{
|
||||
void Extract(string compressedFile, string destination);
|
||||
void ExtractZip(string compressedFile, string destination);
|
||||
void CreateZip(string path, params string[] files);
|
||||
}
|
||||
|
||||
public class ArchiveService : IArchiveService
|
||||
|
@ -40,7 +42,22 @@ namespace NzbDrone.Common
|
|||
_logger.Debug("Extraction complete.");
|
||||
}
|
||||
|
||||
private void ExtractZip(string compressedFile, string destination)
|
||||
public void CreateZip(string path, params string[] files)
|
||||
{
|
||||
using (var zipFile = ZipFile.Create(path))
|
||||
{
|
||||
zipFile.BeginUpdate();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
zipFile.Add(file, Path.GetFileName(file));
|
||||
}
|
||||
|
||||
zipFile.CommitUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public void ExtractZip(string compressedFile, string destination)
|
||||
{
|
||||
using (var fileStream = File.OpenRead(compressedFile))
|
||||
{
|
|
@ -33,7 +33,7 @@ namespace NzbDrone.Common.Disk
|
|||
return new DirectoryInfo(path).CreationTimeUtc;
|
||||
}
|
||||
|
||||
public DateTime FolderGetLastWrite(string path)
|
||||
public DateTime FolderGetLastWriteUtc(string path)
|
||||
{
|
||||
CheckFolderExists(path);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace NzbDrone.Common.Disk
|
|||
void SetPermissions(string path, string mask, string user, string group);
|
||||
long? GetTotalSize(string path);
|
||||
DateTime FolderGetCreationTimeUtc(string path);
|
||||
DateTime FolderGetLastWrite(string path);
|
||||
DateTime FolderGetLastWriteUtc(string path);
|
||||
DateTime FileGetCreationTimeUtc(string path);
|
||||
DateTime FileGetLastWrite(string path);
|
||||
DateTime FileGetLastWriteUtc(string path);
|
||||
|
|
|
@ -22,5 +22,10 @@ namespace NzbDrone.Common
|
|||
|
||||
source.Add(item);
|
||||
}
|
||||
|
||||
public static bool Empty<TSource>(this IEnumerable<TSource> source)
|
||||
{
|
||||
return !source.Any();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,8 +4,21 @@ namespace NzbDrone.Common.Instrumentation
|
|||
{
|
||||
public class CleanseLogMessage
|
||||
{
|
||||
//TODO: remove password=
|
||||
private static readonly Regex CleansingRegex = new Regex(@"(?<=apikey=)(\w+?)(?=\W|$|_)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex[] CleansingRules = new[]
|
||||
{
|
||||
// Url
|
||||
new Regex(@"(<=\?|&)apikey=(?<secret>\w+?)(?=\W|$|_)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"(<=\?|&)[^=]*?(username|password)=(?<secret>\w+?)(?=\W|$|_)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
|
||||
// NzbGet
|
||||
new Regex(@"""Name""\s*:\s*""[^""]*(username|password)""\s*,\s*""Value""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
|
||||
// Sabnzbd
|
||||
new Regex(@"""[^""]*(username|password|api_?key|nzb_key)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||
new Regex(@"""email_(account|to|from|pwd)""\s*:\s*""(?<secret>[^""]+?)""", RegexOptions.Compiled | RegexOptions.IgnoreCase)
|
||||
};
|
||||
|
||||
//private static readonly Regex CleansingRegex = new Regex(@"(?<=apikey=)(\w+?)(?=\W|$|_)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public static string Cleanse(string message)
|
||||
{
|
||||
|
@ -14,7 +27,12 @@ namespace NzbDrone.Common.Instrumentation
|
|||
return message;
|
||||
}
|
||||
|
||||
return CleansingRegex.Replace(message, "<removed>");
|
||||
foreach (var regex in CleansingRules)
|
||||
{
|
||||
message = regex.Replace(message, m => m.Value.Replace(m.Groups["secret"].Index - m.Index, m.Groups["secret"].Length, "<removed>"));
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,10 @@
|
|||
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="RestSharp, Version=104.4.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\RestSharp.104.4.0\lib\net4\RestSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Configuration.Install" />
|
||||
|
@ -59,8 +63,8 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ArchiveProvider.cs" />
|
||||
<Compile Include="ConvertBase32.cs" />
|
||||
<Compile Include="ArchiveService.cs" />
|
||||
<Compile Include="Cache\Cached.cs" />
|
||||
<Compile Include="Cache\CacheManager.cs" />
|
||||
<Compile Include="Cache\ICached.cs" />
|
||||
|
|
|
@ -11,9 +11,9 @@ namespace NzbDrone.Common
|
|||
private const string APP_CONFIG_FILE = "config.xml";
|
||||
private const string NZBDRONE_DB = "nzbdrone.db";
|
||||
private const string NZBDRONE_LOG_DB = "logs.db";
|
||||
private const string BACKUP_ZIP_FILE = "NzbDrone_Backup.zip";
|
||||
private const string NLOG_CONFIG_FILE = "nlog.config";
|
||||
private const string UPDATE_CLIENT_EXE = "NzbDrone.Update.exe";
|
||||
private const string BACKUP_FOLDER = "Backups";
|
||||
|
||||
private static readonly string UPDATE_SANDBOX_FOLDER_NAME = "nzbdrone_update" + Path.DirectorySeparatorChar;
|
||||
private static readonly string UPDATE_PACKAGE_FOLDER_NAME = "NzbDrone" + Path.DirectorySeparatorChar;
|
||||
|
@ -53,6 +53,22 @@ namespace NzbDrone.Common
|
|||
return childPath.Substring(parentPath.Length).Trim(Path.DirectorySeparatorChar);
|
||||
}
|
||||
|
||||
public static string GetParentPath(this string childPath)
|
||||
{
|
||||
var parentPath = childPath.TrimEnd('\\', '/');
|
||||
|
||||
var index = parentPath.LastIndexOfAny(new[] { '\\', '/' });
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
return parentPath.Substring(0, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsParentPath(this string parentPath, string childPath)
|
||||
{
|
||||
parentPath = parentPath.TrimEnd(Path.DirectorySeparatorChar);
|
||||
|
@ -210,9 +226,9 @@ namespace NzbDrone.Common
|
|||
return Path.Combine(GetUpdateSandboxFolder(appFolderInfo), UPDATE_CLIENT_EXE);
|
||||
}
|
||||
|
||||
public static string GetConfigBackupFile(this IAppFolderInfo appFolderInfo)
|
||||
public static string GetBackupFolder(this IAppFolderInfo appFolderInfo)
|
||||
{
|
||||
return Path.Combine(GetAppDataPath(appFolderInfo), BACKUP_ZIP_FILE);
|
||||
return Path.Combine(GetAppDataPath(appFolderInfo), BACKUP_FOLDER);
|
||||
}
|
||||
|
||||
public static string GetNzbDroneDatabase(this IAppFolderInfo appFolderInfo)
|
||||
|
|
|
@ -9,8 +9,4 @@ using System.Runtime.InteropServices;
|
|||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("b6eaa144-e13b-42e5-a738-c60d89c0f728")]
|
||||
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
[assembly: AssemblyFileVersion("10.0.0.*")]
|
||||
|
|
|
@ -15,16 +15,16 @@ namespace NzbDrone.Common.Reflection
|
|||
return properties.Where(c => c.PropertyType.IsSimpleType()).ToList();
|
||||
}
|
||||
|
||||
|
||||
public static List<Type> ImplementationsOf<T>(this Assembly assembly)
|
||||
{
|
||||
return assembly.GetTypes().Where(c => typeof(T).IsAssignableFrom(c)).ToList();
|
||||
}
|
||||
|
||||
|
||||
public static bool IsSimpleType(this Type type)
|
||||
{
|
||||
if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>) || type.GetGenericTypeDefinition() == typeof(List<>)))
|
||||
if (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>) ||
|
||||
type.GetGenericTypeDefinition() == typeof(List<>) ||
|
||||
type.GetGenericTypeDefinition() == typeof(IEnumerable<>)))
|
||||
{
|
||||
type = type.GetGenericArguments()[0];
|
||||
}
|
||||
|
|
|
@ -48,12 +48,12 @@ namespace NzbDrone.Common.Serializer
|
|||
result = Deserialize<T>(json);
|
||||
return true;
|
||||
}
|
||||
catch (JsonReaderException ex)
|
||||
catch (JsonReaderException)
|
||||
{
|
||||
result = default(T);
|
||||
return false;
|
||||
}
|
||||
catch (JsonSerializationException ex)
|
||||
catch (JsonSerializationException)
|
||||
{
|
||||
result = default(T);
|
||||
return false;
|
||||
|
|
|
@ -32,6 +32,13 @@ namespace NzbDrone.Common
|
|||
|
||||
private static readonly Regex CollapseSpace = new Regex(@"\s+", RegexOptions.Compiled);
|
||||
|
||||
public static string Replace(this string text, int index, int length, string replacement)
|
||||
{
|
||||
text = text.Remove(index, length);
|
||||
text = text.Insert(index, replacement);
|
||||
return text;
|
||||
}
|
||||
|
||||
public static string RemoveAccent(this string text)
|
||||
{
|
||||
var normalizedString = text.Normalize(NormalizationForm.FormD);
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
<package id="loggly-csharp" version="2.3" targetFramework="net40" />
|
||||
<package id="Newtonsoft.Json" version="5.0.8" targetFramework="net40" />
|
||||
<package id="NLog" version="2.1.0" targetFramework="net40" />
|
||||
<package id="RestSharp" version="104.4.0" targetFramework="net40" />
|
||||
<package id="SharpZipLib" version="0.86.0" targetFramework="net40" />
|
||||
</packages>
|
|
@ -8,8 +8,4 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyTitle("NzbDrone.Host")]
|
||||
[assembly: Guid("67AADCD9-89AA-4D95-8281-3193740E70E5")]
|
||||
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
[assembly: AssemblyFileVersion("10.0.0.*")]
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
|
@ -14,9 +16,11 @@ namespace NzbDrone.Core.Test.DataAugmentationFixture.Scene
|
|||
|
||||
public class SceneMappingServiceFixture : CoreTest<SceneMappingService>
|
||||
{
|
||||
|
||||
private List<SceneMapping> _fakeMappings;
|
||||
|
||||
private Mock<ISceneMappingProvider> _provider1;
|
||||
private Mock<ISceneMappingProvider> _provider2;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
|
@ -33,14 +37,24 @@ namespace NzbDrone.Core.Test.DataAugmentationFixture.Scene
|
|||
_fakeMappings[2].ParseTerm = "Can";
|
||||
_fakeMappings[3].ParseTerm = "Be";
|
||||
_fakeMappings[4].ParseTerm = "Cleaned";
|
||||
|
||||
_provider1 = new Mock<ISceneMappingProvider>();
|
||||
_provider1.Setup(s => s.GetSceneMappings()).Returns(_fakeMappings);
|
||||
|
||||
_provider2 = new Mock<ISceneMappingProvider>();
|
||||
_provider2.Setup(s => s.GetSceneMappings()).Returns(_fakeMappings);
|
||||
}
|
||||
|
||||
|
||||
private void GivenProviders(IEnumerable<Mock<ISceneMappingProvider>> providers)
|
||||
{
|
||||
Mocker.SetConstant<IEnumerable<ISceneMappingProvider>>(providers.Select(s => s.Object));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateMappings_purge_existing_mapping_and_add_new_ones()
|
||||
public void should_purge_existing_mapping_and_add_new_ones()
|
||||
{
|
||||
Mocker.GetMock<ISceneMappingProxy>().Setup(c => c.Fetch()).Returns(_fakeMappings);
|
||||
GivenProviders(new [] { _provider1 });
|
||||
|
||||
Mocker.GetMock<ISceneMappingRepository>().Setup(c => c.All()).Returns(_fakeMappings);
|
||||
|
||||
Subject.Execute(new UpdateSceneMappingCommand());
|
||||
|
@ -48,27 +62,26 @@ namespace NzbDrone.Core.Test.DataAugmentationFixture.Scene
|
|||
AssertMappingUpdated();
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void UpdateMappings_should_not_delete_if_fetch_fails()
|
||||
public void should_not_delete_if_fetch_fails()
|
||||
{
|
||||
GivenProviders(new[] { _provider1 });
|
||||
|
||||
Mocker.GetMock<ISceneMappingProxy>().Setup(c => c.Fetch()).Throws(new WebException());
|
||||
_provider1.Setup(c => c.GetSceneMappings()).Throws(new WebException());
|
||||
|
||||
Subject.Execute(new UpdateSceneMappingCommand());
|
||||
|
||||
AssertNoUpdate();
|
||||
|
||||
ExceptionVerification.ExpectedErrors(1);
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UpdateMappings_should_not_delete_if_fetch_returns_empty_list()
|
||||
public void should_not_delete_if_fetch_returns_empty_list()
|
||||
{
|
||||
GivenProviders(new[] { _provider1 });
|
||||
|
||||
Mocker.GetMock<ISceneMappingProxy>().Setup(c => c.Fetch()).Returns(new List<SceneMapping>());
|
||||
_provider1.Setup(c => c.GetSceneMappings()).Returns(new List<SceneMapping>());
|
||||
|
||||
Subject.Execute(new UpdateSceneMappingCommand());
|
||||
|
||||
|
@ -77,28 +90,37 @@ namespace NzbDrone.Core.Test.DataAugmentationFixture.Scene
|
|||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_mappings_for_all_providers()
|
||||
{
|
||||
GivenProviders(new[] { _provider1, _provider2 });
|
||||
|
||||
Mocker.GetMock<ISceneMappingRepository>().Setup(c => c.All()).Returns(_fakeMappings);
|
||||
|
||||
Subject.Execute(new UpdateSceneMappingCommand());
|
||||
|
||||
_provider1.Verify(c => c.GetSceneMappings(), Times.Once());
|
||||
_provider2.Verify(c => c.GetSceneMappings(), Times.Once());
|
||||
}
|
||||
|
||||
private void AssertNoUpdate()
|
||||
{
|
||||
Mocker.GetMock<ISceneMappingProxy>().Verify(c => c.Fetch(), Times.Once());
|
||||
Mocker.GetMock<ISceneMappingRepository>().Verify(c => c.Purge(It.IsAny<bool>()), Times.Never());
|
||||
_provider1.Verify(c => c.GetSceneMappings(), Times.Once());
|
||||
Mocker.GetMock<ISceneMappingRepository>().Verify(c => c.Clear(It.IsAny<String>()), Times.Never());
|
||||
Mocker.GetMock<ISceneMappingRepository>().Verify(c => c.InsertMany(_fakeMappings), Times.Never());
|
||||
}
|
||||
|
||||
private void AssertMappingUpdated()
|
||||
{
|
||||
Mocker.GetMock<ISceneMappingProxy>().Verify(c => c.Fetch(), Times.Once());
|
||||
Mocker.GetMock<ISceneMappingRepository>().Verify(c => c.Purge(It.IsAny<bool>()), Times.Once());
|
||||
_provider1.Verify(c => c.GetSceneMappings(), Times.Once());
|
||||
Mocker.GetMock<ISceneMappingRepository>().Verify(c => c.Clear(It.IsAny<String>()), Times.Once());
|
||||
Mocker.GetMock<ISceneMappingRepository>().Verify(c => c.InsertMany(_fakeMappings), Times.Once());
|
||||
|
||||
|
||||
foreach (var sceneMapping in _fakeMappings)
|
||||
{
|
||||
Subject.GetSceneName(sceneMapping.TvdbId).Should().Be(sceneMapping.SearchTerm);
|
||||
Subject.GetSceneNames(sceneMapping.TvdbId, _fakeMappings.Select(m => m.SeasonNumber)).Should().Contain(sceneMapping.SearchTerm);
|
||||
Subject.GetTvDbId(sceneMapping.ParseTerm).Should().Be(sceneMapping.TvdbId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,26 +54,30 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
|
||||
private void GivenEmptyQueue()
|
||||
{
|
||||
Mocker.GetMock<IQueueService>()
|
||||
.Setup(s => s.GetQueue())
|
||||
.Returns(new List<Queue.Queue>());
|
||||
Mocker.GetMock<IDownloadTrackingService>()
|
||||
.Setup(s => s.GetQueuedDownloads())
|
||||
.Returns(new TrackedDownload[0]);
|
||||
}
|
||||
|
||||
private void GivenQueue(IEnumerable<RemoteEpisode> remoteEpisodes)
|
||||
private void GivenQueue(IEnumerable<RemoteEpisode> remoteEpisodes, TrackedDownloadState state = TrackedDownloadState.Downloading)
|
||||
{
|
||||
var queue = new List<Queue.Queue>();
|
||||
var queue = new List<TrackedDownload>();
|
||||
|
||||
foreach (var remoteEpisode in remoteEpisodes)
|
||||
{
|
||||
queue.Add(new Queue.Queue
|
||||
queue.Add(new TrackedDownload
|
||||
{
|
||||
RemoteEpisode = remoteEpisode
|
||||
});
|
||||
State = state,
|
||||
DownloadItem = new DownloadClientItem
|
||||
{
|
||||
RemoteEpisode = remoteEpisode
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Mocker.GetMock<IQueueService>()
|
||||
.Setup(s => s.GetQueue())
|
||||
.Returns(queue);
|
||||
Mocker.GetMock<IDownloadTrackingService>()
|
||||
.Setup(s => s.GetQueuedDownloads())
|
||||
.Returns(queue.ToArray());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -95,6 +99,23 @@ namespace NzbDrone.Core.Test.DecisionEngineTests
|
|||
Subject.IsSatisfiedBy(_remoteEpisode, null).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_download_is_failed()
|
||||
{
|
||||
var remoteEpisode = Builder<RemoteEpisode>.CreateNew()
|
||||
.With(r => r.Series = _series)
|
||||
.With(r => r.Episodes = new List<Episode> { _episode })
|
||||
.With(r => r.ParsedEpisodeInfo = new ParsedEpisodeInfo
|
||||
{
|
||||
Quality = new QualityModel(Quality.DVD)
|
||||
})
|
||||
.Build();
|
||||
|
||||
GivenQueue(new List<RemoteEpisode> { remoteEpisode }, TrackedDownloadState.DownloadFailed);
|
||||
|
||||
Subject.IsSatisfiedBy(_remoteEpisode, null).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_true_when_quality_in_queue_is_lower()
|
||||
{
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NUnit.Framework;
|
||||
using FluentAssertions;
|
||||
using FizzWare.NBuilder;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class DownloadApprovedReportsFixture : CoreTest<DownloadApprovedReports>
|
||||
public class PrioritizeDownloadDecisionFixture : CoreTest<DownloadDecisionPriorizationService>
|
||||
{
|
||||
private Episode GetEpisode(int id)
|
||||
{
|
||||
|
@ -44,16 +45,6 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
|||
return remoteEpisode;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_an_empty_list_when_none_are_appproved()
|
||||
{
|
||||
var decisions = new List<DownloadDecision>();
|
||||
decisions.Add(new DownloadDecision(null, "Failure!"));
|
||||
decisions.Add(new DownloadDecision(null, "Failure!"));
|
||||
|
||||
Subject.GetQualifiedReports(decisions).Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_put_propers_before_non_propers()
|
||||
{
|
||||
|
@ -64,7 +55,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
|||
decisions.Add(new DownloadDecision(remoteEpisode1));
|
||||
decisions.Add(new DownloadDecision(remoteEpisode2));
|
||||
|
||||
var qualifiedReports = Subject.GetQualifiedReports(decisions);
|
||||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteEpisode.ParsedEpisodeInfo.Quality.Proper.Should().BeTrue();
|
||||
}
|
||||
|
||||
|
@ -78,7 +69,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
|||
decisions.Add(new DownloadDecision(remoteEpisode1));
|
||||
decisions.Add(new DownloadDecision(remoteEpisode2));
|
||||
|
||||
var qualifiedReports = Subject.GetQualifiedReports(decisions);
|
||||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteEpisode.ParsedEpisodeInfo.Quality.Quality.Should().Be(Quality.HDTV720p);
|
||||
}
|
||||
|
||||
|
@ -92,7 +83,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
|||
decisions.Add(new DownloadDecision(remoteEpisode1));
|
||||
decisions.Add(new DownloadDecision(remoteEpisode2));
|
||||
|
||||
var qualifiedReports = Subject.GetQualifiedReports(decisions);
|
||||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteEpisode.Episodes.First().EpisodeNumber.Should().Be(1);
|
||||
}
|
||||
|
||||
|
@ -106,7 +97,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
|||
decisions.Add(new DownloadDecision(remoteEpisode1));
|
||||
decisions.Add(new DownloadDecision(remoteEpisode2));
|
||||
|
||||
var qualifiedReports = Subject.GetQualifiedReports(decisions);
|
||||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteEpisode.Episodes.First().EpisodeNumber.Should().Be(1);
|
||||
}
|
||||
|
||||
|
@ -125,7 +116,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
|||
decisions.Add(new DownloadDecision(remoteEpisodeHdSmallYounge));
|
||||
decisions.Add(new DownloadDecision(remoteEpisodeHdLargeYounge));
|
||||
|
||||
var qualifiedReports = Subject.GetQualifiedReports(decisions);
|
||||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisodeHdSmallYounge);
|
||||
}
|
||||
|
||||
|
@ -140,7 +131,7 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
|||
decisions.Add(new DownloadDecision(remoteEpisode1));
|
||||
decisions.Add(new DownloadDecision(remoteEpisode2));
|
||||
|
||||
var qualifiedReports = Subject.GetQualifiedReports(decisions);
|
||||
var qualifiedReports = Subject.PrioritizeDecisions(decisions);
|
||||
qualifiedReports.First().RemoteEpisode.Should().Be(remoteEpisode2);
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ using NzbDrone.Core.History;
|
|||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -103,14 +104,20 @@ namespace NzbDrone.Core.Test.Download
|
|||
{
|
||||
Mocker.GetMock<IDownloadedEpisodesImportService>()
|
||||
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
|
||||
.Returns(new List<Core.MediaFiles.EpisodeImport.ImportDecision>() { new Core.MediaFiles.EpisodeImport.ImportDecision(null) });
|
||||
.Returns(new List<ImportDecision>()
|
||||
{
|
||||
new ImportDecision(null)
|
||||
});
|
||||
}
|
||||
|
||||
private void GivenFailedImport()
|
||||
{
|
||||
Mocker.GetMock<IDownloadedEpisodesImportService>()
|
||||
.Setup(v => v.ProcessFolder(It.IsAny<DirectoryInfo>(), It.IsAny<DownloadClientItem>()))
|
||||
.Returns(new List<Core.MediaFiles.EpisodeImport.ImportDecision>());
|
||||
.Returns(new List<ImportDecision>()
|
||||
{
|
||||
new ImportDecision(new LocalEpisode() { Path = @"C:\TestPath\Droned.S01E01.mkv" }, "Test Failure")
|
||||
});
|
||||
}
|
||||
|
||||
private void VerifyNoImports()
|
||||
|
@ -265,6 +272,8 @@ namespace NzbDrone.Core.Test.Download
|
|||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoImports();
|
||||
|
||||
ExceptionVerification.IgnoreErrors();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -289,6 +298,8 @@ namespace NzbDrone.Core.Test.Download
|
|||
Subject.Execute(new CheckForFinishedDownloadCommand());
|
||||
|
||||
VerifyNoImports();
|
||||
|
||||
ExceptionVerification.IgnoreWarns();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -412,6 +423,8 @@ namespace NzbDrone.Core.Test.Download
|
|||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(c => c.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
|
||||
ExceptionVerification.IgnoreErrors();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -11,12 +11,21 @@ using NzbDrone.Core.Qualities;
|
|||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class DownloadApprovedFixture : CoreTest<DownloadApprovedReports>
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
Mocker.GetMock<IPrioritizeDownloadDecision>()
|
||||
.Setup(v => v.PrioritizeDecisions(It.IsAny<List<DownloadDecision>>()))
|
||||
.Returns<List<DownloadDecision>>(v => v);
|
||||
}
|
||||
|
||||
private Episode GetEpisode(int id)
|
||||
{
|
||||
return Builder<Episode>.CreateNew()
|
||||
|
@ -163,5 +172,15 @@ namespace NzbDrone.Core.Test.Download.DownloadApprovedReportsTests
|
|||
Subject.DownloadApproved(decisions).Should().BeEmpty();
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_an_empty_list_when_none_are_appproved()
|
||||
{
|
||||
var decisions = new List<DownloadDecision>();
|
||||
decisions.Add(new DownloadDecision(null, "Failure!"));
|
||||
decisions.Add(new DownloadDecision(null, "Failure!"));
|
||||
|
||||
Subject.GetQualifiedReports(decisions).Should().BeEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Clients.Nzbget;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
||||
{
|
||||
|
@ -28,7 +29,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
|||
Subject.Definition = new DownloadClientDefinition();
|
||||
Subject.Definition.Settings = new NzbgetSettings
|
||||
{
|
||||
Host = "192.168.5.55",
|
||||
Host = "127.0.0.1",
|
||||
Port = 2222,
|
||||
Username = "admin",
|
||||
Password = "pass",
|
||||
|
@ -65,7 +66,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
|||
FileSizeLo = 1000,
|
||||
Category = "tv",
|
||||
Name = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE",
|
||||
DestDir = "somedirectory",
|
||||
DestDir = "/remote/mount/tv/Droned.S01E01.Pilot.1080p.WEB-DL-DRONE",
|
||||
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
|
||||
ParStatus = "SUCCESS",
|
||||
UnpackStatus = "NONE",
|
||||
|
@ -81,6 +82,19 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
|||
{
|
||||
DownloadRate = 7000000
|
||||
});
|
||||
|
||||
var configItems = new Dictionary<String, String>();
|
||||
configItems.Add("Category1.Name", "tv");
|
||||
configItems.Add("Category1.DestDir", @"/remote/mount/tv");
|
||||
|
||||
Mocker.GetMock<INzbgetProxy>()
|
||||
.Setup(v => v.GetConfig(It.IsAny<NzbgetSettings>()))
|
||||
.Returns(configItems);
|
||||
}
|
||||
|
||||
protected void WithMountPoint(String mountPath)
|
||||
{
|
||||
(Subject.Definition.Settings as NzbgetSettings).TvCategoryLocalPath = mountPath;
|
||||
}
|
||||
|
||||
protected void WithFailedDownload()
|
||||
|
@ -223,5 +237,40 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
|
|||
|
||||
items.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_status_with_outputdir()
|
||||
{
|
||||
var result = Subject.GetStatus();
|
||||
|
||||
result.IsLocalhost.Should().BeTrue();
|
||||
result.OutputRootFolders.Should().NotBeNull();
|
||||
result.OutputRootFolders.First().Should().Be(@"/remote/mount/tv");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_status_with_mounted_outputdir()
|
||||
{
|
||||
WithMountPoint(@"O:\mymount".AsOsAgnostic());
|
||||
|
||||
var result = Subject.GetStatus();
|
||||
|
||||
result.IsLocalhost.Should().BeTrue();
|
||||
result.OutputRootFolders.Should().NotBeNull();
|
||||
result.OutputRootFolders.First().Should().Be(@"O:\mymount".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remap_storage_if_mounted()
|
||||
{
|
||||
WithMountPoint(@"O:\mymount".AsOsAgnostic());
|
||||
|
||||
WithQueue(null);
|
||||
WithHistory(_completed);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
result.OutputPath.Should().Be(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
|||
private SabnzbdQueue _queued;
|
||||
private SabnzbdHistory _failed;
|
||||
private SabnzbdHistory _completed;
|
||||
private SabnzbdConfig _config;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
|
@ -30,7 +31,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
|||
Subject.Definition = new DownloadClientDefinition();
|
||||
Subject.Definition.Settings = new SabnzbdSettings
|
||||
{
|
||||
Host = "192.168.5.55",
|
||||
Host = "127.0.0.1",
|
||||
Port = 2222,
|
||||
ApiKey = "5c770e3197e4fe763423ee7c392c25d1",
|
||||
Username = "admin",
|
||||
|
@ -40,6 +41,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
|||
};
|
||||
_queued = new SabnzbdQueue
|
||||
{
|
||||
DefaultRootFolder = @"Y:\nzbget\root".AsOsAgnostic(),
|
||||
Paused = false,
|
||||
Items = new List<SabnzbdQueueItem>()
|
||||
{
|
||||
|
@ -82,10 +84,31 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
|||
Category = "tv",
|
||||
Id = "sabnzbd_nzb12345",
|
||||
Title = "Droned.S01E01.Pilot.1080p.WEB-DL-DRONE",
|
||||
Storage = "somedirectory"
|
||||
Storage = "/remote/mount/vv/Droned.S01E01.Pilot.1080p.WEB-DL-DRONE"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_config = new SabnzbdConfig
|
||||
{
|
||||
Misc = new SabnzbdConfigMisc
|
||||
{
|
||||
complete_dir = @"/remote/mount"
|
||||
},
|
||||
Categories = new List<SabnzbdCategory>
|
||||
{
|
||||
new SabnzbdCategory { Name = "tv", Dir = "vv" }
|
||||
}
|
||||
};
|
||||
|
||||
Mocker.GetMock<ISabnzbdProxy>()
|
||||
.Setup(s => s.GetConfig(It.IsAny<SabnzbdSettings>()))
|
||||
.Returns(_config);
|
||||
}
|
||||
|
||||
protected void WithMountPoint(String mountPath)
|
||||
{
|
||||
(Subject.Definition.Settings as SabnzbdSettings).TvCategoryLocalPath = mountPath;
|
||||
}
|
||||
|
||||
protected void WithFailedDownload()
|
||||
|
@ -110,7 +133,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
|||
{
|
||||
if (queue == null)
|
||||
{
|
||||
queue = new SabnzbdQueue() { Items = new List<SabnzbdQueueItem>() };
|
||||
queue = new SabnzbdQueue()
|
||||
{
|
||||
DefaultRootFolder = _queued.DefaultRootFolder,
|
||||
Items = new List<SabnzbdQueueItem>()
|
||||
};
|
||||
}
|
||||
|
||||
Mocker.GetMock<ISabnzbdProxy>()
|
||||
|
@ -256,17 +283,34 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
|||
.Verify(v => v.DownloadNzb(It.IsAny<Stream>(), It.IsAny<String>(), It.IsAny<String>(), (int)SabnzbdPriority.High, It.IsAny<SabnzbdSettings>()), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_path_to_folder_instead_of_file()
|
||||
[TestCase(@"Droned.S01E01.Pilot.1080p.WEB-DL-DRONE", @"Droned.S01E01_Pilot_1080p_WEB-DL-DRONE.mkv")]
|
||||
[TestCase(@"Droned.S01E01.Pilot.1080p.WEB-DL-DRONE", @"SubDir\Droned.S01E01_Pilot_1080p_WEB-DL-DRONE.mkv")]
|
||||
[TestCase(@"Droned.S01E01.Pilot.1080p.WEB-DL-DRONE.mkv", @"SubDir\Droned.S01E01_Pilot_1080p_WEB-DL-DRONE.mkv")]
|
||||
[TestCase(@"Droned.S01E01.Pilot.1080p.WEB-DL-DRONE.mkv", @"SubDir\SubDir\Droned.S01E01_Pilot_1080p_WEB-DL-DRONE.mkv")]
|
||||
public void should_return_path_to_jobfolder(String title, String storage)
|
||||
{
|
||||
_completed.Items.First().Storage = @"C:\sorted\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE\Droned.S01E01_Pilot_1080p_WEB-DL-DRONE.mkv".AsOsAgnostic();
|
||||
_completed.Items.First().Title = title;
|
||||
_completed.Items.First().Storage = (@"C:\sorted\" + title + @"\" + storage).AsOsAgnostic();
|
||||
|
||||
WithQueue(null);
|
||||
WithHistory(_completed);
|
||||
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
result.OutputPath.Should().Be(@"C:\sorted\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic());
|
||||
result.OutputPath.Should().Be((@"C:\sorted\" + title).AsOsAgnostic());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_remap_storage_if_mounted()
|
||||
{
|
||||
WithMountPoint(@"O:\mymount".AsOsAgnostic());
|
||||
|
||||
WithQueue(null);
|
||||
WithHistory(_completed);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
result.OutputPath.Should().Be(@"O:\mymount\Droned.S01E01.Pilot.1080p.WEB-DL-DRONE".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -281,5 +325,51 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
|
|||
|
||||
result.OutputPath.Should().Be(@"C:\".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_blow_up_if_storage_doesnt_have_jobfolder()
|
||||
{
|
||||
_completed.Items.First().Storage = @"C:\sorted\somewhere\asdfasdf\asdfasdf.mkv".AsOsAgnostic();
|
||||
|
||||
WithQueue(null);
|
||||
WithHistory(_completed);
|
||||
|
||||
var result = Subject.GetItems().Single();
|
||||
|
||||
result.OutputPath.Should().Be(@"C:\sorted\somewhere\asdfasdf\asdfasdf.mkv".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads\vv")]
|
||||
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed\vv")]
|
||||
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads/vv")]
|
||||
[TestCase(@"/nzbget/root", @"completed", @"vv", @"/nzbget/root/completed/vv")]
|
||||
public void should_return_status_with_outputdir(String rootFolder, String completeDir, String categoryDir, String expectedDir)
|
||||
{
|
||||
_queued.DefaultRootFolder = rootFolder;
|
||||
_config.Misc.complete_dir = completeDir;
|
||||
_config.Categories.First().Dir = categoryDir;
|
||||
|
||||
WithQueue(null);
|
||||
|
||||
var result = Subject.GetStatus();
|
||||
|
||||
result.IsLocalhost.Should().BeTrue();
|
||||
result.OutputRootFolders.Should().NotBeNull();
|
||||
result.OutputRootFolders.First().Should().Be(expectedDir);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_status_with_mounted_outputdir()
|
||||
{
|
||||
WithMountPoint(@"O:\mymount".AsOsAgnostic());
|
||||
|
||||
WithQueue(null);
|
||||
|
||||
var result = Subject.GetStatus();
|
||||
|
||||
result.IsLocalhost.Should().BeTrue();
|
||||
result.OutputRootFolders.Should().NotBeNull();
|
||||
result.OutputRootFolders.First().Should().Be(@"O:\mymount".AsOsAgnostic());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Processes;
|
||||
using NzbDrone.Core.HealthCheck.Checks;
|
||||
|
@ -78,5 +77,30 @@ namespace NzbDrone.Core.Test.HealthCheck.Checks
|
|||
|
||||
Subject.Check().ShouldBeOk();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_ok_when_mono_3_6_1()
|
||||
{
|
||||
GivenOutput("3.6.1");
|
||||
|
||||
Subject.Check().ShouldBeOk();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_ok_when_mono_3_6_1_with_custom_output()
|
||||
{
|
||||
Mocker.GetMock<IProcessProvider>()
|
||||
.Setup(s => s.StartAndCapture("mono", "--version"))
|
||||
.Returns(new ProcessOutput
|
||||
{
|
||||
Standard = new List<string>
|
||||
{
|
||||
"Mono JIT compiler version 3.6.1 (master/fce3972 Fri Jul 4 01:12:43 CEST 2014)",
|
||||
"Copyright (C) 2002-2011 Novell, Inc, Xamarin, Inc and Contributors. www.mono-project.com"
|
||||
}
|
||||
});
|
||||
|
||||
Subject.Check().ShouldBeOk();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using NzbDrone.Core.IndexerSearch;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using NzbDrone.Core.IndexerSearch;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using FizzWare.NBuilder;
|
||||
using System;
|
||||
|
@ -29,9 +30,9 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
|||
.Setup(s => s.GetAvailableProviders())
|
||||
.Returns(new List<IIndexer> { indexer.Object });
|
||||
|
||||
Mocker.GetMock<NzbDrone.Core.DecisionEngine.IMakeDownloadDecision>()
|
||||
Mocker.GetMock<DecisionEngine.IMakeDownloadDecision>()
|
||||
.Setup(s => s.GetSearchDecision(It.IsAny<List<Parser.Model.ReleaseInfo>>(), It.IsAny<SearchCriteriaBase>()))
|
||||
.Returns(new List<NzbDrone.Core.DecisionEngine.Specifications.DownloadDecision>());
|
||||
.Returns(new List<DecisionEngine.Specifications.DownloadDecision>());
|
||||
|
||||
_xemSeries = Builder<Series>.CreateNew()
|
||||
.With(v => v.UseSceneNumbering = true)
|
||||
|
@ -46,6 +47,10 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
|||
Mocker.GetMock<IEpisodeService>()
|
||||
.Setup(v => v.GetEpisodesBySeason(_xemSeries.Id, It.IsAny<int>()))
|
||||
.Returns<int, int>((i, j) => _xemEpisodes.Where(d => d.SeasonNumber == j).ToList());
|
||||
|
||||
Mocker.GetMock<ISceneMappingService>()
|
||||
.Setup(s => s.GetSceneNames(It.IsAny<Int32>(), It.IsAny<IEnumerable<Int32>>()))
|
||||
.Returns(new List<String>());
|
||||
}
|
||||
|
||||
private void WithEpisode(int seasonNumber, int episodeNumber, int sceneSeasonNumber, int sceneEpisodeNumber)
|
||||
|
@ -90,7 +95,7 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
|||
|
||||
private List<SearchCriteriaBase> WatchForSearchCriteria()
|
||||
{
|
||||
List<SearchCriteriaBase> result = new List<SearchCriteriaBase>();
|
||||
var result = new List<SearchCriteriaBase>();
|
||||
|
||||
Mocker.GetMock<IFetchFeedFromIndexers>()
|
||||
.Setup(v => v.Fetch(It.IsAny<IIndexer>(), It.IsAny<SingleEpisodeSearchCriteria>()))
|
||||
|
@ -102,6 +107,11 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
|||
.Callback<IIndexer, SeasonSearchCriteria>((i, s) => result.Add(s))
|
||||
.Returns(new List<Parser.Model.ReleaseInfo>());
|
||||
|
||||
Mocker.GetMock<IFetchFeedFromIndexers>()
|
||||
.Setup(v => v.Fetch(It.IsAny<IIndexer>(), It.IsAny<AnimeEpisodeSearchCriteria>()))
|
||||
.Callback<IIndexer, AnimeEpisodeSearchCriteria>((i, s) => result.Add(s))
|
||||
.Returns(new List<Parser.Model.ReleaseInfo>());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -186,5 +196,21 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
|||
criteria.Count.Should().Be(1);
|
||||
criteria[0].SeasonNumber.Should().Be(7);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void season_search_for_anime_should_search_for_each_episode()
|
||||
{
|
||||
WithEpisodes();
|
||||
_xemSeries.SeriesType = SeriesTypes.Anime;
|
||||
var seasonNumber = 1;
|
||||
|
||||
var allCriteria = WatchForSearchCriteria();
|
||||
|
||||
Subject.SeasonSearch(_xemSeries.Id, seasonNumber);
|
||||
|
||||
var criteria = allCriteria.OfType<AnimeEpisodeSearchCriteria>().ToList();
|
||||
|
||||
criteria.Count.Should().Be(_xemEpisodes.Count(e => e.SeasonNumber == seasonNumber));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
@ -12,8 +14,8 @@ namespace NzbDrone.Core.Test.IndexerSearchTests
|
|||
[TestCase("Franklin & Bash", Result = "Franklin+and+Bash")]
|
||||
public string should_replace_some_special_characters(string input)
|
||||
{
|
||||
Subject.SceneTitle = input;
|
||||
return Subject.QueryTitle;
|
||||
Subject.SceneTitles = new List<string> { input };
|
||||
return Subject.QueryTitles.First();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Indexers.Newznab;
|
||||
|
@ -22,7 +20,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||
{
|
||||
_indexers = new List<IIndexer>();
|
||||
|
||||
_indexers.Add(new Newznab());
|
||||
_indexers.Add(Mocker.GetMock<Newznab>().Object);
|
||||
_indexers.Add(new Omgwtfnzbs());
|
||||
_indexers.Add(new Wombles());
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ using FizzWare.NBuilder;
|
|||
using FluentValidation.Results;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
|
@ -38,7 +37,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||
indexer.Setup(s => s.Parser.Process(It.IsAny<String>(), It.IsAny<String>()))
|
||||
.Returns(results);
|
||||
|
||||
indexer.Setup(s => s.GetSeasonSearchUrls(It.IsAny<String>(), It.IsAny<Int32>(), It.IsAny<Int32>(), It.IsAny<Int32>()))
|
||||
indexer.Setup(s => s.GetSeasonSearchUrls(It.IsAny<List<String>>(), It.IsAny<Int32>(), It.IsAny<Int32>(), It.IsAny<Int32>()))
|
||||
.Returns(new List<string> { "http://www.nzbdrone.com" });
|
||||
|
||||
indexer.SetupGet(s => s.SupportedPageSize).Returns(paging ? 100 : 0);
|
||||
|
@ -56,7 +55,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||
public void should_not_use_offset_if_result_count_is_less_than_90()
|
||||
{
|
||||
var indexer = WithIndexer(true, 25);
|
||||
Subject.Fetch(indexer, new SeasonSearchCriteria { Series = _series, SceneTitle = _series.Title });
|
||||
Subject.Fetch(indexer, new SeasonSearchCriteria { Series = _series, SceneTitles = new List<string>{_series.Title} });
|
||||
|
||||
Mocker.GetMock<IHttpProvider>().Verify(v => v.DownloadString(It.IsAny<String>()), Times.Once());
|
||||
}
|
||||
|
@ -65,7 +64,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||
public void should_not_use_offset_for_sites_that_do_not_support_it()
|
||||
{
|
||||
var indexer = WithIndexer(false, 125);
|
||||
Subject.Fetch(indexer, new SeasonSearchCriteria { Series = _series, SceneTitle = _series.Title });
|
||||
Subject.Fetch(indexer, new SeasonSearchCriteria { Series = _series, SceneTitles = new List<string> { _series.Title } });
|
||||
|
||||
Mocker.GetMock<IHttpProvider>().Verify(v => v.DownloadString(It.IsAny<String>()), Times.Once());
|
||||
}
|
||||
|
@ -74,7 +73,7 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||
public void should_not_use_offset_if_its_already_tried_10_times()
|
||||
{
|
||||
var indexer = WithIndexer(true, 100);
|
||||
Subject.Fetch(indexer, new SeasonSearchCriteria { Series = _series, SceneTitle = _series.Title });
|
||||
Subject.Fetch(indexer, new SeasonSearchCriteria { Series = _series, SceneTitles = new List<string> { _series.Title } });
|
||||
|
||||
Mocker.GetMock<IHttpProvider>().Verify(v => v.DownloadString(It.IsAny<String>()), Times.Exactly(10));
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace NzbDrone.Core.Test.MetadataSourceTests
|
|||
|
||||
[TestCase(75978)]
|
||||
[TestCase(83462)]
|
||||
[TestCase(266189)]
|
||||
public void should_be_able_to_get_series_detail(int tvdbId)
|
||||
{
|
||||
var details = Subject.GetSeriesInfo(tvdbId);
|
||||
|
@ -56,11 +57,20 @@ namespace NzbDrone.Core.Test.MetadataSourceTests
|
|||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_have_period_at_start_of_title_slug()
|
||||
{
|
||||
var details = Subject.GetSeriesInfo(79099);
|
||||
|
||||
details.Item1.TitleSlug.Should().Be("dothack");
|
||||
}
|
||||
|
||||
private void ValidateSeries(Series series)
|
||||
{
|
||||
series.Should().NotBeNull();
|
||||
series.Title.Should().NotBeBlank();
|
||||
series.CleanTitle.Should().Be(Parser.Parser.CleanSeriesTitle(series.Title));
|
||||
series.SortTitle.Should().Be(Parser.Parser.NormalizeEpisodeTitle(series.Title));
|
||||
series.Overview.Should().NotBeBlank();
|
||||
series.AirTime.Should().NotBeBlank();
|
||||
series.FirstAired.Should().HaveValue();
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.MetadataSource.Tvdb;
|
||||
using NzbDrone.Core.Rest;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Test.Common.Categories;
|
||||
|
||||
namespace NzbDrone.Core.Test.MetadataSourceTests
|
||||
{
|
||||
[TestFixture]
|
||||
[IntegrationTest]
|
||||
public class TvdbProxyFixture : CoreTest<TvdbProxy>
|
||||
{
|
||||
// [TestCase("The Simpsons", "The Simpsons")]
|
||||
// [TestCase("South Park", "South Park")]
|
||||
// [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);
|
||||
//
|
||||
// result.Should().NotBeEmpty();
|
||||
//
|
||||
// result[0].Title.Should().Be(expected);
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void no_search_result()
|
||||
// {
|
||||
// var result = Subject.SearchForNewSeries(Guid.NewGuid().ToString());
|
||||
// result.Should().BeEmpty();
|
||||
// }
|
||||
|
||||
[TestCase(88031)]
|
||||
[TestCase(179321)]
|
||||
public void should_be_able_to_get_series_detail(int tvdbId)
|
||||
{
|
||||
var details = Subject.GetSeriesInfo(tvdbId);
|
||||
|
||||
//ValidateSeries(details.Item1);
|
||||
ValidateEpisodes(details.Item2);
|
||||
}
|
||||
|
||||
// [Test]
|
||||
// public void getting_details_of_invalid_series()
|
||||
// {
|
||||
// Assert.Throws<RestException>(() => Subject.GetSeriesInfo(Int32.MaxValue));
|
||||
//
|
||||
// ExceptionVerification.ExpectedWarns(1);
|
||||
// }
|
||||
//
|
||||
// [Test]
|
||||
// public void should_not_have_period_at_start_of_title_slug()
|
||||
// {
|
||||
// var details = Subject.GetSeriesInfo(79099);
|
||||
//
|
||||
// details.Item1.TitleSlug.Should().Be("dothack");
|
||||
// }
|
||||
|
||||
private void ValidateSeries(Series series)
|
||||
{
|
||||
series.Should().NotBeNull();
|
||||
series.Title.Should().NotBeBlank();
|
||||
series.CleanTitle.Should().Be(Parser.Parser.CleanSeriesTitle(series.Title));
|
||||
series.Overview.Should().NotBeBlank();
|
||||
series.AirTime.Should().NotBeBlank();
|
||||
series.FirstAired.Should().HaveValue();
|
||||
series.FirstAired.Value.Kind.Should().Be(DateTimeKind.Utc);
|
||||
series.Images.Should().NotBeEmpty();
|
||||
series.ImdbId.Should().NotBeBlank();
|
||||
series.Network.Should().NotBeBlank();
|
||||
series.Runtime.Should().BeGreaterThan(0);
|
||||
series.TitleSlug.Should().NotBeBlank();
|
||||
series.TvRageId.Should().BeGreaterThan(0);
|
||||
series.TvdbId.Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
private void ValidateEpisodes(List<Episode> episodes)
|
||||
{
|
||||
episodes.Should().NotBeEmpty();
|
||||
|
||||
episodes.GroupBy(e => e.SeasonNumber.ToString("000") + e.EpisodeNumber.ToString("000"))
|
||||
.Max(e => e.Count()).Should().Be(1);
|
||||
|
||||
episodes.Should().Contain(c => c.SeasonNumber > 0);
|
||||
// episodes.Should().Contain(c => !string.IsNullOrWhiteSpace(c.Overview));
|
||||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
ValidateEpisode(episode);
|
||||
|
||||
//if atleast one episdoe has title it means parse it working.
|
||||
// episodes.Should().Contain(c => !string.IsNullOrWhiteSpace(c.Title));
|
||||
}
|
||||
}
|
||||
|
||||
private void ValidateEpisode(Episode episode)
|
||||
{
|
||||
episode.Should().NotBeNull();
|
||||
|
||||
//TODO: Is there a better way to validate that episode number or season number is greater than zero?
|
||||
(episode.EpisodeNumber + episode.SeasonNumber).Should().NotBe(0);
|
||||
|
||||
episode.Should().NotBeNull();
|
||||
|
||||
// if (episode.AirDateUtc.HasValue)
|
||||
// {
|
||||
// episode.AirDateUtc.Value.Kind.Should().Be(DateTimeKind.Utc);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -114,7 +114,7 @@
|
|||
<Compile Include="DecisionEngineTests\RssSync\ProperSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\Search\SeriesSpecificationFixture.cs" />
|
||||
<Compile Include="Download\DownloadApprovedReportsTests\DownloadApprovedFixture.cs" />
|
||||
<Compile Include="Download\DownloadApprovedReportsTests\GetQualifiedReportsFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\PrioritizeDownloadDecisionFixture.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\Blackhole\UsenetBlackholeFixture.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\DownloadClientFixtureBase.cs" />
|
||||
<Compile Include="Download\DownloadClientTests\NzbgetTests\NzbgetFixture.cs" />
|
||||
|
@ -173,6 +173,7 @@
|
|||
<Compile Include="Messaging\Commands\CommandExecutorFixture.cs" />
|
||||
<Compile Include="Messaging\Commands\CommandFixture.cs" />
|
||||
<Compile Include="Messaging\Events\EventAggregatorFixture.cs" />
|
||||
<Compile Include="MetadataSourceTests\TvdbProxyFixture.cs" />
|
||||
<Compile Include="MetadataSourceTests\TraktProxyFixture.cs" />
|
||||
<Compile Include="Metadata\Consumers\Roksbox\FindMetadataFileFixture.cs" />
|
||||
<Compile Include="Metadata\Consumers\Wdtv\FindMetadataFileFixture.cs" />
|
||||
|
@ -189,6 +190,7 @@
|
|||
<Compile Include="OrganizerTests\BuildFilePathFixture.cs" />
|
||||
<Compile Include="OrganizerTests\GetSeriesFolderFixture.cs" />
|
||||
<Compile Include="ParserTests\AbsoluteEpisodeNumberParserFixture.cs" />
|
||||
<Compile Include="ParserTests\AnimeMetadataParserFixture.cs" />
|
||||
<Compile Include="ParserTests\IsPossibleSpecialEpisodeFixture.cs" />
|
||||
<Compile Include="ParserTests\ReleaseGroupParserFixture.cs" />
|
||||
<Compile Include="ParserTests\LanguageParserFixture.cs" />
|
||||
|
@ -249,7 +251,7 @@
|
|||
<Compile Include="TvTests\EpisodeProviderTests\EpisodeProviderTest_GetEpisodesByParseResult.cs" />
|
||||
<Compile Include="FluentTest.cs" />
|
||||
<Compile Include="InstrumentationTests\DatabaseTargetFixture.cs" />
|
||||
<Compile Include="OrganizerTests\GetNewFilenameFixture.cs" />
|
||||
<Compile Include="OrganizerTests\FileNameBuilderFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\MonitoredEpisodeSpecificationFixture.cs" />
|
||||
<Compile Include="DecisionEngineTests\DownloadDecisionMakerFixture.cs" />
|
||||
<Compile Include="Qualities\QualityModelComparerFixture.cs" />
|
||||
|
|
|
@ -42,12 +42,14 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
.With(e => e.Title = "City Sushi")
|
||||
.With(e => e.SeasonNumber = 15)
|
||||
.With(e => e.EpisodeNumber = 6)
|
||||
.With(e => e.AbsoluteEpisodeNumber = 100)
|
||||
.Build();
|
||||
|
||||
_episode2 = Builder<Episode>.CreateNew()
|
||||
.With(e => e.Title = "City Sushi")
|
||||
.With(e => e.SeasonNumber = 15)
|
||||
.With(e => e.EpisodeNumber = 7)
|
||||
.With(e => e.AbsoluteEpisodeNumber = 101)
|
||||
.Build();
|
||||
|
||||
_episodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV720p), ReleaseGroup = "DRONE" };
|
||||
|
@ -435,5 +437,78 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
Subject.BuildFilename(new List<Episode> { episode }, new Series { Title = "Chicago P.D.." }, _episodeFile)
|
||||
.Should().Be("Chicago.P.D.S06E06.Part.1");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_replace_absolute_numbering_when_series_is_not_anime()
|
||||
{
|
||||
_namingConfig.StandardEpisodeFormat = "{Series.Title}.S{season:00}E{episode:00}.{absolute:00}.{Episode.Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.S15E06.City.Sushi");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_replace_standard_and_absolute_numbering_when_series_is_anime()
|
||||
{
|
||||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series.Title}.S{season:00}E{episode:00}.{absolute:00}.{Episode.Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.S15E06.100.City.Sushi");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_replace_standard_numbering_when_series_is_anime()
|
||||
{
|
||||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series.Title}.S{season:00}E{episode:00}.{Episode.Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.S15E06.City.Sushi");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_replace_absolute_numbering_when_series_is_anime()
|
||||
{
|
||||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series.Title}.{absolute:00}.{Episode.Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("South.Park.100.City.Sushi");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_dash_as_separator_when_multi_episode_style_is_extend_for_anime()
|
||||
{
|
||||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series Title} - {absolute:000} - {Episode Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
.Should().Be("South Park - 100-101 - City Sushi");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_standard_naming_when_anime_episode_has_absolute_number_of_zero()
|
||||
{
|
||||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_episode1.AbsoluteEpisodeNumber = 0;
|
||||
|
||||
_namingConfig.StandardEpisodeFormat = "{Series Title} - {season:0}x{episode:00} - {Episode Title}";
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series Title} - {absolute:000} - {Episode Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1, }, _series, _episodeFile)
|
||||
.Should().Be("South Park - 15x06 - City Sushi");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_duplicate_absolute_pattern_when_multi_episode_style_is_duplicate()
|
||||
{
|
||||
_series.SeriesType = SeriesTypes.Anime;
|
||||
_namingConfig.MultiEpisodeStyle = (int)MultiEpisodeStyle.Duplicate;
|
||||
_namingConfig.AnimeEpisodeFormat = "{Series Title} - {absolute:000} - {Episode Title}";
|
||||
|
||||
Subject.BuildFilename(new List<Episode> { _episode1, _episode2 }, _series, _episodeFile)
|
||||
.Should().Be("South Park - 100 - 101 - City Sushi");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,6 +34,38 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[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)]
|
||||
[TestCase("[Underwater-FFF] No Game No Life - 01 (720p) [27AAA0A0].mkv", "No Game No Life", 1, 0, 0)]
|
||||
[TestCase("[FroZen] Miyuki - 23 [DVD][7F6170E6]", "Miyuki", 23, 0, 0)]
|
||||
[TestCase("[Commie] Yowamushi Pedal - 32 [0BA19D5B]", "Yowamushi Pedal", 32, 0, 0)]
|
||||
[TestCase("[Doki] Mahouka Koukou no Rettousei - 07 (1280x720 Hi10P AAC) [80AF7DDE]", "Mahouka Koukou no Rettousei", 7, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Yowamushi Pedal - 32 [480p]", "Yowamushi Pedal", 32, 0, 0)]
|
||||
[TestCase("[CR] Sailor Moon - 004 [480p][48CE2D0F]", "Sailor Moon", 4, 0, 0)]
|
||||
[TestCase("[Chibiki] Puchimas!! - 42 [360p][7A4FC77B]", "Puchimas", 42, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Yowamushi Pedal - 32 [1080p]", "Yowamushi Pedal", 32, 0, 0)]
|
||||
[TestCase("[HorribleSubs] Love Live! S2 - 07 [720p]", "Love Live! S2", 7, 0, 0)]
|
||||
[TestCase("[DeadFish] Onee-chan ga Kita - 09v2 [720p][AAC]", "Onee-chan ga Kita", 9, 0, 0)]
|
||||
[TestCase("[Underwater-FFF] No Game No Life - 01 (720p) [27AAA0A0]", "No Game No Life", 1, 0, 0)]
|
||||
[TestCase("[S-T-D] Soul Eater Not! - 06 (1280x720 10bit AAC) [59B3F2EA].mkv", "Soul Eater Not!", 6, 0, 0)]
|
||||
[TestCase("[Underwater-FFF] No Game No Life - 01 (720p) [27AAA0A0].mkv", "No Game No Life", 1, 0, 0)]
|
||||
[TestCase("No Game No Life - 010 (720p) [27AAA0A0].mkv", "No Game No Life", 10, 0, 0)]
|
||||
[TestCase("Initial D Fifth Stage - 01 DVD - Central Anime", "Initial D Fifth Stage", 1, 0, 0)]
|
||||
[TestCase("Initial_D_Fifth_Stage_-_01(DVD)_-_(Central_Anime)[5AF6F1E4].mkv", "Initial D Fifth Stage", 1, 0, 0)]
|
||||
[TestCase("Initial_D_Fifth_Stage_-_02(DVD)_-_(Central_Anime)[0CA65F00].mkv", "Initial D Fifth Stage", 2, 0, 0)]
|
||||
[TestCase("Initial D Fifth Stage - 03 DVD - Central Anime", "Initial D Fifth Stage", 3, 0, 0)]
|
||||
[TestCase("Initial_D_Fifth_Stage_-_03(DVD)_-_(Central_Anime)[629BD592].mkv", "Initial D Fifth Stage", 3, 0, 0)]
|
||||
[TestCase("Initial D Fifth Stage - 14 DVD - Central Anime", "Initial D Fifth Stage", 14, 0, 0)]
|
||||
[TestCase("Initial_D_Fifth_Stage_-_14(DVD)_-_(Central_Anime)[0183D922].mkv", "Initial D Fifth Stage", 14, 0, 0)]
|
||||
// [TestCase("Initial D - 4th Stage Ep 01.mkv", "Initial D - 4th Stage", 1, 0, 0)]
|
||||
[TestCase("[ChihiroDesuYo].No.Game.No.Life.-.09.1280x720.10bit.AAC.[24CCE81D]", "No.Game.No.Life", 9, 0, 0)]
|
||||
[TestCase("Fairy Tail - 001 - Fairy Tail", "Fairy Tail", 001, 0, 0)]
|
||||
[TestCase("Fairy Tail - 049 - The Day of Fated Meeting", "Fairy Tail", 049, 0, 0)]
|
||||
[TestCase("Fairy Tail - 050 - Special Request Watch Out for the Guy You Like!", "Fairy Tail", 050, 0, 0)]
|
||||
[TestCase("Fairy Tail - 099 - Natsu vs. Gildarts", "Fairy Tail", 099, 0, 0)]
|
||||
[TestCase("Fairy Tail - 100 - Mest", "Fairy Tail", 100, 0, 0)]
|
||||
// [TestCase("Fairy Tail - 101 - Mest", "Fairy Tail", 101, 0, 0)] //This gets caught up in the 'see' numbering
|
||||
[TestCase("[Exiled-Destiny] Angel Beats Ep01 (D2201EC5).mkv", "Angel Beats!", 1, 0, 0)]
|
||||
[TestCase("[Commie] Nobunaga the Fool - 23 [5396CA24].mkv", "Nobunaga the Fool", 23, 0, 0)]
|
||||
[TestCase("[FFF] Seikoku no Dragonar - 01 [1FB538B5].mkv", "Seikoku no Dragonar", 1, 0, 0)]
|
||||
[TestCase("[Hatsuyuki]Fate_Zero-01[1280x720][122E6EF8]", "Fate/Zero", 1, 0, 0)]
|
||||
public void should_parse_absolute_numbers(string postTitle, string title, int absoluteEpisodeNumber, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
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 AnimeMetadataParserFixture : CoreTest
|
||||
{
|
||||
[TestCase("[SubDESU]_High_School_DxD_07_(1280x720_x264-AAC)_[6B7FD717]", "SubDESU", "6B7FD717")]
|
||||
[TestCase("[Chihiro]_Working!!_-_06_[848x480_H.264_AAC][859EEAFA]", "Chihiro", "859EEAFA")]
|
||||
[TestCase("[Underwater]_Rinne_no_Lagrange_-_12_(720p)_[5C7BC4F9]", "Underwater", "5C7BC4F9")]
|
||||
[TestCase("[HorribleSubs]_Hunter_X_Hunter_-_33_[720p]", "HorribleSubs", "")]
|
||||
[TestCase("[HorribleSubs] Tonari no Kaibutsu-kun - 13 [1080p].mkv", "HorribleSubs", "")]
|
||||
[TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].[C65D4B1F].mkv", "Doremi", "C65D4B1F")]
|
||||
[TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].[C65D4B1F]", "Doremi", "C65D4B1F")]
|
||||
[TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].mkv", "Doremi", "")]
|
||||
[TestCase("[K-F] One Piece 214", "K-F", "")]
|
||||
[TestCase("[K-F] One Piece S10E14 214", "K-F", "")]
|
||||
[TestCase("[K-F] One Piece 10x14 214", "K-F", "")]
|
||||
[TestCase("[K-F] One Piece 214 10x14", "K-F", "")]
|
||||
[TestCase("Bleach - 031 - The Resolution to Kill [Lunar].avi", "Lunar", "")]
|
||||
[TestCase("[ACX]Hack Sign 01 Role Play [Kosaka] [9C57891E].mkv", "ACX", "9C57891E")]
|
||||
[TestCase("[S-T-D] Soul Eater Not! - 06 (1280x720 10bit AAC) [59B3F2EA].mkv", "S-T-D", "59B3F2EA")]
|
||||
public void should_parse_absolute_numbers(string postTitle, string subGroup, string hash)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
result.Should().NotBeNull();
|
||||
result.ReleaseGroup.Should().Be(subGroup);
|
||||
result.ReleaseHash.Should().Be(hash);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("0e895c37245186812cb08aab1529cf8ee389dd05.mkv")]
|
||||
[TestCase("08bbc153931ce3ca5fcafe1b92d3297285feb061.mkv")]
|
||||
[TestCase("185d86a343e39f3341e35c4dad3ff159")]
|
||||
[TestCase("ah63jka93jf0jh26ahjas961.mkv")]
|
||||
public void should_not_parse_crap(string title)
|
||||
{
|
||||
Parser.Parser.ParseTitle(title).Should().BeNull();
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
SeriesTitle = ""
|
||||
};
|
||||
|
||||
parsedEpisodeInfo.IsPossibleSpecialEpisode().Should().BeFalse();
|
||||
parsedEpisodeInfo.IsPossibleSpecialEpisode.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -33,7 +33,15 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
SeriesTitle = ""
|
||||
};
|
||||
|
||||
parsedEpisodeInfo.IsPossibleSpecialEpisode().Should().BeTrue();
|
||||
parsedEpisodeInfo.IsPossibleSpecialEpisode.Should().BeTrue();
|
||||
}
|
||||
|
||||
[TestCase("Under.the.Dome.S02.Special-Inside.Chesters.Mill.HDTV.x264-BAJSKORV")]
|
||||
[TestCase("Under.the.Dome.S02.Special-Inside.Chesters.Mill.720p.HDTV.x264-BAJSKORV")]
|
||||
[TestCase("Rookie.Blue.Behind.the.Badge.S05.Special.HDTV.x264-2HD")]
|
||||
public void IsPossibleSpecialEpisode_should_be_true(string title)
|
||||
{
|
||||
Parser.Parser.ParseTitle(title).IsPossibleSpecialEpisode.Should().BeTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,9 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Sonny.With.a.Chance.S02E15.divx", false)]
|
||||
[TestCase("The.Girls.Next.Door.S03E06.HDTV-WiDE", false)]
|
||||
[TestCase("Degrassi.S10E27.WS.DSR.XviD-2HD", false)]
|
||||
[TestCase("[HorribleSubs] Yowamushi Pedal - 32 [480p]", false)]
|
||||
[TestCase("[CR] Sailor Moon - 004 [480p][48CE2D0F]", false)]
|
||||
[TestCase("[Hatsuyuki] Naruto Shippuuden - 363 [848x480][ADE35E38]", false)]
|
||||
public void should_parse_sdtv_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.SDTV, proper);
|
||||
|
@ -69,8 +72,10 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("The.Girls.Next.Door.S03E06.DVD.Rip.XviD-WiDE", false)]
|
||||
[TestCase("the.shield.1x13.circles.ws.xvidvd-tns", false)]
|
||||
[TestCase("the_x-files.9x18.sunshine_days.ac3.ws_dvdrip_xvid-fov.avi", false)]
|
||||
[TestCase("[FroZen] Miyuki - 23 [DVD][7F6170E6]", false)]
|
||||
[TestCase("Hannibal.S01E05.576p.BluRay.DD5.1.x264-HiSD", false)]
|
||||
[TestCase("Hannibal.S01E05.480p.BluRay.DD5.1.x264-HiSD", false)]
|
||||
[TestCase("Heidi Girl of the Alps (BD)(640x480(RAW) (BATCH 1) (1-13)", false)]
|
||||
public void should_parse_dvd_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.DVD, proper);
|
||||
|
@ -96,6 +101,13 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Sonny.With.a.Chance.S02E15.mkv", false)]
|
||||
[TestCase(@"E:\Downloads\tv\The.Big.Bang.Theory.S01E01.720p.HDTV\ajifajjjeaeaeqwer_eppj.avi", false)]
|
||||
[TestCase("Gem.Hunt.S01E08.Tourmaline.Nepal.720p.HDTV.x264-DHD", false)]
|
||||
[TestCase("[Underwater-FFF] No Game No Life - 01 (720p) [27AAA0A0]", false)]
|
||||
[TestCase("[Doki] Mahouka Koukou no Rettousei - 07 (1280x720 Hi10P AAC) [80AF7DDE]", false)]
|
||||
[TestCase("[Doremi].Yes.Pretty.Cure.5.Go.Go!.31.[1280x720].[C65D4B1F].mkv", false)]
|
||||
[TestCase("[HorribleSubs]_Fairy_Tail_-_145_[720p]", false)]
|
||||
[TestCase("[Eveyuu] No Game No Life - 10 [Hi10P 1280x720 H264][10B23BD8]", false)]
|
||||
[TestCase("Hells.Kitchen.US.S12E17.HR.WS.PDTV.X264-DIMENSION", false)]
|
||||
[TestCase("Survivorman.The.Lost.Pilots.Summer.HR.WS.PDTV.x264-DHD", false)]
|
||||
public void should_parse_hdtv720p_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.HDTV720p, proper);
|
||||
|
@ -106,6 +118,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("DEXTER.S07E01.ARE.YOU.1080P.HDTV.x264-QCF", false)]
|
||||
[TestCase("DEXTER.S07E01.ARE.YOU.1080P.HDTV.proper.X264-QCF", true)]
|
||||
[TestCase("Dexter - S01E01 - Title [HDTV-1080p]", false)]
|
||||
[TestCase("[HorribleSubs] Yowamushi Pedal - 32 [1080p]", false)]
|
||||
public void should_parse_hdtv1080p_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.HDTV1080p, proper);
|
||||
|
@ -144,6 +157,12 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Chuck - S01E03 - Come Fly With Me - 720p BluRay.mkv", false)]
|
||||
[TestCase("The Big Bang Theory.S03E01.The Electric Can Opener Fluctuation.m2ts", false)]
|
||||
[TestCase("Revolution.S01E02.Chained.Heat.[Bluray720p].mkv", false)]
|
||||
[TestCase("[FFF] DATE A LIVE - 01 [BD][720p-AAC][0601BED4]", false)]
|
||||
[TestCase("[coldhell] Pupa v3 [BD720p][03192D4C]", false)]
|
||||
[TestCase("[RandomRemux] Nobunagun - 01 [720p BD][043EA407].mkv", false)]
|
||||
[TestCase("[Kaylith] Isshuukan Friends Specials - 01 [BD 720p AAC][B7EEE164].mkv", false)]
|
||||
[TestCase("WEEDS.S03E01-06.DUAL.Blu-ray.AC3.-HELLYWOOD.avi", false)]
|
||||
[TestCase("WEEDS.S03E01-06.DUAL.720p.Blu-ray.AC3.-HELLYWOOD.avi", false)]
|
||||
public void should_parse_bluray720p_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.Bluray720p, proper);
|
||||
|
@ -152,6 +171,12 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Chuck - S01E03 - Come Fly With Me - 1080p BluRay.mkv", false)]
|
||||
[TestCase("Sons.Of.Anarchy.S02E13.1080p.BluRay.x264-AVCDVD", false)]
|
||||
[TestCase("Revolution.S01E02.Chained.Heat.[Bluray1080p].mkv", false)]
|
||||
[TestCase("[FFF] Namiuchigiwa no Muromi-san - 10 [BD][1080p-FLAC][0C4091AF]", false)]
|
||||
[TestCase("[coldhell] Pupa v2 [BD1080p][5A45EABE].mkv", false)]
|
||||
[TestCase("[Kaylith] Isshuukan Friends Specials - 01 [BD 1080p FLAC][429FD8C7].mkv", false)]
|
||||
[TestCase("[Zurako] Log Horizon - 01 - The Apocalypse (BD 1080p AAC) [7AE12174].mkv", false)]
|
||||
[TestCase("WEEDS.S03E01-06.DUAL.1080p.Blu-ray.AC3.-HELLYWOOD.avi", false)]
|
||||
[TestCase("[Coalgirls]_Durarara!!_01_(1920x1080_Blu-ray_FLAC)_[8370CB8F].mkv", false)]
|
||||
public void should_parse_bluray1080p_quality(string title, bool proper)
|
||||
{
|
||||
ParseAndVerifyQuality(title, Quality.Bluray1080p, proper);
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||
[TestCase("Eureka S 01 720p WEB DL DD 5 1 h264 TjHD", "Eureka", 1)]
|
||||
[TestCase("Doctor Who Confidential Season 3", "Doctor Who Confidential", 3)]
|
||||
[TestCase("Fleming.S01.720p.WEBDL.DD5.1.H.264-NTb", "Fleming", 1)]
|
||||
public void should_parsefull_season_release(string postTitle, string title, int season)
|
||||
public void should_parse_full_season_release(string postTitle, string title, int season)
|
||||
{
|
||||
var result = Parser.Parser.ParseTitle(postTitle);
|
||||
result.SeasonNumber.Should().Be(season);
|
||||
|
|
|
@ -25,18 +25,6 @@ using System.Runtime.InteropServices;
|
|||
|
||||
[assembly: Guid("699aed1b-015e-4f0d-9c81-d5557b05d260")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyVersion("10.0.0.*")]
|
||||
[assembly: AssemblyFileVersion("10.0.0.*")]
|
||||
|
||||
[assembly: InternalsVisibleTo("NzbDrone.Core")]
|
|
@ -18,7 +18,7 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests
|
|||
|
||||
private void WithExpired()
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>().Setup(s => s.FolderGetLastWrite(It.IsAny<String>()))
|
||||
Mocker.GetMock<IDiskProvider>().Setup(s => s.FolderGetLastWriteUtc(It.IsAny<String>()))
|
||||
.Returns(DateTime.UtcNow.AddDays(-10));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(s => s.FileGetLastWriteUtc(It.IsAny<String>()))
|
||||
|
@ -27,7 +27,7 @@ namespace NzbDrone.Core.Test.ProviderTests.RecycleBinProviderTests
|
|||
|
||||
private void WithNonExpired()
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>().Setup(s => s.FolderGetLastWrite(It.IsAny<String>()))
|
||||
Mocker.GetMock<IDiskProvider>().Setup(s => s.FolderGetLastWriteUtc(It.IsAny<String>()))
|
||||
.Returns(DateTime.UtcNow.AddDays(-3));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(s => s.FileGetLastWriteUtc(It.IsAny<String>()))
|
||||
|
|
|
@ -23,13 +23,10 @@ namespace NzbDrone.Core.Test.Providers
|
|||
{
|
||||
var ids = Subject.GetXemSeriesIds();
|
||||
|
||||
|
||||
ids.Should().NotBeEmpty();
|
||||
ids.Should().Contain(i => i == 73141);
|
||||
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
[Ignore("XEM's data is not clean")]
|
||||
public void get_mapping_for_all_series()
|
||||
|
@ -45,7 +42,7 @@ namespace NzbDrone.Core.Test.Providers
|
|||
}
|
||||
|
||||
[TestCase(12345, Description = "invalid id")]
|
||||
[TestCase(267440, Description = "no single connection")]
|
||||
[TestCase(279042, Description = "no single connection")]
|
||||
public void should_return_empty_when_known_error(int id)
|
||||
{
|
||||
Subject.GetSceneTvdbMappings(id).Should().BeEmpty();
|
||||
|
@ -62,7 +59,6 @@ namespace NzbDrone.Core.Test.Providers
|
|||
result.Should().OnlyContain(c => c.Tvdb != null);
|
||||
}
|
||||
|
||||
|
||||
[TestCase(78916)]
|
||||
public void should_filter_out_episodes_without_scene_mapping(int seriesId)
|
||||
{
|
||||
|
|
|
@ -39,6 +39,11 @@ namespace NzbDrone.Core.Test.SeriesStatsTests
|
|||
_episode.EpisodeFileId = 1;
|
||||
}
|
||||
|
||||
private void GivenOldEpisode()
|
||||
{
|
||||
_episode.AirDateUtc = DateTime.Now.AddSeconds(-10);
|
||||
}
|
||||
|
||||
private void GivenMonitoredEpisode()
|
||||
{
|
||||
_episode.Monitored = true;
|
||||
|
@ -59,6 +64,7 @@ namespace NzbDrone.Core.Test.SeriesStatsTests
|
|||
|
||||
stats.Should().HaveCount(1);
|
||||
stats.First().NextAiring.Should().Be(_episode.AirDateUtc);
|
||||
stats.First().PreviousAiring.Should().NotHaveValue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -73,6 +79,47 @@ namespace NzbDrone.Core.Test.SeriesStatsTests
|
|||
stats.First().NextAiring.Should().NotHaveValue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_have_previous_airing_for_old_episode_with_file()
|
||||
{
|
||||
GivenEpisodeWithFile();
|
||||
GivenOldEpisode();
|
||||
GivenFile();
|
||||
|
||||
var stats = Subject.SeriesStatistics();
|
||||
|
||||
stats.Should().HaveCount(1);
|
||||
stats.First().NextAiring.Should().NotHaveValue();
|
||||
stats.First().PreviousAiring.Should().Be(_episode.AirDateUtc);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_have_previous_airing_for_old_episode_without_file_monitored()
|
||||
{
|
||||
GivenMonitoredEpisode();
|
||||
GivenOldEpisode();
|
||||
GivenFile();
|
||||
|
||||
var stats = Subject.SeriesStatistics();
|
||||
|
||||
stats.Should().HaveCount(1);
|
||||
stats.First().NextAiring.Should().NotHaveValue();
|
||||
stats.First().PreviousAiring.Should().Be(_episode.AirDateUtc);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_have_previous_airing_for_old_episode_without_file_unmonitored()
|
||||
{
|
||||
GivenOldEpisode();
|
||||
GivenFile();
|
||||
|
||||
var stats = Subject.SeriesStatistics();
|
||||
|
||||
stats.Should().HaveCount(1);
|
||||
stats.First().NextAiring.Should().NotHaveValue();
|
||||
stats.First().PreviousAiring.Should().NotHaveValue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_include_unmonitored_episode_in_episode_count()
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@ using FluentAssertions;
|
|||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.MetadataSource.Tvdb;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
|
@ -42,6 +43,15 @@ namespace NzbDrone.Core.Test.TvTests
|
|||
return series;
|
||||
}
|
||||
|
||||
private Series GetAnimeSeries()
|
||||
{
|
||||
var series = Builder<Series>.CreateNew().Build();
|
||||
series.SeriesType = SeriesTypes.Anime;
|
||||
series.Seasons = new List<Season>();
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
|
@ -61,11 +71,18 @@ namespace NzbDrone.Core.Test.TvTests
|
|||
.Callback<List<Episode>>(e => _deletedEpisodes = e);
|
||||
}
|
||||
|
||||
private void GivenAnimeEpisodes(List<Episode> episodes)
|
||||
{
|
||||
Mocker.GetMock<ITvdbProxy>()
|
||||
.Setup(s => s.GetEpisodeInfo(It.IsAny<Int32>()))
|
||||
.Returns(episodes);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_create_all_when_no_existing_episodes()
|
||||
{
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), GetEpisodes());
|
||||
|
@ -78,7 +95,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||
[Test]
|
||||
public void should_update_all_when_all_existing_episodes()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(GetEpisodes());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), GetEpisodes());
|
||||
|
@ -91,7 +108,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||
[Test]
|
||||
public void should_delete_all_when_all_existing_episodes_are_gone_from_trakt()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(GetEpisodes());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), new List<Episode>());
|
||||
|
@ -106,7 +123,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||
{
|
||||
var duplicateEpisodes = GetEpisodes().Skip(5).Take(2).ToList();
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(GetEpisodes().Union(duplicateEpisodes).ToList());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), GetEpisodes());
|
||||
|
@ -127,7 +144,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||
|
||||
episodes.ForEach(e => e.Monitored = true);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(episodes);
|
||||
|
||||
Subject.RefreshEpisodeInfo(series, GetEpisodes());
|
||||
|
@ -139,7 +156,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||
[Test]
|
||||
public void should_remove_duplicate_remote_episodes_before_processing()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(5)
|
||||
|
@ -157,21 +174,137 @@ namespace NzbDrone.Core.Test.TvTests
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void should_set_absolute_episode_number()
|
||||
public void should_not_set_absolute_episode_number_for_non_anime()
|
||||
{
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<Episode>());
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetSeries(), GetEpisodes());
|
||||
|
||||
var season1 = _insertedEpisodes.Where(e => e.SeasonNumber == 1 && e.EpisodeNumber > 0);
|
||||
var season2episode1 = _insertedEpisodes.Single(e => e.SeasonNumber == 2 && e.EpisodeNumber == 1);
|
||||
_insertedEpisodes.All(e => e.AbsoluteEpisodeNumber == 0 || !e.AbsoluteEpisodeNumber.HasValue).Should().BeTrue();
|
||||
}
|
||||
|
||||
season2episode1.AbsoluteEpisodeNumber.Should().Be(season1.Count() + 1);
|
||||
[Test]
|
||||
public void should_set_absolute_episode_number_for_anime()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(3).Build().ToList();
|
||||
GivenAnimeEpisodes(episodes);
|
||||
|
||||
_insertedEpisodes.Where(e => e.SeasonNumber > 0 && e.EpisodeNumber > 0).All(e => e.AbsoluteEpisodeNumber > 0).Should().BeTrue();
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes);
|
||||
|
||||
_insertedEpisodes.All(e => e.AbsoluteEpisodeNumber > 0).Should().BeTrue();
|
||||
_updatedEpisodes.Should().BeEmpty();
|
||||
_deletedEpisodes.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_set_absolute_episode_number_even_if_not_previously_set_for_anime()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(3).Build().ToList();
|
||||
GivenAnimeEpisodes(episodes);
|
||||
|
||||
var existingEpisodes = episodes.JsonClone();
|
||||
existingEpisodes.ForEach(e => e.AbsoluteEpisodeNumber = 0);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(existingEpisodes);
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes);
|
||||
|
||||
_insertedEpisodes.Should().BeEmpty();
|
||||
_updatedEpisodes.All(e => e.AbsoluteEpisodeNumber > 0).Should().BeTrue();
|
||||
_deletedEpisodes.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_new_season_and_episode_numbers_when_absolute_episode_number_match_found()
|
||||
{
|
||||
const Int32 expectedSeasonNumber = 10;
|
||||
const Int32 expectedEpisodeNumber = 5;
|
||||
const Int32 expectedAbsoluteNumber = 3;
|
||||
|
||||
var episode = Builder<Episode>.CreateNew()
|
||||
.With(e => e.SeasonNumber = expectedSeasonNumber)
|
||||
.With(e => e.EpisodeNumber = expectedEpisodeNumber)
|
||||
.With(e => e.AbsoluteEpisodeNumber = expectedAbsoluteNumber)
|
||||
.Build();
|
||||
|
||||
GivenAnimeEpisodes(new List<Episode> { episode });
|
||||
|
||||
var existingEpisode = episode.JsonClone();
|
||||
existingEpisode.SeasonNumber = 1;
|
||||
existingEpisode.EpisodeNumber = 1;
|
||||
existingEpisode.AbsoluteEpisodeNumber = expectedAbsoluteNumber;
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(new List<Episode>{ existingEpisode });
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), new List<Episode> { episode });
|
||||
|
||||
_insertedEpisodes.Should().BeEmpty();
|
||||
_deletedEpisodes.Should().BeEmpty();
|
||||
|
||||
_updatedEpisodes.First().SeasonNumber.Should().Be(expectedSeasonNumber);
|
||||
_updatedEpisodes.First().EpisodeNumber.Should().Be(expectedEpisodeNumber);
|
||||
_updatedEpisodes.First().AbsoluteEpisodeNumber.Should().Be(expectedAbsoluteNumber);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_prefer_absolute_match_over_season_and_epsiode_match()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(2)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
episodes[0].AbsoluteEpisodeNumber = 0;
|
||||
episodes[0].SeasonNumber.Should().NotBe(episodes[1].SeasonNumber);
|
||||
episodes[0].EpisodeNumber.Should().NotBe(episodes[1].EpisodeNumber);
|
||||
episodes[0].AbsoluteEpisodeNumber.Should().NotBe(episodes[1].AbsoluteEpisodeNumber);
|
||||
|
||||
GivenAnimeEpisodes(episodes);
|
||||
|
||||
var existingEpisode = new Episode
|
||||
{
|
||||
SeasonNumber = episodes[0].SeasonNumber,
|
||||
EpisodeNumber = episodes[0].EpisodeNumber,
|
||||
AbsoluteEpisodeNumber = episodes[1].AbsoluteEpisodeNumber
|
||||
};
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(new List<Episode> { existingEpisode });
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes);
|
||||
|
||||
_updatedEpisodes.First().SeasonNumber.Should().Be(episodes[1].SeasonNumber);
|
||||
_updatedEpisodes.First().EpisodeNumber.Should().Be(episodes[1].EpisodeNumber);
|
||||
_updatedEpisodes.First().AbsoluteEpisodeNumber.Should().Be(episodes[1].AbsoluteEpisodeNumber);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_ignore_episodes_with_absolute_episode_of_zero_in_distinct_by_absolute()
|
||||
{
|
||||
var episodes = Builder<Episode>.CreateListOfSize(10)
|
||||
.Build()
|
||||
.ToList();
|
||||
|
||||
episodes[0].AbsoluteEpisodeNumber = 0;
|
||||
episodes[1].AbsoluteEpisodeNumber = 0;
|
||||
episodes[2].AbsoluteEpisodeNumber = 0;
|
||||
episodes[3].AbsoluteEpisodeNumber = 0;
|
||||
episodes[4].AbsoluteEpisodeNumber = 0;
|
||||
|
||||
GivenAnimeEpisodes(episodes);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>().Setup(c => c.GetEpisodeBySeries(It.IsAny<Int32>()))
|
||||
.Returns(new List<Episode>());
|
||||
|
||||
Subject.RefreshEpisodeInfo(GetAnimeSeries(), episodes);
|
||||
|
||||
_insertedEpisodes.Should().HaveCount(episodes.Count);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,12 +49,12 @@ namespace NzbDrone.Core.Test.TvTests
|
|||
[Test]
|
||||
public void should_monitor_new_seasons_automatically()
|
||||
{
|
||||
var series = _series.JsonClone();
|
||||
series.Seasons.Add(Builder<Season>.CreateNew()
|
||||
var newSeriesInfo = _series.JsonClone();
|
||||
newSeriesInfo.Seasons.Add(Builder<Season>.CreateNew()
|
||||
.With(s => s.SeasonNumber = 2)
|
||||
.Build());
|
||||
|
||||
GivenNewSeriesInfo(series);
|
||||
GivenNewSeriesInfo(newSeriesInfo);
|
||||
|
||||
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
||||
|
||||
|
@ -77,5 +77,19 @@ namespace NzbDrone.Core.Test.TvTests
|
|||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Seasons.Count == 2 && s.Seasons.Single(season => season.SeasonNumber == 0).Monitored == false)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_tvrage_id_if_changed()
|
||||
{
|
||||
var newSeriesInfo = _series.JsonClone();
|
||||
newSeriesInfo.TvRageId = _series.TvRageId + 1;
|
||||
|
||||
GivenNewSeriesInfo(newSeriesInfo);
|
||||
|
||||
Subject.Execute(new RefreshSeriesCommand(_series.Id));
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.TvRageId == newSeriesInfo.TvRageId)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,12 @@ namespace NzbDrone.Core.Annotations
|
|||
Order = order;
|
||||
}
|
||||
|
||||
public int Order { get; private set; }
|
||||
public string Label { get; set; }
|
||||
public string HelpText { get; set; }
|
||||
public string HelpLink { get; set; }
|
||||
public Int32 Order { get; private set; }
|
||||
public String Label { get; set; }
|
||||
public String HelpText { get; set; }
|
||||
public String HelpLink { get; set; }
|
||||
public FieldType Type { get; set; }
|
||||
public Boolean Advanced { get; set; }
|
||||
public Type SelectOptions { get; set; }
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Backup
|
||||
{
|
||||
public class Backup
|
||||
{
|
||||
public String Path { get; set; }
|
||||
public BackupType Type { get; set; }
|
||||
public DateTime Time { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Backup
|
||||
{
|
||||
public class BackupCommand : Command
|
||||
{
|
||||
public BackupType Type { get; set; }
|
||||
|
||||
public override bool SendUpdatesToClient
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum BackupType
|
||||
{
|
||||
Scheduled = 0 ,
|
||||
Manual = 1,
|
||||
Update = 2
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Marr.Data;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Backup
|
||||
{
|
||||
public interface IBackupService
|
||||
{
|
||||
void Backup(BackupType backupType);
|
||||
List<Backup> GetBackups();
|
||||
}
|
||||
|
||||
public class BackupService : IBackupService, IExecute<BackupCommand>
|
||||
{
|
||||
private readonly IDatabase _maindDb;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IAppFolderInfo _appFolderInfo;
|
||||
private readonly IArchiveService _archiveService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private string _backupTempFolder;
|
||||
|
||||
private static readonly Regex BackupFileRegex = new Regex(@"nzbdrone_backup_[._0-9]+\.zip", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public BackupService(IDatabase maindDb,
|
||||
IDiskProvider diskProvider,
|
||||
IAppFolderInfo appFolderInfo,
|
||||
IArchiveService archiveService,
|
||||
Logger logger)
|
||||
{
|
||||
_maindDb = maindDb;
|
||||
_diskProvider = diskProvider;
|
||||
_appFolderInfo = appFolderInfo;
|
||||
_archiveService = archiveService;
|
||||
_logger = logger;
|
||||
|
||||
_backupTempFolder = Path.Combine(_appFolderInfo.TempFolder, "nzbdrone_backup");
|
||||
}
|
||||
|
||||
public void Backup(BackupType backupType)
|
||||
{
|
||||
_logger.ProgressInfo("Starting Backup");
|
||||
|
||||
_diskProvider.EnsureFolder(_backupTempFolder);
|
||||
_diskProvider.EnsureFolder(GetBackupFolder(backupType));
|
||||
|
||||
var backupFilename = String.Format("nzbdrone_backup_{0:yyyy.MM.dd_HH.mm.ss}.zip", DateTime.Now);
|
||||
var backupPath = Path.Combine(GetBackupFolder(backupType), backupFilename);
|
||||
|
||||
Cleanup();
|
||||
|
||||
if (backupType != BackupType.Manual)
|
||||
{
|
||||
CleanupOldBackups(backupType);
|
||||
}
|
||||
|
||||
BackupConfigFile();
|
||||
BackupDatabase();
|
||||
|
||||
_logger.ProgressDebug("Creating backup zip");
|
||||
_archiveService.CreateZip(backupPath, _diskProvider.GetFiles(_backupTempFolder, SearchOption.TopDirectoryOnly));
|
||||
_logger.ProgressDebug("Backup zip created");
|
||||
}
|
||||
|
||||
public List<Backup> GetBackups()
|
||||
{
|
||||
var backups = new List<Backup>();
|
||||
|
||||
foreach (var backupType in Enum.GetValues(typeof(BackupType)).Cast<BackupType>())
|
||||
{
|
||||
var folder = GetBackupFolder(backupType);
|
||||
|
||||
if (_diskProvider.FolderExists(folder))
|
||||
{
|
||||
backups.AddRange(GetBackupFiles(folder).Select(b => new Backup
|
||||
{
|
||||
Path = Path.GetFileName(b),
|
||||
Type = backupType,
|
||||
Time = _diskProvider.FileGetLastWriteUtc(b)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
return backups;
|
||||
}
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
if (_diskProvider.FolderExists(_backupTempFolder))
|
||||
{
|
||||
_diskProvider.EmptyFolder(_backupTempFolder);
|
||||
}
|
||||
}
|
||||
|
||||
private void BackupDatabase()
|
||||
{
|
||||
_logger.ProgressDebug("Backing up database");
|
||||
|
||||
using (var unitOfWork = new UnitOfWork(() => _maindDb.GetDataMapper()))
|
||||
{
|
||||
unitOfWork.BeginTransaction();
|
||||
|
||||
var databaseFile = _appFolderInfo.GetNzbDroneDatabase();
|
||||
var tempDatabaseFile = Path.Combine(_backupTempFolder, Path.GetFileName(databaseFile));
|
||||
|
||||
_diskProvider.CopyFile(databaseFile, tempDatabaseFile, true);
|
||||
|
||||
unitOfWork.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
private void BackupConfigFile()
|
||||
{
|
||||
_logger.ProgressDebug("Backing up config.xml");
|
||||
|
||||
var configFile = _appFolderInfo.GetConfigPath();
|
||||
var tempConfigFile = Path.Combine(_backupTempFolder, Path.GetFileName(configFile));
|
||||
|
||||
_diskProvider.CopyFile(configFile, tempConfigFile, true);
|
||||
}
|
||||
|
||||
private void CleanupOldBackups(BackupType backupType)
|
||||
{
|
||||
_logger.Debug("Cleaning up old backup files");
|
||||
var files = GetBackupFiles(GetBackupFolder(backupType));
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var lastWriteTime = _diskProvider.FileGetLastWriteUtc(file);
|
||||
|
||||
if (lastWriteTime.AddDays(28) < DateTime.UtcNow)
|
||||
{
|
||||
_logger.Debug("Deleting old backup file: {0}", file);
|
||||
_diskProvider.DeleteFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Debug("Finished cleaning up old backup files");
|
||||
}
|
||||
|
||||
private String GetBackupFolder(BackupType backupType)
|
||||
{
|
||||
return Path.Combine(_appFolderInfo.GetBackupFolder(), backupType.ToString().ToLower());
|
||||
}
|
||||
|
||||
private IEnumerable<String> GetBackupFiles(String path)
|
||||
{
|
||||
var files = _diskProvider.GetFiles(path, SearchOption.TopDirectoryOnly);
|
||||
|
||||
return files.Where(f => BackupFileRegex.IsMatch(f));
|
||||
}
|
||||
|
||||
public void Execute(BackupCommand message)
|
||||
{
|
||||
Backup(message.Type);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.DataAugmentation.Scene
|
||||
{
|
||||
public interface ISceneMappingProvider
|
||||
{
|
||||
List<SceneMapping> GetSceneMappings();
|
||||
}
|
||||
}
|
|
@ -16,5 +16,7 @@ namespace NzbDrone.Core.DataAugmentation.Scene
|
|||
|
||||
[JsonProperty("season")]
|
||||
public int SeasonNumber { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using System.Collections.Generic;
|
||||
|
@ -8,6 +9,7 @@ namespace NzbDrone.Core.DataAugmentation.Scene
|
|||
public interface ISceneMappingRepository : IBasicRepository<SceneMapping>
|
||||
{
|
||||
List<SceneMapping> FindByTvdbid(int tvdbId);
|
||||
void Clear(string type);
|
||||
}
|
||||
|
||||
public class SceneMappingRepository : BasicRepository<SceneMapping>, ISceneMappingRepository
|
||||
|
@ -21,5 +23,10 @@ namespace NzbDrone.Core.DataAugmentation.Scene
|
|||
{
|
||||
return Query.Where(x => x.TvdbId == tvdbId);
|
||||
}
|
||||
|
||||
public void Clear(string type)
|
||||
{
|
||||
Delete(s => s.Type == type);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,56 +1,66 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.DataAugmentation.Scene
|
||||
{
|
||||
public interface ISceneMappingService
|
||||
{
|
||||
string GetSceneName(int tvdbId);
|
||||
Nullable<int> GetTvDbId(string cleanName);
|
||||
List<String> GetSceneNames(int tvdbId, IEnumerable<Int32> seasonNumbers);
|
||||
Nullable<int> GetTvDbId(string title);
|
||||
List<SceneMapping> FindByTvdbid(int tvdbId);
|
||||
Nullable<Int32> GetSeasonNumber(string title);
|
||||
}
|
||||
|
||||
public class SceneMappingService : ISceneMappingService,
|
||||
IHandleAsync<ApplicationStartedEvent>,
|
||||
IExecute<UpdateSceneMappingCommand>
|
||||
IHandleAsync<ApplicationStartedEvent>,
|
||||
IHandle<SeriesRefreshStartingEvent>,
|
||||
IExecute<UpdateSceneMappingCommand>
|
||||
{
|
||||
private readonly ISceneMappingRepository _repository;
|
||||
private readonly ISceneMappingProxy _sceneMappingProxy;
|
||||
private readonly IEnumerable<ISceneMappingProvider> _sceneMappingProviders;
|
||||
private readonly Logger _logger;
|
||||
private readonly ICached<SceneMapping> _getSceneNameCache;
|
||||
private readonly ICached<SceneMapping> _gettvdbIdCache;
|
||||
private readonly ICached<List<SceneMapping>> _findbytvdbIdCache;
|
||||
|
||||
public SceneMappingService(ISceneMappingRepository repository, ISceneMappingProxy sceneMappingProxy, ICacheManager cacheManager, Logger logger)
|
||||
public SceneMappingService(ISceneMappingRepository repository,
|
||||
ICacheManager cacheManager,
|
||||
IEnumerable<ISceneMappingProvider> sceneMappingProviders,
|
||||
Logger logger)
|
||||
{
|
||||
_repository = repository;
|
||||
_sceneMappingProxy = sceneMappingProxy;
|
||||
_sceneMappingProviders = sceneMappingProviders;
|
||||
|
||||
_getSceneNameCache = cacheManager.GetCache<SceneMapping>(GetType(), "scene_name");
|
||||
_gettvdbIdCache = cacheManager.GetCache<SceneMapping>(GetType(), "tvdb_id");
|
||||
_findbytvdbIdCache = cacheManager.GetCache<List<SceneMapping>>(GetType(), "find_tvdb_id");
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string GetSceneName(int tvdbId)
|
||||
public List<String> GetSceneNames(int tvdbId, IEnumerable<Int32> seasonNumbers)
|
||||
{
|
||||
var mapping = _getSceneNameCache.Find(tvdbId.ToString());
|
||||
var names = _findbytvdbIdCache.Find(tvdbId.ToString());
|
||||
|
||||
if (mapping == null) return null;
|
||||
if (names == null)
|
||||
{
|
||||
return new List<String>();
|
||||
}
|
||||
|
||||
return mapping.SearchTerm;
|
||||
return FilterNonEnglish(names.Where(s => seasonNumbers.Contains(s.SeasonNumber) ||
|
||||
s.SeasonNumber == -1)
|
||||
.Select(m => m.SearchTerm).Distinct().ToList());
|
||||
}
|
||||
|
||||
public Nullable<Int32> GetTvDbId(string cleanName)
|
||||
public Nullable<Int32> GetTvDbId(string title)
|
||||
{
|
||||
var mapping = _gettvdbIdCache.Find(cleanName.CleanSeriesTitle());
|
||||
var mapping = _gettvdbIdCache.Find(title.CleanSeriesTitle());
|
||||
|
||||
if (mapping == null)
|
||||
return null;
|
||||
|
@ -60,66 +70,95 @@ namespace NzbDrone.Core.DataAugmentation.Scene
|
|||
|
||||
public List<SceneMapping> FindByTvdbid(int tvdbId)
|
||||
{
|
||||
return _findbytvdbIdCache.Find(tvdbId.ToString());
|
||||
var mappings = _findbytvdbIdCache.Find(tvdbId.ToString());
|
||||
|
||||
if (mappings == null)
|
||||
{
|
||||
return new List<SceneMapping>();
|
||||
}
|
||||
|
||||
return mappings;
|
||||
}
|
||||
|
||||
public Nullable<Int32> GetSeasonNumber(string title)
|
||||
{
|
||||
var mapping = _gettvdbIdCache.Find(title.CleanSeriesTitle());
|
||||
|
||||
if (mapping == null)
|
||||
return null;
|
||||
|
||||
return mapping.SeasonNumber;
|
||||
}
|
||||
|
||||
private void UpdateMappings()
|
||||
{
|
||||
_logger.Info("Updating Scene mapping");
|
||||
_logger.Info("Updating Scene mappings");
|
||||
|
||||
try
|
||||
foreach (var sceneMappingProvider in _sceneMappingProviders)
|
||||
{
|
||||
var mappings = _sceneMappingProxy.Fetch();
|
||||
|
||||
if (mappings.Any())
|
||||
try
|
||||
{
|
||||
_repository.Purge();
|
||||
var mappings = sceneMappingProvider.GetSceneMappings();
|
||||
|
||||
foreach (var sceneMapping in mappings)
|
||||
if (mappings.Any())
|
||||
{
|
||||
sceneMapping.ParseTerm = sceneMapping.Title.CleanSeriesTitle();
|
||||
_repository.Clear(sceneMappingProvider.GetType().Name);
|
||||
|
||||
foreach (var sceneMapping in mappings)
|
||||
{
|
||||
sceneMapping.ParseTerm = sceneMapping.Title.CleanSeriesTitle();
|
||||
sceneMapping.Type = sceneMappingProvider.GetType().Name;
|
||||
}
|
||||
|
||||
_repository.InsertMany(mappings.DistinctBy(s => s.ParseTerm).ToList());
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Warn("Received empty list of mapping. will not update.");
|
||||
}
|
||||
|
||||
_repository.InsertMany(mappings);
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn("Received empty list of mapping. will not update.");
|
||||
_logger.ErrorException("Failed to Update Scene Mappings:", ex);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Failed to Update Scene Mappings:", ex);
|
||||
}
|
||||
|
||||
|
||||
RefreshCache();
|
||||
}
|
||||
|
||||
private void RefreshCache()
|
||||
{
|
||||
var mappings = _repository.All();
|
||||
var mappings = _repository.All().ToList();
|
||||
|
||||
_gettvdbIdCache.Clear();
|
||||
_getSceneNameCache.Clear();
|
||||
_findbytvdbIdCache.Clear();
|
||||
|
||||
foreach (var sceneMapping in mappings)
|
||||
{
|
||||
_getSceneNameCache.Set(sceneMapping.TvdbId.ToString(), sceneMapping);
|
||||
_gettvdbIdCache.Set(sceneMapping.ParseTerm.CleanSeriesTitle(), sceneMapping);
|
||||
}
|
||||
|
||||
foreach (var sceneMapping in mappings.GroupBy(x => x.TvdbId))
|
||||
{
|
||||
_findbytvdbIdCache.Set(sceneMapping.Key.ToString(), sceneMapping.ToList());
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> FilterNonEnglish(List<String> titles)
|
||||
{
|
||||
return titles.Where(title => title.All(c => c <= 255)).ToList();
|
||||
}
|
||||
|
||||
public void HandleAsync(ApplicationStartedEvent message)
|
||||
{
|
||||
UpdateMappings();
|
||||
}
|
||||
|
||||
public void Handle(SeriesRefreshStartingEvent message)
|
||||
{
|
||||
UpdateMappings();
|
||||
}
|
||||
|
||||
public void Execute(UpdateSceneMappingCommand message)
|
||||
{
|
||||
UpdateMappings();
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NzbDrone.Core.DataAugmentation.Scene
|
||||
{
|
||||
public class ServicesProvider : ISceneMappingProvider
|
||||
{
|
||||
private readonly ISceneMappingProxy _sceneMappingProxy;
|
||||
|
||||
public ServicesProvider(ISceneMappingProxy sceneMappingProxy)
|
||||
{
|
||||
_sceneMappingProxy = sceneMappingProxy;
|
||||
}
|
||||
|
||||
public List<SceneMapping> GetSceneMappings()
|
||||
{
|
||||
return _sceneMappingProxy.Fetch();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using NzbDrone.Core.DataAugmentation.Xem.Model;
|
||||
using NzbDrone.Core.Rest;
|
||||
using RestSharp;
|
||||
|
@ -12,6 +14,7 @@ namespace NzbDrone.Core.DataAugmentation.Xem
|
|||
{
|
||||
List<int> GetXemSeriesIds();
|
||||
List<XemSceneTvdbMapping> GetSceneTvdbMappings(int id);
|
||||
List<SceneMapping> GetSceneTvdbNames();
|
||||
}
|
||||
|
||||
public class XemProxy : IXemProxy
|
||||
|
@ -40,7 +43,7 @@ namespace NzbDrone.Core.DataAugmentation.Xem
|
|||
{
|
||||
_logger.Debug("Fetching Series IDs from");
|
||||
|
||||
var restClient = new RestClient(XEM_BASE_URL);
|
||||
var restClient = RestClientFactory.BuildClient(XEM_BASE_URL);
|
||||
|
||||
var request = BuildRequest("havemap");
|
||||
|
||||
|
@ -54,7 +57,7 @@ namespace NzbDrone.Core.DataAugmentation.Xem
|
|||
{
|
||||
_logger.Debug("Fetching Mappings for: {0}", id);
|
||||
|
||||
var restClient = new RestClient(XEM_BASE_URL);
|
||||
var restClient = RestClientFactory.BuildClient(XEM_BASE_URL);
|
||||
|
||||
var request = BuildRequest("all");
|
||||
request.AddParameter("id", id);
|
||||
|
@ -65,6 +68,52 @@ namespace NzbDrone.Core.DataAugmentation.Xem
|
|||
return response.Data.Where(c => c.Scene != null).ToList();
|
||||
}
|
||||
|
||||
public List<SceneMapping> GetSceneTvdbNames()
|
||||
{
|
||||
_logger.Debug("Fetching alternate names");
|
||||
var restClient = RestClientFactory.BuildClient(XEM_BASE_URL);
|
||||
|
||||
var request = BuildRequest("allNames");
|
||||
request.AddParameter("origin", "tvdb");
|
||||
request.AddParameter("seasonNumbers", true);
|
||||
|
||||
var response = restClient.ExecuteAndValidate<XemResult<Dictionary<Int32, List<JObject>>>>(request);
|
||||
CheckForFailureResult(response);
|
||||
|
||||
var result = new List<SceneMapping>();
|
||||
|
||||
foreach (var series in response.Data)
|
||||
{
|
||||
foreach (var name in series.Value)
|
||||
{
|
||||
foreach (var n in name)
|
||||
{
|
||||
int seasonNumber;
|
||||
if (!Int32.TryParse(n.Value.ToString(), out seasonNumber))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//hack to deal with Fate/Zero
|
||||
if (series.Key == 79151 && seasonNumber > 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Add(new SceneMapping
|
||||
{
|
||||
Title = n.Key,
|
||||
SearchTerm = n.Key,
|
||||
SeasonNumber = seasonNumber,
|
||||
TvdbId = series.Key
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void CheckForFailureResult<T>(XemResult<T> response)
|
||||
{
|
||||
if (response.Result.Equals("failure", StringComparison.InvariantCultureIgnoreCase) &&
|
||||
|
@ -73,7 +122,5 @@ namespace NzbDrone.Core.DataAugmentation.Xem
|
|||
throw new Exception("Error response received from Xem: " + response.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.DataAugmentation.Xem
|
||||
{
|
||||
public class XemService : IHandle<SeriesUpdatedEvent>, IHandle<SeriesRefreshStartingEvent>
|
||||
public class XemService : ISceneMappingProvider, IHandle<SeriesUpdatedEvent>, IHandle<SeriesRefreshStartingEvent>
|
||||
{
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly IXemProxy _xemProxy;
|
||||
|
@ -47,7 +49,7 @@ namespace NzbDrone.Core.DataAugmentation.Xem
|
|||
|
||||
foreach (var episode in episodes)
|
||||
{
|
||||
episode.AbsoluteEpisodeNumber = 0;
|
||||
episode.SceneAbsoluteEpisodeNumber = 0;
|
||||
episode.SceneSeasonNumber = 0;
|
||||
episode.SceneEpisodeNumber = 0;
|
||||
}
|
||||
|
@ -64,7 +66,7 @@ namespace NzbDrone.Core.DataAugmentation.Xem
|
|||
continue;
|
||||
}
|
||||
|
||||
episode.AbsoluteEpisodeNumber = mapping.Scene.Absolute;
|
||||
episode.SceneAbsoluteEpisodeNumber = mapping.Scene.Absolute;
|
||||
episode.SceneSeasonNumber = mapping.Scene.Season;
|
||||
episode.SceneEpisodeNumber = mapping.Scene.Episode;
|
||||
}
|
||||
|
@ -96,6 +98,24 @@ namespace NzbDrone.Core.DataAugmentation.Xem
|
|||
}
|
||||
}
|
||||
|
||||
public List<SceneMapping> GetSceneMappings()
|
||||
{
|
||||
var mappings = _xemProxy.GetSceneTvdbNames();
|
||||
|
||||
return mappings.Where(m =>
|
||||
{
|
||||
int id;
|
||||
|
||||
if (Int32.TryParse(m.Title, out id))
|
||||
{
|
||||
_logger.Debug("Skipping all numeric name: {0} for {1}", m.Title, m.TvdbId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public void Handle(SeriesUpdatedEvent message)
|
||||
{
|
||||
if (_cache.Count == 0)
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FluentMigrator;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
using FluentMigrator;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(52)]
|
||||
public class add_columns_for_anime : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
//Support XEM names
|
||||
Alter.Table("SceneMappings").AddColumn("Type").AsString().Nullable();
|
||||
Execute.Sql("DELETE FROM SceneMappings");
|
||||
|
||||
//Add AnimeEpisodeFormat (set to Stardard Episode format for now)
|
||||
Alter.Table("NamingConfig").AddColumn("AnimeEpisodeFormat").AsString().Nullable();
|
||||
Execute.Sql("UPDATE NamingConfig SET AnimeEpisodeFormat = StandardEpisodeFormat");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
using System.Data;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(53)]
|
||||
public class add_series_sorttitle : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Create.Column("SortTitle").OnTable("Series").AsString().Nullable();
|
||||
|
||||
Execute.WithConnection(SetSortTitles);
|
||||
}
|
||||
|
||||
private void SetSortTitles(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
using (IDbCommand getSeriesCmd = conn.CreateCommand())
|
||||
{
|
||||
getSeriesCmd.Transaction = tran;
|
||||
getSeriesCmd.CommandText = @"SELECT Id, Title FROM Series";
|
||||
using (IDataReader seriesReader = getSeriesCmd.ExecuteReader())
|
||||
{
|
||||
while (seriesReader.Read())
|
||||
{
|
||||
var id = seriesReader.GetInt32(0);
|
||||
var title = seriesReader.GetString(1);
|
||||
|
||||
var sortTitle = Parser.Parser.NormalizeEpisodeTitle(title).ToLower();
|
||||
|
||||
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||
{
|
||||
updateCmd.Transaction = tran;
|
||||
updateCmd.CommandText = "UPDATE Series SET SortTitle = ? WHERE Id = ?";
|
||||
updateCmd.AddParameter(sortTitle);
|
||||
updateCmd.AddParameter(id);
|
||||
|
||||
updateCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,12 +2,14 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine
|
||||
{
|
||||
|
@ -63,16 +65,17 @@ namespace NzbDrone.Core.DecisionEngine
|
|||
{
|
||||
var parsedEpisodeInfo = Parser.Parser.ParseTitle(report.Title);
|
||||
|
||||
if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode())
|
||||
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))
|
||||
if (parsedEpisodeInfo != null && !parsedEpisodeInfo.SeriesTitle.IsNullOrWhiteSpace())
|
||||
{
|
||||
var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, report.TvRageId, searchCriteria);
|
||||
remoteEpisode.Release = report;
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine
|
||||
{
|
||||
public interface IPrioritizeDownloadDecision
|
||||
{
|
||||
List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions);
|
||||
}
|
||||
|
||||
public class DownloadDecisionPriorizationService : IPrioritizeDownloadDecision
|
||||
{
|
||||
public List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions)
|
||||
{
|
||||
return decisions
|
||||
.Where(c => c.RemoteEpisode.Series != null)
|
||||
.GroupBy(c => c.RemoteEpisode.Series.Id, (i, s) => s
|
||||
.OrderByDescending(c => c.RemoteEpisode.ParsedEpisodeInfo.Quality, new QualityModelComparer(s.First().RemoteEpisode.Series.QualityProfile))
|
||||
.ThenBy(c => c.RemoteEpisode.Episodes.Select(e => e.EpisodeNumber).MinOrDefault())
|
||||
.ThenBy(c => c.RemoteEpisode.Release.Size.Round(200.Megabytes()) / c.RemoteEpisode.Episodes.Count)
|
||||
.ThenBy(c => c.RemoteEpisode.Release.Age))
|
||||
.SelectMany(c => c)
|
||||
.Union(decisions.Where(c => c.RemoteEpisode.Series == null))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue