1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-17 21:26:22 -04:00

Fixed: Backend/Frontend Cleanup

This commit is contained in:
Qstick
2019-06-30 00:58:54 -04:00
parent 286f73f38d
commit d178dce0d3
56 changed files with 519 additions and 925 deletions

View File

@@ -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<TDispatcher> : TestBase<HttpClient> 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<IPlatformInfo>().Setup(c => c.Version).Returns(new Version("1.0.0"));
Mocker.GetMock<IOsInfo>().Setup(c => c.Name).Returns("TestOS");
Mocker.GetMock<IOsInfo>().Setup(c => c.Version).Returns("9.0.0");
Mocker.SetConstant<IUserAgentBuilder>(Mocker.Resolve<UserAgentBuilder>());
Mocker.SetConstant<ICacheManager>(Mocker.Resolve<CacheManager>());
@@ -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<HttpBinResource>(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<ICacheManager>(), Mocker.Resolve<IRateLimitService>(), Mocker.Resolve<IHttpDispatcher>(), Mocker.GetMock<IUserAgentBuilder>().Object, Mocker.Resolve<Logger>());
@@ -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<HttpBinResource>(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<HttpBinResource>(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<HttpCookieResource>(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<HttpCookieResource>(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<HttpCookieResource>(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<string, object> Args { get; set; }
public Dictionary<string, object> Headers { get; set; }
public string Origin { get; set; }
public string Url { get; set; }

View File

@@ -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<ITorrentFileInfoReader>()
.Setup(s => s.GetHashFromTorrentFile(It.IsAny<Byte[]>()))

View File

@@ -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<Nyaa>();
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<Nyaa>();
indexer.Definition = new IndexerDefinition
{
Name = "MyIndexer",
Settings = new NyaaSettings()
};
var result = indexer.Fetch(_singleSearchCriteria);
ValidateTorrentResult(result, hasSize: true);
}
private void ValidateTorrentResult(IList<ReleaseInfo> reports, bool hasSize = false, bool hasInfoUrl = false, bool hasMagnet = false)
{
reports.Should().OnlyContain(c => c.GetType() == typeof(TorrentInfo));

View File

@@ -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<DownloadedEpisodesCommandService>
{
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<IDownloadedEpisodesImportService>()
.Setup(v => v.ProcessRootFolder(It.IsAny<DirectoryInfo>()))
.Returns(new List<ImportResult>());
Mocker.GetMock<IDownloadedEpisodesImportService>()
.Setup(v => v.ProcessPath(It.IsAny<string>(), It.IsAny<ImportMode>(), It.IsAny<Series>(), It.IsAny<DownloadClientItem>()))
.Returns(new List<ImportResult>());
var downloadItem = Builder<DownloadClientItem>.CreateNew()
.With(v => v.DownloadId = "sab1")
.With(v => v.Status = DownloadItemStatus.Downloading)
.Build();
var remoteEpisode = Builder<RemoteEpisode>.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<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>()))
.Returns(true);
}
private void GivenExistingFile(string path)
{
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(It.IsAny<string>()))
.Returns(true);
}
private void GivenValidQueueItem()
{
Mocker.GetMock<ITrackedDownloadService>()
.Setup(s => s.Find("sab1"))
.Returns(_trackedDownload);
}
[Test]
public void should_skip_import_if_dronefactory_doesnt_exist()
{
Assert.Throws<ArgumentException>(() => Subject.Execute(new DownloadedEpisodesScanCommand()));
Mocker.GetMock<IDownloadedEpisodesImportService>().Verify(c => c.ProcessRootFolder(It.IsAny<DirectoryInfo>()), Times.Never());
}
[Test]
public void should_process_folder_if_downloadclientid_is_not_specified()
{
GivenExistingFolder(_downloadFolder);
Subject.Execute(new DownloadedEpisodesScanCommand() { Path = _downloadFolder });
Mocker.GetMock<IDownloadedEpisodesImportService>().Verify(c => c.ProcessPath(It.IsAny<string>(), 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<IDownloadedEpisodesImportService>().Verify(c => c.ProcessPath(It.IsAny<string>(), 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<IDownloadedEpisodesImportService>().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<IDownloadedEpisodesImportService>().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<IDownloadedEpisodesImportService>().Verify(c => c.ProcessPath(It.IsAny<string>(), 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<IDownloadedEpisodesImportService>().Verify(c => c.ProcessPath(It.IsAny<string>(), ImportMode.Copy, null, null), Times.Once());
}
}
}

View File

@@ -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<DownloadedEpisodesImportService>
{
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<IDiskScanService>().Setup(c => c.GetVideoFiles(It.IsAny<string>(), It.IsAny<bool>()))
.Returns(_videoFiles);
Mocker.GetMock<IDiskProvider>().Setup(c => c.GetDirectories(It.IsAny<string>()))
.Returns(_subFolders);
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>()))
.Returns(true);
Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto))
.Returns(new List<ImportResult>());
}
private void GivenValidSeries()
{
Mocker.GetMock<IParsingService>()
.Setup(s => s.GetSeries(It.IsAny<string>()))
.Returns(Builder<Series>.CreateNew().Build());
}
[Test]
public void should_search_for_series_using_folder_name()
{
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IParsingService>().Verify(c => c.GetSeries("foldername"), Times.Once());
}
[Test]
public void should_skip_if_file_is_in_use_by_another_process()
{
GivenValidSeries();
Mocker.GetMock<IDiskProvider>().Setup(c => c.IsFileLocked(It.IsAny<string>()))
.Returns(true);
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
VerifyNoImport();
}
[Test]
public void should_skip_if_no_series_found()
{
Mocker.GetMock<IParsingService>().Setup(c => c.GetSeries("foldername")).Returns((Series)null);
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IMakeImportDecision>()
.Verify(c => c.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Series>(), It.IsAny<ParsedEpisodeInfo>(), It.IsAny<bool>()),
Times.Never());
VerifyNoImport();
}
[Test]
public void should_not_import_if_folder_is_a_series_path()
{
GivenValidSeries();
Mocker.GetMock<ISeriesService>()
.Setup(s => s.SeriesPathExists(It.IsAny<string>()))
.Returns(true);
Mocker.GetMock<IDiskScanService>()
.Setup(c => c.GetVideoFiles(It.IsAny<string>(), It.IsAny<bool>()))
.Returns(new string[0]);
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IDiskScanService>()
.Verify(v => v.GetVideoFiles(It.IsAny<string>(), true), Times.Never());
ExceptionVerification.ExpectedWarns(1);
}
[Test]
public void should_not_delete_folder_if_no_files_were_imported()
{
Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), false, null, ImportMode.Auto))
.Returns(new List<ImportResult>());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.GetFolderSize(It.IsAny<string>()), 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<ImportDecision>();
imported.Add(new ImportDecision(localEpisode));
Mocker.GetMock<IMakeImportDecision>()
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Series>(), null, true))
.Returns(imported);
Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto))
.Returns(imported.Select(i => new ImportResult(i)).ToList());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.DeleteFolder(It.IsAny<string>(), 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<ImportDecision>();
imported.Add(new ImportDecision(localEpisode));
Mocker.GetMock<IMakeImportDecision>()
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Series>(), null, true))
.Returns(imported);
Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto))
.Returns(imported.Select(i => new ImportResult(i)).ToList());
Mocker.GetMock<IDetectSample>()
.Setup(s => s.IsSample(It.IsAny<Series>(),
It.IsAny<QualityModel>(),
It.IsAny<string>(),
It.IsAny<long>(),
It.IsAny<bool>()))
.Returns(true);
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.DeleteFolder(It.IsAny<string>(), 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<IDiskProvider>()
.Setup(c => c.GetDirectories(It.IsAny<string>()))
.Returns(folders);
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IParsingService>()
.Verify(v => v.GetSeries(folderName), Times.Once());
Mocker.GetMock<IParsingService>()
.Verify(v => v.GetSeries(It.Is<string>(s => s.StartsWith(prefix))), Times.Never());
}
[Test]
public void should_return_importresult_on_unknown_series()
{
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>()))
.Returns(false);
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(It.IsAny<string>()))
.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<ImportDecision>();
imported.Add(new ImportDecision(localEpisode));
Mocker.GetMock<IMakeImportDecision>()
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Series>(), null, true))
.Returns(imported);
Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto))
.Returns(imported.Select(i => new ImportResult(i)).ToList());
Mocker.GetMock<IDetectSample>()
.Setup(s => s.IsSample(It.IsAny<Series>(),
It.IsAny<QualityModel>(),
It.IsAny<string>(),
It.IsAny<long>(),
It.IsAny<bool>()))
.Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetFiles(It.IsAny<string>(), SearchOption.AllDirectories))
.Returns(new []{ _videoFiles.First().Replace(".ext", ".rar") });
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetFileSize(It.IsAny<string>()))
.Returns(15.Megabytes());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.DeleteFolder(It.IsAny<string>(), 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<IDiskProvider>().Setup(c => c.FolderExists(folderName))
.Returns(true);
Mocker.GetMock<IDiskProvider>().Setup(c => c.GetFiles(folderName, SearchOption.TopDirectoryOnly))
.Returns(new[] { fileName });
var localEpisode = new LocalEpisode();
var imported = new List<ImportDecision>();
imported.Add(new ImportDecision(localEpisode));
Subject.ProcessPath(fileName);
Mocker.GetMock<IMakeImportDecision>()
.Verify(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Series>(), It.Is<ParsedEpisodeInfo>(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<IDiskProvider>().Setup(c => c.FolderExists(fileName))
.Returns(false);
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(fileName))
.Returns(true);
var localEpisode = new LocalEpisode();
var imported = new List<ImportDecision>();
imported.Add(new ImportDecision(localEpisode));
var result = Subject.ProcessPath(fileName);
Mocker.GetMock<IMakeImportDecision>()
.Verify(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Series>(), 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<IDiskProvider>().Setup(c => c.FolderExists(folderName))
.Returns(false);
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(folderName))
.Returns(false);
Subject.ProcessPath(folderName).Should().BeEmpty();
Mocker.GetMock<IParsingService>()
.Verify(v => v.GetSeries(It.IsAny<string>()), 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<ImportDecision>();
imported.Add(new ImportDecision(localEpisode));
Mocker.GetMock<IMakeImportDecision>()
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Series>(), null, true))
.Returns(imported);
Mocker.GetMock<IImportApprovedEpisodes>()
.Setup(s => s.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto))
.Returns(new List<ImportResult>());
Mocker.GetMock<IDetectSample>()
.Setup(s => s.IsSample(It.IsAny<Series>(),
It.IsAny<QualityModel>(),
It.IsAny<string>(),
It.IsAny<long>(),
It.IsAny<bool>()))
.Returns(true);
Mocker.GetMock<IDiskProvider>()
.Setup(s => s.GetFileSize(It.IsAny<string>()))
.Returns(15.Megabytes());
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Never());
}
private void VerifyNoImport()
{
Mocker.GetMock<IImportApprovedEpisodes>().Verify(c => c.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto),
Times.Never());
}
private void VerifyImport()
{
Mocker.GetMock<IImportApprovedEpisodes>().Verify(c => c.Import(It.IsAny<List<ImportDecision>>(), true, null, ImportMode.Auto),
Times.Once());
}
}
}

View File

@@ -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");

View File

@@ -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("", "")]

View File

@@ -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<ImageFileResult>();
}
var source = _mediaCoverService.GetCoverPath(movie.Id, image.CoverType);

View File

@@ -110,7 +110,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport.Manual
if (movie == null)
{
movie = trackedDownload.RemoteMovie.Movie;
movie = trackedDownload.RemoteMovie?.Movie;
}
}

View File

@@ -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<DiscordSettings>
{
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<Embed>
{
new Embed
{
Description = message.Message,
Title = message.Movie.Title,
Text = message.Message,
Color = (int)DiscordColors.Warning
}
};
var payload = CreatePayload($"Grabbed: {message.Message}", embeds);
_proxy.SendPayload(payload, Settings);
}
public override void OnDownload(DownloadMessage message)
{
var embeds = new List<Embed>
{
new Embed
{
Description = message.Message,
Title = message.Movie.Title,
Text = message.Message,
Color = (int)DiscordColors.Success
}
};
var payload = CreatePayload($"Imported: {message.Message}", embeds);
_proxy.SendPayload(payload, Settings);
}
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();
failures.AddIfNotNull(TestMessage());
return new ValidationResult(failures);
}
public ValidationFailure TestMessage()
{
try
{
var message = $"Test message from Radarr posted at {DateTime.Now}";
var payload = CreatePayload(message);
_proxy.SendPayload(payload, Settings);
}
catch (DiscordException ex)
{
return new NzbDroneValidationFailure("Unable to post", ex.Message);
}
return null;
}
private DiscordPayload CreatePayload(string message, List<Embed> embeds = null)
{
var avatar = Settings.Avatar;
var payload = new DiscordPayload
{
Username = Settings.Username,
Content = message,
Embeds = embeds
};
if (avatar.IsNotNullOrWhiteSpace())
{
payload.AvatarUrl = avatar;
}
if (Settings.Username.IsNotNullOrWhiteSpace())
{
payload.Username = Settings.Username;
}
return payload;
}
}
}

View File

@@ -0,0 +1,9 @@
namespace NzbDrone.Core.Notifications.Discord
{
public enum DiscordColors
{
Danger = 15749200,
Success = 2605644,
Warning = 16753920
}
}

View File

@@ -0,0 +1,16 @@
using System;
using NzbDrone.Common.Exceptions;
namespace NzbDrone.Core.Notifications.Discord
{
class DiscordException : NzbDroneException
{
public DiscordException(string message) : base(message)
{
}
public DiscordException(string message, Exception innerException, params object[] args) : base(message, innerException, args)
{
}
}
}

View File

@@ -0,0 +1,46 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Notifications.Discord.Payloads;
using NzbDrone.Core.Rest;
namespace NzbDrone.Core.Notifications.Discord
{
public interface IDiscordProxy
{
void SendPayload(DiscordPayload payload, DiscordSettings settings);
}
public class DiscordProxy : IDiscordProxy
{
private readonly IHttpClient _httpClient;
private readonly Logger _logger;
public DiscordProxy(IHttpClient httpClient, Logger logger)
{
_httpClient = httpClient;
_logger = logger;
}
public void SendPayload(DiscordPayload payload, DiscordSettings settings)
{
try
{
var request = new HttpRequestBuilder(settings.WebHookUrl)
.Accept(HttpAccept.Json)
.Build();
request.Method = HttpMethod.POST;
request.Headers.ContentType = "application/json";
request.SetContent(payload.ToJson());
_httpClient.Execute(request);
}
catch (RestException ex)
{
_logger.Error(ex, "Unable to post payload {0}", payload);
throw new DiscordException("Unable to post payload", ex);
}
}
}
}

View File

@@ -0,0 +1,35 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Notifications.Discord
{
public class DiscordSettingsValidator : AbstractValidator<DiscordSettings>
{
public DiscordSettingsValidator()
{
RuleFor(c => c.WebHookUrl).IsValidUrl();
}
}
public class DiscordSettings : IProviderConfig
{
private static readonly DiscordSettingsValidator Validator = new DiscordSettingsValidator();
[FieldDefinition(0, Label = "Webhook URL", HelpText = "Discord channel webhook url")]
public string WebHookUrl { get; set; }
[FieldDefinition(1, Label = "Username", HelpText = "The username to post as, defaults to Discord webhook default")]
public string Username { get; set; }
[FieldDefinition(2, Label = "Avatar", HelpText = "Change the avatar that is used for messages from this integration", Type = FieldType.Textbox)]
public string Avatar { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

View File

@@ -0,0 +1,17 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace NzbDrone.Core.Notifications.Discord.Payloads
{
public class DiscordPayload
{
public string Content { get; set; }
public string Username { get; set; }
[JsonProperty("avatar_url")]
public string AvatarUrl { get; set; }
public List<Embed> Embeds { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
namespace NzbDrone.Core.Notifications.Discord.Payloads
{
public class Embed
{
public string Description { get; set; }
public string Title { get; set; }
public string Text { get; set; }
public int Color { get; set; }
}
}

View File

@@ -1,4 +1,5 @@
namespace NzbDrone.Core.Notifications.Gotify
{
public enum GotifyPriority
{

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using FluentValidation.Results;
using NLog;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Notifications.Slack.Payloads;
using NzbDrone.Core.Movies;
@@ -13,12 +12,10 @@ namespace NzbDrone.Core.Notifications.Slack
public class Slack : NotificationBase<SlackSettings>
{
private readonly ISlackProxy _proxy;
private readonly Logger _logger;
public Slack(ISlackProxy proxy, Logger logger)
public Slack(ISlackProxy proxy)
{
_proxy = proxy;
_logger = logger;
}
public override string Name => "Slack";

View File

@@ -964,10 +964,17 @@
<Compile Include="Extras\Metadata\MetadataType.cs" />
<Compile Include="MetadataSource\TmdbConfigurationService.cs" />
<Compile Include="NetImport\NetImportSyncCommand.cs" />
<Compile Include="Notifications\Discord\Discord.cs" />
<Compile Include="Notifications\Discord\DiscordColors.cs" />
<Compile Include="Notifications\Discord\DiscordException.cs" />
<Compile Include="Notifications\Discord\DiscordProxy.cs" />
<Compile Include="Notifications\Discord\DiscordSettings.cs" />
<Compile Include="Notifications\Discord\Payloads\DiscordPayload.cs" />
<Compile Include="Notifications\Discord\Payloads\Embed.cs" />
<Compile Include="Notifications\Gotify\GotifyProxy.cs" />
<Compile Include="Notifications\Gotify\InvalidResponseException.cs" />
<Compile Include="Notifications\Gotify\Gotify.cs" />
<Compile Include="Notifications\Gotify\GotifyPriority.cs" />
<Compile Include="Notifications\Gotify\GotifyService.cs" />
<Compile Include="Notifications\Gotify\GotifySettings.cs" />
<Compile Include="Notifications\Join\JoinAuthException.cs" />
<Compile Include="Notifications\Join\JoinInvalidDeviceException.cs" />

View File

@@ -35,18 +35,9 @@ namespace NzbDrone.Core.Organizer
private static readonly Regex TitleRegex = new Regex(@"\{(?<prefix>[- ._\[(]*)(?<token>(?:[a-z0-9]+)(?:(?<separator>[- ._]+)(?:[a-z0-9]+))?)(?::(?<customFormat>[a-z0-9]+))?(?<suffix>[- ._)\]]*)\}",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex EpisodeRegex = new Regex(@"(?<episode>\{episode(?:\:0+)?})",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex TagsRegex = new Regex(@"(?<tags>\{tags(?:\:0+)?})",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex SeasonRegex = new Regex(@"(?<season>\{season(?:\:0+)?})",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex AbsoluteEpisodeRegex = new Regex(@"(?<absolute>\{absolute(?:\:0+)?})",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex SeasonEpisodePatternRegex = new Regex(@"(?<separator>(?<=})[- ._]+?)?(?<seasonEpisode>s?{season(?:\:0+)?}(?<episodeSeparator>[- ._]?[ex])(?<episode>{episode(?:\:0+)?}))(?<separator>[- ._]+?(?={))?",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
@@ -178,48 +169,6 @@ namespace NzbDrone.Core.Organizer
{
return new BasicNamingConfig(); //For now let's be lazy
//var episodeFormat = GetEpisodeFormat(nameSpec.StandardMovieFormat).LastOrDefault();
//if (episodeFormat == null)
//{
// return new BasicNamingConfig();
//}
//var basicNamingConfig = new BasicNamingConfig
//{
// Separator = episodeFormat.Separator,
// NumberStyle = episodeFormat.SeasonEpisodePattern
//};
//var titleTokens = TitleRegex.Matches(nameSpec.StandardMovieFormat);
//foreach (Match match in titleTokens)
//{
// var separator = match.Groups["separator"].Value;
// var token = match.Groups["token"].Value;
// if (!separator.Equals(" "))
// {
// basicNamingConfig.ReplaceSpaces = true;
// }
// if (token.StartsWith("{Series", StringComparison.InvariantCultureIgnoreCase))
// {
// basicNamingConfig.IncludeSeriesTitle = true;
// }
// if (token.StartsWith("{Episode", StringComparison.InvariantCultureIgnoreCase))
// {
// basicNamingConfig.IncludeEpisodeTitle = true;
// }
// if (token.StartsWith("{Quality", StringComparison.InvariantCultureIgnoreCase))
// {
// basicNamingConfig.IncludeQuality = true;
// }
//}
//return basicNamingConfig;
}
public string GetMovieFolder(Movie movie, NamingConfig namingConfig = null)
@@ -521,18 +470,6 @@ namespace NzbDrone.Core.Organizer
return value.ToString(split[1]);
}
private EpisodeFormat[] GetEpisodeFormat(string pattern)
{
return _episodeFormatCache.Get(pattern, () => SeasonEpisodePatternRegex.Matches(pattern).OfType<Match>()
.Select(match => new EpisodeFormat
{
EpisodeSeparator = match.Groups["episodeSeparator"].Value,
Separator = match.Groups["separator"].Value,
EpisodePattern = match.Groups["episode"].Value,
SeasonEpisodePattern = match.Groups["seasonEpisode"].Value,
}).ToArray());
}
private string GetQualityProper(Movie movie, QualityModel quality)
{
if (quality.Revision.Version > 1)

View File

@@ -113,7 +113,7 @@ namespace NzbDrone.Core.Parser
private static readonly Regex SixDigitAirDateRegex = new Regex(@"(?<=[_.-])(?<airdate>(?<!\d)(?<airyear>[1-9]\d{1})(?<airmonth>[0-1][0-9])(?<airday>[0-3][0-9]))(?=[_.-])",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex CleanReleaseGroupRegex = new Regex(@"^(.*?[-._ ](S\d+E\d+)[-._ ])|(-(RP|1|NZBGeek|Obfuscated|sample|Pre|postbot|xpost))+$",
private static readonly Regex CleanReleaseGroupRegex = new Regex(@"^(.*?[-._ ](S\d+E\d+)[-._ ])|(-(RP|1|NZBGeek|Obfuscated|sample|Pre|postbot|xpost|Rakuv[a-z]*|WhiteRev|BUYMORE))+$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex CleanTorrentSuffixRegex = new Regex(@"\[(?:ettv|rartv|rarbg|cttv)\]$",

View File

@@ -16,10 +16,12 @@ namespace NzbDrone.Integration.Test
config.LogLevel = "Trace";
HostConfig.Put(config);
var resultGet = Movies.All();
var logFile = Path.Combine(_runner.AppData, "logs", "radarr.trace.txt");
var logLines = File.ReadAllLines(logFile);
var result = Movies.InvalidPost(new MovieResource());
var resultPost = Movies.InvalidPost(new MovieResource());
logLines = File.ReadAllLines(logFile).Skip(logLines.Length).ToArray();

View File

@@ -125,6 +125,9 @@ namespace NzbDrone.Integration.Test
public void IntegrationSetUp()
{
TempDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "_test_" + DateTime.UtcNow.Ticks);
// Wait for things to get quiet, otherwise the previous test might influence the current one.
Commands.WaitAll();
}
[TearDown]

View File

@@ -26,4 +26,4 @@ namespace NzbDrone.Mono.Test.EnvironmentInfo
info.Version.Should().NotBeNullOrWhiteSpace();
}
}
}
}

View File

@@ -74,4 +74,4 @@ namespace NzbDrone.Mono.Test.EnvironmentInfo.VersionAdapters
.Verify(c => c.GetFiles(It.IsAny<string>(), SearchOption.TopDirectoryOnly), Times.Never());
}
}
}
}

View File

@@ -79,4 +79,4 @@ namespace NzbDrone.Mono.Test.EnvironmentInfo.VersionAdapters
}
}
}
}

View File

@@ -10,6 +10,7 @@ namespace NzbDrone.Mono.Disk
{
{ "afpfs", DriveType.Network },
{ "apfs", DriveType.Fixed },
{ "fuse.mergerfs", DriveType.Fixed },
{ "zfs", DriveType.Fixed }
};

View File

@@ -88,7 +88,7 @@
<Compile Include="SignalRDependencyResolver.cs" />
<Compile Include="SignalRJsonSerializer.cs" />
<Compile Include="SignalRMessage.cs" />
<Compile Include="SonarrPerformanceCounterManager.cs" />
<Compile Include="RadarrPerformanceCounterManager.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NzbDrone.Common\NzbDrone.Common.csproj">

View File

@@ -3,7 +3,7 @@ using Microsoft.AspNet.SignalR.Infrastructure;
namespace NzbDrone.SignalR
{
public class SonarrPerformanceCounterManager : IPerformanceCounterManager
public class RadarrPerformanceCounterManager : IPerformanceCounterManager
{
private readonly IPerformanceCounter _counter = new NoOpPerformanceCounter();

View File

@@ -17,7 +17,7 @@ namespace NzbDrone.SignalR
private SignalRDependencyResolver(IContainer container)
{
_container = container;
var performanceCounterManager = new SonarrPerformanceCounterManager();
var performanceCounterManager = new RadarrPerformanceCounterManager();
Register(typeof(IPerformanceCounterManager), () => performanceCounterManager);
}

View File

@@ -36,7 +36,6 @@ namespace Radarr.Api.V2.Calendar
var start = DateTime.Today.AddDays(-pastDays);
var end = DateTime.Today.AddDays(futureDays);
var unmonitored = false;
//var premiersOnly = false;
var tags = new List<int>();
// TODO: Remove start/end parameters in v3, they don't work well for iCal
@@ -45,7 +44,6 @@ namespace Radarr.Api.V2.Calendar
var queryPastDays = Request.Query.PastDays;
var queryFutureDays = Request.Query.FutureDays;
var queryUnmonitored = Request.Query.Unmonitored;
// var queryPremiersOnly = Request.Query.PremiersOnly;
var queryTags = Request.Query.Tags;
if (queryStart.HasValue) start = DateTime.Parse(queryStart.Value);
@@ -68,11 +66,6 @@ namespace Radarr.Api.V2.Calendar
unmonitored = bool.Parse(queryUnmonitored.Value);
}
//if (queryPremiersOnly.HasValue)
//{
// premiersOnly = bool.Parse(queryPremiersOnly.Value);
//}
if (queryTags.HasValue)
{
var tagInput = (string)queryTags.Value.ToString();
@@ -116,7 +109,7 @@ namespace Radarr.Api.V2.Calendar
}
var occurrence = calendar.Create<Event>();
occurrence.Uid = "NzbDrone_movie_" + movie.Id + (cinemasRelease ? "_cinemas" : "_physical");
occurrence.Uid = "Radarr_movie_" + movie.Id + (cinemasRelease ? "_cinemas" : "_physical");
occurrence.Status = movie.Status == MovieStatusType.Announced ? EventStatus.Tentative : EventStatus.Confirmed;
occurrence.Start = new CalDateTime(date.Value);

View File

@@ -2,9 +2,9 @@ using System;
using System.Collections.Generic;
using FluentValidation;
using Nancy;
using Nancy.ModelBinding;
using NLog;
using NzbDrone.Common.Cache;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.Exceptions;
@@ -43,12 +43,12 @@ namespace Radarr.Api.V2.Indexers
_downloadService = downloadService;
_logger = logger;
GetResourceAll = GetReleases;
Post["/"] = x => DownloadRelease(ReadResourceFromRequest());
PostValidator.RuleFor(s => s.IndexerId).ValidId();
PostValidator.RuleFor(s => s.Guid).NotEmpty();
GetResourceAll = GetReleases;
Post["/"] = x => DownloadRelease(ReadResourceFromRequest());
_remoteMovieCache = cacheManager.GetCache<RemoteMovie>(GetType(), "remoteMovies");
}
@@ -69,7 +69,7 @@ namespace Radarr.Api.V2.Indexers
}
catch (ReleaseDownloadException ex)
{
_logger.ErrorException(ex.Message, ex);
_logger.Error(ex, ex.Message);
throw new NzbDroneClientException(HttpStatusCode.Conflict, "Getting release from indexer failed");
}

View File

@@ -56,10 +56,10 @@ namespace Radarr.Api.V2.Indexers
if (firstDecision?.RemoteMovie.ParsedMovieInfo == null)
{
throw new ValidationException(new List<ValidationFailure> { new ValidationFailure("Title", "Unable to parse", release.Title) });
throw new ValidationException(new List<ValidationFailure>{ new ValidationFailure("Title", "Unable to parse", release.Title) });
}
return MapDecisions(new[] { firstDecision }).AsResponse();
return MapDecisions(new [] { firstDecision }).AsResponse();
}
private void ResolveIndexer(ReleaseInfo release)
@@ -74,7 +74,7 @@ namespace Radarr.Api.V2.Indexers
}
else
{
_logger.Debug("Push Release {0} not associated with unknown indexer {1}.", release.Title, release.Indexer);
_logger.Debug("Push Release {0} not associated with known indexer {1}.", release.Title, release.Indexer);
}
}
else if (release.IndexerId != 0 && release.Indexer.IsNullOrWhiteSpace())
@@ -87,7 +87,7 @@ namespace Radarr.Api.V2.Indexers
}
catch (ModelNotFoundException)
{
_logger.Debug("Push Release {0} not associated with unknown indexer {0}.", release.Title, release.IndexerId);
_logger.Debug("Push Release {0} not associated with known indexer {0}.", release.Title, release.IndexerId);
release.IndexerId = 0;
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Languages;
@@ -46,11 +47,16 @@ namespace Radarr.Api.V2.Indexers
public int? Leechers { get; set; }
public DownloadProtocol Protocol { get; set; }
public bool IsDaily { get; set; }
public bool IsAbsoluteNumbering { get; set; }
public bool IsPossibleSpecialEpisode { get; set; }
public bool Special { get; set; }
// Sent when queuing an unknown release
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]
public int? MovieId { get; set; }
}
public static class ReleaseResourceMapper
@@ -88,7 +94,7 @@ namespace Radarr.Api.V2.Indexers
CommentUrl = releaseInfo.CommentUrl,
DownloadUrl = releaseInfo.DownloadUrl,
InfoUrl = releaseInfo.InfoUrl,
// DownloadAllowed = remoteMovie.DownloadAllowed,
DownloadAllowed = remoteMovie.DownloadAllowed,
//ReleaseWeight