mirror of
https://github.com/Sonarr/Sonarr.git
synced 2026-04-18 21:35:27 -04:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 779ab39f50 | |||
| 00283e3d6e | |||
| 2b4429f8b7 | |||
| 2446c4185a | |||
| 04900e5f90 | |||
| ce59db528b | |||
| 31b266659e | |||
| e071b0c2e0 | |||
| 270f04d2d2 | |||
| 9af57c6786 | |||
| ff4a550cbb | |||
| 537e4d7c39 | |||
| 9f16d9b2fc | |||
| ae6d920e2a | |||
| 0d22f9ec29 | |||
| 699076a405 | |||
| df593f486f | |||
| 0d95873a05 | |||
| b20acc9063 | |||
| 70d6d25178 | |||
| 196d165432 | |||
| bb3ca998fc | |||
| da73221cef | |||
| 36f66eed21 | |||
| 8e916d60f5 | |||
| 44048207f2 | |||
| b73b99df8d | |||
| ad69ecc5eb | |||
| 1304bc8fb9 | |||
| a4f63e728c | |||
| 307b3536b7 |
@@ -9,7 +9,11 @@ APPNAME="Sonarr"
|
|||||||
|
|
||||||
#set up environment
|
#set up environment
|
||||||
if [[ -x '/opt/local/bin/mono' ]]; then
|
if [[ -x '/opt/local/bin/mono' ]]; then
|
||||||
|
# Macports and mono-supplied installer path
|
||||||
export PATH="/opt/local/bin:$PATH"
|
export PATH="/opt/local/bin:$PATH"
|
||||||
|
elif [[ -x '/usr/local/bin/mono' ]]; then
|
||||||
|
# Homebrew-supplied path to mono
|
||||||
|
export PATH="/usr/local/bin:$PATH"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export DYLD_FALLBACK_LIBRARY_PATH="$DIR"
|
export DYLD_FALLBACK_LIBRARY_PATH="$DIR"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Data.Common;
|
using System.Data.Common;
|
||||||
@@ -91,9 +91,11 @@ namespace Marr.Data.Mapping
|
|||||||
Type entType = ent.GetType();
|
Type entType = ent.GetType();
|
||||||
if (_repos.Relationships.ContainsKey(entType))
|
if (_repos.Relationships.ContainsKey(entType))
|
||||||
{
|
{
|
||||||
|
var provider = _db.ProviderFactory;
|
||||||
|
var connectionString = _db.ConnectionString;
|
||||||
Func<IDataMapper> dbCreate = () =>
|
Func<IDataMapper> dbCreate = () =>
|
||||||
{
|
{
|
||||||
var db = new DataMapper(_db.ProviderFactory, _db.ConnectionString);
|
var db = new DataMapper(provider, connectionString);
|
||||||
db.SqlMode = SqlModes.Text;
|
db.SqlMode = SqlModes.Text;
|
||||||
return db;
|
return db;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||||||
public string SceneName { get; set; }
|
public string SceneName { get; set; }
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
public MediaInfoResource MediaInfo { get; set; }
|
public MediaInfoResource MediaInfo { get; set; }
|
||||||
|
public string OriginalFilePath { get; set; }
|
||||||
|
|
||||||
public bool QualityCutoffNotMet { get; set; }
|
public bool QualityCutoffNotMet { get; set; }
|
||||||
}
|
}
|
||||||
@@ -38,8 +39,8 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||||||
DateAdded = model.DateAdded,
|
DateAdded = model.DateAdded,
|
||||||
SceneName = model.SceneName,
|
SceneName = model.SceneName,
|
||||||
Quality = model.Quality,
|
Quality = model.Quality,
|
||||||
MediaInfo = model.MediaInfo.ToResource(model.SceneName)
|
MediaInfo = model.MediaInfo.ToResource(model.SceneName),
|
||||||
//QualityCutoffNotMet
|
OriginalFilePath = model.OriginalFilePath
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +62,7 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||||||
Quality = model.Quality,
|
Quality = model.Quality,
|
||||||
QualityCutoffNotMet = qualityUpgradableSpecification.CutoffNotMet(series.Profile.Value, model.Quality),
|
QualityCutoffNotMet = qualityUpgradableSpecification.CutoffNotMet(series.Profile.Value, model.Quality),
|
||||||
MediaInfo = model.MediaInfo.ToResource(model.SceneName),
|
MediaInfo = model.MediaInfo.ToResource(model.SceneName),
|
||||||
|
OriginalFilePath = model.OriginalFilePath
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -30,6 +30,7 @@ namespace NzbDrone.Api.Episodes
|
|||||||
public bool UnverifiedSceneNumbering { get; set; }
|
public bool UnverifiedSceneNumbering { get; set; }
|
||||||
public string SeriesTitle { get; set; }
|
public string SeriesTitle { get; set; }
|
||||||
public SeriesResource Series { get; set; }
|
public SeriesResource Series { get; set; }
|
||||||
|
public DateTime? LastSearchTime { get; set; }
|
||||||
|
|
||||||
//Hiding this so people don't think its usable (only used to set the initial state)
|
//Hiding this so people don't think its usable (only used to set the initial state)
|
||||||
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
|
||||||
@@ -65,6 +66,7 @@ namespace NzbDrone.Api.Episodes
|
|||||||
UnverifiedSceneNumbering = model.UnverifiedSceneNumbering,
|
UnverifiedSceneNumbering = model.UnverifiedSceneNumbering,
|
||||||
SeriesTitle = model.SeriesTitle,
|
SeriesTitle = model.SeriesTitle,
|
||||||
//Series = model.Series.MapToResource(),
|
//Series = model.Series.MapToResource(),
|
||||||
|
LastSearchTime = model.LastSearchTime
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using Nancy;
|
using Nancy;
|
||||||
using Nancy.Bootstrapper;
|
using Nancy.Bootstrapper;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
|
||||||
namespace NzbDrone.Api.Extensions.Pipelines
|
namespace NzbDrone.Api.Extensions.Pipelines
|
||||||
@@ -15,9 +16,14 @@ namespace NzbDrone.Api.Extensions.Pipelines
|
|||||||
|
|
||||||
public int Order => 0;
|
public int Order => 0;
|
||||||
|
|
||||||
|
private readonly Action<Action<Stream>, Stream> _writeGZipStream;
|
||||||
|
|
||||||
public GzipCompressionPipeline(Logger logger)
|
public GzipCompressionPipeline(Logger logger)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
|
// On Mono GZipStream/DeflateStream leaks memory if an exception is thrown, use an intermediate buffer in that case.
|
||||||
|
_writeGZipStream = PlatformInfo.IsMono ? WriteGZipStreamMono : (Action<Action<Stream>, Stream>)WriteGZipStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Register(IPipelines pipelines)
|
public void Register(IPipelines pipelines)
|
||||||
@@ -43,14 +49,7 @@ namespace NzbDrone.Api.Extensions.Pipelines
|
|||||||
var contents = response.Contents;
|
var contents = response.Contents;
|
||||||
|
|
||||||
response.Headers["Content-Encoding"] = "gzip";
|
response.Headers["Content-Encoding"] = "gzip";
|
||||||
response.Contents = responseStream =>
|
response.Contents = responseStream => _writeGZipStream(contents, responseStream);
|
||||||
{
|
|
||||||
using (var gzip = new GZipStream(responseStream, CompressionMode.Compress, true))
|
|
||||||
using (var buffered = new BufferedStream(gzip, 8192))
|
|
||||||
{
|
|
||||||
contents.Invoke(buffered);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +60,25 @@ namespace NzbDrone.Api.Extensions.Pipelines
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void WriteGZipStreamMono(Action<Stream> innerContent, Stream targetStream)
|
||||||
|
{
|
||||||
|
using (var membuffer = new MemoryStream())
|
||||||
|
{
|
||||||
|
WriteGZipStream(innerContent, membuffer);
|
||||||
|
membuffer.Position = 0;
|
||||||
|
membuffer.CopyTo(targetStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteGZipStream(Action<Stream> innerContent, Stream targetStream)
|
||||||
|
{
|
||||||
|
using (var gzip = new GZipStream(targetStream, CompressionMode.Compress, true))
|
||||||
|
using (var buffered = new BufferedStream(gzip, 8192))
|
||||||
|
{
|
||||||
|
innerContent.Invoke(buffered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static bool ContentLengthIsTooSmall(Response response)
|
private static bool ContentLengthIsTooSmall(Response response)
|
||||||
{
|
{
|
||||||
var contentLength = response.Headers.GetValueOrDefault("Content-Length");
|
var contentLength = response.Headers.GetValueOrDefault("Content-Length");
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
namespace NzbDrone.Common.EnvironmentInfo
|
namespace NzbDrone.Common.EnvironmentInfo
|
||||||
{
|
{
|
||||||
public interface IRuntimeInfo
|
public interface IRuntimeInfo
|
||||||
{
|
{
|
||||||
|
DateTime StartTime { get; }
|
||||||
bool IsUserInteractive { get; }
|
bool IsUserInteractive { get; }
|
||||||
bool IsAdmin { get; }
|
bool IsAdmin { get; }
|
||||||
bool IsWindowsService { get; }
|
bool IsWindowsService { get; }
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace NzbDrone.Common.EnvironmentInfo
|
|||||||
public class RuntimeInfo : IRuntimeInfo
|
public class RuntimeInfo : IRuntimeInfo
|
||||||
{
|
{
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
private readonly DateTime _startTime = DateTime.UtcNow;
|
||||||
|
|
||||||
public RuntimeInfo(IServiceProvider serviceProvider, Logger logger)
|
public RuntimeInfo(IServiceProvider serviceProvider, Logger logger)
|
||||||
{
|
{
|
||||||
@@ -37,6 +38,14 @@ namespace NzbDrone.Common.EnvironmentInfo
|
|||||||
IsProduction = InternalIsProduction();
|
IsProduction = InternalIsProduction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DateTime StartTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _startTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsUserInteractive => Environment.UserInteractive;
|
public static bool IsUserInteractive => Environment.UserInteractive;
|
||||||
|
|
||||||
bool IRuntimeInfo.IsUserInteractive => IsUserInteractive;
|
bool IRuntimeInfo.IsUserInteractive => IsUserInteractive;
|
||||||
|
|||||||
@@ -191,6 +191,24 @@ namespace NzbDrone.Common.Extensions
|
|||||||
return directories;
|
return directories;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetAncestorPath(this string path, string ancestorName)
|
||||||
|
{
|
||||||
|
var parent = Path.GetDirectoryName(path);
|
||||||
|
|
||||||
|
while (parent != null)
|
||||||
|
{
|
||||||
|
var currentPath = parent;
|
||||||
|
parent = Path.GetDirectoryName(parent);
|
||||||
|
|
||||||
|
if (Path.GetFileName(currentPath) == ancestorName)
|
||||||
|
{
|
||||||
|
return currentPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetAppDataPath(this IAppFolderInfo appFolderInfo)
|
public static string GetAppDataPath(this IAppFolderInfo appFolderInfo)
|
||||||
{
|
{
|
||||||
return appFolderInfo.AppDataFolder;
|
return appFolderInfo.AppDataFolder;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
@@ -25,11 +26,20 @@ namespace NzbDrone.Common.Http.Dispatchers
|
|||||||
{
|
{
|
||||||
var webRequest = (HttpWebRequest)WebRequest.Create((Uri)request.Url);
|
var webRequest = (HttpWebRequest)WebRequest.Create((Uri)request.Url);
|
||||||
|
|
||||||
// Deflate is not a standard and could break depending on implementation.
|
if (PlatformInfo.IsMono)
|
||||||
// we should just stick with the more compatible Gzip
|
{
|
||||||
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
|
// On Mono GZipStream/DeflateStream leaks memory if an exception is thrown, use an intermediate buffer in that case.
|
||||||
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
|
webRequest.AutomaticDecompression = DecompressionMethods.None;
|
||||||
|
webRequest.Headers.Add("Accept-Encoding", "gzip");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Deflate is not a standard and could break depending on implementation.
|
||||||
|
// we should just stick with the more compatible Gzip
|
||||||
|
//http://stackoverflow.com/questions/8490718/how-to-decompress-stream-deflated-with-java-util-zip-deflater-in-net
|
||||||
|
webRequest.AutomaticDecompression = DecompressionMethods.GZip;
|
||||||
|
}
|
||||||
|
|
||||||
webRequest.Method = request.Method.ToString();
|
webRequest.Method = request.Method.ToString();
|
||||||
webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent);
|
webRequest.UserAgent = _userAgentBuilder.GetUserAgent(request.UseSimplifiedUserAgent);
|
||||||
webRequest.KeepAlive = request.ConnectionKeepAlive;
|
webRequest.KeepAlive = request.ConnectionKeepAlive;
|
||||||
@@ -107,6 +117,19 @@ namespace NzbDrone.Common.Http.Dispatchers
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
data = responseStream.ToBytes();
|
data = responseStream.ToBytes();
|
||||||
|
|
||||||
|
if (PlatformInfo.IsMono && httpWebResponse.ContentEncoding == "gzip")
|
||||||
|
{
|
||||||
|
using (var compressedStream = new MemoryStream(data))
|
||||||
|
using (var gzip = new GZipStream(compressedStream, CompressionMode.Decompress))
|
||||||
|
using (var decompressedStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
gzip.CopyTo(decompressedStream);
|
||||||
|
data = decompressedStream.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
httpWebResponse.Headers.Remove("Content-Encoding");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -267,6 +267,7 @@ namespace NzbDrone.Common.Http
|
|||||||
public HttpResponse<T> Get<T>(HttpRequest request) where T : new()
|
public HttpResponse<T> Get<T>(HttpRequest request) where T : new()
|
||||||
{
|
{
|
||||||
var response = Get(request);
|
var response = Get(request);
|
||||||
|
CheckResponseContentType(response);
|
||||||
return new HttpResponse<T>(response);
|
return new HttpResponse<T>(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +286,16 @@ namespace NzbDrone.Common.Http
|
|||||||
public HttpResponse<T> Post<T>(HttpRequest request) where T : new()
|
public HttpResponse<T> Post<T>(HttpRequest request) where T : new()
|
||||||
{
|
{
|
||||||
var response = Post(request);
|
var response = Post(request);
|
||||||
|
CheckResponseContentType(response);
|
||||||
return new HttpResponse<T>(response);
|
return new HttpResponse<T>(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CheckResponseContentType(HttpResponse response)
|
||||||
|
{
|
||||||
|
if (response.Headers.ContentType != null && response.Headers.ContentType.Contains("text/html"))
|
||||||
|
{
|
||||||
|
throw new UnexpectedHtmlContentException(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,13 +7,19 @@ namespace NzbDrone.Common.Http
|
|||||||
public HttpRequest Request { get; private set; }
|
public HttpRequest Request { get; private set; }
|
||||||
public HttpResponse Response { get; private set; }
|
public HttpResponse Response { get; private set; }
|
||||||
|
|
||||||
public HttpException(HttpRequest request, HttpResponse response)
|
public HttpException(HttpRequest request, HttpResponse response, string message)
|
||||||
: base(string.Format("HTTP request failed: [{0}:{1}] [{2}] at [{3}]", (int)response.StatusCode, response.StatusCode, request.Method, request.Url))
|
: base(message)
|
||||||
{
|
{
|
||||||
Request = request;
|
Request = request;
|
||||||
Response = response;
|
Response = response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HttpException(HttpRequest request, HttpResponse response)
|
||||||
|
: this(request, response, string.Format("HTTP request failed: [{0}:{1}] [{2}] at [{3}]", (int)response.StatusCode, response.StatusCode, request.Method, request.Url))
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public HttpException(HttpResponse response)
|
public HttpException(HttpResponse response)
|
||||||
: this(response.Request, response)
|
: this(response.Request, response)
|
||||||
{
|
{
|
||||||
@@ -30,4 +36,4 @@ namespace NzbDrone.Common.Http
|
|||||||
return base.ToString();
|
return base.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NzbDrone.Common.Http
|
||||||
|
{
|
||||||
|
public class UnexpectedHtmlContentException : HttpException
|
||||||
|
{
|
||||||
|
public UnexpectedHtmlContentException(HttpResponse response)
|
||||||
|
: base(response.Request, response, $"Site responded with browser content instead of api data. This disruption may be temporary, please try again later. [{response.Request.Url}]")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -177,6 +177,7 @@
|
|||||||
<Compile Include="Http\HttpRequestBuilderFactory.cs" />
|
<Compile Include="Http\HttpRequestBuilderFactory.cs" />
|
||||||
<Compile Include="Http\Proxy\ProxyType.cs" />
|
<Compile Include="Http\Proxy\ProxyType.cs" />
|
||||||
<Compile Include="Http\TlsFailureException.cs" />
|
<Compile Include="Http\TlsFailureException.cs" />
|
||||||
|
<Compile Include="Http\UnexpectedHtmlContentException.cs" />
|
||||||
<Compile Include="Http\TooManyRequestsException.cs" />
|
<Compile Include="Http\TooManyRequestsException.cs" />
|
||||||
<Compile Include="Extensions\IEnumerableExtensions.cs" />
|
<Compile Include="Extensions\IEnumerableExtensions.cs" />
|
||||||
<Compile Include="Http\UserAgentBuilder.cs" />
|
<Compile Include="Http\UserAgentBuilder.cs" />
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.History;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.Qualities;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||||
|
using NzbDrone.Core.Indexers;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.DecisionEngineTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class AlreadyImportedSpecificationFixture : CoreTest<AlreadyImportedSpecification>
|
||||||
|
{
|
||||||
|
private const int FIRST_EPISODE_ID = 1;
|
||||||
|
private const string TITLE = "Series.Title.S01E01.720p.HDTV.x264-Sonarr";
|
||||||
|
|
||||||
|
private Series _series;
|
||||||
|
private QualityModel _hdtv720p;
|
||||||
|
private QualityModel _hdtv1080p;
|
||||||
|
private RemoteEpisode _remoteEpisode;
|
||||||
|
private List<History.History> _history;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
var singleEpisodeList = new List<Episode>
|
||||||
|
{
|
||||||
|
new Episode
|
||||||
|
{
|
||||||
|
Id = FIRST_EPISODE_ID,
|
||||||
|
SeasonNumber = 12,
|
||||||
|
EpisodeNumber = 3,
|
||||||
|
EpisodeFileId = 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_series = Builder<Series>.CreateNew()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
_hdtv720p = new QualityModel(Quality.HDTV720p, new Revision(version: 1));
|
||||||
|
_hdtv1080p = new QualityModel(Quality.HDTV1080p, new Revision(version: 1));
|
||||||
|
|
||||||
|
_remoteEpisode = new RemoteEpisode
|
||||||
|
{
|
||||||
|
Series = _series,
|
||||||
|
ParsedEpisodeInfo = new ParsedEpisodeInfo { Quality = _hdtv720p },
|
||||||
|
Episodes = singleEpisodeList,
|
||||||
|
Release = Builder<ReleaseInfo>.CreateNew()
|
||||||
|
.Build()
|
||||||
|
};
|
||||||
|
|
||||||
|
_history = new List<History.History>();
|
||||||
|
|
||||||
|
Mocker.GetMock<IConfigService>()
|
||||||
|
.SetupGet(s => s.EnableCompletedDownloadHandling)
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
Mocker.GetMock<IHistoryService>()
|
||||||
|
.Setup(s => s.FindByEpisodeId(It.IsAny<int>()))
|
||||||
|
.Returns(_history);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenCdhDisabled()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IConfigService>()
|
||||||
|
.SetupGet(s => s.EnableCompletedDownloadHandling)
|
||||||
|
.Returns(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenHistoryItem(string downloadId, string sourceTitle, QualityModel quality, HistoryEventType eventType)
|
||||||
|
{
|
||||||
|
_history.Add(new History.History
|
||||||
|
{
|
||||||
|
DownloadId = downloadId,
|
||||||
|
SourceTitle = sourceTitle,
|
||||||
|
Quality = quality,
|
||||||
|
Date = DateTime.UtcNow,
|
||||||
|
EventType = eventType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_be_accepted_if_CDH_is_disabled()
|
||||||
|
{
|
||||||
|
GivenCdhDisabled();
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_be_accepted_if_episode_does_not_have_a_file()
|
||||||
|
{
|
||||||
|
_remoteEpisode.Episodes.First().EpisodeFileId = 0;
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_be_accepted_if_episode_does_not_have_grabbed_event()
|
||||||
|
{
|
||||||
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_be_accepted_if_episode_does_not_have_imported_event()
|
||||||
|
{
|
||||||
|
GivenHistoryItem(Guid.NewGuid().ToString().ToUpper(), TITLE, _hdtv720p, HistoryEventType.Grabbed);
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_be_accepted_if_grabbed_and_imported_quality_is_the_same()
|
||||||
|
{
|
||||||
|
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||||
|
|
||||||
|
GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed);
|
||||||
|
GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.DownloadFolderImported);
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_be_rejected_if_grabbed_download_id_matches_release_torrent_hash()
|
||||||
|
{
|
||||||
|
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||||
|
|
||||||
|
GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed);
|
||||||
|
GivenHistoryItem(downloadId, TITLE, _hdtv1080p, HistoryEventType.DownloadFolderImported);
|
||||||
|
|
||||||
|
_remoteEpisode.Release = Builder<TorrentInfo>.CreateNew()
|
||||||
|
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
||||||
|
.With(t => t.InfoHash = downloadId)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_be_rejected_if_release_title_matches_grabbed_event_source_title()
|
||||||
|
{
|
||||||
|
var downloadId = Guid.NewGuid().ToString().ToUpper();
|
||||||
|
|
||||||
|
GivenHistoryItem(downloadId, TITLE, _hdtv720p, HistoryEventType.Grabbed);
|
||||||
|
GivenHistoryItem(downloadId, TITLE, _hdtv1080p, HistoryEventType.DownloadFolderImported);
|
||||||
|
|
||||||
|
_remoteEpisode.Release = Builder<TorrentInfo>.CreateNew()
|
||||||
|
.With(t => t.DownloadProtocol = DownloadProtocol.Torrent)
|
||||||
|
.With(t => t.InfoHash = downloadId)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(_remoteEpisode, null).Accepted.Should().BeFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
@@ -16,7 +16,7 @@ using NzbDrone.Core.DecisionEngine;
|
|||||||
|
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.DecisionEngineTests
|
namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class HistorySpecificationFixture : CoreTest<HistorySpecification>
|
public class HistorySpecificationFixture : CoreTest<HistorySpecification>
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Core.Download;
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
@@ -16,6 +17,10 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
public void SetUp()
|
public void SetUp()
|
||||||
{
|
{
|
||||||
_epoch = DateTime.UtcNow;
|
_epoch = DateTime.UtcNow;
|
||||||
|
|
||||||
|
Mocker.GetMock<IRuntimeInfo>()
|
||||||
|
.SetupGet(v => v.StartTime)
|
||||||
|
.Returns(_epoch - TimeSpan.FromHours(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private DownloadClientStatus WithStatus(DownloadClientStatus status)
|
private DownloadClientStatus WithStatus(DownloadClientStatus status)
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
|
||||||
@@ -16,6 +17,10 @@ namespace NzbDrone.Core.Test.IndexerTests
|
|||||||
public void SetUp()
|
public void SetUp()
|
||||||
{
|
{
|
||||||
_epoch = DateTime.UtcNow;
|
_epoch = DateTime.UtcNow;
|
||||||
|
|
||||||
|
Mocker.GetMock<IRuntimeInfo>()
|
||||||
|
.SetupGet(v => v.StartTime)
|
||||||
|
.Returns(_epoch - TimeSpan.FromHours(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WithStatus(IndexerStatus status)
|
private void WithStatus(IndexerStatus status)
|
||||||
|
|||||||
+24
@@ -3,6 +3,7 @@ using System.Linq;
|
|||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators;
|
using NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators;
|
||||||
using NzbDrone.Core.Parser;
|
using NzbDrone.Core.Parser;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
@@ -124,5 +125,28 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Aggregation.Aggregators
|
|||||||
Mocker.GetMock<IParsingService>()
|
Mocker.GetMock<IParsingService>()
|
||||||
.Verify(v => v.GetEpisodes(fileEpisodeInfo, _series, localEpisode.SceneSource, null), Times.Once());
|
.Verify(v => v.GetEpisodes(fileEpisodeInfo, _series, localEpisode.SceneSource, null), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_use_special_info_when_not_null()
|
||||||
|
{
|
||||||
|
var fileEpisodeInfo = Parser.Parser.ParseTitle("S00E01");
|
||||||
|
var specialEpisodeInfo = fileEpisodeInfo.JsonClone();
|
||||||
|
|
||||||
|
var localEpisode = new LocalEpisode
|
||||||
|
{
|
||||||
|
FileEpisodeInfo = fileEpisodeInfo,
|
||||||
|
Path = @"C:\Test\TV\Series\Specials\S00E01.mkv".AsOsAgnostic(),
|
||||||
|
Series = _series
|
||||||
|
};
|
||||||
|
|
||||||
|
Mocker.GetMock<IParsingService>()
|
||||||
|
.Setup(s => s.ParseSpecialEpisodeTitle(fileEpisodeInfo, It.IsAny<string>(), _series))
|
||||||
|
.Returns(specialEpisodeInfo);
|
||||||
|
|
||||||
|
Subject.Aggregate(localEpisode, false);
|
||||||
|
|
||||||
|
Mocker.GetMock<IParsingService>()
|
||||||
|
.Verify(v => v.GetEpisodes(specialEpisodeInfo, _series, localEpisode.SceneSource, null), Times.Once());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||||||
|
|
||||||
private void GivenAugmentationSuccess()
|
private void GivenAugmentationSuccess()
|
||||||
{
|
{
|
||||||
Mocker.GetMock<IAugmentingService>()
|
Mocker.GetMock<IAggregationService>()
|
||||||
.Setup(s => s.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
.Setup(s => s.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
||||||
.Callback<LocalEpisode, bool>((localEpisode, otherFiles) =>
|
.Callback<LocalEpisode, bool>((localEpisode, otherFiles) =>
|
||||||
{
|
{
|
||||||
@@ -158,7 +158,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||||||
{
|
{
|
||||||
GivenSpecifications(_pass1);
|
GivenSpecifications(_pass1);
|
||||||
|
|
||||||
Mocker.GetMock<IAugmentingService>()
|
Mocker.GetMock<IAggregationService>()
|
||||||
.Setup(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
.Setup(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
||||||
.Throws<TestException>();
|
.Throws<TestException>();
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||||||
|
|
||||||
Subject.GetImportDecisions(_videoFiles, _series);
|
Subject.GetImportDecisions(_videoFiles, _series);
|
||||||
|
|
||||||
Mocker.GetMock<IAugmentingService>()
|
Mocker.GetMock<IAggregationService>()
|
||||||
.Verify(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()), Times.Exactly(_videoFiles.Count));
|
.Verify(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()), Times.Exactly(_videoFiles.Count));
|
||||||
|
|
||||||
ExceptionVerification.ExpectedErrors(3);
|
ExceptionVerification.ExpectedErrors(3);
|
||||||
@@ -195,7 +195,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||||||
|
|
||||||
var decisions = Subject.GetImportDecisions(_videoFiles, _series);
|
var decisions = Subject.GetImportDecisions(_videoFiles, _series);
|
||||||
|
|
||||||
Mocker.GetMock<IAugmentingService>()
|
Mocker.GetMock<IAggregationService>()
|
||||||
.Verify(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()), Times.Exactly(_videoFiles.Count));
|
.Verify(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()), Times.Exactly(_videoFiles.Count));
|
||||||
|
|
||||||
decisions.Should().HaveCount(3);
|
decisions.Should().HaveCount(3);
|
||||||
@@ -205,7 +205,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_return_a_decision_when_exception_is_caught()
|
public void should_return_a_decision_when_exception_is_caught()
|
||||||
{
|
{
|
||||||
Mocker.GetMock<IAugmentingService>()
|
Mocker.GetMock<IAggregationService>()
|
||||||
.Setup(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
.Setup(c => c.Augment(It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
||||||
.Throws<TestException>();
|
.Throws<TestException>();
|
||||||
|
|
||||||
|
|||||||
-123
@@ -1,123 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using FizzWare.NBuilder;
|
|
||||||
using FluentAssertions;
|
|
||||||
using Moq;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using NzbDrone.Core.Download;
|
|
||||||
using NzbDrone.Core.History;
|
|
||||||
using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
|
||||||
using NzbDrone.Core.Qualities;
|
|
||||||
using NzbDrone.Core.Test.Framework;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
|
|
||||||
{
|
|
||||||
[TestFixture]
|
|
||||||
public class GrabbedReleaseQualityFixture : CoreTest<GrabbedReleaseQualitySpecification>
|
|
||||||
{
|
|
||||||
private LocalEpisode _localEpisode;
|
|
||||||
private DownloadClientItem _downloadClientItem;
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
_localEpisode = Builder<LocalEpisode>.CreateNew()
|
|
||||||
.With(l => l.Quality = new QualityModel(Quality.Bluray720p))
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
_downloadClientItem = Builder<DownloadClientItem>.CreateNew()
|
|
||||||
.Build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GivenHistory(List<History.History> history)
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IHistoryService>()
|
|
||||||
.Setup(s => s.FindByDownloadId(It.IsAny<string>()))
|
|
||||||
.Returns(history);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_be_accepted_when_downloadClientItem_is_null()
|
|
||||||
{
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_be_accepted_if_no_history_for_downloadId()
|
|
||||||
{
|
|
||||||
GivenHistory(new List<History.History>());
|
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_be_accepted_if_no_grabbed_history_for_downloadId()
|
|
||||||
{
|
|
||||||
var history = Builder<History.History>.CreateListOfSize(1)
|
|
||||||
.All()
|
|
||||||
.With(h => h.EventType = HistoryEventType.Unknown)
|
|
||||||
.BuildList();
|
|
||||||
|
|
||||||
GivenHistory(history);
|
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_be_accepted_if_grabbed_history_is_for_a_season_pack()
|
|
||||||
{
|
|
||||||
var history = Builder<History.History>.CreateListOfSize(1)
|
|
||||||
.All()
|
|
||||||
.With(h => h.EventType = HistoryEventType.Grabbed)
|
|
||||||
.With(h => h.Quality = _localEpisode.Quality)
|
|
||||||
.With(h => h.SourceTitle = "Series.Title.S01.720p.HDTV.x264-RlsGroup")
|
|
||||||
.BuildList();
|
|
||||||
|
|
||||||
GivenHistory(history);
|
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_be_accepted_if_grabbed_history_quality_is_unknown()
|
|
||||||
{
|
|
||||||
var history = Builder<History.History>.CreateListOfSize(1)
|
|
||||||
.All()
|
|
||||||
.With(h => h.EventType = HistoryEventType.Grabbed)
|
|
||||||
.With(h => h.Quality = new QualityModel(Quality.Unknown))
|
|
||||||
.BuildList();
|
|
||||||
|
|
||||||
GivenHistory(history);
|
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_be_accepted_if_grabbed_history_quality_matches()
|
|
||||||
{
|
|
||||||
var history = Builder<History.History>.CreateListOfSize(1)
|
|
||||||
.All()
|
|
||||||
.With(h => h.EventType = HistoryEventType.Grabbed)
|
|
||||||
.With(h => h.Quality = _localEpisode.Quality)
|
|
||||||
.BuildList();
|
|
||||||
|
|
||||||
GivenHistory(history);
|
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void should_be_rejected_if_grabbed_history_quality_does_not_match()
|
|
||||||
{
|
|
||||||
var history = Builder<History.History>.CreateListOfSize(1)
|
|
||||||
.All()
|
|
||||||
.With(h => h.EventType = HistoryEventType.Grabbed)
|
|
||||||
.With(h => h.Quality = new QualityModel(Quality.HDTV720p))
|
|
||||||
.BuildList();
|
|
||||||
|
|
||||||
GivenHistory(history);
|
|
||||||
|
|
||||||
Subject.IsSatisfiedBy(_localEpisode, _downloadClientItem).Accepted.Should().BeFalse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ using FizzWare.NBuilder;
|
|||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Core.DecisionEngine;
|
using NzbDrone.Core.DecisionEngine;
|
||||||
using NzbDrone.Core.Download;
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
@@ -34,6 +35,8 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
_rejectedDecisions = new List<ImportDecision>();
|
_rejectedDecisions = new List<ImportDecision>();
|
||||||
_approvedDecisions = new List<ImportDecision>();
|
_approvedDecisions = new List<ImportDecision>();
|
||||||
|
|
||||||
|
var outputPath = @"C:\Test\Unsorted\TV\30.Rock.S01E01".AsOsAgnostic();
|
||||||
|
|
||||||
var series = Builder<Series>.CreateNew()
|
var series = Builder<Series>.CreateNew()
|
||||||
.With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() })
|
.With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||||
.With(s => s.Path = @"C:\Test\TV\30 Rock".AsOsAgnostic())
|
.With(s => s.Path = @"C:\Test\TV\30 Rock".AsOsAgnostic())
|
||||||
@@ -66,7 +69,14 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
.Setup(s => s.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
.Setup(s => s.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), It.IsAny<LocalEpisode>(), It.IsAny<bool>()))
|
||||||
.Returns(new EpisodeFileMoveResult());
|
.Returns(new EpisodeFileMoveResult());
|
||||||
|
|
||||||
_downloadClientItem = Builder<DownloadClientItem>.CreateNew().Build();
|
_downloadClientItem = Builder<DownloadClientItem>.CreateNew()
|
||||||
|
.With(d => d.OutputPath = new OsPath(outputPath))
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenNewDownload()
|
||||||
|
{
|
||||||
|
_approvedDecisions.ForEach(a => a.LocalEpisode.Path = Path.Combine(_downloadClientItem.OutputPath.ToString(), Path.GetFileName(a.LocalEpisode.Path)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -140,6 +150,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_use_nzb_title_as_scene_name()
|
public void should_use_nzb_title_as_scene_name()
|
||||||
{
|
{
|
||||||
|
GivenNewDownload();
|
||||||
_downloadClientItem.Title = "malcolm.in.the.middle.s02e05.dvdrip.xvid-ingot";
|
_downloadClientItem.Title = "malcolm.in.the.middle.s02e05.dvdrip.xvid-ingot";
|
||||||
|
|
||||||
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, _downloadClientItem);
|
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, _downloadClientItem);
|
||||||
@@ -152,6 +163,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
[TestCase(".nzb")]
|
[TestCase(".nzb")]
|
||||||
public void should_remove_extension_from_nzb_title_for_scene_name(string extension)
|
public void should_remove_extension_from_nzb_title_for_scene_name(string extension)
|
||||||
{
|
{
|
||||||
|
GivenNewDownload();
|
||||||
var title = "malcolm.in.the.middle.s02e05.dvdrip.xvid-ingot";
|
var title = "malcolm.in.the.middle.s02e05.dvdrip.xvid-ingot";
|
||||||
|
|
||||||
_downloadClientItem.Title = title + extension;
|
_downloadClientItem.Title = title + extension;
|
||||||
@@ -164,7 +176,8 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_not_use_nzb_title_as_scene_name_if_full_season()
|
public void should_not_use_nzb_title_as_scene_name_if_full_season()
|
||||||
{
|
{
|
||||||
_approvedDecisions.First().LocalEpisode.Path = "c:\\tv\\season1\\malcolm.in.the.middle.s02e23.dvdrip.xvid-ingot.mkv".AsOsAgnostic();
|
GivenNewDownload();
|
||||||
|
_approvedDecisions.First().LocalEpisode.Path = Path.Combine(_downloadClientItem.OutputPath.ToString(), "malcolm.in.the.middle.s02e23.dvdrip.xvid-ingot.mkv");
|
||||||
_downloadClientItem.Title = "malcolm.in.the.middle.s02.dvdrip.xvid-ingot";
|
_downloadClientItem.Title = "malcolm.in.the.middle.s02.dvdrip.xvid-ingot";
|
||||||
|
|
||||||
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, _downloadClientItem);
|
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, _downloadClientItem);
|
||||||
@@ -175,7 +188,8 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_use_file_name_as_scenename_only_if_it_looks_like_scenename()
|
public void should_use_file_name_as_scenename_only_if_it_looks_like_scenename()
|
||||||
{
|
{
|
||||||
_approvedDecisions.First().LocalEpisode.Path = "c:\\tv\\malcolm.in.the.middle.s02e23.dvdrip.xvid-ingot.mkv".AsOsAgnostic();
|
GivenNewDownload();
|
||||||
|
_approvedDecisions.First().LocalEpisode.Path = Path.Combine(_downloadClientItem.OutputPath.ToString(), "malcolm.in.the.middle.s02e23.dvdrip.xvid-ingot.mkv");
|
||||||
|
|
||||||
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true);
|
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true);
|
||||||
|
|
||||||
@@ -185,7 +199,8 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_not_use_file_name_as_scenename_if_it_doesnt_looks_like_scenename()
|
public void should_not_use_file_name_as_scenename_if_it_doesnt_looks_like_scenename()
|
||||||
{
|
{
|
||||||
_approvedDecisions.First().LocalEpisode.Path = "c:\\tv\\aaaaa.mkv".AsOsAgnostic();
|
GivenNewDownload();
|
||||||
|
_approvedDecisions.First().LocalEpisode.Path = Path.Combine(_downloadClientItem.OutputPath.ToString(), "aaaaa.mkv");
|
||||||
|
|
||||||
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true);
|
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true);
|
||||||
|
|
||||||
@@ -223,7 +238,11 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_copy_when_cannot_move_files_downloads()
|
public void should_copy_when_cannot_move_files_downloads()
|
||||||
{
|
{
|
||||||
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, new DownloadClientItem { Title = "30.Rock.S01E01", CanMoveFiles = false});
|
GivenNewDownload();
|
||||||
|
_downloadClientItem.Title = "30.Rock.S01E01";
|
||||||
|
_downloadClientItem.CanMoveFiles = false;
|
||||||
|
|
||||||
|
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, _downloadClientItem);
|
||||||
|
|
||||||
Mocker.GetMock<IUpgradeMediaFiles>()
|
Mocker.GetMock<IUpgradeMediaFiles>()
|
||||||
.Verify(v => v.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), _approvedDecisions.First().LocalEpisode, true), Times.Once());
|
.Verify(v => v.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), _approvedDecisions.First().LocalEpisode, true), Times.Once());
|
||||||
@@ -232,10 +251,71 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_use_override_importmode()
|
public void should_use_override_importmode()
|
||||||
{
|
{
|
||||||
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, new DownloadClientItem { Title = "30.Rock.S01E01", CanMoveFiles = false }, ImportMode.Move);
|
GivenNewDownload();
|
||||||
|
_downloadClientItem.Title = "30.Rock.S01E01";
|
||||||
|
_downloadClientItem.CanMoveFiles = false;
|
||||||
|
|
||||||
|
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, _downloadClientItem, ImportMode.Move);
|
||||||
|
|
||||||
Mocker.GetMock<IUpgradeMediaFiles>()
|
Mocker.GetMock<IUpgradeMediaFiles>()
|
||||||
.Verify(v => v.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), _approvedDecisions.First().LocalEpisode, false), Times.Once());
|
.Verify(v => v.UpgradeEpisodeFile(It.IsAny<EpisodeFile>(), _approvedDecisions.First().LocalEpisode, false), Times.Once());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_use_file_name_only_for_download_client_item_without_a_job_folder()
|
||||||
|
{
|
||||||
|
var fileName = "Series.Title.S01E01.720p.HDTV.x264-Sonarr.mkv";
|
||||||
|
var path = Path.Combine(@"C:\Test\Unsorted\TV\".AsOsAgnostic(), fileName);
|
||||||
|
|
||||||
|
_downloadClientItem.OutputPath = new OsPath(path);
|
||||||
|
_approvedDecisions.First().LocalEpisode.Path = path;
|
||||||
|
|
||||||
|
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, _downloadClientItem);
|
||||||
|
|
||||||
|
Mocker.GetMock<IMediaFileService>().Verify(v => v.Add(It.Is<EpisodeFile>(c => c.OriginalFilePath == fileName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_use_folder_and_file_name_only_for_download_client_item_with_a_job_folder()
|
||||||
|
{
|
||||||
|
var name = "Series.Title.S01E01.720p.HDTV.x264-Sonarr";
|
||||||
|
var outputPath = Path.Combine(@"C:\Test\Unsorted\TV\".AsOsAgnostic(), name);
|
||||||
|
|
||||||
|
_downloadClientItem.OutputPath = new OsPath(outputPath);
|
||||||
|
_approvedDecisions.First().LocalEpisode.Path = Path.Combine(outputPath, name + ".mkv");
|
||||||
|
|
||||||
|
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, _downloadClientItem);
|
||||||
|
|
||||||
|
Mocker.GetMock<IMediaFileService>().Verify(v => v.Add(It.Is<EpisodeFile>(c => c.OriginalFilePath == $"{name}\\{name}.mkv".AsOsAgnostic())));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_include_intermediate_folders_for_download_client_item_with_a_job_folder()
|
||||||
|
{
|
||||||
|
var name = "Series.Title.S01E01.720p.HDTV.x264-Sonarr";
|
||||||
|
var outputPath = Path.Combine(@"C:\Test\Unsorted\TV\".AsOsAgnostic(), name);
|
||||||
|
|
||||||
|
_downloadClientItem.OutputPath = new OsPath(outputPath);
|
||||||
|
_approvedDecisions.First().LocalEpisode.Path = Path.Combine(outputPath, "subfolder", name + ".mkv");
|
||||||
|
|
||||||
|
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, _downloadClientItem);
|
||||||
|
|
||||||
|
Mocker.GetMock<IMediaFileService>().Verify(v => v.Add(It.Is<EpisodeFile>(c => c.OriginalFilePath == $"{name}\\subfolder\\{name}.mkv".AsOsAgnostic())));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_use_folder_info_release_title_to_find_relative_path()
|
||||||
|
{
|
||||||
|
var name = "Series.Title.S01E01.720p.HDTV.x264-Sonarr";
|
||||||
|
var outputPath = Path.Combine(@"C:\Test\Unsorted\TV\".AsOsAgnostic(), name);
|
||||||
|
var localEpisode = _approvedDecisions.First().LocalEpisode;
|
||||||
|
|
||||||
|
localEpisode.FolderEpisodeInfo = new ParsedEpisodeInfo { ReleaseTitle = name };
|
||||||
|
localEpisode.Path = Path.Combine(outputPath, "subfolder", name + ".mkv");
|
||||||
|
|
||||||
|
Subject.Import(new List<ImportDecision> { _approvedDecisions.First() }, true, null);
|
||||||
|
|
||||||
|
Mocker.GetMock<IMediaFileService>().Verify(v => v.Add(It.Is<EpisodeFile>(c => c.OriginalFilePath == $"{name}\\subfolder\\{name}.mkv".AsOsAgnostic())));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,12 +44,12 @@ namespace NzbDrone.Core.Test.MetadataSource.SkyHook
|
|||||||
[TestCase("tvdbid: 0")]
|
[TestCase("tvdbid: 0")]
|
||||||
[TestCase("tvdbid: -12")]
|
[TestCase("tvdbid: -12")]
|
||||||
[TestCase("tvdbid:289578")]
|
[TestCase("tvdbid:289578")]
|
||||||
[TestCase("adjalkwdjkalwdjklawjdlKAJD;EF")]
|
[TestCase("adjalkwdjkalwdjklawjdlKAJD")]
|
||||||
public void no_search_result(string term)
|
public void no_search_result(string term)
|
||||||
{
|
{
|
||||||
var result = Subject.SearchForNewSeries(term);
|
var result = Subject.SearchForNewSeries(term);
|
||||||
result.Should().BeEmpty();
|
result.Should().BeEmpty();
|
||||||
|
|
||||||
ExceptionVerification.IgnoreWarns();
|
ExceptionVerification.IgnoreWarns();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,7 +166,8 @@
|
|||||||
<Compile Include="DecisionEngineTests\ProtocolSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\ProtocolSpecificationFixture.cs" />
|
||||||
<Compile Include="DecisionEngineTests\CutoffSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\CutoffSpecificationFixture.cs" />
|
||||||
<Compile Include="DecisionEngineTests\DownloadDecisionMakerFixture.cs" />
|
<Compile Include="DecisionEngineTests\DownloadDecisionMakerFixture.cs" />
|
||||||
<Compile Include="DecisionEngineTests\HistorySpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\AlreadyImportedSpecificationFixture.cs" />
|
||||||
|
<Compile Include="DecisionEngineTests\RssSync\HistorySpecificationFixture.cs" />
|
||||||
<Compile Include="DecisionEngineTests\LanguageSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\LanguageSpecificationFixture.cs" />
|
||||||
<Compile Include="DecisionEngineTests\MonitoredEpisodeSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\MonitoredEpisodeSpecificationFixture.cs" />
|
||||||
<Compile Include="DecisionEngineTests\QueueSpecificationFixture.cs" />
|
<Compile Include="DecisionEngineTests\QueueSpecificationFixture.cs" />
|
||||||
@@ -316,7 +317,6 @@
|
|||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecificationFixture.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecificationFixture.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecificationFixture.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecificationFixture.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\SameFileSpecificationFixture.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\SameFileSpecificationFixture.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\GrabbedReleaseQualityFixture.cs" />
|
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\MatchesFolderSpecificationFixture.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\MatchesFolderSpecificationFixture.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotSampleSpecificationFixture.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotSampleSpecificationFixture.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotUnpackingSpecificationFixture.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotUnpackingSpecificationFixture.cs" />
|
||||||
|
|||||||
@@ -91,6 +91,9 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Love Rerun 2018 06 720p x265 AOZ.mp4", "Love Rerun 2018", 6, 0, 0)]
|
[TestCase("Love Rerun 2018 06 720p x265 AOZ.mp4", "Love Rerun 2018", 6, 0, 0)]
|
||||||
[TestCase("Boku No Hero Academia S03 - EP14 VOSTFR [1080p] [HardSub] Yass'Kun", "Boku No Hero Academia S03", 14, 0, 0)]
|
[TestCase("Boku No Hero Academia S03 - EP14 VOSTFR [1080p] [HardSub] Yass'Kun", "Boku No Hero Academia S03", 14, 0, 0)]
|
||||||
[TestCase("Boku No Hero Academia S3 - 15 VOSTFR [720p]", "Boku No Hero Academia S3", 15, 0, 0)]
|
[TestCase("Boku No Hero Academia S3 - 15 VOSTFR [720p]", "Boku No Hero Academia S3", 15, 0, 0)]
|
||||||
|
[TestCase("Tokyo Ghoul: RE S2 - Episode 4 VOSTFR (1080p)", "Tokyo Ghoul RE S2", 4, 0, 0)]
|
||||||
|
[TestCase("To Aru Majutsu no Index III - Episode 5 VOSTFR (1080p)", "To Aru Majutsu no Index III", 5, 0, 0)]
|
||||||
|
[TestCase("[Prout] Steins;Gate 0 - Episode 5 VOSTFR (BDRip 1920x1080 x264 FLAC)", "Steins;Gate 0", 5, 0, 0)]
|
||||||
//[TestCase("", "", 0, 0, 0)]
|
//[TestCase("", "", 0, 0, 0)]
|
||||||
public void should_parse_absolute_numbers(string postTitle, string title, int absoluteEpisodeNumber, int seasonNumber, int episodeNumber)
|
public void should_parse_absolute_numbers(string postTitle, string title, int absoluteEpisodeNumber, int seasonNumber, int episodeNumber)
|
||||||
{
|
{
|
||||||
@@ -133,5 +136,29 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
result.SeriesTitle.Should().Be(title);
|
result.SeriesTitle.Should().Be(title);
|
||||||
result.FullSeason.Should().BeFalse();
|
result.FullSeason.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase("[Vivid] Living Sky Saga S01 [Web][MKV][h264 10-bit][1080p][AAC 2.0]", "Living Sky Saga", 1)]
|
||||||
|
public void should_parse_anime_season_packs(string postTitle, string title, int seasonNumber)
|
||||||
|
{
|
||||||
|
var result = Parser.Parser.ParseTitle(postTitle);
|
||||||
|
result.Should().NotBeNull();
|
||||||
|
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||||
|
result.SeriesTitle.Should().Be(title);
|
||||||
|
result.FullSeason.Should().BeTrue();
|
||||||
|
result.SeasonNumber.Should().Be(seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("[HorribleSubs] Goblin Slayer - 10.5 [1080p].mkv", "Goblin Slayer", 10.5)]
|
||||||
|
public void should_handle_anime_recap_numbering(string postTitle, string title, double specialEpisodeNumber)
|
||||||
|
{
|
||||||
|
var result = Parser.Parser.ParseTitle(postTitle);
|
||||||
|
result.Should().NotBeNull();
|
||||||
|
result.SeriesTitle.Should().Be(title);
|
||||||
|
result.AbsoluteEpisodeNumbers.Should().BeEmpty();
|
||||||
|
result.SpecialAbsoluteEpisodeNumbers.Should().NotBeEmpty();
|
||||||
|
result.SpecialAbsoluteEpisodeNumbers.Should().BeEquivalentTo(new[] { (decimal)specialEpisodeNumber });
|
||||||
|
result.FullSeason.Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
//[TestCase("Corrie.07.01.15", "Corrie", 2015, 1, 7)]
|
//[TestCase("Corrie.07.01.15", "Corrie", 2015, 1, 7)]
|
||||||
[TestCase("The Nightly Show with Larry Wilmore 2015 02 09 WEBRIP s01e13", "The Nightly Show with Larry Wilmore", 2015, 2, 9)]
|
[TestCase("The Nightly Show with Larry Wilmore 2015 02 09 WEBRIP s01e13", "The Nightly Show with Larry Wilmore", 2015, 2, 9)]
|
||||||
[TestCase("Jimmy_Fallon_2018_06_22_Seth_Meyers_720p_HEVC_x265-MeGusta", "Jimmy Fallon", 2018, 6, 22)]
|
[TestCase("Jimmy_Fallon_2018_06_22_Seth_Meyers_720p_HEVC_x265-MeGusta", "Jimmy Fallon", 2018, 6, 22)]
|
||||||
|
[TestCase("20161024- Exotic Payback.21x41_720.mkv", "", 2016, 10, 24)]
|
||||||
|
[TestCase("2018-11-14.1080.all.mp4", "", 2018, 11, 14)]
|
||||||
//[TestCase("", "", 0, 0, 0)]
|
//[TestCase("", "", 0, 0, 0)]
|
||||||
public void should_parse_daily_episode(string postTitle, string title, int year, int month, int day)
|
public void should_parse_daily_episode(string postTitle, string title, int year, int month, int day)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -87,6 +87,13 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
"Fargo",
|
"Fargo",
|
||||||
Quality.WEBDL1080p,
|
Quality.WEBDL1080p,
|
||||||
"RARBG"
|
"RARBG"
|
||||||
|
},
|
||||||
|
new object[]
|
||||||
|
{
|
||||||
|
@"C:\Test\XxQVHK4GJMP3n2dLpmhW\XxQVHK4GJMP3n2dLpmhW\MKV\010E70S.yhcranA.fo.snoS.mkv".AsOsAgnostic(),
|
||||||
|
"Sons of Anarchy",
|
||||||
|
Quality.HDTV720p,
|
||||||
|
null
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Hells.Kitchen.US.S12E17.HR.WS.PDTV.X264-DIMENSION", false)]
|
[TestCase("Hells.Kitchen.US.S12E17.HR.WS.PDTV.X264-DIMENSION", false)]
|
||||||
[TestCase("Survivorman.The.Lost.Pilots.Summer.HR.WS.PDTV.x264-DHD", false)]
|
[TestCase("Survivorman.The.Lost.Pilots.Summer.HR.WS.PDTV.x264-DHD", false)]
|
||||||
[TestCase("Victoria S01E07 - Motor zmen (CZ)[TvRip][HEVC][720p]", false)]
|
[TestCase("Victoria S01E07 - Motor zmen (CZ)[TvRip][HEVC][720p]", false)]
|
||||||
|
[TestCase("flashpoint.S05E06.720p.HDTV.x264-FHD", false)]
|
||||||
public void should_parse_hdtv720p_quality(string title, bool proper)
|
public void should_parse_hdtv720p_quality(string title, bool proper)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, Quality.HDTV720p, proper);
|
ParseAndVerifyQuality(title, Quality.HDTV720p, proper);
|
||||||
@@ -130,11 +131,27 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Dexter - S01E01 - Title [HDTV-1080p]", false)]
|
[TestCase("Dexter - S01E01 - Title [HDTV-1080p]", false)]
|
||||||
[TestCase("[HorribleSubs] Yowamushi Pedal - 32 [1080p]", false)]
|
[TestCase("[HorribleSubs] Yowamushi Pedal - 32 [1080p]", false)]
|
||||||
[TestCase("Victoria S01E07 - Motor zmen (CZ)[TvRip][HEVC][1080p]", false)]
|
[TestCase("Victoria S01E07 - Motor zmen (CZ)[TvRip][HEVC][1080p]", false)]
|
||||||
|
[TestCase("Sword Art Online Alicization 04 vostfr FHD", false)]
|
||||||
|
[TestCase("Goblin Slayer 04 vostfr FHD.mkv", false)]
|
||||||
|
[TestCase("[Onii-ChanSub] SSSS.Gridman - 02 vostfr (FHD 1080p 10bits).mkv", false)]
|
||||||
|
[TestCase("[Miaou] Akanesasu Shoujo 02 VOSTFR FHD 10 bits", false)]
|
||||||
|
[TestCase("[mhastream.com]_Episode_05_FHD.mp4", false)]
|
||||||
|
[TestCase("[Kousei]_One_Piece_ - _609_[FHD][648A87C7].mp4", false)]
|
||||||
|
[TestCase("Presunto culpable 1x02 Culpabilidad [HDTV 1080i AVC MP2 2.0 Sub][GrupoHDS]", false)]
|
||||||
|
[TestCase("Cuéntame cómo pasó - 19x15 [344] Cuarenta años de baile [HDTV 1080i AVC MP2 2.0 Sub][GrupoHDS]", false)]
|
||||||
public void should_parse_hdtv1080p_quality(string title, bool proper)
|
public void should_parse_hdtv1080p_quality(string title, bool proper)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, Quality.HDTV1080p, proper);
|
ParseAndVerifyQuality(title, Quality.HDTV1080p, proper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase("My Title - S01E01 - EpTitle [HEVC 4k DTSHD-MA-6ch]", false)]
|
||||||
|
[TestCase("My Title - S01E01 - EpTitle [HEVC-4k DTSHD-MA-6ch]", false)]
|
||||||
|
[TestCase("My Title - S01E01 - EpTitle [4k HEVC DTSHD-MA-6ch]", false)]
|
||||||
|
public void should_parse_hdtv2160p_quality(string title, bool proper)
|
||||||
|
{
|
||||||
|
ParseAndVerifyQuality(title, Quality.HDTV2160p, proper);
|
||||||
|
}
|
||||||
|
|
||||||
[TestCase("Arrested.Development.S04E01.720p.WEBRip.AAC2.0.x264-NFRiP", false)]
|
[TestCase("Arrested.Development.S04E01.720p.WEBRip.AAC2.0.x264-NFRiP", false)]
|
||||||
[TestCase("Vanguard S01E04 Mexicos Death Train 720p WEB DL", false)]
|
[TestCase("Vanguard S01E04 Mexicos Death Train 720p WEB DL", false)]
|
||||||
[TestCase("Hawaii Five 0 S02E21 720p WEB DL DD5 1 H 264", false)]
|
[TestCase("Hawaii Five 0 S02E21 720p WEB DL DD5 1 H 264", false)]
|
||||||
@@ -178,6 +195,8 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("Incorporated.S01E08.Das.geloeschte.Ich.German.DD51.Dubbed.DL.1080p.AmazonHD.x264-TVS", false)]
|
[TestCase("Incorporated.S01E08.Das.geloeschte.Ich.German.DD51.Dubbed.DL.1080p.AmazonHD.x264-TVS", false)]
|
||||||
[TestCase("Death.Note.2017.German.DD51.DL.1080p.NetflixHD.x264-TVS", false)]
|
[TestCase("Death.Note.2017.German.DD51.DL.1080p.NetflixHD.x264-TVS", false)]
|
||||||
[TestCase("Played.S01E08.Pro.Gamer.1440p.BKPL.WEB-DL.H.264-LiGHT", false)]
|
[TestCase("Played.S01E08.Pro.Gamer.1440p.BKPL.WEB-DL.H.264-LiGHT", false)]
|
||||||
|
[TestCase("Good.Luck.Charlie.S04E11.Teddy's.Choice.FHD.1080p.Web-DL", false)]
|
||||||
|
[TestCase("Outlander.S04E03.The.False.Bride.1080p.NF.WEB.DDP5.1.x264-NTb[rartv]", false)]
|
||||||
public void should_parse_webdl1080p_quality(string title, bool proper)
|
public void should_parse_webdl1080p_quality(string title, bool proper)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, Quality.WEBDL1080p, proper);
|
ParseAndVerifyQuality(title, Quality.WEBDL1080p, proper);
|
||||||
@@ -210,6 +229,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("[Elysium]Lucky.Star.01(BD.720p.AAC.DA)[0BB96AD8].mkv", false)]
|
[TestCase("[Elysium]Lucky.Star.01(BD.720p.AAC.DA)[0BB96AD8].mkv", false)]
|
||||||
[TestCase("Battlestar.Galactica.S01E01.33.720p.HDDVD.x264-SiNNERS.mkv", false)]
|
[TestCase("Battlestar.Galactica.S01E01.33.720p.HDDVD.x264-SiNNERS.mkv", false)]
|
||||||
[TestCase("The.Expanse.S01E07.RERIP.720p.BluRay.x264-DEMAND", true)]
|
[TestCase("The.Expanse.S01E07.RERIP.720p.BluRay.x264-DEMAND", true)]
|
||||||
|
[TestCase("Sans.Laisser.De.Traces.FRENCH.720p.BluRay.x264-FHD", false)]
|
||||||
public void should_parse_bluray720p_quality(string title, bool proper)
|
public void should_parse_bluray720p_quality(string title, bool proper)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, Quality.Bluray720p, proper);
|
ParseAndVerifyQuality(title, Quality.Bluray720p, proper);
|
||||||
@@ -225,6 +245,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
[TestCase("WEEDS.S03E01-06.DUAL.1080p.Blu-ray.AC3.-HELLYWOOD.avi", false)]
|
[TestCase("WEEDS.S03E01-06.DUAL.1080p.Blu-ray.AC3.-HELLYWOOD.avi", false)]
|
||||||
[TestCase("[Coalgirls]_Durarara!!_01_(1920x1080_Blu-ray_FLAC)_[8370CB8F].mkv", false)]
|
[TestCase("[Coalgirls]_Durarara!!_01_(1920x1080_Blu-ray_FLAC)_[8370CB8F].mkv", false)]
|
||||||
[TestCase("Planet.Earth.S01E11.Ocean.Deep.1080p.HD-DVD.DD.VC1-TRB", false)]
|
[TestCase("Planet.Earth.S01E11.Ocean.Deep.1080p.HD-DVD.DD.VC1-TRB", false)]
|
||||||
|
[TestCase("Spirited Away(2001) Bluray FHD Hi10P.mkv", false)]
|
||||||
public void should_parse_bluray1080p_quality(string title, bool proper)
|
public void should_parse_bluray1080p_quality(string title, bool proper)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, Quality.Bluray1080p, proper);
|
ParseAndVerifyQuality(title, Quality.Bluray1080p, proper);
|
||||||
@@ -232,6 +253,7 @@ namespace NzbDrone.Core.Test.ParserTests
|
|||||||
|
|
||||||
[TestCase("House.of.Cards.US.s05e13.4K.UHD.Bluray", false)]
|
[TestCase("House.of.Cards.US.s05e13.4K.UHD.Bluray", false)]
|
||||||
[TestCase("House.of.Cards.US.s05e13.UHD.4K.Bluray", false)]
|
[TestCase("House.of.Cards.US.s05e13.UHD.4K.Bluray", false)]
|
||||||
|
[TestCase("[DameDesuYo] Backlog Bundle - Part 1 (BD 4K 8bit FLAC)", false)]
|
||||||
public void should_parse_bluray2160p_quality(string title, bool proper)
|
public void should_parse_bluray2160p_quality(string title, bool proper)
|
||||||
{
|
{
|
||||||
ParseAndVerifyQuality(title, Quality.Bluray2160p, proper);
|
ParseAndVerifyQuality(title, Quality.Bluray2160p, proper);
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Test.Framework;
|
using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
@@ -25,8 +26,8 @@ namespace NzbDrone.Core.Test.ThingiProviderTests
|
|||||||
|
|
||||||
public class MockProviderStatusService : ProviderStatusServiceBase<IMockProvider, MockProviderStatus>
|
public class MockProviderStatusService : ProviderStatusServiceBase<IMockProvider, MockProviderStatus>
|
||||||
{
|
{
|
||||||
public MockProviderStatusService(IMockProviderStatusRepository providerStatusRepository, IEventAggregator eventAggregator, Logger logger)
|
public MockProviderStatusService(IMockProviderStatusRepository providerStatusRepository, IEventAggregator eventAggregator, IRuntimeInfo runtimeInfo, Logger logger)
|
||||||
: base(providerStatusRepository, eventAggregator, logger)
|
: base(providerStatusRepository, eventAggregator, runtimeInfo, logger)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -40,9 +41,20 @@ namespace NzbDrone.Core.Test.ThingiProviderTests
|
|||||||
public void SetUp()
|
public void SetUp()
|
||||||
{
|
{
|
||||||
_epoch = DateTime.UtcNow;
|
_epoch = DateTime.UtcNow;
|
||||||
|
|
||||||
|
Mocker.GetMock<IRuntimeInfo>()
|
||||||
|
.SetupGet(v => v.StartTime)
|
||||||
|
.Returns(_epoch - TimeSpan.FromHours(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WithStatus(MockProviderStatus status)
|
private void GivenRecentStartup()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IRuntimeInfo>()
|
||||||
|
.SetupGet(v => v.StartTime)
|
||||||
|
.Returns(_epoch - TimeSpan.FromMinutes(12));
|
||||||
|
}
|
||||||
|
|
||||||
|
private MockProviderStatus WithStatus(MockProviderStatus status)
|
||||||
{
|
{
|
||||||
Mocker.GetMock<IMockProviderStatusRepository>()
|
Mocker.GetMock<IMockProviderStatusRepository>()
|
||||||
.Setup(v => v.FindByProviderId(1))
|
.Setup(v => v.FindByProviderId(1))
|
||||||
@@ -51,6 +63,8 @@ namespace NzbDrone.Core.Test.ThingiProviderTests
|
|||||||
Mocker.GetMock<IMockProviderStatusRepository>()
|
Mocker.GetMock<IMockProviderStatusRepository>()
|
||||||
.Setup(v => v.All())
|
.Setup(v => v.All())
|
||||||
.Returns(new[] { status });
|
.Returns(new[] { status });
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VerifyUpdate()
|
private void VerifyUpdate()
|
||||||
@@ -122,5 +136,32 @@ namespace NzbDrone.Core.Test.ThingiProviderTests
|
|||||||
status.DisabledTill.Should().HaveValue();
|
status.DisabledTill.Should().HaveValue();
|
||||||
status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(15), 500);
|
status.DisabledTill.Value.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(15), 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_escalate_further_till_after_5_minutes_since_startup()
|
||||||
|
{
|
||||||
|
GivenRecentStartup();
|
||||||
|
|
||||||
|
var origStatus = WithStatus(new MockProviderStatus
|
||||||
|
{
|
||||||
|
InitialFailure = _epoch - TimeSpan.FromMinutes(6),
|
||||||
|
MostRecentFailure = _epoch - TimeSpan.FromSeconds(120),
|
||||||
|
EscalationLevel = 3
|
||||||
|
});
|
||||||
|
|
||||||
|
Subject.RecordFailure(1);
|
||||||
|
Subject.RecordFailure(1);
|
||||||
|
Subject.RecordFailure(1);
|
||||||
|
Subject.RecordFailure(1);
|
||||||
|
Subject.RecordFailure(1);
|
||||||
|
Subject.RecordFailure(1);
|
||||||
|
Subject.RecordFailure(1);
|
||||||
|
|
||||||
|
var status = Subject.GetBlockedProviders().FirstOrDefault();
|
||||||
|
status.Should().NotBeNull();
|
||||||
|
|
||||||
|
origStatus.EscalationLevel.Should().Be(3);
|
||||||
|
status.DisabledTill.Should().BeCloseTo(_epoch + TimeSpan.FromMinutes(5), 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
@@ -10,6 +10,7 @@ namespace NzbDrone.Core.Test.TvTests
|
|||||||
[TestCase("A to Z", 281588, "a to z")]
|
[TestCase("A to Z", 281588, "a to z")]
|
||||||
[TestCase("A.D. The Bible Continues", 289260, "ad bible continues")]
|
[TestCase("A.D. The Bible Continues", 289260, "ad bible continues")]
|
||||||
[TestCase("A.P. Bio", 328534, "ap bio")]
|
[TestCase("A.P. Bio", 328534, "ap bio")]
|
||||||
|
[TestCase("The A-Team", 77904, "ateam")]
|
||||||
public void should_use_precomputed_title(string title, int tvdbId, string expected)
|
public void should_use_precomputed_title(string title, int tvdbId, string expected)
|
||||||
{
|
{
|
||||||
SeriesTitleNormalizer.Normalize(title, tvdbId).Should().Be(expected);
|
SeriesTitleNormalizer.Normalize(title, tvdbId).Should().Be(expected);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace NzbDrone.Core.Datastore
|
|||||||
var connectionBuilder = new SQLiteConnectionStringBuilder();
|
var connectionBuilder = new SQLiteConnectionStringBuilder();
|
||||||
|
|
||||||
connectionBuilder.DataSource = dbPath;
|
connectionBuilder.DataSource = dbPath;
|
||||||
connectionBuilder.CacheSize = (int)-10.Megabytes();
|
connectionBuilder.CacheSize = (int)-10000;
|
||||||
connectionBuilder.DateTimeKind = DateTimeKind.Utc;
|
connectionBuilder.DateTimeKind = DateTimeKind.Utc;
|
||||||
connectionBuilder.JournalMode = OsInfo.IsOsx ? SQLiteJournalModeEnum.Truncate : SQLiteJournalModeEnum.Wal;
|
connectionBuilder.JournalMode = OsInfo.IsOsx ? SQLiteJournalModeEnum.Truncate : SQLiteJournalModeEnum.Wal;
|
||||||
connectionBuilder.Pooling = true;
|
connectionBuilder.Pooling = true;
|
||||||
|
|||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(129)]
|
||||||
|
public class add_relative_original_path_to_episode_file : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Alter.Table("EpisodeFiles").AddColumn("OriginalFilePath").AsString().Nullable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(130)]
|
||||||
|
public class episode_last_searched_time : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Alter.Table("Episodes").AddColumn("LastSearchTime").AsDateTime().Nullable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.History;
|
||||||
|
using NzbDrone.Core.Indexers;
|
||||||
|
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||||
|
{
|
||||||
|
public class AlreadyImportedSpecification : IDecisionEngineSpecification
|
||||||
|
{
|
||||||
|
private readonly IHistoryService _historyService;
|
||||||
|
private readonly IConfigService _configService;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public AlreadyImportedSpecification(IHistoryService historyService,
|
||||||
|
IConfigService configService,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_historyService = historyService;
|
||||||
|
_configService = configService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpecificationPriority Priority => SpecificationPriority.Database;
|
||||||
|
public RejectionType Type => RejectionType.Permanent;
|
||||||
|
|
||||||
|
public Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)
|
||||||
|
{
|
||||||
|
var cdhEnabled = _configService.EnableCompletedDownloadHandling;
|
||||||
|
|
||||||
|
if (!cdhEnabled)
|
||||||
|
{
|
||||||
|
_logger.Debug("Skipping already imported check because CDH is disabled");
|
||||||
|
return Decision.Accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Debug("Performing alerady imported check on report");
|
||||||
|
foreach (var episode in subject.Episodes)
|
||||||
|
{
|
||||||
|
if (!episode.HasFile)
|
||||||
|
{
|
||||||
|
_logger.Debug("Skipping already imported check for episode without file");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var historyForEpisode = _historyService.FindByEpisodeId(episode.Id);
|
||||||
|
var lastGrabbed = historyForEpisode.FirstOrDefault(h => h.EventType == HistoryEventType.Grabbed);
|
||||||
|
|
||||||
|
if (lastGrabbed == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var imported = historyForEpisode.FirstOrDefault(h =>
|
||||||
|
h.EventType == HistoryEventType.DownloadFolderImported &&
|
||||||
|
h.DownloadId == lastGrabbed.DownloadId);
|
||||||
|
|
||||||
|
if (imported == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is really only a guard against redownloading the same release over
|
||||||
|
// and over when the grabbed and imported qualities do not match, if they do
|
||||||
|
// match skip this check.
|
||||||
|
if (lastGrabbed.Quality.Equals(imported.Quality))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var release = subject.Release;
|
||||||
|
|
||||||
|
if (release.DownloadProtocol == DownloadProtocol.Torrent)
|
||||||
|
{
|
||||||
|
var torrentInfo = release as TorrentInfo;
|
||||||
|
|
||||||
|
if (torrentInfo != null && torrentInfo.InfoHash.ToUpper() == lastGrabbed.DownloadId)
|
||||||
|
{
|
||||||
|
_logger.Debug("Has same torrent hash as a grabbed and imported release");
|
||||||
|
return Decision.Reject("Has same torrent hash as a grabbed and imported release");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only based on title because a release with the same title on another indexer/released at
|
||||||
|
// a different time very likely has the exact same content and we don't need to also try it.
|
||||||
|
|
||||||
|
if (release.Title.Equals(lastGrabbed.SourceTitle, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.Debug("Has same release name as a grabbed and imported release");
|
||||||
|
return Decision.Reject("Has same release name as a grabbed and imported release");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Decision.Accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
-3
@@ -30,7 +30,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||||||
|
|
||||||
if (!subject.Series.Monitored)
|
if (!subject.Series.Monitored)
|
||||||
{
|
{
|
||||||
_logger.Debug("{0} is present in the DB but not tracked. skipping.", subject.Series);
|
_logger.Debug("{0} is present in the DB but not tracked. Rejecting", subject.Series);
|
||||||
return Decision.Reject("Series is not monitored");
|
return Decision.Reject("Series is not monitored");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,8 +40,22 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||||||
return Decision.Accept();
|
return Decision.Accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug("Only {0}/{1} episodes are monitored. skipping.", monitoredCount, subject.Episodes.Count);
|
if (subject.Episodes.Count == 1)
|
||||||
return Decision.Reject("Episode is not monitored");
|
{
|
||||||
|
_logger.Debug("Episode is not monitored. Rejecting", monitoredCount, subject.Episodes.Count);
|
||||||
|
return Decision.Reject("Episode is not monitored");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitoredCount == 0)
|
||||||
|
{
|
||||||
|
_logger.Debug("No episodes in the release are monitored. Rejecting", monitoredCount, subject.Episodes.Count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Debug("Only {0}/{1} episodes in the release are monitored. Rejecting", monitoredCount, subject.Episodes.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Decision.Reject("One or more episodes is not monitored");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -13,6 +13,7 @@ using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
|
|||||||
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
using NzbDrone.Core.MediaFiles.TorrentInfo;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.DownloadStation
|
namespace NzbDrone.Core.Download.Clients.DownloadStation
|
||||||
@@ -47,6 +48,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
|||||||
|
|
||||||
public override string Name => "Download Station";
|
public override string Name => "Download Station";
|
||||||
|
|
||||||
|
public override ProviderMessage Message => new ProviderMessage("Sonarr is unable to connect to Download Station if 2-Factor Authentication is enabled on your DSM account", ProviderMessageType.Warning);
|
||||||
|
|
||||||
protected IEnumerable<DownloadStationTask> GetTasks()
|
protected IEnumerable<DownloadStationTask> GetTasks()
|
||||||
{
|
{
|
||||||
return _dsTaskProxy.GetTasks(Settings).Where(v => v.Type.ToLower() == DownloadStationTaskType.BT.ToString().ToLower());
|
return _dsTaskProxy.GetTasks(Settings).Where(v => v.Type.ToLower() == DownloadStationTaskType.BT.ToString().ToLower());
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using NzbDrone.Core.Configuration;
|
|||||||
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
|
using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.RemotePathMappings;
|
using NzbDrone.Core.RemotePathMappings;
|
||||||
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Validation;
|
using NzbDrone.Core.Validation;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Download.Clients.DownloadStation
|
namespace NzbDrone.Core.Download.Clients.DownloadStation
|
||||||
@@ -46,6 +47,8 @@ namespace NzbDrone.Core.Download.Clients.DownloadStation
|
|||||||
|
|
||||||
public override string Name => "Download Station";
|
public override string Name => "Download Station";
|
||||||
|
|
||||||
|
public override ProviderMessage Message => new ProviderMessage("Sonarr is unable to connect to Download Station if 2-Factor Authentication is enabled on your DSM account", ProviderMessageType.Warning);
|
||||||
|
|
||||||
protected IEnumerable<DownloadStationTask> GetTasks()
|
protected IEnumerable<DownloadStationTask> GetTasks()
|
||||||
{
|
{
|
||||||
return _dsTaskProxy.GetTasks(Settings).Where(v => v.Type.ToLower() == DownloadStationTaskType.NZB.ToString().ToLower());
|
return _dsTaskProxy.GetTasks(Settings).Where(v => v.Type.ToLower() == DownloadStationTaskType.NZB.ToString().ToLower());
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.ThingiProvider.Status;
|
using NzbDrone.Core.ThingiProvider.Status;
|
||||||
|
|
||||||
@@ -12,8 +13,8 @@ namespace NzbDrone.Core.Download
|
|||||||
|
|
||||||
public class DownloadClientStatusService : ProviderStatusServiceBase<IDownloadClient, DownloadClientStatus>, IDownloadClientStatusService
|
public class DownloadClientStatusService : ProviderStatusServiceBase<IDownloadClient, DownloadClientStatus>, IDownloadClientStatusService
|
||||||
{
|
{
|
||||||
public DownloadClientStatusService(IDownloadClientStatusRepository providerStatusRepository, IEventAggregator eventAggregator, Logger logger)
|
public DownloadClientStatusService(IDownloadClientStatusRepository providerStatusRepository, IEventAggregator eventAggregator, IRuntimeInfo runtimeInfo, Logger logger)
|
||||||
: base(providerStatusRepository, eventAggregator, logger)
|
: base(providerStatusRepository, eventAggregator, runtimeInfo, logger)
|
||||||
{
|
{
|
||||||
MinimumTimeSinceInitialFailure = TimeSpan.FromMinutes(5);
|
MinimumTimeSinceInitialFailure = TimeSpan.FromMinutes(5);
|
||||||
MaximumEscalationLevel = 5;
|
MaximumEscalationLevel = 5;
|
||||||
|
|||||||
@@ -16,18 +16,18 @@ namespace NzbDrone.Core.Extras.Metadata
|
|||||||
public class ExistingMetadataImporter : ImportExistingExtraFilesBase<MetadataFile>
|
public class ExistingMetadataImporter : ImportExistingExtraFilesBase<MetadataFile>
|
||||||
{
|
{
|
||||||
private readonly IExtraFileService<MetadataFile> _metadataFileService;
|
private readonly IExtraFileService<MetadataFile> _metadataFileService;
|
||||||
private readonly IAugmentingService _augmentingService;
|
private readonly IAggregationService _aggregationService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
private readonly List<IMetadata> _consumers;
|
private readonly List<IMetadata> _consumers;
|
||||||
|
|
||||||
public ExistingMetadataImporter(IExtraFileService<MetadataFile> metadataFileService,
|
public ExistingMetadataImporter(IExtraFileService<MetadataFile> metadataFileService,
|
||||||
IEnumerable<IMetadata> consumers,
|
IEnumerable<IMetadata> consumers,
|
||||||
IAugmentingService augmentingService,
|
IAggregationService aggregationService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(metadataFileService)
|
: base(metadataFileService)
|
||||||
{
|
{
|
||||||
_metadataFileService = metadataFileService;
|
_metadataFileService = metadataFileService;
|
||||||
_augmentingService = augmentingService;
|
_aggregationService = aggregationService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_consumers = consumers.ToList();
|
_consumers = consumers.ToList();
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_augmentingService.Augment(localEpisode, false);
|
_aggregationService.Augment(localEpisode, false);
|
||||||
}
|
}
|
||||||
catch (AugmentingFailedException ex)
|
catch (AugmentingFailedException ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,16 +15,16 @@ namespace NzbDrone.Core.Extras.Others
|
|||||||
public class ExistingOtherExtraImporter : ImportExistingExtraFilesBase<OtherExtraFile>
|
public class ExistingOtherExtraImporter : ImportExistingExtraFilesBase<OtherExtraFile>
|
||||||
{
|
{
|
||||||
private readonly IExtraFileService<OtherExtraFile> _otherExtraFileService;
|
private readonly IExtraFileService<OtherExtraFile> _otherExtraFileService;
|
||||||
private readonly IAugmentingService _augmentingService;
|
private readonly IAggregationService _aggregationService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public ExistingOtherExtraImporter(IExtraFileService<OtherExtraFile> otherExtraFileService,
|
public ExistingOtherExtraImporter(IExtraFileService<OtherExtraFile> otherExtraFileService,
|
||||||
IAugmentingService augmentingService,
|
IAggregationService aggregationService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base(otherExtraFileService)
|
: base(otherExtraFileService)
|
||||||
{
|
{
|
||||||
_otherExtraFileService = otherExtraFileService;
|
_otherExtraFileService = otherExtraFileService;
|
||||||
_augmentingService = augmentingService;
|
_aggregationService = aggregationService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ namespace NzbDrone.Core.Extras.Others
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_augmentingService.Augment(localEpisode, false);
|
_aggregationService.Augment(localEpisode, false);
|
||||||
}
|
}
|
||||||
catch (AugmentingFailedException ex)
|
catch (AugmentingFailedException ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ namespace NzbDrone.Core.Extras.Subtitles
|
|||||||
public class ExistingSubtitleImporter : ImportExistingExtraFilesBase<SubtitleFile>
|
public class ExistingSubtitleImporter : ImportExistingExtraFilesBase<SubtitleFile>
|
||||||
{
|
{
|
||||||
private readonly IExtraFileService<SubtitleFile> _subtitleFileService;
|
private readonly IExtraFileService<SubtitleFile> _subtitleFileService;
|
||||||
private readonly IAugmentingService _augmentingService;
|
private readonly IAggregationService _aggregationService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public ExistingSubtitleImporter(IExtraFileService<SubtitleFile> subtitleFileService,
|
public ExistingSubtitleImporter(IExtraFileService<SubtitleFile> subtitleFileService,
|
||||||
IAugmentingService augmentingService,
|
IAggregationService aggregationService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
: base (subtitleFileService)
|
: base (subtitleFileService)
|
||||||
{
|
{
|
||||||
_subtitleFileService = subtitleFileService;
|
_subtitleFileService = subtitleFileService;
|
||||||
_augmentingService = augmentingService;
|
_aggregationService = aggregationService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ namespace NzbDrone.Core.Extras.Subtitles
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_augmentingService.Augment(localEpisode, false);
|
_aggregationService.Augment(localEpisode, false);
|
||||||
}
|
}
|
||||||
catch (AugmentingFailedException ex)
|
catch (AugmentingFailedException ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace NzbDrone.Core.History
|
|||||||
{
|
{
|
||||||
List<QualityModel> GetBestQualityInHistory(int episodeId);
|
List<QualityModel> GetBestQualityInHistory(int episodeId);
|
||||||
History MostRecentForEpisode(int episodeId);
|
History MostRecentForEpisode(int episodeId);
|
||||||
|
List<History> FindByEpisodeId(int episodeId);
|
||||||
History MostRecentForDownloadId(string downloadId);
|
History MostRecentForDownloadId(string downloadId);
|
||||||
List<History> FindByDownloadId(string downloadId);
|
List<History> FindByDownloadId(string downloadId);
|
||||||
List<History> FindDownloadHistory(int idSeriesId, QualityModel quality);
|
List<History> FindDownloadHistory(int idSeriesId, QualityModel quality);
|
||||||
@@ -43,6 +44,13 @@ namespace NzbDrone.Core.History
|
|||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<History> FindByEpisodeId(int episodeId)
|
||||||
|
{
|
||||||
|
return Query.Where(h => h.EpisodeId == episodeId)
|
||||||
|
.OrderByDescending(h => h.Date)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public History MostRecentForDownloadId(string downloadId)
|
public History MostRecentForDownloadId(string downloadId)
|
||||||
{
|
{
|
||||||
return Query.Where(h => h.DownloadId == downloadId)
|
return Query.Where(h => h.DownloadId == downloadId)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace NzbDrone.Core.History
|
|||||||
QualityModel GetBestQualityInHistory(Profile profile, int episodeId);
|
QualityModel GetBestQualityInHistory(Profile profile, int episodeId);
|
||||||
PagingSpec<History> Paged(PagingSpec<History> pagingSpec);
|
PagingSpec<History> Paged(PagingSpec<History> pagingSpec);
|
||||||
History MostRecentForEpisode(int episodeId);
|
History MostRecentForEpisode(int episodeId);
|
||||||
|
List<History> FindByEpisodeId(int episodeId);
|
||||||
History MostRecentForDownloadId(string downloadId);
|
History MostRecentForDownloadId(string downloadId);
|
||||||
History Get(int historyId);
|
History Get(int historyId);
|
||||||
List<History> Find(string downloadId, HistoryEventType eventType);
|
List<History> Find(string downloadId, HistoryEventType eventType);
|
||||||
@@ -55,6 +56,11 @@ namespace NzbDrone.Core.History
|
|||||||
return _historyRepository.MostRecentForEpisode(episodeId);
|
return _historyRepository.MostRecentForEpisode(episodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<History> FindByEpisodeId(int episodeId)
|
||||||
|
{
|
||||||
|
return _historyRepository.FindByEpisodeId(episodeId);
|
||||||
|
}
|
||||||
|
|
||||||
public History MostRecentForDownloadId(string downloadId)
|
public History MostRecentForDownloadId(string downloadId)
|
||||||
{
|
{
|
||||||
return _historyRepository.MostRecentForDownloadId(downloadId);
|
return _historyRepository.MostRecentForDownloadId(downloadId);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -314,6 +314,16 @@ namespace NzbDrone.Core.IndexerSearch
|
|||||||
|
|
||||||
_logger.Debug("Total of {0} reports were found for {1} from {2} indexers", reports.Count, criteriaBase, indexers.Count);
|
_logger.Debug("Total of {0} reports were found for {1} from {2} indexers", reports.Count, criteriaBase, indexers.Count);
|
||||||
|
|
||||||
|
// Update the last search time for all episodes if at least 1 indexer was searched.
|
||||||
|
if (indexers.Any())
|
||||||
|
{
|
||||||
|
var lastSearchTime = DateTime.UtcNow;
|
||||||
|
_logger.Debug("Setting last search time to: {0}", lastSearchTime);
|
||||||
|
|
||||||
|
criteriaBase.Episodes.ForEach(e => e.LastSearchTime = lastSearchTime);
|
||||||
|
_episodeService.UpdateEpisodes(criteriaBase.Episodes);
|
||||||
|
}
|
||||||
|
|
||||||
return _makeDownloadDecision.GetSearchDecision(reports, criteriaBase).ToList();
|
return _makeDownloadDecision.GetSearchDecision(reports, criteriaBase).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.ThingiProvider.Status;
|
using NzbDrone.Core.ThingiProvider.Status;
|
||||||
@@ -14,8 +15,8 @@ namespace NzbDrone.Core.Indexers
|
|||||||
|
|
||||||
public class IndexerStatusService : ProviderStatusServiceBase<IIndexer, IndexerStatus>, IIndexerStatusService
|
public class IndexerStatusService : ProviderStatusServiceBase<IIndexer, IndexerStatus>, IIndexerStatusService
|
||||||
{
|
{
|
||||||
public IndexerStatusService(IIndexerStatusRepository providerStatusRepository, IEventAggregator eventAggregator, Logger logger)
|
public IndexerStatusService(IIndexerStatusRepository providerStatusRepository, IEventAggregator eventAggregator, IRuntimeInfo runtimeInfo, Logger logger)
|
||||||
: base(providerStatusRepository, eventAggregator, logger)
|
: base(providerStatusRepository, eventAggregator, runtimeInfo, logger)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -253,12 +253,25 @@ namespace NzbDrone.Core.Indexers
|
|||||||
protected virtual RssEnclosure[] GetEnclosures(XElement item)
|
protected virtual RssEnclosure[] GetEnclosures(XElement item)
|
||||||
{
|
{
|
||||||
var enclosures = item.Elements("enclosure")
|
var enclosures = item.Elements("enclosure")
|
||||||
.Select(v => new RssEnclosure
|
.Select(v =>
|
||||||
{
|
{
|
||||||
Url = v.Attribute("url").Value,
|
try
|
||||||
Type = v.Attribute("type").Value,
|
{
|
||||||
Length = (long)v.Attribute("length")
|
return new RssEnclosure
|
||||||
|
{
|
||||||
|
Url = v.Attribute("url").Value,
|
||||||
|
Type = v.Attribute("type").Value,
|
||||||
|
Length = (long)v.Attribute("length")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Warn(e, "Failed to get enclosure for: {0}", item.Title());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
})
|
})
|
||||||
|
.Where(v => v != null)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
return enclosures;
|
return enclosures;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Marr.Data;
|
using Marr.Data;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
@@ -17,6 +17,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
public long Size { get; set; }
|
public long Size { get; set; }
|
||||||
public DateTime DateAdded { get; set; }
|
public DateTime DateAdded { get; set; }
|
||||||
|
public string OriginalFilePath { get; set; }
|
||||||
public string SceneName { get; set; }
|
public string SceneName { get; set; }
|
||||||
public string ReleaseGroup { get; set; }
|
public string ReleaseGroup { get; set; }
|
||||||
public QualityModel Quality { get; set; }
|
public QualityModel Quality { get; set; }
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ using NzbDrone.Core.Parser.Model;
|
|||||||
|
|
||||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation
|
||||||
{
|
{
|
||||||
public interface IAugmentingService
|
public interface IAggregationService
|
||||||
{
|
{
|
||||||
LocalEpisode Augment(LocalEpisode localEpisode, bool otherFiles);
|
LocalEpisode Augment(LocalEpisode localEpisode, bool otherFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AugmentingService : IAugmentingService
|
public class AggregationService : IAggregationService
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<IAggregateLocalEpisode> _augmenters;
|
private readonly IEnumerable<IAggregateLocalEpisode> _augmenters;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
@@ -23,7 +23,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation
|
|||||||
private readonly IConfigService _configService;
|
private readonly IConfigService _configService;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public AugmentingService(IEnumerable<IAggregateLocalEpisode> augmenters,
|
public AggregationService(IEnumerable<IAggregateLocalEpisode> augmenters,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IVideoFileInfoReader videoFileInfoReader,
|
IVideoFileInfoReader videoFileInfoReader,
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
@@ -38,11 +38,13 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation
|
|||||||
|
|
||||||
public LocalEpisode Augment(LocalEpisode localEpisode, bool otherFiles)
|
public LocalEpisode Augment(LocalEpisode localEpisode, bool otherFiles)
|
||||||
{
|
{
|
||||||
|
var isMediaFile = MediaFileExtensions.Extensions.Contains(Path.GetExtension(localEpisode.Path));
|
||||||
|
|
||||||
if (localEpisode.DownloadClientEpisodeInfo == null &&
|
if (localEpisode.DownloadClientEpisodeInfo == null &&
|
||||||
localEpisode.FolderEpisodeInfo == null &&
|
localEpisode.FolderEpisodeInfo == null &&
|
||||||
localEpisode.FileEpisodeInfo == null)
|
localEpisode.FileEpisodeInfo == null)
|
||||||
{
|
{
|
||||||
if (MediaFileExtensions.Extensions.Contains(Path.GetExtension(localEpisode.Path)))
|
if (isMediaFile)
|
||||||
{
|
{
|
||||||
throw new AugmentingFailedException("Unable to parse episode info from path: {0}", localEpisode.Path);
|
throw new AugmentingFailedException("Unable to parse episode info from path: {0}", localEpisode.Path);
|
||||||
}
|
}
|
||||||
@@ -50,7 +52,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation
|
|||||||
|
|
||||||
localEpisode.Size = _diskProvider.GetFileSize(localEpisode.Path);
|
localEpisode.Size = _diskProvider.GetFileSize(localEpisode.Path);
|
||||||
|
|
||||||
if (!localEpisode.ExistingFile || _configService.EnableMediaInfo)
|
if (isMediaFile && (!localEpisode.ExistingFile || _configService.EnableMediaInfo))
|
||||||
{
|
{
|
||||||
localEpisode.MediaInfo = _videoFileInfoReader.GetMediaInfo(localEpisode.Path);
|
localEpisode.MediaInfo = _videoFileInfoReader.GetMediaInfo(localEpisode.Path);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -49,7 +49,10 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Aggregation.Aggregators
|
|||||||
var title = Path.GetFileNameWithoutExtension(localEpisode.Path);
|
var title = Path.GetFileNameWithoutExtension(localEpisode.Path);
|
||||||
var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, title, localEpisode.Series);
|
var specialEpisodeInfo = _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, title, localEpisode.Series);
|
||||||
|
|
||||||
return specialEpisodeInfo;
|
if (specialEpisodeInfo != null)
|
||||||
|
{
|
||||||
|
parsedEpisodeInfo = specialEpisodeInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedEpisodeInfo;
|
return parsedEpisodeInfo;
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||||||
|
|
||||||
if (newDownload)
|
if (newDownload)
|
||||||
{
|
{
|
||||||
|
episodeFile.OriginalFilePath = GetOriginalFilePath(downloadClientItem, localEpisode);
|
||||||
episodeFile.SceneName = GetSceneName(downloadClientItem, localEpisode);
|
episodeFile.SceneName = GetSceneName(downloadClientItem, localEpisode);
|
||||||
|
|
||||||
var moveResult = _episodeFileUpgrader.UpgradeEpisodeFile(episodeFile, localEpisode, copyOnly);
|
var moveResult = _episodeFileUpgrader.UpgradeEpisodeFile(episodeFile, localEpisode, copyOnly);
|
||||||
@@ -148,6 +149,37 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||||||
return importResults;
|
return importResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetOriginalFilePath(DownloadClientItem downloadClientItem, LocalEpisode localEpisode)
|
||||||
|
{
|
||||||
|
if (downloadClientItem != null)
|
||||||
|
{
|
||||||
|
return downloadClientItem.OutputPath.Directory.ToString().GetRelativePath(localEpisode.Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = localEpisode.Path;
|
||||||
|
var folderEpisodeInfo = localEpisode.FolderEpisodeInfo;
|
||||||
|
|
||||||
|
if (folderEpisodeInfo != null)
|
||||||
|
{
|
||||||
|
var folderPath = path.GetAncestorPath(folderEpisodeInfo.ReleaseTitle);
|
||||||
|
|
||||||
|
if (folderPath != null)
|
||||||
|
{
|
||||||
|
return folderPath.GetParentPath().GetRelativePath(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parentPath = path.GetParentPath();
|
||||||
|
var grandparentPath = parentPath.GetParentPath();
|
||||||
|
|
||||||
|
if (grandparentPath != null)
|
||||||
|
{
|
||||||
|
return grandparentPath.GetRelativePath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Path.Combine(Path.GetFileName(parentPath), Path.GetFileName(path));
|
||||||
|
}
|
||||||
|
|
||||||
private string GetSceneName(DownloadClientItem downloadClientItem, LocalEpisode localEpisode)
|
private string GetSceneName(DownloadClientItem downloadClientItem, LocalEpisode localEpisode)
|
||||||
{
|
{
|
||||||
if (downloadClientItem != null)
|
if (downloadClientItem != null)
|
||||||
|
|||||||
@@ -23,21 +23,21 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||||||
{
|
{
|
||||||
private readonly IEnumerable<IImportDecisionEngineSpecification> _specifications;
|
private readonly IEnumerable<IImportDecisionEngineSpecification> _specifications;
|
||||||
private readonly IMediaFileService _mediaFileService;
|
private readonly IMediaFileService _mediaFileService;
|
||||||
private readonly IAugmentingService _augmentingService;
|
private readonly IAggregationService _aggregationService;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly IDetectSample _detectSample;
|
private readonly IDetectSample _detectSample;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public ImportDecisionMaker(IEnumerable<IImportDecisionEngineSpecification> specifications,
|
public ImportDecisionMaker(IEnumerable<IImportDecisionEngineSpecification> specifications,
|
||||||
IMediaFileService mediaFileService,
|
IMediaFileService mediaFileService,
|
||||||
IAugmentingService augmentingService,
|
IAggregationService aggregationService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IDetectSample detectSample,
|
IDetectSample detectSample,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_specifications = specifications;
|
_specifications = specifications;
|
||||||
_mediaFileService = mediaFileService;
|
_mediaFileService = mediaFileService;
|
||||||
_augmentingService = augmentingService;
|
_aggregationService = aggregationService;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_detectSample = detectSample;
|
_detectSample = detectSample;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@@ -96,7 +96,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_augmentingService.Augment(localEpisode, otherFiles);
|
_aggregationService.Augment(localEpisode, otherFiles);
|
||||||
|
|
||||||
if (localEpisode.Episodes.Empty())
|
if (localEpisode.Episodes.Empty())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||||||
private readonly IEpisodeService _episodeService;
|
private readonly IEpisodeService _episodeService;
|
||||||
private readonly IVideoFileInfoReader _videoFileInfoReader;
|
private readonly IVideoFileInfoReader _videoFileInfoReader;
|
||||||
private readonly IImportApprovedEpisodes _importApprovedEpisodes;
|
private readonly IImportApprovedEpisodes _importApprovedEpisodes;
|
||||||
private readonly IAugmentingService _augmentingService;
|
private readonly IAggregationService _aggregationService;
|
||||||
private readonly ITrackedDownloadService _trackedDownloadService;
|
private readonly ITrackedDownloadService _trackedDownloadService;
|
||||||
private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService;
|
private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService;
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
@@ -47,7 +47,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||||||
ISeriesService seriesService,
|
ISeriesService seriesService,
|
||||||
IEpisodeService episodeService,
|
IEpisodeService episodeService,
|
||||||
IVideoFileInfoReader videoFileInfoReader,
|
IVideoFileInfoReader videoFileInfoReader,
|
||||||
IAugmentingService augmentingService,
|
IAggregationService aggregationService,
|
||||||
IImportApprovedEpisodes importApprovedEpisodes,
|
IImportApprovedEpisodes importApprovedEpisodes,
|
||||||
ITrackedDownloadService trackedDownloadService,
|
ITrackedDownloadService trackedDownloadService,
|
||||||
IDownloadedEpisodesImportService downloadedEpisodesImportService,
|
IDownloadedEpisodesImportService downloadedEpisodesImportService,
|
||||||
@@ -61,7 +61,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||||||
_seriesService = seriesService;
|
_seriesService = seriesService;
|
||||||
_episodeService = episodeService;
|
_episodeService = episodeService;
|
||||||
_videoFileInfoReader = videoFileInfoReader;
|
_videoFileInfoReader = videoFileInfoReader;
|
||||||
_augmentingService = augmentingService;
|
_aggregationService = aggregationService;
|
||||||
_importApprovedEpisodes = importApprovedEpisodes;
|
_importApprovedEpisodes = importApprovedEpisodes;
|
||||||
_trackedDownloadService = trackedDownloadService;
|
_trackedDownloadService = trackedDownloadService;
|
||||||
_downloadedEpisodesImportService = downloadedEpisodesImportService;
|
_downloadedEpisodesImportService = downloadedEpisodesImportService;
|
||||||
@@ -281,7 +281,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||||||
localEpisode.FolderEpisodeInfo = Parser.Parser.ParseTitle(file.FolderName);
|
localEpisode.FolderEpisodeInfo = Parser.Parser.ParseTitle(file.FolderName);
|
||||||
}
|
}
|
||||||
|
|
||||||
localEpisode = _augmentingService.Augment(localEpisode, false);
|
localEpisode = _aggregationService.Augment(localEpisode, false);
|
||||||
|
|
||||||
// Apply the user-chosen values.
|
// Apply the user-chosen values.
|
||||||
localEpisode.Series = series;
|
localEpisode.Series = series;
|
||||||
|
|||||||
-60
@@ -1,60 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Core.DecisionEngine;
|
|
||||||
using NzbDrone.Core.Download;
|
|
||||||
using NzbDrone.Core.History;
|
|
||||||
using NzbDrone.Core.Parser.Model;
|
|
||||||
using NzbDrone.Core.Qualities;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|
||||||
{
|
|
||||||
public class GrabbedReleaseQualitySpecification : IImportDecisionEngineSpecification
|
|
||||||
{
|
|
||||||
private readonly IHistoryService _historyService;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
public GrabbedReleaseQualitySpecification(IHistoryService historyService, Logger logger)
|
|
||||||
{
|
|
||||||
_historyService = historyService;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem)
|
|
||||||
{
|
|
||||||
if (downloadClientItem == null)
|
|
||||||
{
|
|
||||||
_logger.Debug("No download client item provided, skipping.");
|
|
||||||
return Decision.Accept();
|
|
||||||
}
|
|
||||||
|
|
||||||
var grabbedHistory = _historyService.FindByDownloadId(downloadClientItem.DownloadId)
|
|
||||||
.Where(h => h.EventType == HistoryEventType.Grabbed)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (grabbedHistory.Empty())
|
|
||||||
{
|
|
||||||
_logger.Debug("No grabbed history for this download client item");
|
|
||||||
return Decision.Accept();
|
|
||||||
}
|
|
||||||
|
|
||||||
var parsedReleaseName = Parser.Parser.ParseTitle(grabbedHistory.First().SourceTitle);
|
|
||||||
|
|
||||||
if (parsedReleaseName != null && parsedReleaseName.FullSeason)
|
|
||||||
{
|
|
||||||
_logger.Debug("File is part of a season pack, skipping.");
|
|
||||||
return Decision.Accept();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var item in grabbedHistory)
|
|
||||||
{
|
|
||||||
if (item.Quality.Quality != Quality.Unknown && item.Quality != localEpisode.Quality)
|
|
||||||
{
|
|
||||||
_logger.Debug("Quality for grabbed release ({0}) does not match the quality of the file ({1})", item.Quality, localEpisode.Quality);
|
|
||||||
return Decision.Reject("File quality does not match quality of the grabbed release");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Decision.Accept();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -43,8 +43,9 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
|||||||
environmentVariables.Add("Sonarr_Series_ImdbId", series.ImdbId ?? string.Empty);
|
environmentVariables.Add("Sonarr_Series_ImdbId", series.ImdbId ?? string.Empty);
|
||||||
environmentVariables.Add("Sonarr_Series_Type", series.SeriesType.ToString());
|
environmentVariables.Add("Sonarr_Series_Type", series.SeriesType.ToString());
|
||||||
environmentVariables.Add("Sonarr_Release_EpisodeCount", remoteEpisode.Episodes.Count.ToString());
|
environmentVariables.Add("Sonarr_Release_EpisodeCount", remoteEpisode.Episodes.Count.ToString());
|
||||||
environmentVariables.Add("Sonarr_Release_SeasonNumber", remoteEpisode.ParsedEpisodeInfo.SeasonNumber.ToString());
|
environmentVariables.Add("Sonarr_Release_SeasonNumber", remoteEpisode.Episodes.First().SeasonNumber.ToString());
|
||||||
environmentVariables.Add("Sonarr_Release_EpisodeNumbers", string.Join(",", remoteEpisode.Episodes.Select(e => e.EpisodeNumber)));
|
environmentVariables.Add("Sonarr_Release_EpisodeNumbers", string.Join(",", remoteEpisode.Episodes.Select(e => e.EpisodeNumber)));
|
||||||
|
environmentVariables.Add("Sonarr_Release_AbsoluteEpisodeNumbers", string.Join(",", remoteEpisode.Episodes.Select(e => e.AbsoluteEpisodeNumber)));
|
||||||
environmentVariables.Add("Sonarr_Release_EpisodeAirDates", string.Join(",", remoteEpisode.Episodes.Select(e => e.AirDate)));
|
environmentVariables.Add("Sonarr_Release_EpisodeAirDates", string.Join(",", remoteEpisode.Episodes.Select(e => e.AirDate)));
|
||||||
environmentVariables.Add("Sonarr_Release_EpisodeAirDatesUtc", string.Join(",", remoteEpisode.Episodes.Select(e => e.AirDateUtc)));
|
environmentVariables.Add("Sonarr_Release_EpisodeAirDatesUtc", string.Join(",", remoteEpisode.Episodes.Select(e => e.AirDateUtc)));
|
||||||
environmentVariables.Add("Sonarr_Release_EpisodeTitles", string.Join("|", remoteEpisode.Episodes.Select(e => e.Title)));
|
environmentVariables.Add("Sonarr_Release_EpisodeTitles", string.Join("|", remoteEpisode.Episodes.Select(e => e.Title)));
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace NzbDrone.Core.Notifications.Join
|
||||||
|
{
|
||||||
|
public enum JoinPriority
|
||||||
|
{
|
||||||
|
Silent = -2,
|
||||||
|
Quiet = -1,
|
||||||
|
Normal = 0,
|
||||||
|
High = 1,
|
||||||
|
Emergency = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -94,6 +94,7 @@ namespace NzbDrone.Core.Notifications.Join
|
|||||||
request.AddParameter("text", message);
|
request.AddParameter("text", message);
|
||||||
request.AddParameter("icon", "https://cdn.rawgit.com/Sonarr/Sonarr/develop/Logo/256.png"); // Use the Sonarr logo.
|
request.AddParameter("icon", "https://cdn.rawgit.com/Sonarr/Sonarr/develop/Logo/256.png"); // Use the Sonarr logo.
|
||||||
request.AddParameter("smallicon", "https://cdn.rawgit.com/Sonarr/Sonarr/develop/Logo/96-Outline-White.png"); // 96x96px with outline at 88x88px on a transparent background.
|
request.AddParameter("smallicon", "https://cdn.rawgit.com/Sonarr/Sonarr/develop/Logo/96-Outline-White.png"); // 96x96px with outline at 88x88px on a transparent background.
|
||||||
|
request.AddParameter("priority", settings.Priority);
|
||||||
|
|
||||||
var response = client.ExecuteAndValidate(request);
|
var response = client.ExecuteAndValidate(request);
|
||||||
var res = Json.Deserialize<JoinResponseModel>(response.Content);
|
var res = Json.Deserialize<JoinResponseModel>(response.Content);
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ namespace NzbDrone.Core.Notifications.Join
|
|||||||
|
|
||||||
public class JoinSettings : IProviderConfig
|
public class JoinSettings : IProviderConfig
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public JoinSettings()
|
||||||
|
{
|
||||||
|
Priority = (int)JoinPriority.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
private static readonly JoinSettingsValidator Validator = new JoinSettingsValidator();
|
private static readonly JoinSettingsValidator Validator = new JoinSettingsValidator();
|
||||||
|
|
||||||
[FieldDefinition(0, Label = "API Key", HelpText = "The API Key from your Join account settings (click Join API button).", HelpLink = "https://joinjoaomgcd.appspot.com/")]
|
[FieldDefinition(0, Label = "API Key", HelpText = "The API Key from your Join account settings (click Join API button).", HelpLink = "https://joinjoaomgcd.appspot.com/")]
|
||||||
@@ -27,6 +33,9 @@ namespace NzbDrone.Core.Notifications.Join
|
|||||||
[FieldDefinition(2, Label = "Device Names", HelpText = "Comma separated list of full or partial device names you'd like to send notifications to. If unset, all devices will receive notifications.", HelpLink = "https://joaoapps.com/join/api/")]
|
[FieldDefinition(2, Label = "Device Names", HelpText = "Comma separated list of full or partial device names you'd like to send notifications to. If unset, all devices will receive notifications.", HelpLink = "https://joaoapps.com/join/api/")]
|
||||||
public string DeviceNames { get; set; }
|
public string DeviceNames { get; set; }
|
||||||
|
|
||||||
|
[FieldDefinition(3, Label = "Notification Priority", Type = FieldType.Select, SelectOptions = typeof(JoinPriority))]
|
||||||
|
public int Priority { get; set; }
|
||||||
|
|
||||||
public NzbDroneValidationResult Validate()
|
public NzbDroneValidationResult Validate()
|
||||||
{
|
{
|
||||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -53,6 +53,18 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||||||
|
|
||||||
public void Clean(XbmcSettings settings)
|
public void Clean(XbmcSettings settings)
|
||||||
{
|
{
|
||||||
|
if (!settings.AlwaysUpdate)
|
||||||
|
{
|
||||||
|
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
|
||||||
|
var activePlayers = GetActivePlayers(settings);
|
||||||
|
|
||||||
|
if (activePlayers.Any(a => a.Type.Equals("video")))
|
||||||
|
{
|
||||||
|
_logger.Debug("Video is currently playing, skipping library cleaning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const string cleanVideoLibrary = "CleanLibrary(video)";
|
const string cleanVideoLibrary = "CleanLibrary(video)";
|
||||||
var command = BuildExecBuiltInCommand(cleanVideoLibrary);
|
var command = BuildExecBuiltInCommand(cleanVideoLibrary);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
@@ -33,7 +33,7 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||||||
if (!settings.AlwaysUpdate)
|
if (!settings.AlwaysUpdate)
|
||||||
{
|
{
|
||||||
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
|
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
|
||||||
var activePlayers = _proxy.GetActivePlayers(settings);
|
var activePlayers = GetActivePlayers(settings);
|
||||||
|
|
||||||
if (activePlayers.Any(a => a.Type.Equals("video")))
|
if (activePlayers.Any(a => a.Type.Equals("video")))
|
||||||
{
|
{
|
||||||
@@ -47,6 +47,18 @@ namespace NzbDrone.Core.Notifications.Xbmc
|
|||||||
|
|
||||||
public void Clean(XbmcSettings settings)
|
public void Clean(XbmcSettings settings)
|
||||||
{
|
{
|
||||||
|
if (!settings.AlwaysUpdate)
|
||||||
|
{
|
||||||
|
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
|
||||||
|
var activePlayers = GetActivePlayers(settings);
|
||||||
|
|
||||||
|
if (activePlayers.Any(a => a.Type.Equals("video")))
|
||||||
|
{
|
||||||
|
_logger.Debug("Video is currently playing, skipping library cleaning");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_proxy.CleanLibrary(settings);
|
_proxy.CleanLibrary(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -143,6 +143,9 @@
|
|||||||
<Compile Include="Configuration\IConfigService.cs" />
|
<Compile Include="Configuration\IConfigService.cs" />
|
||||||
<Compile Include="Configuration\InvalidConfigFileException.cs" />
|
<Compile Include="Configuration\InvalidConfigFileException.cs" />
|
||||||
<Compile Include="Configuration\ResetApiKeyCommand.cs" />
|
<Compile Include="Configuration\ResetApiKeyCommand.cs" />
|
||||||
|
<Compile Include="Datastore\Migration\130_episode_last_searched_time.cs" />
|
||||||
|
<Compile Include="Datastore\Migration\129_add_relative_original_path_to_episode_file.cs" />
|
||||||
|
<Compile Include="DecisionEngine\Specifications\AlreadyImportedSpecification.cs" />
|
||||||
<Compile Include="Indexers\SeedConfigProvider.cs" />
|
<Compile Include="Indexers\SeedConfigProvider.cs" />
|
||||||
<Compile Include="DataAugmentation\DailySeries\DailySeries.cs" />
|
<Compile Include="DataAugmentation\DailySeries\DailySeries.cs" />
|
||||||
<Compile Include="DataAugmentation\DailySeries\DailySeriesDataProxy.cs" />
|
<Compile Include="DataAugmentation\DailySeries\DailySeriesDataProxy.cs" />
|
||||||
@@ -817,7 +820,6 @@
|
|||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\EpisodeTitleSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\EpisodeTitleSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\SameFileSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\SameFileSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\GrabbedReleaseQualitySpecification.cs" />
|
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\MatchesFolderSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\MatchesFolderSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\FullSeasonSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotSampleSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotSampleSpecification.cs" />
|
||||||
@@ -911,6 +913,7 @@
|
|||||||
<Compile Include="MetadataSource\ISearchForNewSeries.cs" />
|
<Compile Include="MetadataSource\ISearchForNewSeries.cs" />
|
||||||
<Compile Include="Notifications\Join\JoinAuthException.cs" />
|
<Compile Include="Notifications\Join\JoinAuthException.cs" />
|
||||||
<Compile Include="Notifications\Join\JoinInvalidDeviceException.cs" />
|
<Compile Include="Notifications\Join\JoinInvalidDeviceException.cs" />
|
||||||
|
<Compile Include="Notifications\Join\JoinPriority.cs" />
|
||||||
<Compile Include="Notifications\Join\JoinResponseModel.cs" />
|
<Compile Include="Notifications\Join\JoinResponseModel.cs" />
|
||||||
<Compile Include="Notifications\Join\Join.cs" />
|
<Compile Include="Notifications\Join\Join.cs" />
|
||||||
<Compile Include="Notifications\Join\JoinException.cs" />
|
<Compile Include="Notifications\Join\JoinException.cs" />
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace NzbDrone.Core.Parser.Model
|
|||||||
public int SeasonNumber { get; set; }
|
public int SeasonNumber { get; set; }
|
||||||
public int[] EpisodeNumbers { get; set; }
|
public int[] EpisodeNumbers { get; set; }
|
||||||
public int[] AbsoluteEpisodeNumbers { get; set; }
|
public int[] AbsoluteEpisodeNumbers { get; set; }
|
||||||
|
public decimal[] SpecialAbsoluteEpisodeNumbers { get; set; }
|
||||||
public string AirDate { get; set; }
|
public string AirDate { get; set; }
|
||||||
public Language Language { get; set; }
|
public Language Language { get; set; }
|
||||||
public bool FullSeason { get; set; }
|
public bool FullSeason { get; set; }
|
||||||
@@ -27,6 +28,7 @@ namespace NzbDrone.Core.Parser.Model
|
|||||||
{
|
{
|
||||||
EpisodeNumbers = new int[0];
|
EpisodeNumbers = new int[0];
|
||||||
AbsoluteEpisodeNumbers = new int[0];
|
AbsoluteEpisodeNumbers = new int[0];
|
||||||
|
SpecialAbsoluteEpisodeNumbers = new decimal[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsDaily
|
public bool IsDaily
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@@ -22,6 +23,10 @@ namespace NzbDrone.Core.Parser
|
|||||||
// new Regex(@"^(?:(?<absoluteepisode>\d{2,3})(?:_|-|\s|\.)+)+(?<title>.+?)(?:\W|_)+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)",
|
// new Regex(@"^(?:(?<absoluteepisode>\d{2,3})(?:_|-|\s|\.)+)+(?<title>.+?)(?:\W|_)+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)",
|
||||||
// RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
// RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
|
//Daily episodes without title (2018-10-12, 20181012) (Strict pattern to avoid false matches)
|
||||||
|
new Regex(@"^(?<airyear>19[6-9]\d|20\d\d)(?<sep>[-]?)(?<airmonth>0\d|1[0-2])\k<sep>(?<airday>[0-2]\d|3[01])(?!\d)",
|
||||||
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Multi-Part episodes without a title (S01E05.S01E06)
|
//Multi-Part episodes without a title (S01E05.S01E06)
|
||||||
new Regex(@"^(?:\W*S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[ex]){1,2}(?<episode>\d{1,3}(?!\d+)))+){2,}",
|
new Regex(@"^(?:\W*S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:[ex]){1,2}(?<episode>\d{1,3}(?!\d+)))+){2,}",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
@@ -35,15 +40,15 @@ namespace NzbDrone.Core.Parser
|
|||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - [SubGroup] Title Episode Absolute Episode Number ([SubGroup] Series Title Episode 01)
|
//Anime - [SubGroup] Title Episode Absolute Episode Number ([SubGroup] Series Title Episode 01)
|
||||||
new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ]?)(?<title>.+?)[-_. ](?:Episode)(?:[-_. ]+(?<absoluteepisode>(?<!\d+)\d{2,3}(?!\d+)))+(?:_|-|\s|\.)*?(?<hash>\[.{8}\])?(?:$|\.)?",
|
new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ]?)(?<title>.+?)[-_. ](?:Episode)(?:[-_. ]+(?<absoluteepisode>(?<!\d+)\d{2,3}(\.\d{1,2})?(?!\d+)))+(?:_|-|\s|\.)*?(?<hash>\[.{8}\])?(?:$|\.)?",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - [SubGroup] Title Absolute Episode Number + Season+Episode
|
//Anime - [SubGroup] Title Absolute Episode Number + Season+Episode
|
||||||
new Regex(@"^(?:\[(?<subgroup>.+?)\](?:_|-|\s|\.)?)(?<title>.+?)(?:(?:[-_\W](?<![()\[!]))+(?<absoluteepisode>\d{2,3}))+(?:_|-|\s|\.)+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+).*?(?<hash>[(\[]\w{8}[)\]])?(?:$|\.)",
|
new Regex(@"^(?:\[(?<subgroup>.+?)\](?:_|-|\s|\.)?)(?<title>.+?)(?:(?:[-_\W](?<![()\[!]))+(?<absoluteepisode>\d{2,3}(\.\d{1,2})?))+(?:_|-|\s|\.)+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+).*?(?<hash>[(\[]\w{8}[)\]])?(?:$|\.)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - [SubGroup] Title Season+Episode + Absolute Episode Number
|
//Anime - [SubGroup] Title Season+Episode + Absolute Episode Number
|
||||||
new Regex(@"^(?:\[(?<subgroup>.+?)\](?:_|-|\s|\.)?)(?<title>.+?)(?:[-_\W](?<![()\[!]))+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)(?:(?:_|-|\s|\.)+(?<absoluteepisode>(?<!\d+)\d{2,3}(?!\d+)))+.*?(?<hash>\[\w{8}\])?(?:$|\.)",
|
new Regex(@"^(?:\[(?<subgroup>.+?)\](?:_|-|\s|\.)?)(?<title>.+?)(?:[-_\W](?<![()\[!]))+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)(?:(?:_|-|\s|\.)+(?<absoluteepisode>(?<!\d+)\d{2,3}(\.\d{1,2})?(?!\d+)))+.*?(?<hash>\[\w{8}\])?(?:$|\.)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - [SubGroup] Title Season+Episode
|
//Anime - [SubGroup] Title Season+Episode
|
||||||
@@ -51,15 +56,15 @@ namespace NzbDrone.Core.Parser
|
|||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - [SubGroup] Title with trailing number Absolute Episode Number
|
//Anime - [SubGroup] Title with trailing number Absolute Episode Number
|
||||||
new Regex(@"^\[(?<subgroup>.+?)\][-_. ]?(?<title>[^-]+?\d+?)[-_. ]+(?:[-_. ]?(?<absoluteepisode>\d{3}(?!\d+)))+(?:[-_. ]+(?<special>special|ova|ovd))?.*?(?<hash>\[\w{8}\])?(?:$|\.mkv)",
|
new Regex(@"^\[(?<subgroup>.+?)\][-_. ]?(?<title>[^-]+?\d+?)[-_. ]+(?:[-_. ]?(?<absoluteepisode>\d{3}(\.\d{1,2})?(?!\d+)))+(?:[-_. ]+(?<special>special|ova|ovd))?.*?(?<hash>\[\w{8}\])?(?:$|\.mkv)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - [SubGroup] Title - Absolute Episode Number
|
//Anime - [SubGroup] Title - Absolute Episode Number
|
||||||
new Regex(@"^\[(?<subgroup>.+?)\][-_. ]?(?<title>.+?)(?:[. ]-[. ](?<absoluteepisode>\d{2,3}(?!\d+|[-])))+(?:[-_. ]+(?<special>special|ova|ovd))?.*?(?<hash>\[\w{8}\])?(?:$|\.mkv)",
|
new Regex(@"^\[(?<subgroup>.+?)\][-_. ]?(?<title>.+?)(?:[. ]-[. ](?<absoluteepisode>\d{2,3}(\.\d{1,2})?(?!\d+|[-])))+(?:[-_. ]+(?<special>special|ova|ovd))?.*?(?<hash>\[\w{8}\])?(?:$|\.mkv)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - [SubGroup] Title Absolute Episode Number
|
//Anime - [SubGroup] Title Absolute Episode Number
|
||||||
new Regex(@"^\[(?<subgroup>.+?)\][-_. ]?(?<title>.+?)[-_. ]+\(?(?:[-_. ]?#?(?<absoluteepisode>\d{2,3}(?!\d+)))+\)?(?:[-_. ]+(?<special>special|ova|ovd))?.*?(?<hash>\[\w{8}\])?(?:$|\.mkv)",
|
new Regex(@"^\[(?<subgroup>.+?)\][-_. ]?(?<title>.+?)[-_. ]+\(?(?:[-_. ]?#?(?<absoluteepisode>\d{2,3}(\.\d{1,2})?(?!\d+)))+\)?(?:[-_. ]+(?<special>special|ova|ovd))?.*?(?<hash>\[\w{8}\])?(?:$|\.mkv)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Multi-episode Repeated (S01E05 - S01E06, 1x05 - 1x06, etc)
|
//Multi-episode Repeated (S01E05 - S01E06, 1x05 - 1x06, etc)
|
||||||
@@ -71,7 +76,7 @@ namespace NzbDrone.Core.Parser
|
|||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - Title Season EpisodeNumber + Absolute Episode Number [SubGroup]
|
//Anime - Title Season EpisodeNumber + Absolute Episode Number [SubGroup]
|
||||||
new Regex(@"^(?<title>.+?)(?:[-_\W](?<![()\[!]))+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:[ex]|\W[ex]){1,2}(?<episode>(?<!\d+)\d{2}(?!\d+)))).+?(?:[-_. ]?(?<absoluteepisode>(?<!\d+)\d{3}(?!\d+)))+.+?\[(?<subgroup>.+?)\](?:$|\.mkv)",
|
new Regex(@"^(?<title>.+?)(?:[-_\W](?<![()\[!]))+(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:[ex]|\W[ex]){1,2}(?<episode>(?<!\d+)\d{2}(?!\d+)))).+?(?:[-_. ]?(?<absoluteepisode>(?<!\d+)\d{3}(\.\d{1,2})?(?!\d+)))+.+?\[(?<subgroup>.+?)\](?:$|\.mkv)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Multi-Episode with a title (S01E05E06, S01E05-06, S01E05 E06, etc) and trailing info in slashes
|
//Multi-Episode with a title (S01E05E06, S01E05-06, S01E05 E06, etc) and trailing info in slashes
|
||||||
@@ -79,11 +84,11 @@ namespace NzbDrone.Core.Parser
|
|||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - Title Absolute Episode Number [SubGroup]
|
//Anime - Title Absolute Episode Number [SubGroup]
|
||||||
new Regex(@"^(?<title>.+?)(?:(?:_|-|\s|\.)+(?<absoluteepisode>\d{3}(?!\d+)))+(?:.+?)\[(?<subgroup>.+?)\].*?(?<hash>\[\w{8}\])?(?:$|\.)",
|
new Regex(@"^(?<title>.+?)(?:(?:_|-|\s|\.)+(?<absoluteepisode>\d{3}(\.\d{1,2})?(?!\d+)))+(?:.+?)\[(?<subgroup>.+?)\].*?(?<hash>\[\w{8}\])?(?:$|\.)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - Title Absolute Episode Number [Hash]
|
//Anime - Title Absolute Episode Number [Hash]
|
||||||
new Regex(@"^(?<title>.+?)(?:(?:_|-|\s|\.)+(?<absoluteepisode>\d{2,3}(?!\d+)))+(?:[-_. ]+(?<special>special|ova|ovd))?[-_. ]+.*?(?<hash>\[\w{8}\])(?:$|\.)",
|
new Regex(@"^(?<title>.+?)(?:(?:_|-|\s|\.)+(?<absoluteepisode>\d{2,3}(\.\d{1,2})?(?!\d+)))+(?:[-_. ]+(?<special>special|ova|ovd))?[-_. ]+.*?(?<hash>\[\w{8}\])(?:$|\.)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Episodes with airdate AND season/episode number, capture season/epsiode only
|
//Episodes with airdate AND season/episode number, capture season/epsiode only
|
||||||
@@ -167,7 +172,11 @@ namespace NzbDrone.Core.Parser
|
|||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
// Anime - Title with season number - Absolute Episode Number (Title S01 - EP14)
|
// Anime - Title with season number - Absolute Episode Number (Title S01 - EP14)
|
||||||
new Regex(@"^(?<title>.+?S\d{1,2})[-_. ]{3,}(?:EP)?(?<absoluteepisode>\d{2,3}(?!\d+|[-]))",
|
new Regex(@"^(?<title>.+?S\d{1,2})[-_. ]{3,}(?:EP)?(?<absoluteepisode>\d{2,3}(\.\d{1,2})?(?!\d+|[-]))",
|
||||||
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
|
// Anime - French titles with single episode numbers, with or without leading sub group ([RlsGroup] Title - Episode 1)
|
||||||
|
new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ]?)?(?<title>.+?)[-_. ]+?(?:Episode[-_. ]+?)(?<absoluteepisode>\d{1}(\.\d{1,2})?(?!\d+))",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Season only releases
|
//Season only releases
|
||||||
@@ -222,19 +231,19 @@ namespace NzbDrone.Core.Parser
|
|||||||
|
|
||||||
// TODO: THIS ONE
|
// TODO: THIS ONE
|
||||||
//Anime - Title Absolute Episode Number (e66)
|
//Anime - Title Absolute Episode Number (e66)
|
||||||
new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ]?)?(?<title>.+?)(?:(?:_|-|\s|\.)+(?:e|ep)(?<absoluteepisode>\d{2,3}))+.*?(?<hash>\[\w{8}\])?(?:$|\.)",
|
new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ]?)?(?<title>.+?)(?:(?:_|-|\s|\.)+(?:e|ep)(?<absoluteepisode>\d{2,3}(\.\d{1,2})?))+.*?(?<hash>\[\w{8}\])?(?:$|\.)",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - Title Episode Absolute Episode Number (Series Title Episode 01)
|
//Anime - Title Episode Absolute Episode Number (Series Title Episode 01)
|
||||||
new Regex(@"^(?<title>.+?)[-_. ](?:Episode)(?:[-_. ]+(?<absoluteepisode>(?<!\d+)\d{2,3}(?!\d+)))+(?:_|-|\s|\.)*?(?<hash>\[.{8}\])?(?:$|\.)?",
|
new Regex(@"^(?<title>.+?)[-_. ](?:Episode)(?:[-_. ]+(?<absoluteepisode>(?<!\d+)\d{2,3}(\.\d{1,2})?(?!\d+)))+(?:_|-|\s|\.)*?(?<hash>\[.{8}\])?(?:$|\.)?",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - Title Absolute Episode Number
|
//Anime - Title Absolute Episode Number
|
||||||
new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ]?)?(?<title>.+?)(?:[-_. ]+(?<absoluteepisode>(?<!\d+)\d{2,3}(?!\d+)))+(?:_|-|\s|\.)*?(?<hash>\[.{8}\])?(?:$|\.)?",
|
new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ]?)?(?<title>.+?)(?:[-_. ]+(?<absoluteepisode>(?<!\d+)\d{2,3}(\.\d{1,2})?(?!\d+)))+(?:_|-|\s|\.)*?(?<hash>\[.{8}\])?(?:$|\.)?",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Anime - Title {Absolute Episode Number}
|
//Anime - Title {Absolute Episode Number}
|
||||||
new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ]?)?(?<title>.+?)(?:(?:[-_\W](?<![()\[!]))+(?<absoluteepisode>(?<!\d+)\d{2,3}(?!\d+)))+(?:_|-|\s|\.)*?(?<hash>\[.{8}\])?(?:$|\.)?",
|
new Regex(@"^(?:\[(?<subgroup>.+?)\][-_. ]?)?(?<title>.+?)(?:(?:[-_\W](?<![()\[!]))+(?<absoluteepisode>(?<!\d+)\d{2,3}(\.\d{1,2})?(?!\d+)))+(?:_|-|\s|\.)*?(?<hash>\[.{8}\])?(?:$|\.)?",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
RegexOptions.IgnoreCase | RegexOptions.Compiled),
|
||||||
|
|
||||||
//Extant, terrible multi-episode naming (extant.10708.hdtv-lol.mp4)
|
//Extant, terrible multi-episode naming (extant.10708.hdtv-lol.mp4)
|
||||||
@@ -278,11 +287,11 @@ namespace NzbDrone.Core.Parser
|
|||||||
new Regex(@"^b00bs$", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new Regex(@"^b00bs$", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|
||||||
// 170424_26 - Started appearing August 2018
|
// 170424_26 - Started appearing August 2018
|
||||||
new Regex(@"^\d{6}_\d{2}$"),
|
new Regex(@"^\d{6}_\d{2}$"),
|
||||||
};
|
};
|
||||||
|
|
||||||
//Regex to detect whether the title was reversed.
|
//Regex to detect whether the title was reversed.
|
||||||
private static readonly Regex ReversedTitleRegex = new Regex(@"[-._ ](p027|p0801|\d{2}E\d{2}S)[-._ ]", RegexOptions.Compiled);
|
private static readonly Regex ReversedTitleRegex = new Regex(@"[-._ ](p027|p0801|\d{2,3}E\d{2}S)[-._ ]", RegexOptions.Compiled);
|
||||||
|
|
||||||
private static readonly Regex NormalizeRegex = new Regex(@"((?:\b|_)(?<!^)(a(?!$)|an|the|and|or|of)(?:\b|_))|\W|_",
|
private static readonly Regex NormalizeRegex = new Regex(@"((?:\b|_)(?<!^)(a(?!$)|an|the|and|or|of)(?:\b|_))|\W|_",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
@@ -290,7 +299,7 @@ namespace NzbDrone.Core.Parser
|
|||||||
private static readonly Regex FileExtensionRegex = new Regex(@"\.[a-z0-9]{2,4}$",
|
private static readonly Regex FileExtensionRegex = new Regex(@"\.[a-z0-9]{2,4}$",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
private static readonly Regex SimpleTitleRegex = new Regex(@"(?:(480|720|1080|2160)[ip]|[xh][\W_]?26[45]|DD\W?5\W1|[<>?*:|]|848x480|1280x720|1920x1080|3840x2160|4096x2160|(8|10)b(it)?)\s*?",
|
private static readonly Regex SimpleTitleRegex = new Regex(@"(?:(480|720|1080|2160)[ip]|[xh][\W_]?26[45]|DD\W?5\W1|[<>?*:|]|848x480|1280x720|1920x1080|3840x2160|4096x2160|(8|10)b(it)?|10-bit)\s*?",
|
||||||
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
private static readonly Regex WebsitePrefixRegex = new Regex(@"^\[\s*[a-z]+(\.[a-z]+)+\s*\][- ]*|^www\.[a-z]+\.(?:com|net)[ -]*",
|
private static readonly Regex WebsitePrefixRegex = new Regex(@"^\[\s*[a-z]+(\.[a-z]+)+\s*\][- ]*|^www\.[a-z]+\.(?:com|net)[ -]*",
|
||||||
@@ -645,21 +654,32 @@ namespace NzbDrone.Core.Parser
|
|||||||
|
|
||||||
if (absoluteEpisodeCaptures.Any())
|
if (absoluteEpisodeCaptures.Any())
|
||||||
{
|
{
|
||||||
var first = Convert.ToInt32(absoluteEpisodeCaptures.First().Value);
|
var first = Convert.ToDecimal(absoluteEpisodeCaptures.First().Value, CultureInfo.InvariantCulture);
|
||||||
var last = Convert.ToInt32(absoluteEpisodeCaptures.Last().Value);
|
var last = Convert.ToDecimal(absoluteEpisodeCaptures.Last().Value, CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
if (first > last)
|
if (first > last)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var count = last - first + 1;
|
if ((first % 1) != 0 || (last % 1) != 0)
|
||||||
result.AbsoluteEpisodeNumbers = Enumerable.Range(first, count).ToArray();
|
|
||||||
|
|
||||||
if (matchGroup.Groups["special"].Success)
|
|
||||||
{
|
{
|
||||||
|
if (absoluteEpisodeCaptures.Count != 1)
|
||||||
|
return null; // Multiple matches not allowed for specials
|
||||||
|
|
||||||
|
result.SpecialAbsoluteEpisodeNumbers = new decimal[] { first };
|
||||||
result.Special = true;
|
result.Special = true;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var count = last - first + 1;
|
||||||
|
result.AbsoluteEpisodeNumbers = Enumerable.Range((int)first, (int)count).ToArray();
|
||||||
|
|
||||||
|
if (matchGroup.Groups["special"].Success)
|
||||||
|
{
|
||||||
|
result.Special = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!episodeCaptures.Any() && !absoluteEpisodeCaptures.Any())
|
if (!episodeCaptures.Any() && !absoluteEpisodeCaptures.Any())
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace NzbDrone.Core.Parser
|
|||||||
|
|
||||||
private static readonly Regex SourceRegex = new Regex(@"\b(?:
|
private static readonly Regex SourceRegex = new Regex(@"\b(?:
|
||||||
(?<bluray>BluRay|Blu-Ray|HD-?DVD|BD)|
|
(?<bluray>BluRay|Blu-Ray|HD-?DVD|BD)|
|
||||||
(?<webdl>WEB[-_. ]DL|WEBDL|WebRip|AmazonHD|iTunesHD|NetflixU?HD|WebHD|[. ]WEB[. ](?:[xh]26[45]|DD5[. ]1)|\d+0p[. ]WEB[. ]|WEB-DLMux)|
|
(?<webdl>WEB[-_. ]DL|WEBDL|WebRip|AmazonHD|iTunesHD|NetflixU?HD|WebHD|[. ]WEB[. ](?:[xh]26[45]|DDP?5[. ]1)|\d+0p[. ]WEB[. ]|WEB-DLMux)|
|
||||||
(?<hdtv>HDTV)|
|
(?<hdtv>HDTV)|
|
||||||
(?<bdrip>BDRip)|
|
(?<bdrip>BDRip)|
|
||||||
(?<brrip>BRRip)|
|
(?<brrip>BRRip)|
|
||||||
@@ -40,7 +40,7 @@ namespace NzbDrone.Core.Parser
|
|||||||
private static readonly Regex RealRegex = new Regex(@"\b(?<real>REAL)\b",
|
private static readonly Regex RealRegex = new Regex(@"\b(?<real>REAL)\b",
|
||||||
RegexOptions.Compiled);
|
RegexOptions.Compiled);
|
||||||
|
|
||||||
private static readonly Regex ResolutionRegex = new Regex(@"\b(?:(?<R480p>480p|640x480|848x480)|(?<R576p>576p)|(?<R720p>720p|1280x720)|(?<R1080p>1080p|1920x1080|1440p)|(?<R2160p>2160p|4k[-_. ]UHD|UHD[-_. ]4k))\b",
|
private static readonly Regex ResolutionRegex = new Regex(@"\b(?:(?<R480p>480p|640x480|848x480)|(?<R576p>576p)|(?<R720p>720p|1280x720)|(?<R1080p>1080p|1920x1080|1440p|FHD|1080i)|(?<R2160p>2160p|4k[-_. ](?:UHD|HEVC|BD)|(?:UHD|HEVC|BD)[-_. ]4k))\b",
|
||||||
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
private static readonly Regex CodecRegex = new Regex(@"\b(?:(?<x264>x264)|(?<h264>h264)|(?<xvidhd>XvidHD)|(?<xvid>Xvid)|(?<divx>divx))\b",
|
private static readonly Regex CodecRegex = new Regex(@"\b(?:(?<x264>x264)|(?<h264>h264)|(?<xvidhd>XvidHD)|(?<xvid>Xvid)|(?<divx>divx))\b",
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.ThingiProvider.Events;
|
using NzbDrone.Core.ThingiProvider.Events;
|
||||||
|
|
||||||
@@ -24,15 +25,18 @@ namespace NzbDrone.Core.ThingiProvider.Status
|
|||||||
|
|
||||||
protected readonly IProviderStatusRepository<TModel> _providerStatusRepository;
|
protected readonly IProviderStatusRepository<TModel> _providerStatusRepository;
|
||||||
protected readonly IEventAggregator _eventAggregator;
|
protected readonly IEventAggregator _eventAggregator;
|
||||||
|
protected readonly IRuntimeInfo _runtimeInfo;
|
||||||
protected readonly Logger _logger;
|
protected readonly Logger _logger;
|
||||||
|
|
||||||
protected int MaximumEscalationLevel { get; set; } = EscalationBackOff.Periods.Length - 1;
|
protected int MaximumEscalationLevel { get; set; } = EscalationBackOff.Periods.Length - 1;
|
||||||
protected TimeSpan MinimumTimeSinceInitialFailure { get; set; } = TimeSpan.Zero;
|
protected TimeSpan MinimumTimeSinceInitialFailure { get; set; } = TimeSpan.Zero;
|
||||||
|
protected TimeSpan MinimumTimeSinceStartup { get; set; } = TimeSpan.FromMinutes(15);
|
||||||
|
|
||||||
public ProviderStatusServiceBase(IProviderStatusRepository<TModel> providerStatusRepository, IEventAggregator eventAggregator, Logger logger)
|
public ProviderStatusServiceBase(IProviderStatusRepository<TModel> providerStatusRepository, IEventAggregator eventAggregator, IRuntimeInfo runtimeInfo, Logger logger)
|
||||||
{
|
{
|
||||||
_providerStatusRepository = providerStatusRepository;
|
_providerStatusRepository = providerStatusRepository;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
|
_runtimeInfo = runtimeInfo;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,9 +93,10 @@ namespace NzbDrone.Core.ThingiProvider.Status
|
|||||||
escalate = false;
|
escalate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var inStartupGracePeriod = (_runtimeInfo.StartTime + MinimumTimeSinceStartup) > now;
|
||||||
var inGracePeriod = (status.InitialFailure.Value + MinimumTimeSinceInitialFailure) > now;
|
var inGracePeriod = (status.InitialFailure.Value + MinimumTimeSinceInitialFailure) > now;
|
||||||
|
|
||||||
if (escalate && !inGracePeriod)
|
if (escalate && !inGracePeriod && !inStartupGracePeriod)
|
||||||
{
|
{
|
||||||
status.EscalationLevel = Math.Min(MaximumEscalationLevel, status.EscalationLevel + 1);
|
status.EscalationLevel = Math.Min(MaximumEscalationLevel, status.EscalationLevel + 1);
|
||||||
}
|
}
|
||||||
@@ -109,6 +114,15 @@ namespace NzbDrone.Core.ThingiProvider.Status
|
|||||||
status.DisabledTill = now + CalculateBackOffPeriod(status);
|
status.DisabledTill = now + CalculateBackOffPeriod(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inStartupGracePeriod && minimumBackOff == TimeSpan.Zero && status.DisabledTill.HasValue)
|
||||||
|
{
|
||||||
|
var maximumDisabledTill = now + TimeSpan.FromSeconds(EscalationBackOff.Periods[1]);
|
||||||
|
if (maximumDisabledTill < status.DisabledTill)
|
||||||
|
{
|
||||||
|
status.DisabledTill = maximumDisabledTill;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_providerStatusRepository.Upsert(status);
|
_providerStatusRepository.Upsert(status);
|
||||||
|
|
||||||
_eventAggregator.PublishEvent(new ProviderStatusChangedEvent<TProvider>(providerId, status));
|
_eventAggregator.PublishEvent(new ProviderStatusChangedEvent<TProvider>(providerId, status));
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Marr.Data;
|
using Marr.Data;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
@@ -32,6 +32,7 @@ namespace NzbDrone.Core.Tv
|
|||||||
public bool UnverifiedSceneNumbering { get; set; }
|
public bool UnverifiedSceneNumbering { get; set; }
|
||||||
public Ratings Ratings { get; set; }
|
public Ratings Ratings { get; set; }
|
||||||
public List<MediaCover.MediaCover> Images { get; set; }
|
public List<MediaCover.MediaCover> Images { get; set; }
|
||||||
|
public DateTime? LastSearchTime { get; set; }
|
||||||
|
|
||||||
public string SeriesTitle { get; private set; }
|
public string SeriesTitle { get; private set; }
|
||||||
|
|
||||||
@@ -46,4 +47,4 @@ namespace NzbDrone.Core.Tv
|
|||||||
return string.Format("[{0}]{1}", Id, Title.NullSafe());
|
return string.Format("[{0}]{1}", Id, Title.NullSafe());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Tv
|
namespace NzbDrone.Core.Tv
|
||||||
{
|
{
|
||||||
public static class SeriesTitleNormalizer
|
public static class SeriesTitleNormalizer
|
||||||
{
|
{
|
||||||
private readonly static Dictionary<int, string> PreComputedTitles = new Dictionary<int, string>
|
private static readonly Dictionary<int, string> PreComputedTitles = new Dictionary<int, string>
|
||||||
{
|
{
|
||||||
{ 281588, "a to z" },
|
{ 281588, "a to z" },
|
||||||
{ 289260, "ad bible continues"},
|
{ 289260, "ad bible continues"},
|
||||||
{ 328534, "ap bio"}
|
{ 328534, "ap bio"},
|
||||||
|
{ 77904, "ateam" }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static string Normalize(string title, int tvdbId)
|
public static string Normalize(string title, int tvdbId)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -268,8 +268,6 @@ namespace NzbDrone.Mono.Disk
|
|||||||
}
|
}
|
||||||
|
|
||||||
return g.gr_gid;
|
return g.gr_gid;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -117,6 +117,12 @@ namespace NzbDrone.Mono.Disk
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mount.StartsWith("/snap/"))
|
||||||
|
{
|
||||||
|
// Mount point for snap packages
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var driveType = FindDriveType.Find(type);
|
var driveType = FindDriveType.Find(type);
|
||||||
|
|
||||||
if (name.StartsWith("/dev/") || GetFileSystems().GetValueOrDefault(type, false))
|
if (name.StartsWith("/dev/") || GetFileSystems().GetValueOrDefault(type, false))
|
||||||
|
|||||||
@@ -30,9 +30,13 @@
|
|||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/FORCE_WHILE_BRACES_STYLE/@EntryValue">ALWAYS_ADD</s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_NESTED_FIXED_STMT/@EntryValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_NESTED_FIXED_STMT/@EntryValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_NESTED_USINGS_STMT/@EntryValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/INDENT_NESTED_USINGS_STMT/@EntryValue">True</s:Boolean>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ATTRIBUTE_ON_SAME_LINE/@EntryValue">False</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ACCESSOR_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_EMBEDDED_STATEMENT_ON_SAME_LINE/@EntryValue">ALWAYS</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">ON_SINGLE_LINE</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SIMPLE_EMBEDDED_STATEMENT_STYLE/@EntryValue">ON_SINGLE_LINE</s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AllowAlias/@EntryValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/AllowAlias/@EntryValue">False</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/CanUseGlobalAlias/@EntryValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CSharpUsing/CanUseGlobalAlias/@EntryValue">False</s:Boolean>
|
||||||
@@ -71,7 +75,12 @@
|
|||||||
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File_003A_003AC_003A_005CDropbox_005CGit_005CNzbDrone_005CNzbDrone_002Esln_002EDotSettings/@KeyIndexDefined">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File_003A_003AC_003A_005CDropbox_005CGit_005CNzbDrone_005CNzbDrone_002Esln_002EDotSettings/@KeyIndexDefined">True</s:Boolean>
|
||||||
<s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File_003A_003AC_003A_005CDropbox_005CGit_005CNzbDrone_005CNzbDrone_002Esln_002EDotSettings/RelativePriority/@EntryValue">2</s:Double>
|
<s:Double x:Key="/Default/Environment/InjectedLayers/InjectedLayerCustomization/=File_003A_003AC_003A_005CDropbox_005CGit_005CNzbDrone_005CNzbDrone_002Esln_002EDotSettings/RelativePriority/@EntryValue">2</s:Double>
|
||||||
<s:Boolean x:Key="/Default/Environment/MemoryUsageIndicator/IsVisible/@EntryValue">False</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/MemoryUsageIndicator/IsVisible/@EntryValue">False</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/Environment/TextControl/HighlightCurrentLine/@EntryValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/TextControl/HighlightCurrentLine/@EntryValue">True</s:Boolean>
|
||||||
|
|||||||
Reference in New Issue
Block a user