mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-18 21:35:51 -04:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 35f911286f | |||
| 650f01176c | |||
| 2246dfab05 | |||
| 6bfb790eb8 | |||
| 0e85e39815 | |||
| 9471343533 | |||
| 2d1d1c8a99 | |||
| 7e5e136930 | |||
| c659ba1c10 | |||
| caf7a8c69e | |||
| 40e5626ddb | |||
| 1b9ccc319f | |||
| 89e804814b | |||
| ce6a5713d1 |
@@ -139,11 +139,26 @@ namespace NzbDrone.Common.Test.Http
|
|||||||
var request = new HttpRequest($"http://{_httpBinHost}/redirect/1");
|
var request = new HttpRequest($"http://{_httpBinHost}/redirect/1");
|
||||||
request.AllowAutoRedirect = true;
|
request.AllowAutoRedirect = true;
|
||||||
|
|
||||||
Subject.Get(request);
|
var response = Subject.Get(request);
|
||||||
|
|
||||||
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||||
|
|
||||||
ExceptionVerification.ExpectedErrors(0);
|
ExceptionVerification.ExpectedErrors(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_follow_redirects()
|
||||||
|
{
|
||||||
|
var request = new HttpRequest($"http://{_httpBinHost}/redirect/1");
|
||||||
|
request.AllowAutoRedirect = false;
|
||||||
|
|
||||||
|
var response = Subject.Get(request);
|
||||||
|
|
||||||
|
response.StatusCode.Should().Be(HttpStatusCode.Found);
|
||||||
|
|
||||||
|
ExceptionVerification.ExpectedErrors(1);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_follow_redirects_to_https()
|
public void should_follow_redirects_to_https()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace NzbDrone.Common.Test.InstrumentationTests
|
|||||||
[TestCase(@"https://rss.omgwtfnzbs.org/rss-search.php?catid=19,20&user=sonarr&api=mySecret&eng=1")]
|
[TestCase(@"https://rss.omgwtfnzbs.org/rss-search.php?catid=19,20&user=sonarr&api=mySecret&eng=1")]
|
||||||
[TestCase(@"https://dognzb.cr/fetch/2b51db35e1912ffc138825a12b9933d2/2b51db35e1910123321025a12b9933d2")]
|
[TestCase(@"https://dognzb.cr/fetch/2b51db35e1912ffc138825a12b9933d2/2b51db35e1910123321025a12b9933d2")]
|
||||||
[TestCase(@"https://baconbits.org/feeds.php?feed=torrents_tv&user=12345&auth=2b51db35e1910123321025a12b9933d2&passkey=mySecret&authkey=2b51db35e1910123321025a12b9933d2")]
|
[TestCase(@"https://baconbits.org/feeds.php?feed=torrents_tv&user=12345&auth=2b51db35e1910123321025a12b9933d2&passkey=mySecret&authkey=2b51db35e1910123321025a12b9933d2")]
|
||||||
|
[TestCase(@"http://127.0.0.1:9117/dl/indexername?jackett_apikey=flwjiefewklfjacketmySecretsdfldskjfsdlk&path=we0re9f0sdfbase64sfdkfjsdlfjk&file=The+Torrent+File+Name.torrent")]
|
||||||
// NzbGet
|
// NzbGet
|
||||||
[TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")]
|
[TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")]
|
||||||
[TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")]
|
[TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")]
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace NzbDrone.Common.Disk
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (VolumeLabel.IsNullOrWhiteSpace())
|
if (VolumeLabel.IsNullOrWhiteSpace() || VolumeLabel.StartsWith("UUID=") || Name == VolumeLabel)
|
||||||
{
|
{
|
||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,19 +47,19 @@ namespace NzbDrone.Common.Http.Dispatchers
|
|||||||
AddRequestHeaders(webRequest, request.Headers);
|
AddRequestHeaders(webRequest, request.Headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.ContentData != null)
|
|
||||||
{
|
|
||||||
webRequest.ContentLength = request.ContentData.Length;
|
|
||||||
using (var writeStream = webRequest.GetRequestStream())
|
|
||||||
{
|
|
||||||
writeStream.Write(request.ContentData, 0, request.ContentData.Length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpWebResponse httpWebResponse;
|
HttpWebResponse httpWebResponse;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (request.ContentData != null)
|
||||||
|
{
|
||||||
|
webRequest.ContentLength = request.ContentData.Length;
|
||||||
|
using (var writeStream = webRequest.GetRequestStream())
|
||||||
|
{
|
||||||
|
writeStream.Write(request.ContentData, 0, request.ContentData.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
|
httpWebResponse = (HttpWebResponse)webRequest.GetResponse();
|
||||||
}
|
}
|
||||||
catch (WebException e)
|
catch (WebException e)
|
||||||
@@ -78,13 +78,17 @@ namespace NzbDrone.Common.Http.Dispatchers
|
|||||||
{
|
{
|
||||||
throw new WebException($"DNS Name Resolution Failure: '{webRequest.RequestUri.Host}'", e.Status);
|
throw new WebException($"DNS Name Resolution Failure: '{webRequest.RequestUri.Host}'", e.Status);
|
||||||
}
|
}
|
||||||
else if (e.Status == WebExceptionStatus.SendFailure && e.ToString().Contains("The authentication or decryption has failed."))
|
else if (e.ToString().Contains("TLS Support not"))
|
||||||
|
{
|
||||||
|
throw new TlsFailureException(webRequest, e);
|
||||||
|
}
|
||||||
|
else if (e.ToString().Contains("The authentication or decryption has failed."))
|
||||||
{
|
{
|
||||||
throw new TlsFailureException(webRequest, e);
|
throw new TlsFailureException(webRequest, e);
|
||||||
}
|
}
|
||||||
else if (OsInfo.IsNotWindows)
|
else if (OsInfo.IsNotWindows)
|
||||||
{
|
{
|
||||||
throw new WebException($"{e.Message}: '{webRequest.RequestUri}'", e.Status);
|
throw new WebException($"{e.Message}: '{webRequest.RequestUri}'", e, e.Status, e.Response);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,36 +52,33 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
public HttpResponse Execute(HttpRequest request)
|
public HttpResponse Execute(HttpRequest request)
|
||||||
{
|
{
|
||||||
var autoRedirectCount = 0;
|
|
||||||
var autoRedirectChain = new List<string>();
|
|
||||||
autoRedirectChain.Add(request.Url.ToString());
|
|
||||||
|
|
||||||
var response = ExecuteRequest(request);
|
var response = ExecuteRequest(request);
|
||||||
|
|
||||||
while (response.StatusCode == HttpStatusCode.Moved ||
|
if (request.AllowAutoRedirect && response.HasHttpRedirect)
|
||||||
response.StatusCode == HttpStatusCode.MovedPermanently ||
|
|
||||||
response.StatusCode == HttpStatusCode.Found)
|
|
||||||
{
|
{
|
||||||
if (request.AllowAutoRedirect)
|
var autoRedirectChain = new List<string>();
|
||||||
|
autoRedirectChain.Add(request.Url.ToString());
|
||||||
|
|
||||||
|
do
|
||||||
{
|
{
|
||||||
request.Url += new HttpUri(response.Headers.GetSingleValue("Location"));
|
request.Url += new HttpUri(response.Headers.GetSingleValue("Location"));
|
||||||
autoRedirectChain.Add(request.Url.ToString());
|
autoRedirectChain.Add(request.Url.ToString());
|
||||||
|
|
||||||
_logger.Trace("Redirected to {0}", request.Url);
|
_logger.Trace("Redirected to {0}", request.Url);
|
||||||
|
|
||||||
autoRedirectCount++;
|
if (autoRedirectChain.Count > 3)
|
||||||
if (autoRedirectCount > 3)
|
|
||||||
{
|
{
|
||||||
throw new WebException($"Too many automatic redirections were attempted for {autoRedirectChain.Join(" -> ")}", WebExceptionStatus.ProtocolError);
|
throw new WebException($"Too many automatic redirections were attempted for {autoRedirectChain.Join(" -> ")}", WebExceptionStatus.ProtocolError);
|
||||||
}
|
}
|
||||||
|
|
||||||
response = ExecuteRequest(request);
|
response = ExecuteRequest(request);
|
||||||
}
|
}
|
||||||
else if (!RuntimeInfo.IsProduction)
|
while (response.HasHttpRedirect);
|
||||||
{
|
}
|
||||||
_logger.Error("Server requested a redirect to [{0}]. Update the request URL to avoid this redirect.", response.Headers["Location"]);
|
|
||||||
break;
|
if (response.HasHttpRedirect && !RuntimeInfo.IsProduction)
|
||||||
}
|
{
|
||||||
|
_logger.Error("Server requested a redirect to [{0}] while in developer mode. Update the request URL to avoid this redirect.", response.Headers["Location"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request.SuppressHttpError && response.HasHttpError)
|
if (!request.SuppressHttpError && response.HasHttpError)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
private string _content;
|
private string _content;
|
||||||
|
|
||||||
public string Content
|
public string Content
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@@ -51,6 +51,10 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
public bool HasHttpError => (int)StatusCode >= 400;
|
public bool HasHttpError => (int)StatusCode >= 400;
|
||||||
|
|
||||||
|
public bool HasHttpRedirect => StatusCode == HttpStatusCode.Moved ||
|
||||||
|
StatusCode == HttpStatusCode.MovedPermanently ||
|
||||||
|
StatusCode == HttpStatusCode.Found;
|
||||||
|
|
||||||
public Dictionary<string, string> GetCookies()
|
public Dictionary<string, string> GetCookies()
|
||||||
{
|
{
|
||||||
var result = new Dictionary<string, string>();
|
var result = new Dictionary<string, string>();
|
||||||
@@ -95,4 +99,4 @@ namespace NzbDrone.Common.Http
|
|||||||
|
|
||||||
public T Resource { get; private set; }
|
public T Resource { get; private set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ namespace NzbDrone.Common.Instrumentation
|
|||||||
{
|
{
|
||||||
public class CleanseLogMessage
|
public class CleanseLogMessage
|
||||||
{
|
{
|
||||||
private static readonly Regex[] CleansingRules = new[]
|
private static readonly Regex[] CleansingRules = new[]
|
||||||
{
|
{
|
||||||
// Url
|
// Url
|
||||||
new Regex(@"(?<=\?|&)(apikey|token|passkey|auth|authkey|user|uid|api)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new Regex(@"(?<=\?|&)(apikey|token|passkey|auth|authkey|user|uid|api|[a-z_]*apikey)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new Regex(@"(?<=\?|&)[^=]*?(username|password)=(?<secret>[^&=]+?)(?= |&|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new Regex(@"torrentleech\.org/(?!rss)(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
new Regex(@"torrentleech\.org/rss/download/[0-9]+/(?<secret>[0-9a-z]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase),
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.EnvironmentInfo;
|
using NzbDrone.Common.EnvironmentInfo;
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Common.Instrumentation;
|
using NzbDrone.Common.Instrumentation;
|
||||||
|
|
||||||
namespace NzbDrone.Common.Security
|
namespace NzbDrone.Common.Security
|
||||||
@@ -19,11 +18,6 @@ namespace NzbDrone.Common.Security
|
|||||||
if (OsInfo.IsNotWindows)
|
if (OsInfo.IsNotWindows)
|
||||||
{
|
{
|
||||||
// This was never meant to be used on mono, and will cause issues with mono 5 and higher if btls is enabled.
|
// This was never meant to be used on mono, and will cause issues with mono 5 and higher if btls is enabled.
|
||||||
// Instead, force TLS provider to legacy for now due to conflict between btls and mediainfo, unless the user explicitly specified it.
|
|
||||||
if (Environment.GetEnvironmentVariable("MONO_TLS_PROVIDER").IsNullOrWhiteSpace())
|
|
||||||
{
|
|
||||||
Environment.SetEnvironmentVariable("MONO_TLS_PROVIDER", "legacy");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -130,5 +130,26 @@ namespace NzbDrone.Core.Test.DiskSpace
|
|||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
.Verify(v => v.GetAvailableSpace(It.IsAny<string>()), Times.Never());
|
.Verify(v => v.GetAvailableSpace(It.IsAny<string>()), Times.Never());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase("/boot")]
|
||||||
|
[TestCase("/var/lib/rancher")]
|
||||||
|
[TestCase("/var/lib/rancher/volumes")]
|
||||||
|
[TestCase("/var/lib/kubelet")]
|
||||||
|
[TestCase("/var/lib/docker")]
|
||||||
|
[TestCase("/some/place/docker/aufs")]
|
||||||
|
public void should_not_check_diskspace_for_irrelevant_mounts(string path)
|
||||||
|
{
|
||||||
|
var mount = new Mock<IMount>();
|
||||||
|
mount.SetupGet(v => v.RootDirectory).Returns(path);
|
||||||
|
mount.SetupGet(v => v.DriveType).Returns(System.IO.DriveType.Fixed);
|
||||||
|
|
||||||
|
Mocker.GetMock<IDiskProvider>()
|
||||||
|
.Setup(v => v.GetMounts())
|
||||||
|
.Returns(new List<IMount> { mount.Object });
|
||||||
|
|
||||||
|
var freeSpace = Subject.GetFreeSpace();
|
||||||
|
|
||||||
|
freeSpace.Should().BeEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
{
|
{
|
||||||
var mock = WithUsenetClient();
|
var mock = WithUsenetClient();
|
||||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()));
|
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()));
|
||||||
|
|
||||||
Subject.DownloadReport(_parseResult);
|
Subject.DownloadReport(_parseResult);
|
||||||
|
|
||||||
VerifyEventPublished<EpisodeGrabbedEvent>();
|
VerifyEventPublished<EpisodeGrabbedEvent>();
|
||||||
@@ -93,7 +93,7 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
{
|
{
|
||||||
var mock = WithUsenetClient();
|
var mock = WithUsenetClient();
|
||||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()));
|
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()));
|
||||||
|
|
||||||
Subject.DownloadReport(_parseResult);
|
Subject.DownloadReport(_parseResult);
|
||||||
|
|
||||||
mock.Verify(s => s.Download(It.IsAny<RemoteEpisode>()), Times.Once());
|
mock.Verify(s => s.Download(It.IsAny<RemoteEpisode>()), Times.Once());
|
||||||
@@ -117,7 +117,7 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
var mock = WithUsenetClient();
|
var mock = WithUsenetClient();
|
||||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()))
|
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()))
|
||||||
.Callback<RemoteEpisode>(v => {
|
.Callback<RemoteEpisode>(v => {
|
||||||
throw new ReleaseDownloadException(v.Release, "Error", new WebException());
|
throw new ReleaseDownloadException(v.Release, "Error", new WebException());
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.Throws<ReleaseDownloadException>(() => Subject.DownloadReport(_parseResult));
|
Assert.Throws<ReleaseDownloadException>(() => Subject.DownloadReport(_parseResult));
|
||||||
@@ -136,7 +136,7 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
var mock = WithUsenetClient();
|
var mock = WithUsenetClient();
|
||||||
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()))
|
mock.Setup(s => s.Download(It.IsAny<RemoteEpisode>()))
|
||||||
.Callback<RemoteEpisode>(v => {
|
.Callback<RemoteEpisode>(v => {
|
||||||
throw new ReleaseDownloadException(v.Release, "Error", new TooManyRequestsException(request, response));
|
throw new ReleaseDownloadException(v.Release, "Error", new TooManyRequestsException(request, response));
|
||||||
});
|
});
|
||||||
|
|
||||||
Assert.Throws<ReleaseDownloadException>(() => Subject.DownloadReport(_parseResult));
|
Assert.Throws<ReleaseDownloadException>(() => Subject.DownloadReport(_parseResult));
|
||||||
@@ -182,12 +182,10 @@ namespace NzbDrone.Core.Test.Download
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_not_attempt_download_if_client_isnt_configure()
|
public void should_not_attempt_download_if_client_isnt_configure()
|
||||||
{
|
{
|
||||||
Subject.DownloadReport(_parseResult);
|
Assert.Throws<DownloadClientUnavailableException>(() => Subject.DownloadReport(_parseResult));
|
||||||
|
|
||||||
Mocker.GetMock<IDownloadClient>().Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never());
|
Mocker.GetMock<IDownloadClient>().Verify(c => c.Download(It.IsAny<RemoteEpisode>()), Times.Never());
|
||||||
VerifyEventNotPublished<EpisodeGrabbedEvent>();
|
VerifyEventNotPublished<EpisodeGrabbedEvent>();
|
||||||
|
|
||||||
ExceptionVerification.ExpectedWarns(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|||||||
+2
@@ -30,6 +30,8 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo.MediaInfoFormatterTests
|
|||||||
[TestCase("TrueHD, A_TRUEHD, , ", "", "TrueHD")]
|
[TestCase("TrueHD, A_TRUEHD, , ", "", "TrueHD")]
|
||||||
[TestCase("WMA, 161, , ", "Droned.wmv", "WMA")]
|
[TestCase("WMA, 161, , ", "Droned.wmv", "WMA")]
|
||||||
[TestCase("WMA, 162, Pro, ", "B.N.S04E18.720p.WEB-DL", "WMA")]
|
[TestCase("WMA, 162, Pro, ", "B.N.S04E18.720p.WEB-DL", "WMA")]
|
||||||
|
[TestCase("Opus, A_OPUS, , ", "Roadkill Ep3x11 - YouTube.webm", "Opus")]
|
||||||
|
[TestCase("mp3 , 0, , ", "climbing.mp4", "MP3")]
|
||||||
public void should_format_audio_format(string audioFormatPack, string sceneName, string expectedFormat)
|
public void should_format_audio_format(string audioFormatPack, string sceneName, string expectedFormat)
|
||||||
{
|
{
|
||||||
var split = audioFormatPack.Split(new string[] { ", " }, System.StringSplitOptions.None);
|
var split = audioFormatPack.Split(new string[] { ", " }, System.StringSplitOptions.None);
|
||||||
|
|||||||
+5
@@ -34,6 +34,11 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo.MediaInfoFormatterTests
|
|||||||
[TestCase("V.MPEG4/ISO/AVC, V.MPEG4/ISO/AVC, , ", "pd.2015.S03E08.720p.iP.WEBRip.AAC2.0.H264-BTW", "h264")]
|
[TestCase("V.MPEG4/ISO/AVC, V.MPEG4/ISO/AVC, , ", "pd.2015.S03E08.720p.iP.WEBRip.AAC2.0.H264-BTW", "h264")]
|
||||||
[TestCase("WMV2, WMV2, , ", "Droned.wmv", "WMV")]
|
[TestCase("WMV2, WMV2, , ", "Droned.wmv", "WMV")]
|
||||||
[TestCase("xvid, xvid, , ", "", "XviD")]
|
[TestCase("xvid, xvid, , ", "", "XviD")]
|
||||||
|
[TestCase("div3, div3, , ", "spsm.dvdrip.divx.avi'.", "DivX")]
|
||||||
|
[TestCase("VP6, 4, , ", "Top Gear - S12E01 - Lorries - SD TV.flv", "VP6")]
|
||||||
|
[TestCase("VP7, VP70, General, ", "Sweet Seymour.avi", "VP7")]
|
||||||
|
[TestCase("VP8, V_VP8, , ", "Dick.mkv", "VP8")]
|
||||||
|
[TestCase("VP9, V_VP9, , ", "Roadkill Ep3x11 - YouTube.webm", "VP9")]
|
||||||
public void should_format_video_format(string videoFormatPack, string sceneName, string expectedFormat)
|
public void should_format_video_format(string videoFormatPack, string sceneName, string expectedFormat)
|
||||||
{
|
{
|
||||||
var split = videoFormatPack.Split(new string[] { ", " }, System.StringSplitOptions.None);
|
var split = videoFormatPack.Split(new string[] { ", " }, System.StringSplitOptions.None);
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
@@ -22,6 +23,8 @@ namespace NzbDrone.Core.DiskSpace
|
|||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
private static readonly Regex _regexSpecialDrive = new Regex("^/var/lib/(docker|rancher|kubelet)(/|$)|^/boot(/|$)|/docker(/var)?/aufs(/|$)", RegexOptions.Compiled);
|
||||||
|
|
||||||
public DiskSpaceService(ISeriesService seriesService, IConfigService configService, IDiskProvider diskProvider, Logger logger)
|
public DiskSpaceService(ISeriesService seriesService, IConfigService configService, IDiskProvider diskProvider, Logger logger)
|
||||||
{
|
{
|
||||||
_seriesService = seriesService;
|
_seriesService = seriesService;
|
||||||
@@ -32,37 +35,37 @@ namespace NzbDrone.Core.DiskSpace
|
|||||||
|
|
||||||
public List<DiskSpace> GetFreeSpace()
|
public List<DiskSpace> GetFreeSpace()
|
||||||
{
|
{
|
||||||
var diskSpace = new List<DiskSpace>();
|
var importantRootFolders = GetSeriesRootPaths().Concat(GetDroneFactoryRootPaths()).Distinct().ToList();
|
||||||
diskSpace.AddRange(GetSeriesFreeSpace());
|
|
||||||
diskSpace.AddRange(GetDroneFactoryFreeSpace());
|
|
||||||
diskSpace.AddRange(GetFixedDisksFreeSpace());
|
|
||||||
|
|
||||||
return diskSpace.DistinctBy(d => d.Path).ToList();
|
var optionalRootFolders = GetFixedDisksRootPaths().Except(importantRootFolders).Distinct().ToList();
|
||||||
|
|
||||||
|
var diskSpace = GetDiskSpace(importantRootFolders).Concat(GetDiskSpace(optionalRootFolders, true)).ToList();
|
||||||
|
|
||||||
|
return diskSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<DiskSpace> GetSeriesFreeSpace()
|
private IEnumerable<string> GetSeriesRootPaths()
|
||||||
{
|
{
|
||||||
var seriesRootPaths = _seriesService.GetAllSeries()
|
return _seriesService.GetAllSeries()
|
||||||
.Where(s => _diskProvider.FolderExists(s.Path))
|
.Where(s => _diskProvider.FolderExists(s.Path))
|
||||||
.Select(s => _diskProvider.GetPathRoot(s.Path))
|
.Select(s => _diskProvider.GetPathRoot(s.Path))
|
||||||
.Distinct();
|
.Distinct();
|
||||||
|
|
||||||
return GetDiskSpace(seriesRootPaths);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<DiskSpace> GetDroneFactoryFreeSpace()
|
private IEnumerable<string> GetDroneFactoryRootPaths()
|
||||||
{
|
{
|
||||||
if (_configService.DownloadedEpisodesFolder.IsNotNullOrWhiteSpace() && _diskProvider.FolderExists(_configService.DownloadedEpisodesFolder))
|
if (_configService.DownloadedEpisodesFolder.IsNotNullOrWhiteSpace() && _diskProvider.FolderExists(_configService.DownloadedEpisodesFolder))
|
||||||
{
|
{
|
||||||
return GetDiskSpace(new[] { _diskProvider.GetPathRoot(_configService.DownloadedEpisodesFolder) });
|
yield return _configService.DownloadedEpisodesFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new List<DiskSpace>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<DiskSpace> GetFixedDisksFreeSpace()
|
private IEnumerable<string> GetFixedDisksRootPaths()
|
||||||
{
|
{
|
||||||
return GetDiskSpace(_diskProvider.GetMounts().Where(d => d.DriveType == DriveType.Fixed).Select(d => d.RootDirectory), true);
|
return _diskProvider.GetMounts()
|
||||||
|
.Where(d => d.DriveType == DriveType.Fixed)
|
||||||
|
.Where(d => !_regexSpecialDrive.IsMatch(d.RootDirectory))
|
||||||
|
.Select(d => d.RootDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<DiskSpace> GetDiskSpace(IEnumerable<string> paths, bool suppressWarnings = false)
|
private IEnumerable<DiskSpace> GetDiskSpace(IEnumerable<string> paths, bool suppressWarnings = false)
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
{
|
{
|
||||||
case "error": // some error occurred, applies to paused torrents
|
case "error": // some error occurred, applies to paused torrents
|
||||||
item.Status = DownloadItemStatus.Failed;
|
item.Status = DownloadItemStatus.Failed;
|
||||||
item.Message = "QBittorrent is reporting an error";
|
item.Message = "qBittorrent is reporting an error";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "pausedDL": // torrent is paused and has NOT finished downloading
|
case "pausedDL": // torrent is paused and has NOT finished downloading
|
||||||
@@ -222,7 +222,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
var config = _proxy.GetConfig(Settings);
|
var config = _proxy.GetConfig(Settings);
|
||||||
if (config.MaxRatioEnabled && config.RemoveOnMaxRatio)
|
if (config.MaxRatioEnabled && config.RemoveOnMaxRatio)
|
||||||
{
|
{
|
||||||
return new NzbDroneValidationFailure(String.Empty, "QBittorrent is configured to remove torrents when they reach their Share Ratio Limit")
|
return new NzbDroneValidationFailure(String.Empty, "qBittorrent is configured to remove torrents when they reach their Share Ratio Limit")
|
||||||
{
|
{
|
||||||
DetailedDescription = "Sonarr will be unable to perform Completed Download Handling as configured. You can fix this in qBittorrent ('Tools -> Options...' in the menu) by changing 'Options -> BitTorrent -> Share Ratio Limiting' from 'Remove them' to 'Pause them'."
|
DetailedDescription = "Sonarr will be unable to perform Completed Download Handling as configured. You can fix this in qBittorrent ('Tools -> Options...' in the menu) by changing 'Options -> BitTorrent -> Share Ratio Limiting' from 'Remove them' to 'Pause them'."
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
}
|
}
|
||||||
catch(DownloadClientException ex)
|
catch(DownloadClientException ex)
|
||||||
{
|
{
|
||||||
// if setCategory fails due to method not being found, then try older setLabel command for qbittorent < v.3.3.5
|
// if setCategory fails due to method not being found, then try older setLabel command for qBittorrent < v.3.3.5
|
||||||
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.NotFound)
|
if (ex.InnerException is HttpException && (ex.InnerException as HttpException).Response.StatusCode == HttpStatusCode.NotFound)
|
||||||
{
|
{
|
||||||
var setLabelRequest = BuildRequest(settings).Resource("/command/setLabel")
|
var setLabelRequest = BuildRequest(settings).Resource("/command/setLabel")
|
||||||
@@ -197,12 +197,12 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new DownloadClientException("Failed to connect to qBitTorrent, check your settings.", ex);
|
throw new DownloadClientException("Failed to connect to qBittorrent, check your settings.", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (WebException ex)
|
catch (WebException ex)
|
||||||
{
|
{
|
||||||
throw new DownloadClientException("Failed to connect to qBitTorrent, please check your settings.", ex);
|
throw new DownloadClientException("Failed to connect to qBittorrent, please check your settings.", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.Content;
|
return response.Content;
|
||||||
@@ -239,23 +239,23 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
|
|||||||
_logger.Debug("qbitTorrent authentication failed.");
|
_logger.Debug("qbitTorrent authentication failed.");
|
||||||
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
|
if (ex.Response.StatusCode == HttpStatusCode.Forbidden)
|
||||||
{
|
{
|
||||||
throw new DownloadClientAuthenticationException("Failed to authenticate with qbitTorrent.", ex);
|
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new DownloadClientException("Failed to connect to qBitTorrent, please check your settings.", ex);
|
throw new DownloadClientException("Failed to connect to qBittorrent, please check your settings.", ex);
|
||||||
}
|
}
|
||||||
catch (WebException ex)
|
catch (WebException ex)
|
||||||
{
|
{
|
||||||
throw new DownloadClientUnavailableException("Failed to connect to qBitTorrent, please check your settings.", ex);
|
throw new DownloadClientUnavailableException("Failed to connect to qBittorrent, please check your settings.", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.Content != "Ok.") // returns "Fails." on bad login
|
if (response.Content != "Ok.") // returns "Fails." on bad login
|
||||||
{
|
{
|
||||||
_logger.Debug("qbitTorrent authentication failed.");
|
_logger.Debug("qbitTorrent authentication failed.");
|
||||||
throw new DownloadClientAuthenticationException("Failed to authenticate with qbitTorrent.");
|
throw new DownloadClientAuthenticationException("Failed to authenticate with qBittorrent.");
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Debug("qbitTorrent authentication succeeded.");
|
_logger.Debug("qBittorrent authentication succeeded.");
|
||||||
|
|
||||||
cookies = response.GetCookies();
|
cookies = response.GetCookies();
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using NzbDrone.Common.Extensions;
|
|||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Common.Instrumentation.Extensions;
|
using NzbDrone.Common.Instrumentation.Extensions;
|
||||||
using NzbDrone.Common.TPL;
|
using NzbDrone.Common.TPL;
|
||||||
|
using NzbDrone.Core.Download.Clients;
|
||||||
using NzbDrone.Core.Exceptions;
|
using NzbDrone.Core.Exceptions;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
@@ -52,8 +53,7 @@ namespace NzbDrone.Core.Download
|
|||||||
|
|
||||||
if (downloadClient == null)
|
if (downloadClient == null)
|
||||||
{
|
{
|
||||||
_logger.Warn("{0} Download client isn't configured yet.", remoteEpisode.Release.DownloadProtocol);
|
throw new DownloadClientUnavailableException($"{remoteEpisode.Release.DownloadProtocol} Download client isn't configured yet");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit grabs to 2 per second.
|
// Limit grabs to 2 per second.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace NzbDrone.Core.IndexerSearch.Definitions
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return string.Format("[{0} : {1:yyyy-MM-dd}", Series.Title, AirDate);
|
return string.Format("[{0} : {1:yyyy-MM-dd}]", Series.Title, AirDate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,11 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||||||
return "FLAC";
|
return "FLAC";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (audioFormat.Trim().EqualsIgnoreCase("mp3"))
|
||||||
|
{
|
||||||
|
return "MP3";
|
||||||
|
}
|
||||||
|
|
||||||
if (audioFormat.EqualsIgnoreCase("MPEG Audio"))
|
if (audioFormat.EqualsIgnoreCase("MPEG Audio"))
|
||||||
{
|
{
|
||||||
if (mediaInfo.AudioCodecID == "55" || mediaInfo.AudioCodecID == "A_MPEG/L3" || mediaInfo.AudioProfile == "Layer 3")
|
if (mediaInfo.AudioCodecID == "55" || mediaInfo.AudioCodecID == "A_MPEG/L3" || mediaInfo.AudioProfile == "Layer 3")
|
||||||
@@ -102,6 +107,11 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (audioFormat.EqualsIgnoreCase("Opus"))
|
||||||
|
{
|
||||||
|
return "Opus";
|
||||||
|
}
|
||||||
|
|
||||||
if (audioFormat.EqualsIgnoreCase("PCM"))
|
if (audioFormat.EqualsIgnoreCase("PCM"))
|
||||||
{
|
{
|
||||||
return "PCM";
|
return "PCM";
|
||||||
@@ -214,7 +224,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||||||
return GetSceneNameMatch(sceneName, "AVC", "h264");
|
return GetSceneNameMatch(sceneName, "AVC", "h264");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoFormat.EqualsIgnoreCase("DivX"))
|
if (videoFormat.EqualsIgnoreCase("DivX") || videoFormat.EqualsIgnoreCase("div3"))
|
||||||
{
|
{
|
||||||
return "DivX";
|
return "DivX";
|
||||||
}
|
}
|
||||||
@@ -267,6 +277,12 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||||||
return "VC1";
|
return "VC1";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (videoFormat.EqualsIgnoreCase("VP6") || videoFormat.EqualsIgnoreCase("VP7") ||
|
||||||
|
videoFormat.EqualsIgnoreCase("VP8") || videoFormat.EqualsIgnoreCase("VP9"))
|
||||||
|
{
|
||||||
|
return videoFormat.ToUpperInvariant();
|
||||||
|
}
|
||||||
|
|
||||||
if (videoFormat == "WMV2")
|
if (videoFormat == "WMV2")
|
||||||
{
|
{
|
||||||
return "WMV";
|
return "WMV";
|
||||||
|
|||||||
@@ -40,24 +40,15 @@ namespace NzbDrone.Mono.Disk
|
|||||||
{
|
{
|
||||||
Ensure.That(path, () => path).IsValidPath();
|
Ensure.That(path, () => path).IsValidPath();
|
||||||
|
|
||||||
try
|
var mount = GetMount(path);
|
||||||
{
|
|
||||||
var mount = GetMount(path);
|
|
||||||
|
|
||||||
if (mount == null)
|
if (mount == null)
|
||||||
{
|
|
||||||
Logger.Debug("Unable to get free space for '{0}', unable to find suitable drive", path);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mount.AvailableFreeSpace;
|
|
||||||
}
|
|
||||||
catch (InvalidOperationException ex)
|
|
||||||
{
|
{
|
||||||
Logger.Error(ex, "Couldn't get free space for {0}", path);
|
Logger.Debug("Unable to get free space for '{0}', unable to find suitable drive", path);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return mount.AvailableFreeSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void InheritFolderPermissions(string filename)
|
public override void InheritFolderPermissions(string filename)
|
||||||
@@ -100,20 +91,9 @@ namespace NzbDrone.Mono.Disk
|
|||||||
{
|
{
|
||||||
Ensure.That(path, () => path).IsValidPath();
|
Ensure.That(path, () => path).IsValidPath();
|
||||||
|
|
||||||
try
|
var mount = GetMount(path);
|
||||||
{
|
|
||||||
var mount = GetMount(path);
|
|
||||||
|
|
||||||
if (mount == null) return null;
|
return mount?.TotalSize;
|
||||||
|
|
||||||
return mount.TotalSize;
|
|
||||||
}
|
|
||||||
catch (InvalidOperationException e)
|
|
||||||
{
|
|
||||||
Logger.Error(e, "Couldn't get total space for {0}", path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool TryCreateHardLink(string source, string destination)
|
public override bool TryCreateHardLink(string source, string destination)
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace NzbDrone.Mono.Disk
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (VolumeLabel.IsNullOrWhiteSpace() || VolumeLabel.StartsWith("UUID="))
|
if (VolumeLabel.IsNullOrWhiteSpace() || VolumeLabel.StartsWith("UUID=") || Name == VolumeLabel)
|
||||||
{
|
{
|
||||||
return Name;
|
return Name;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ module.exports = Backgrid.Cell.extend({
|
|||||||
|
|
||||||
var contents = path;
|
var contents = path;
|
||||||
|
|
||||||
if (label) {
|
if (label && label !== path && !label.startsWith("UUID=")) {
|
||||||
contents += ' ({0})'.format(label);
|
contents += ' ({0})'.format(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user