{
@@ -529,20 +370,12 @@ NamingModal.propTypes = {
value: PropTypes.string.isRequired,
isOpen: PropTypes.bool.isRequired,
advancedSettings: PropTypes.bool.isRequired,
- season: PropTypes.bool.isRequired,
- episode: PropTypes.bool.isRequired,
- daily: PropTypes.bool.isRequired,
- anime: PropTypes.bool.isRequired,
additional: PropTypes.bool.isRequired,
onInputChange: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
NamingModal.defaultProps = {
- season: false,
- episode: false,
- daily: false,
- anime: false,
additional: false
};
diff --git a/frontend/src/Settings/MediaManagement/Naming/NamingOption.css b/frontend/src/Settings/MediaManagement/Naming/NamingOption.css
index 299c98936..c895cb6bc 100644
--- a/frontend/src/Settings/MediaManagement/Naming/NamingOption.css
+++ b/frontend/src/Settings/MediaManagement/Naming/NamingOption.css
@@ -1,6 +1,6 @@
.option {
display: flex;
- align-items: center;
+ align-items: stretch;
flex-wrap: wrap;
margin: 3px;
border: 1px solid $borderColor;
@@ -17,7 +17,7 @@
}
.small {
- width: 420px;
+ width: 480px;
}
.large {
@@ -32,6 +32,9 @@
}
.example {
+ display: flex;
+ align-items: center;
+ align-self: stretch;
flex: 0 0 50%;
padding: 6px 16px;
background-color: #ddd;
diff --git a/frontend/src/Settings/Notifications/Notifications/Notification.js b/frontend/src/Settings/Notifications/Notifications/Notification.js
index 143e5491a..29c2b1465 100644
--- a/frontend/src/Settings/Notifications/Notifications/Notification.js
+++ b/frontend/src/Settings/Notifications/Notifications/Notification.js
@@ -84,7 +84,7 @@ class Notification extends Component {
{
supportsOnDownload && onDownload &&
}
diff --git a/frontend/src/System/Status/MoreInfo/MoreInfo.js b/frontend/src/System/Status/MoreInfo/MoreInfo.js
index f338b3f1f..24c2d3548 100644
--- a/frontend/src/System/Status/MoreInfo/MoreInfo.js
+++ b/frontend/src/System/Status/MoreInfo/MoreInfo.js
@@ -19,6 +19,11 @@ class MoreInfo extends Component {
radarr.video
+
Discord
+
+ discord.gg/AD3UP37
+
+
Wiki
github.com/Radarr/Radarr/wiki
diff --git a/src/Libraries/MediaInfo/MediaInfo.dll b/src/Libraries/MediaInfo/MediaInfo.dll
index ca4ce4fb6..e877e7599 100644
Binary files a/src/Libraries/MediaInfo/MediaInfo.dll and b/src/Libraries/MediaInfo/MediaInfo.dll differ
diff --git a/src/Libraries/MediaInfo/libmediainfo.0.dylib b/src/Libraries/MediaInfo/libmediainfo.0.dylib
index 73ff0ba4f..0ffd2fdcc 100644
Binary files a/src/Libraries/MediaInfo/libmediainfo.0.dylib and b/src/Libraries/MediaInfo/libmediainfo.0.dylib differ
diff --git a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs
index b6d3edb00..b072ff395 100644
--- a/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs
+++ b/src/NzbDrone.Common.Test/Http/HttpClientFixture.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
+using System.Linq;
using System.Net;
using System.Threading;
using FluentAssertions;
@@ -24,18 +25,64 @@ namespace NzbDrone.Common.Test.Http
[TestFixture(typeof(CurlHttpDispatcher))]
public class HttpClientFixture : TestBase where TDispatcher : IHttpDispatcher
{
- private static string[] _httpBinHosts = new[] { "eu.httpbin.org", "httpbin.org" };
- private static int _httpBinRandom;
+ private string[] _httpBinHosts;
+ private int _httpBinSleep;
+ private int _httpBinRandom;
private string _httpBinHost;
+ private string _httpBinHost2;
+
+ [OneTimeSetUp]
+ public void FixtureSetUp()
+ {
+ var candidates = new[] { "eu.httpbin.org", /*"httpbin.org",*/ "www.httpbin.org" };
+ // httpbin.org is broken right now, occassionally redirecting to https if it's unavailable.
+ _httpBinHosts = candidates.Where(IsTestSiteAvailable).ToArray();
+
+ TestLogger.Info($"{candidates.Length} TestSites available.");
+
+ _httpBinSleep = _httpBinHosts.Count() < 2 ? 100 : 10;
+ }
+
+ private bool IsTestSiteAvailable(string site)
+ {
+ try
+ {
+ var req = WebRequest.Create($"http://{site}/get") as HttpWebRequest;
+ var res = req.GetResponse() as HttpWebResponse;
+ if (res.StatusCode != HttpStatusCode.OK) return false;
+
+ try
+ {
+ req = WebRequest.Create($"http://{site}/status/429") as HttpWebRequest;
+ res = req.GetResponse() as HttpWebResponse;
+ }
+ catch (WebException ex)
+ {
+ res = ex.Response as HttpWebResponse;
+ }
+
+ if (res == null || res.StatusCode != (HttpStatusCode)429) return false;
+
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
[SetUp]
public void SetUp()
{
+ if (!_httpBinHosts.Any())
+ {
+ Assert.Inconclusive("No TestSites available");
+ }
Mocker.GetMock().Setup(c => c.Version).Returns(new Version("1.0.0"));
Mocker.GetMock().Setup(c => c.Name).Returns("TestOS");
Mocker.GetMock().Setup(c => c.Version).Returns("9.0.0");
-
+
Mocker.SetConstant(Mocker.Resolve());
Mocker.SetConstant(Mocker.Resolve());
@@ -51,6 +98,13 @@ namespace NzbDrone.Common.Test.Http
// Roundrobin over the two servers, to reduce the chance of hitting the ratelimiter.
_httpBinHost = _httpBinHosts[_httpBinRandom++ % _httpBinHosts.Length];
+ _httpBinHost2 = _httpBinHosts[_httpBinRandom % _httpBinHosts.Length];
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ Thread.Sleep(_httpBinSleep);
}
[Test]
@@ -76,11 +130,12 @@ namespace NzbDrone.Common.Test.Http
[Test]
public void should_execute_typed_get()
{
- var request = new HttpRequest($"http://{_httpBinHost}/get");
+ var request = new HttpRequest($"http://{_httpBinHost}/get?test=1");
var response = Subject.Get(request);
- response.Resource.Url.Should().Be(request.Url.FullUri);
+ response.Resource.Url.EndsWith("/get?test=1");
+ response.Resource.Args.Should().Contain("test", "1");
}
[Test]
@@ -163,6 +218,11 @@ namespace NzbDrone.Common.Test.Http
[Test]
public void should_follow_redirects_to_https()
{
+ if (typeof(TDispatcher) == typeof(ManagedHttpDispatcher) && PlatformInfo.IsMono)
+ {
+ Assert.Ignore("Will fail on tls1.2 via managed dispatcher, ignore.");
+ }
+
var request = new HttpRequestBuilder($"http://{_httpBinHost}/redirect-to")
.AddQueryParam("url", $"https://sonarr.tv/")
.Build();
@@ -241,7 +301,12 @@ namespace NzbDrone.Common.Test.Http
public void GivenOldCookie()
{
- var oldRequest = new HttpRequest("http://eu.httpbin.org/get");
+ if (_httpBinHost == _httpBinHost2)
+ {
+ Assert.Inconclusive("Need both httpbin.org and eu.httpbin.org to run this test.");
+ }
+
+ var oldRequest = new HttpRequest($"http://{_httpBinHost2}/get");
oldRequest.Cookies["my"] = "cookie";
var oldClient = new HttpClient(new IHttpRequestInterceptor[0], Mocker.Resolve(), Mocker.Resolve(), Mocker.Resolve(), Mocker.GetMock().Object, Mocker.Resolve());
@@ -258,7 +323,7 @@ namespace NzbDrone.Common.Test.Http
{
GivenOldCookie();
- var request = new HttpRequest("http://eu.httpbin.org/get");
+ var request = new HttpRequest($"http://{_httpBinHost2}/get");
var response = Subject.Get(request);
@@ -274,7 +339,7 @@ namespace NzbDrone.Common.Test.Http
{
GivenOldCookie();
- var request = new HttpRequest("http://httpbin.org/get");
+ var request = new HttpRequest($"http://{_httpBinHost}/get");
var response = Subject.Get(request);
@@ -334,6 +399,28 @@ namespace NzbDrone.Common.Test.Http
responseCookies.Resource.Cookies.Should().BeEmpty();
}
+ [Test]
+ public void should_clear_request_cookie()
+ {
+ var requestSet = new HttpRequest($"http://{_httpBinHost}/cookies");
+ requestSet.Cookies.Add("my", "cookie");
+ requestSet.AllowAutoRedirect = false;
+ requestSet.StoreRequestCookie = true;
+ requestSet.StoreResponseCookie = false;
+
+ var responseSet = Subject.Get(requestSet);
+
+ var requestClear = new HttpRequest($"http://{_httpBinHost}/cookies");
+ requestClear.Cookies.Add("my", null);
+ requestClear.AllowAutoRedirect = false;
+ requestClear.StoreRequestCookie = true;
+ requestClear.StoreResponseCookie = false;
+
+ var responseClear = Subject.Get(requestClear);
+
+ responseClear.Resource.Cookies.Should().BeEmpty();
+ }
+
[Test]
public void should_not_store_response_cookie()
{
@@ -518,20 +605,6 @@ namespace NzbDrone.Common.Test.Http
ExceptionVerification.IgnoreErrors();
}
- [Test]
- public void should_not_send_old_cookie()
- {
- GivenOldCookie();
-
- var requestCookies = new HttpRequest($"http://{_httpBinHost}/cookies");
- requestCookies.IgnorePersistentCookies = true;
- requestCookies.StoreRequestCookie = false;
- requestCookies.StoreResponseCookie = false;
- var responseCookies = Subject.Get(requestCookies);
-
- responseCookies.Resource.Cookies.Should().BeEmpty();
- }
-
[Test]
public void should_throw_on_http429_too_many_requests()
{
@@ -610,8 +683,7 @@ namespace NzbDrone.Common.Test.Http
{
try
{
- string url =
- $"http://{_httpBinHost}/response-headers?Set-Cookie={Uri.EscapeUriString(malformedCookie)}";
+ string url = $"http://{_httpBinHost}/response-headers?Set-Cookie={Uri.EscapeUriString(malformedCookie)}";
var requestSet = new HttpRequest(url);
requestSet.AllowAutoRedirect = false;
@@ -635,6 +707,7 @@ namespace NzbDrone.Common.Test.Http
public class HttpBinResource
{
+ public Dictionary Args { get; set; }
public Dictionary Headers { get; set; }
public string Origin { get; set; }
public string Url { get; set; }
diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/QBittorrentTests/QBittorrentFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/QBittorrentTests/QBittorrentFixture.cs
index b3d05e7f6..5625e954f 100644
--- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/QBittorrentTests/QBittorrentFixture.cs
+++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/QBittorrentTests/QBittorrentFixture.cs
@@ -21,13 +21,13 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
{
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new QBittorrentSettings
- {
- Host = "127.0.0.1",
- Port = 2222,
- Username = "admin",
- Password = "pass",
- MovieCategory = "movies-radarr"
- };
+ {
+ Host = "127.0.0.1",
+ Port = 2222,
+ Username = "admin",
+ Password = "pass",
+ MovieCategory = "movies-radarr"
+ };
Mocker.GetMock()
.Setup(s => s.GetHashFromTorrentFile(It.IsAny()))
diff --git a/src/NzbDrone.Core.Test/IndexerTests/IntegrationTests/IndexerIntegrationTests.cs b/src/NzbDrone.Core.Test/IndexerTests/IntegrationTests/IndexerIntegrationTests.cs
index 2ac169b30..39d382bbd 100644
--- a/src/NzbDrone.Core.Test/IndexerTests/IntegrationTests/IndexerIntegrationTests.cs
+++ b/src/NzbDrone.Core.Test/IndexerTests/IntegrationTests/IndexerIntegrationTests.cs
@@ -4,11 +4,9 @@ using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Indexers;
-using NzbDrone.Core.Indexers.Nyaa;
using NzbDrone.Core.IndexerSearch.Definitions;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Test.Framework;
-using NzbDrone.Core.ThingiProvider;
using NzbDrone.Test.Common.Categories;
namespace NzbDrone.Core.Test.IndexerTests.IntegrationTests
@@ -30,40 +28,6 @@ namespace NzbDrone.Core.Test.IndexerTests.IntegrationTests
};
}
- [Test]
- public void nyaa_fetch_recent()
- {
- var indexer = Mocker.Resolve();
-
- indexer.Definition = new IndexerDefinition
- {
- Name = "MyIndexer",
- Settings = new NyaaSettings()
- };
-
- var result = indexer.FetchRecent();
-
- ValidateTorrentResult(result, hasSize: true);
- }
-
- [Test]
- public void nyaa_search_single()
- {
- var indexer = Mocker.Resolve();
-
- indexer.Definition = new IndexerDefinition
- {
- Name = "MyIndexer",
- Settings = new NyaaSettings()
- };
-
- var result = indexer.Fetch(_singleSearchCriteria);
-
- ValidateTorrentResult(result, hasSize: true);
- }
-
-
-
private void ValidateTorrentResult(IList reports, bool hasSize = false, bool hasInfoUrl = false, bool hasMagnet = false)
{
reports.Should().OnlyContain(c => c.GetType() == typeof(TorrentInfo));
diff --git a/src/NzbDrone.Core.Test/MediaFiles/DownloadedEpisodesCommandServiceFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/DownloadedEpisodesCommandServiceFixture.cs
deleted file mode 100644
index 3eebc70d4..000000000
--- a/src/NzbDrone.Core.Test/MediaFiles/DownloadedEpisodesCommandServiceFixture.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-using System.Collections.Generic;
-using System.IO;
-using FizzWare.NBuilder;
-using Moq;
-using NUnit.Framework;
-using NzbDrone.Common.Disk;
-using NzbDrone.Core.Download;
-using NzbDrone.Core.Download.TrackedDownloads;
-using NzbDrone.Core.MediaFiles;
-using NzbDrone.Core.MediaFiles.Commands;
-using NzbDrone.Core.MediaFiles.EpisodeImport;
-using NzbDrone.Core.Parser.Model;
-using NzbDrone.Core.Test.Framework;
-using NzbDrone.Core.Tv;
-using NzbDrone.Test.Common;
-
-namespace NzbDrone.Core.Test.MediaFiles
-{
- [TestFixture]
- public class DownloadedEpisodesCommandServiceFixture : CoreTest
- {
- private string _downloadFolder = "c:\\drop_other\\Show.S01E01\\".AsOsAgnostic();
- private string _downloadFile = "c:\\drop_other\\Show.S01E01.mkv".AsOsAgnostic();
-
- private TrackedDownload _trackedDownload;
-
- [SetUp]
- public void Setup()
- {
- Mocker.GetMock()
- .Setup(v => v.ProcessRootFolder(It.IsAny()))
- .Returns(new List());
-
- Mocker.GetMock()
- .Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
- .Returns(new List());
-
- var downloadItem = Builder.CreateNew()
- .With(v => v.DownloadId = "sab1")
- .With(v => v.Status = DownloadItemStatus.Downloading)
- .Build();
-
- var remoteEpisode = Builder.CreateNew()
- .With(v => v.Series = new Series())
- .Build();
-
- _trackedDownload = new TrackedDownload
- {
- DownloadItem = downloadItem,
- RemoteEpisode = remoteEpisode,
- State = TrackedDownloadStage.Downloading
- };
- }
-
- private void GivenExistingFolder(string path)
- {
- Mocker.GetMock().Setup(c => c.FolderExists(It.IsAny()))
- .Returns(true);
- }
-
- private void GivenExistingFile(string path)
- {
- Mocker.GetMock().Setup(c => c.FileExists(It.IsAny()))
- .Returns(true);
- }
-
- private void GivenValidQueueItem()
- {
- Mocker.GetMock()
- .Setup(s => s.Find("sab1"))
- .Returns(_trackedDownload);
- }
-
- [Test]
- public void should_skip_import_if_dronefactory_doesnt_exist()
- {
- Assert.Throws(() => Subject.Execute(new DownloadedEpisodesScanCommand()));
-
- Mocker.GetMock().Verify(c => c.ProcessRootFolder(It.IsAny()), Times.Never());
- }
-
- [Test]
- public void should_process_folder_if_downloadclientid_is_not_specified()
- {
- GivenExistingFolder(_downloadFolder);
-
- Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFolder });
-
- Mocker.GetMock().Verify(c => c.ProcessPath(It.IsAny(), ImportMode.Auto, null, null), Times.Once());
- }
-
- [Test]
- public void should_process_file_if_downloadclientid_is_not_specified()
- {
- GivenExistingFile(_downloadFile);
-
- Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFile });
-
- Mocker.GetMock().Verify(c => c.ProcessPath(It.IsAny(), ImportMode.Auto, null, null), Times.Once());
- }
-
- [Test]
- public void should_process_folder_with_downloadclientitem_if_available()
- {
- GivenExistingFolder(_downloadFolder);
- GivenValidQueueItem();
-
- Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFolder, DownloadClientId = "sab1" });
-
- Mocker.GetMock().Verify(c => c.ProcessPath(_downloadFolder, ImportMode.Auto, _trackedDownload.RemoteEpisode.Series, _trackedDownload.DownloadItem), Times.Once());
- }
-
- [Test]
- public void should_process_folder_without_downloadclientitem_if_not_available()
- {
- GivenExistingFolder(_downloadFolder);
-
- Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFolder, DownloadClientId = "sab1" });
-
- Mocker.GetMock().Verify(c => c.ProcessPath(_downloadFolder, ImportMode.Auto, null, null), Times.Once());
-
- ExceptionVerification.ExpectedWarns(1);
- }
-
- [Test]
- public void should_warn_if_neither_folder_or_file_exists()
- {
- Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFolder });
-
- Mocker.GetMock().Verify(c => c.ProcessPath(It.IsAny(), ImportMode.Auto, null, null), Times.Never());
-
- ExceptionVerification.ExpectedWarns(1);
- }
-
- [Test]
- public void should_override_import_mode()
- {
- GivenExistingFile(_downloadFile);
-
- Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFile, ImportMode = ImportMode.Copy });
-
- Mocker.GetMock().Verify(c => c.ProcessPath(It.IsAny(), ImportMode.Copy, null, null), Times.Once());
- }
- }
-}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/DownloadedEpisodesImportServiceFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/DownloadedEpisodesImportServiceFixture.cs
deleted file mode 100644
index 0fd99b058..000000000
--- a/src/NzbDrone.Core.Test/MediaFiles/DownloadedEpisodesImportServiceFixture.cs
+++ /dev/null
@@ -1,377 +0,0 @@
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using FizzWare.NBuilder;
-using Moq;
-using NUnit.Framework;
-using NzbDrone.Common.Disk;
-using NzbDrone.Core.MediaFiles;
-using NzbDrone.Core.MediaFiles.EpisodeImport;
-using NzbDrone.Core.Parser;
-using NzbDrone.Core.Parser.Model;
-using NzbDrone.Core.Qualities;
-using NzbDrone.Core.Test.Framework;
-using NzbDrone.Core.Tv;
-using NzbDrone.Test.Common;
-using FluentAssertions;
-
-namespace NzbDrone.Core.Test.MediaFiles
-{
- [TestFixture]
- public class DownloadedEpisodesImportServiceFixture : CoreTest
- {
- private string _droneFactory = "c:\\drop\\".AsOsAgnostic();
- private string[] _subFolders = new[] { "c:\\root\\foldername".AsOsAgnostic() };
- private string[] _videoFiles = new[] { "c:\\root\\foldername\\30.rock.s01e01.ext".AsOsAgnostic() };
-
- [SetUp]
- public void Setup()
- {
- Mocker.GetMock().Setup(c => c.GetVideoFiles(It.IsAny(), It.IsAny()))
- .Returns(_videoFiles);
-
- Mocker.GetMock().Setup(c => c.GetDirectories(It.IsAny()))
- .Returns(_subFolders);
-
- Mocker.GetMock().Setup(c => c.FolderExists(It.IsAny()))
- .Returns(true);
-
- Mocker.GetMock()
- .Setup(s => s.Import(It.IsAny>(), true, null, ImportMode.Auto))
- .Returns(new List());
- }
-
- private void GivenValidSeries()
- {
- Mocker.GetMock()
- .Setup(s => s.GetSeries(It.IsAny()))
- .Returns(Builder.CreateNew().Build());
- }
-
- [Test]
- public void should_search_for_series_using_folder_name()
- {
- Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
-
- Mocker.GetMock().Verify(c => c.GetSeries("foldername"), Times.Once());
- }
-
- [Test]
- public void should_skip_if_file_is_in_use_by_another_process()
- {
- GivenValidSeries();
-
- Mocker.GetMock().Setup(c => c.IsFileLocked(It.IsAny()))
- .Returns(true);
-
- Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
-
- VerifyNoImport();
- }
-
- [Test]
- public void should_skip_if_no_series_found()
- {
- Mocker.GetMock().Setup(c => c.GetSeries("foldername")).Returns((Series)null);
-
- Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
-
- Mocker.GetMock()
- .Verify(c => c.GetImportDecisions(It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny()),
- Times.Never());
-
- VerifyNoImport();
- }
-
- [Test]
- public void should_not_import_if_folder_is_a_series_path()
- {
- GivenValidSeries();
-
- Mocker.GetMock()
- .Setup(s => s.SeriesPathExists(It.IsAny()))
- .Returns(true);
-
- Mocker.GetMock()
- .Setup(c => c.GetVideoFiles(It.IsAny(), It.IsAny()))
- .Returns(new string[0]);
-
- Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
-
- Mocker.GetMock()
- .Verify(v => v.GetVideoFiles(It.IsAny(), true), Times.Never());
-
- ExceptionVerification.ExpectedWarns(1);
- }
-
- [Test]
- public void should_not_delete_folder_if_no_files_were_imported()
- {
- Mocker.GetMock()
- .Setup(s => s.Import(It.IsAny>(), false, null, ImportMode.Auto))
- .Returns(new List());
-
- Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
-
- Mocker.GetMock()
- .Verify(v => v.GetFolderSize(It.IsAny()), Times.Never());
- }
-
- [Test]
- public void should_not_delete_folder_if_files_were_imported_and_video_files_remain()
- {
- GivenValidSeries();
-
- var localEpisode = new LocalEpisode();
-
- var imported = new List();
- imported.Add(new ImportDecision(localEpisode));
-
- Mocker.GetMock()
- .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true))
- .Returns(imported);
-
- Mocker.GetMock()
- .Setup(s => s.Import(It.IsAny>(), true, null, ImportMode.Auto))
- .Returns(imported.Select(i => new ImportResult(i)).ToList());
-
- Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
-
- Mocker.GetMock()
- .Verify(v => v.DeleteFolder(It.IsAny(), true), Times.Never());
-
- ExceptionVerification.ExpectedWarns(1);
- }
-
- [Test]
- public void should_delete_folder_if_files_were_imported_and_only_sample_files_remain()
- {
- GivenValidSeries();
-
- var localEpisode = new LocalEpisode();
-
- var imported = new List();
- imported.Add(new ImportDecision(localEpisode));
-
- Mocker.GetMock()
- .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true))
- .Returns(imported);
-
- Mocker.GetMock()
- .Setup(s => s.Import(It.IsAny>(), true, null, ImportMode.Auto))
- .Returns(imported.Select(i => new ImportResult(i)).ToList());
-
- Mocker.GetMock()
- .Setup(s => s.IsSample(It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny()))
- .Returns(true);
-
- Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
-
- Mocker.GetMock()
- .Verify(v => v.DeleteFolder(It.IsAny(), true), Times.Once());
- }
-
- [TestCase("_UNPACK_")]
- [TestCase("_FAILED_")]
- public void should_remove_unpack_from_folder_name(string prefix)
- {
- var folderName = "30.rock.s01e01.pilot.hdtv-lol";
- var folders = new[] { string.Format(@"C:\Test\Unsorted\{0}{1}", prefix, folderName).AsOsAgnostic() };
-
- Mocker.GetMock()
- .Setup(c => c.GetDirectories(It.IsAny()))
- .Returns(folders);
-
- Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
-
- Mocker.GetMock()
- .Verify(v => v.GetSeries(folderName), Times.Once());
-
- Mocker.GetMock()
- .Verify(v => v.GetSeries(It.Is(s => s.StartsWith(prefix))), Times.Never());
- }
-
- [Test]
- public void should_return_importresult_on_unknown_series()
- {
- Mocker.GetMock().Setup(c => c.FolderExists(It.IsAny()))
- .Returns(false);
-
- Mocker.GetMock().Setup(c => c.FileExists(It.IsAny()))
- .Returns(true);
-
- var fileName = @"C:\folder\file.mkv".AsOsAgnostic();
-
- var result = Subject.ProcessPath(fileName);
-
- result.Should().HaveCount(1);
- result.First().ImportDecision.Should().NotBeNull();
- result.First().ImportDecision.LocalEpisode.Should().NotBeNull();
- result.First().ImportDecision.LocalEpisode.Path.Should().Be(fileName);
- result.First().Result.Should().Be(ImportResultType.Rejected);
- }
-
- [Test]
- public void should_not_delete_if_there_is_large_rar_file()
- {
- GivenValidSeries();
-
- var localEpisode = new LocalEpisode();
-
- var imported = new List();
- imported.Add(new ImportDecision(localEpisode));
-
- Mocker.GetMock()
- .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true))
- .Returns(imported);
-
- Mocker.GetMock()
- .Setup(s => s.Import(It.IsAny>(), true, null, ImportMode.Auto))
- .Returns(imported.Select(i => new ImportResult(i)).ToList());
-
- Mocker.GetMock()
- .Setup(s => s.IsSample(It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny()))
- .Returns(true);
-
- Mocker.GetMock()
- .Setup(s => s.GetFiles(It.IsAny(), SearchOption.AllDirectories))
- .Returns(new []{ _videoFiles.First().Replace(".ext", ".rar") });
-
- Mocker.GetMock()
- .Setup(s => s.GetFileSize(It.IsAny()))
- .Returns(15.Megabytes());
-
- Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
-
- Mocker.GetMock()
- .Verify(v => v.DeleteFolder(It.IsAny(), true), Times.Never());
-
- ExceptionVerification.ExpectedWarns(1);
- }
-
- [Test]
- public void should_use_folder_if_folder_import()
- {
- GivenValidSeries();
-
- var folderName = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] Maria the Virgin Witch - 09 [720p]".AsOsAgnostic();
- var fileName = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] Maria the Virgin Witch - 09 [720p]\[HorribleSubs] Maria the Virgin Witch - 09 [720p].mkv".AsOsAgnostic();
-
- Mocker.GetMock().Setup(c => c.FolderExists(folderName))
- .Returns(true);
-
- Mocker.GetMock().Setup(c => c.GetFiles(folderName, SearchOption.TopDirectoryOnly))
- .Returns(new[] { fileName });
-
- var localEpisode = new LocalEpisode();
-
- var imported = new List();
- imported.Add(new ImportDecision(localEpisode));
-
-
- Subject.ProcessPath(fileName);
-
- Mocker.GetMock()
- .Verify(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), It.Is(v => v.AbsoluteEpisodeNumbers.First() == 9), true), Times.Once());
- }
-
- [Test]
- public void should_not_use_folder_if_file_import()
- {
- GivenValidSeries();
-
- var fileName = @"C:\media\ba09030e-1234-1234-1234-123456789abc\Torrents\[HorribleSubs] Maria the Virgin Witch - 09 [720p].mkv".AsOsAgnostic();
-
- Mocker.GetMock().Setup(c => c.FolderExists(fileName))
- .Returns(false);
-
- Mocker.GetMock().Setup(c => c.FileExists(fileName))
- .Returns(true);
-
- var localEpisode = new LocalEpisode();
-
- var imported = new List();
- imported.Add(new ImportDecision(localEpisode));
-
- var result = Subject.ProcessPath(fileName);
-
- Mocker.GetMock()
- .Verify(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true), Times.Once());
- }
-
- [Test]
- public void should_not_process_if_file_and_folder_do_not_exist()
- {
- var folderName = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] Maria the Virgin Witch - 09 [720p]".AsOsAgnostic();
-
- Mocker.GetMock().Setup(c => c.FolderExists(folderName))
- .Returns(false);
-
- Mocker.GetMock().Setup(c => c.FileExists(folderName))
- .Returns(false);
-
- Subject.ProcessPath(folderName).Should().BeEmpty();
-
- Mocker.GetMock()
- .Verify(v => v.GetSeries(It.IsAny()), Times.Never());
-
- ExceptionVerification.ExpectedErrors(1);
- }
-
- [Test]
- public void should_not_delete_if_no_files_were_imported()
- {
- GivenValidSeries();
-
- var localEpisode = new LocalEpisode();
-
- var imported = new List();
- imported.Add(new ImportDecision(localEpisode));
-
- Mocker.GetMock()
- .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true))
- .Returns(imported);
-
- Mocker.GetMock()
- .Setup(s => s.Import(It.IsAny>(), true, null, ImportMode.Auto))
- .Returns(new List());
-
- Mocker.GetMock()
- .Setup(s => s.IsSample(It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny(),
- It.IsAny()))
- .Returns(true);
-
- Mocker.GetMock()
- .Setup(s => s.GetFileSize(It.IsAny()))
- .Returns(15.Megabytes());
-
- Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
-
- Mocker.GetMock()
- .Verify(v => v.DeleteFolder(It.IsAny(), true), Times.Never());
- }
-
- private void VerifyNoImport()
- {
- Mocker.GetMock().Verify(c => c.Import(It.IsAny>(), true, null, ImportMode.Auto),
- Times.Never());
- }
-
- private void VerifyImport()
- {
- Mocker.GetMock().Verify(c => c.Import(It.IsAny>(), true, null, ImportMode.Auto),
- Times.Once());
- }
- }
-}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs
index aef8580d5..5a4372369 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/VideoFileInfoReaderFixture.cs
@@ -53,7 +53,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
info.AudioBitrate.Should().Be(128000);
info.AudioChannels.Should().Be(2);
info.AudioLanguages.Should().Be("English");
- info.AudioAdditionalFeatures.Should().Be("LC");
+ info.AudioAdditionalFeatures.Should().BeOneOf("", "LC");
info.Height.Should().Be(320);
info.RunTime.Seconds.Should().Be(10);
info.ScanType.Should().Be("Progressive");
@@ -90,7 +90,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
info.AudioBitrate.Should().Be(128000);
info.AudioChannels.Should().Be(2);
info.AudioLanguages.Should().Be("English");
- info.AudioAdditionalFeatures.Should().Be("LC");
+ info.AudioAdditionalFeatures.Should().BeOneOf("", "LC");
info.Height.Should().Be(320);
info.RunTime.Seconds.Should().Be(10);
info.ScanType.Should().Be("Progressive");
diff --git a/src/NzbDrone.Core.Test/ParserTests/ReleaseGroupParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/ReleaseGroupParserFixture.cs
index 0690e4d6e..5e3399eb5 100644
--- a/src/NzbDrone.Core.Test/ParserTests/ReleaseGroupParserFixture.cs
+++ b/src/NzbDrone.Core.Test/ParserTests/ReleaseGroupParserFixture.cs
@@ -27,6 +27,9 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Seed S02E09 HDTV x264-2HD [eztv]-[rarbg.com]", "2HD")]
[TestCase("7s-atlantis-s02e01-720p.mkv", null)]
[TestCase("The.Middle.720p.HEVC.x265-MeGusta-Pre", "MeGusta")]
+ [TestCase("Blue.Bloods.S08E05.The.Forgotten.1080p.AMZN.WEB-DL.DDP5.1.H.264-NTb-Rakuv", "NTb")]
+ [TestCase("Lie.To.Me.S01E13.720p.BluRay.x264-SiNNERS-Rakuvfinhel", "SiNNERS")]
+ [TestCase("Who.is.America.S01E01.INTERNAL.720p.HDTV.x264-aAF-RakuvUS-Obfuscated", "aAF")]
[TestCase("Haunted.Hayride.2018.720p.WEBRip.DDP5.1.x264-NTb-postbot", "NTb")]
[TestCase("Haunted.Hayride.2018.720p.WEBRip.DDP5.1.x264-NTb-xpost", "NTb")]
//[TestCase("", "")]
diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadata.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadata.cs
index e379da197..8956a583d 100644
--- a/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadata.cs
+++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Roksbox/RoksboxMetadata.cs
@@ -142,7 +142,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
if (image == null)
{
_logger.Trace("Failed to find suitable Movie image for movie {0}.", movie.Title);
- return null;
+ return new List();
}
var source = _mediaCoverService.GetCoverPath(movie.Id, image.CoverType);
diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs
index fdd17bf68..c1253c151 100644
--- a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs
+++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs
@@ -110,7 +110,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
if (movie == null)
{
- movie = trackedDownload.RemoteMovie.Movie;
+ movie = trackedDownload.RemoteMovie?.Movie;
}
}
diff --git a/src/NzbDrone.Core/Notifications/Discord/Discord.cs b/src/NzbDrone.Core/Notifications/Discord/Discord.cs
new file mode 100644
index 000000000..df1d2eb33
--- /dev/null
+++ b/src/NzbDrone.Core/Notifications/Discord/Discord.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using FluentValidation.Results;
+using NzbDrone.Common.Extensions;
+using NzbDrone.Core.Notifications.Discord.Payloads;
+using NzbDrone.Core.Validation;
+
+namespace NzbDrone.Core.Notifications.Discord
+{
+ public class Discord : NotificationBase
+ {
+ private readonly IDiscordProxy _proxy;
+
+ public Discord(IDiscordProxy proxy)
+ {
+ _proxy = proxy;
+ }
+
+ public override string Name => "Discord";
+ public override string Link => "https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks";
+
+ public override void OnGrab(GrabMessage message)
+ {
+ var embeds = new List