1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-27 17:54:34 -04:00

Compare commits

...

47 Commits

Author SHA1 Message Date
Taloth Saldono
efbb587290 Fixed MediaCover endpoint. 2017-12-13 21:28:42 +01:00
Mark McDowall
72a12a73af Fixed: Don't handle content requests in IndexHtmlMapper 2017-12-13 21:28:21 +01:00
fhscholl
95bc93042c Added: Separate naming tags for AudioLanguage and SubtitleLanguage (#2261) (Fixes #2257) 2017-12-12 23:53:11 +01:00
Leonardo Galli
172cf4d06e Fixed: Movies parsed from lists with no year and only title getting added mutliple times. 2017-12-12 23:26:16 +01:00
Taloth Saldono
5ac0f28fff Fixed: Security Vulnerabilities allowing authentication to be bypassed (discovered by Kyle Neideck) 2017-12-12 23:15:46 +01:00
Leonardo Galli
948af901da Added: Include APFS disks in disk space calculation. 2017-12-12 22:46:00 +01:00
Leonardo Galli
f36716135b Added: Upgrade MediaInfo to 17.10 (Windows/macOS) 2017-12-12 22:44:14 +01:00
kriegalex
b70016d082 Added: Support for VF2 french tag. (#2291) (Fixes #2290) 2017-12-12 22:28:36 +01:00
grokdesigns
6a1b099117 Added: Customize Slack Channel (#2308) (Fixes #2298) 2017-12-04 09:07:42 +01:00
Leonardo Galli
ffb098357d Fixed: Movie Editor Path screwed up. Might also fix some other movie editor issues. (Fixes #2170) 2017-11-19 15:11:53 +01:00
Leonardo Galli
1a22486aba Fixed: Tags disappearing (Fixes #2204) 2017-11-19 14:57:15 +01:00
Fish2
72631eab8f Fixed: moment.js deprecated zone and add functions (Fixes #2232) (Fixes #2231) (#2264) 2017-11-16 20:20:41 +01:00
Mike
e4a3e63c44 Fixed: CPU locking at a 100% in certain instances. (#2258) (Fixes #2218) 2017-11-12 12:25:46 +01:00
Fish2
5dc2df3d49 Revert "Fixed: moment.js deprecated zone and Added: and lossless compression of images (#2232) (Fixes #2231)"
This reverts commit 32b1f75eb3.
2017-11-10 17:11:42 +01:00
fhscholl
01f0c6d85f Added: SceneName to MovieFile API output (#2250) (Fixes #2245) 2017-11-10 16:13:14 +01:00
fhscholl
c7c423b13d Added: Functionality to XBMC and Plex to update indivdual titles. Also: Notification Cleanup (#2240) 2017-11-10 16:11:09 +01:00
Fish2
32b1f75eb3 Fixed: moment.js deprecated zone and Added: and lossless compression of images (#2232) (Fixes #2231) 2017-11-10 16:08:02 +01:00
adnanklink
29909db604 Added: FolderPath to the Movie Webhook (#2230) 2017-11-10 16:06:45 +01:00
Mike
ec3f094d12 Fixes #2218. (#2254)
* Fixed: Raise ApplicationStartupEvent after Owin is running.

* Actually inject the container.
2017-11-08 19:39:50 +01:00
adnanklink
cb857934c4 Added: Download_Id to On Download/On Upgrade (#2229) 2017-10-29 19:19:30 +01:00
Leonardo Galli
d0174c7b7b Merge remote-tracking branch 'origin/develop' into develop 2017-10-29 12:24:41 +01:00
Leonardo Galli
9d19c4ec21 Fixed: Manual Import. Fixes #2160 2017-10-29 12:24:35 +01:00
fhscholl
0a030386f2 Added: Movie_Quality to onGrab (#2221) (Fixes #1833) 2017-10-28 17:19:49 +02:00
fhscholl
5e121c78e1 Updated: Webhook Improvements (#2220) (Fixes #1751) 2017-10-28 17:18:52 +02:00
James White
b521ffb588 Added: Message about adblockers preventing the log table from loading (#2213) (Fixes #2209) 2017-10-23 21:50:03 +02:00
James White
386a434aeb Changed: Sabnzbd Update test cases and rename to MovieCategory (#2212) 2017-10-23 21:49:02 +02:00
James White
5674d8ad60 Changed: Nzbget Rename TvCategory references to MovieCategory (#2211) 2017-10-23 21:47:49 +02:00
Oliver Rivett-Carnac
b313dd1845 Minor error message tweak (#1778)
* Added: some tips to how to build. Gave some info to Windows developers.

* Fixed: Alignment of validation errors in labels

* Fixed: error message mentioning 'series'
2017-10-22 20:58:25 -04:00
James White
dffa50a82f uTorrent initial state feature (#2192)
* New: Initial state for torrents added to UTorrent

Closes #409

(cherry picked from commit 19a4d3536b)

* Change default port

* Rename TvCategory to MovieCategory
2017-10-22 20:51:07 -04:00
James White
5337f79281 Change default port of qBittorrent download client config (#2187) 2017-10-22 20:49:54 -04:00
fhscholl
8861c8d8a4 Add IsUpgrade and related deleted file paths for CustomScript (#2205)
* Add IsUpgrade flag and deleted file paths for updates

* use OldMovieFiles instead of OldFiles
2017-10-22 20:49:37 -04:00
James White
4574ff5f6d Fixed: typo on margin-bottom (#2182) 2017-10-15 16:11:27 +02:00
James White
dd53e51468 @cosmetic Fix jshint warnings on MoviesCollection.js (#2180) 2017-10-15 13:37:19 +02:00
James White
7ae2d455c3 Fixed: Remove unit on zero values (#2178) 2017-10-15 13:29:32 +02:00
James White
e2e6630b69 Added: Initial state for torrents added to qBittorrent (#2176) 2017-10-15 12:35:53 +02:00
James White
ed744b5702 Fixed: Jackett apikey cleaned from log again. (#2177) 2017-10-15 12:35:04 +02:00
Leonardo Galli
5ffa27ec29 @cosmetic changed title 2017-10-14 12:05:17 +02:00
Leonardo Galli
53bfe61eb6 @cosmetic Added status images for websites and update api. 2017-10-14 12:04:22 +02:00
Leonardo Galli
a4a8e4547f Merge remote-tracking branch 'origin/develop' into develop 2017-10-11 23:09:36 +02:00
Leonardo Galli
e2bda29737 Fixed: Manual Movie Page Filtering. 2017-10-11 23:09:29 +02:00
James White
ab117082ed @cosmetic Stop commented out code appearing in HTML source (#2158) 2017-10-11 22:55:33 +02:00
Leonardo Galli
c708c3f5a1 Merge remote-tracking branch 'origin/develop' into develop 2017-10-11 22:54:51 +02:00
Leonardo Galli
a98494ab63 Fixed: MediaInfo not getting read when quality isn't Bluray, Web-dl or HDTV. Fixes #1465. Fixes #1572. 2017-10-11 22:54:45 +02:00
James White
779a722175 Changed: Adjust ambiguous date options (#2165)
(cherry picked from commit 00c3074216)
2017-10-11 22:45:15 +02:00
James White
805927205c @cosmetic Simplify ical ProductId code since adding properties (#2164) 2017-10-11 21:11:16 +02:00
James White
1d8eec42ef Added: a default name for Radarr.ics (#2163) 2017-10-11 19:19:57 +02:00
Leonardo Galli
a951ad811d @cosmetic Updated changelog. 2017-10-09 21:51:21 +02:00
162 changed files with 8226 additions and 2665 deletions

View File

@@ -82,7 +82,7 @@ ignore_regexps = [
## whenever you are tweaking this variable.
##
section_regexps = [
('**New Features**', [
('**New features**', [
r'^[aA]dded?\s*:?\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
r'^[uU]pdated?\s*:?\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',
r'^[cC]hanged?\s*:?\s*((dev|use?r|pkg|test|doc)\s*:\s*)?([^\n]*)$',

3
.gitignore vendored
View File

@@ -150,3 +150,6 @@ Thumbs.db
# AppVeyor
/tools-cake/
/_artifacts/
# Cake
/tools/Addins/*

File diff suppressed because it is too large Load Diff

View File

@@ -50,6 +50,13 @@ The project was inspired by other Usenet/BitTorrent movie downloaders such as Co
| AppVeyor | [![AppVeyor](https://img.shields.io/appveyor/ci/galli-leo/Radarr/master.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/Radarr) | [![AppVeyor](https://img.shields.io/appveyor/ci/galli-leo/Radarr-usby1/develop.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/Radarr-usby1) |
| Travis | [![Travis](https://img.shields.io/travis/Radarr/Radarr/master.svg?maxAge=60&style=flat-square)](https://travis-ci.org/Radarr/Radarr) | [![Travis](https://img.shields.io/travis/Radarr/Radarr/develop.svg?maxAge=60&style=flat-square)](https://travis-ci.org/Radarr/Radarr) |
### [Site and API Status](https://status.radarr.video)
| API | Updates | Sites |
|-------|:----:|:----:|
| [![API V2](http://status.radarr.video/component/1/shield?style=flat-square)](https://api.radarr.video/v2/) | [![Update Server](http://status.radarr.video/component/4/shield?style=flat-square)](https://radarr.aeonlucid.com) | [![Radarr Mappings](http://status.radarr.video/component/6/shield?style=flat-square)](https://mappings.radarr.video/)
| [![API Staging](http://status.radarr.video/component/2/shield?style=flat-square)](https://staging.api.radarr.video/) | [![Github Updates](http://status.radarr.video/component/5/shield?style=flat-square)](https://api.github.com/v3/) | [![Main Site](http://status.radarr.video/component/7/shield?style=flat-square)](https://radarr.video/)
Radarr is currently undergoing rapid development and pull requests are actively added into the repository.
## Features
@@ -108,10 +115,17 @@ Radarr is currently undergoing rapid development and pull requests are actively
> **Notice**
> Gulp must be running at all times while you are working with Radarr client source files.
### Build
* To build run `sh build.sh`
**Note:** Windows users must have bash available to do this. [cmder](http://cmder.net/) which is a console emulator for windows has bash as part of it's default installation.
### Development
* Open `NzbDrone.sln` in Visual Studio or run the build.sh script, if Mono is installed
* Make sure `NzbDrone.Console` is set as the startup project
* Run `build.sh` before running
### License

View File

@@ -5,11 +5,10 @@
{{#sections}}
### {{{label}}}
{{#commits}}
- {{{subject}}} [{{{author}}}]
{{/commits}}
{{/sections}}
{{/versions}}

View File

@@ -1,9 +1,10 @@
using Nancy;
using Nancy;
using System;
using System.Collections.Generic;
using System.Linq;
using Ical.Net;
using Ical.Net.DataTypes;
using Ical.Net.General;
using Ical.Net.Interfaces.Serialization;
using Ical.Net.Serialization;
using Ical.Net.Serialization.iCalendar.Factory;
@@ -86,6 +87,10 @@ namespace NzbDrone.Api.Calendar
ProductId = "-//radarr.video//Radarr//EN"
};
var calendarName = "Radarr Movies Calendar";
calendar.AddProperty(new CalendarProperty("NAME", calendarName));
calendar.AddProperty(new CalendarProperty("X-WR-CALNAME", calendarName));
foreach (var movie in movies.OrderBy(v => v.Added))
{
if (tags.Any() && tags.None(movie.Tags.Contains))
@@ -114,8 +119,10 @@ namespace NzbDrone.Api.Calendar
occurrence.End = new CalDateTime(movie.InCinemas.Value.AddMinutes(movie.Runtime)) { HasTime = true };
}
break;
case MovieStatusType.Announced:
continue; // no date
default:
if (movie.PhysicalRelease != null)
{

View File

@@ -23,6 +23,8 @@ namespace NzbDrone.Api.Extensions.Pipelines
private void Handle(NancyContext context)
{
if (context.Request.Method == "OPTIONS") return;
if (_cacheableSpecification.IsCacheable(context))
{
context.Response.Headers.EnableCache();
@@ -33,4 +35,4 @@ namespace NzbDrone.Api.Extensions.Pipelines
}
}
}
}
}

View File

@@ -2,6 +2,7 @@
using System.Linq;
using Nancy;
using Nancy.Bootstrapper;
using NzbDrone.Common.Extensions;
namespace NzbDrone.Api.Extensions.Pipelines
{
@@ -11,10 +12,25 @@ namespace NzbDrone.Api.Extensions.Pipelines
public void Register(IPipelines pipelines)
{
pipelines.AfterRequest.AddItemToEndOfPipeline((Action<NancyContext>) Handle);
pipelines.BeforeRequest.AddItemToEndOfPipeline(HandleRequest);
pipelines.AfterRequest.AddItemToEndOfPipeline(HandleResponse);
}
private void Handle(NancyContext context)
private Response HandleRequest(NancyContext context)
{
if (context == null || context.Request.Method != "OPTIONS")
{
return null;
}
var response = new Response()
.WithStatusCode(HttpStatusCode.OK)
.WithContentType("");
ApplyResponseHeaders(response, context.Request);
return response;
}
private void HandleResponse(NancyContext context)
{
if (context == null || context.Response.Headers.ContainsKey(AccessControlHeaders.AllowOrigin))
{
@@ -26,21 +42,39 @@ namespace NzbDrone.Api.Extensions.Pipelines
private static void ApplyResponseHeaders(Response response, Request request)
{
var allowedMethods = "GET, OPTIONS, PATCH, POST, PUT, DELETE";
if (response.Headers.ContainsKey("Allow"))
if (request.IsApiRequest())
{
allowedMethods = response.Headers["Allow"];
// Allow Cross-Origin access to the API since it's protected with the apikey, and nothing else.
ApplyCorsResponseHeaders(response, request, "*", "GET, OPTIONS, PATCH, POST, PUT, DELETE");
}
var requestedHeaders = string.Join(", ", request.Headers[AccessControlHeaders.RequestHeaders]);
response.Headers.Add(AccessControlHeaders.AllowOrigin, "*");
response.Headers.Add(AccessControlHeaders.AllowMethods, allowedMethods);
if (request.Headers[AccessControlHeaders.RequestHeaders].Any())
else if (request.IsSharedContentRequest())
{
response.Headers.Add(AccessControlHeaders.AllowHeaders, requestedHeaders);
// Allow Cross-Origin access to specific shared content such as mediacovers and images.
ApplyCorsResponseHeaders(response, request, "*", "GET, OPTIONS");
}
// Disallow Cross-Origin access for any other route.
}
private static void ApplyCorsResponseHeaders(Response response, Request request, string allowOrigin, string allowedMethods)
{
response.Headers.Add(AccessControlHeaders.AllowOrigin, allowOrigin);
if (request.Method == "OPTIONS")
{
if (response.Headers.ContainsKey("Allow"))
{
allowedMethods = response.Headers["Allow"];
}
response.Headers.Add(AccessControlHeaders.AllowMethods, allowedMethods);
if (request.Headers[AccessControlHeaders.RequestHeaders].Any())
{
var requestedHeaders = string.Join(", ", request.Headers[AccessControlHeaders.RequestHeaders]);
response.Headers.Add(AccessControlHeaders.AllowHeaders, requestedHeaders);
}
}
}
}

View File

@@ -33,7 +33,8 @@ namespace NzbDrone.Api.Extensions.Pipelines
try
{
if (
!response.ContentType.Contains("image")
response.Contents != Response.NoBody
&& !response.ContentType.Contains("image")
&& !response.ContentType.Contains("font")
&& request.Headers.AcceptEncoding.Any(x => x.Contains("gzip"))
&& !AlreadyGzipEncoded(response)
@@ -80,4 +81,4 @@ namespace NzbDrone.Api.Extensions.Pipelines
return false;
}
}
}
}

View File

@@ -36,5 +36,11 @@ namespace NzbDrone.Api.Extensions
{
return request.Path.StartsWith("/Content/", StringComparison.InvariantCultureIgnoreCase);
}
public static bool IsSharedContentRequest(this Request request)
{
return request.Path.StartsWith("/MediaCover/", StringComparison.InvariantCultureIgnoreCase) ||
request.Path.StartsWith("/Content/Images/", StringComparison.InvariantCultureIgnoreCase);
}
}
}

View File

@@ -49,7 +49,12 @@ namespace NzbDrone.Api.Frontend.Mappers
public override bool CanHandle(string resourceUrl)
{
return !resourceUrl.Contains(".") && !resourceUrl.StartsWith("/login");
resourceUrl = resourceUrl.ToLowerInvariant();
return !resourceUrl.StartsWith("/content") &&
!resourceUrl.StartsWith("/mediacover") &&
!resourceUrl.Contains(".") &&
!resourceUrl.StartsWith("/login");
}
public override Response GetResponse(string resourceUrl)
@@ -113,4 +118,4 @@ namespace NzbDrone.Api.Frontend.Mappers
return _generatedContent;
}
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.IO;
using System.Text.RegularExpressions;
using NLog;
@@ -42,7 +43,7 @@ namespace NzbDrone.Api.Frontend.Mappers
public override bool CanHandle(string resourceUrl)
{
return resourceUrl.StartsWith("/MediaCover");
return resourceUrl.StartsWith("/MediaCover", StringComparison.InvariantCultureIgnoreCase);
}
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.IO;
using NLog;
using NzbDrone.Common.Disk;
@@ -28,7 +29,9 @@ namespace NzbDrone.Api.Frontend.Mappers
public override bool CanHandle(string resourceUrl)
{
return resourceUrl.StartsWith("/Content") ||
resourceUrl = resourceUrl.ToLowerInvariant();
return resourceUrl.StartsWith("/content") ||
resourceUrl.EndsWith(".js") ||
resourceUrl.EndsWith(".map") ||
resourceUrl.EndsWith(".css") ||
@@ -37,4 +40,4 @@ namespace NzbDrone.Api.Frontend.Mappers
resourceUrl.EndsWith("oauth.html");
}
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Nancy.Responses;
using NLog;
using Nancy;
using NzbDrone.Api.Frontend.Mappers;

View File

@@ -34,7 +34,6 @@ namespace NzbDrone.Api
RegisterPipelines(pipelines);
container.Resolve<DatabaseTarget>().Register();
container.Resolve<IEventAggregator>().PublishEvent(new ApplicationStartedEvent());
}
private void RegisterPipelines(IPipelines pipelines)
@@ -56,4 +55,4 @@ namespace NzbDrone.Api
protected override byte[] FavIcon => null;
}
}
}

View File

@@ -60,6 +60,7 @@ namespace NzbDrone.Api.Movie
Path = model.Path,
Size = model.Size,
DateAdded = model.DateAdded,
SceneName = model.SceneName,
ReleaseGroup = model.ReleaseGroup,
Quality = model.Quality,
Movie = movie,

View File

@@ -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://dognzb.cr/fetch/2b51db35e1912ffc138825a12b9933d2/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
[TestCase(@"{ ""Name"" : ""ControlUsername"", ""Value"" : ""mySecret"" }, { ""Name"" : ""ControlPassword"", ""Value"" : ""mySecret"" }, ")]
[TestCase(@"{ ""Name"" : ""Server1.Username"", ""Value"" : ""mySecret"" }, { ""Name"" : ""Server1.Password"", ""Value"" : ""mySecret"" }, ")]

View File

@@ -6,10 +6,10 @@ namespace NzbDrone.Common.Instrumentation
{
public class CleanseLogMessage
{
private static readonly Regex[] CleansingRules = new[]
private static readonly Regex[] CleansingRules = new[]
{
// 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(@"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),

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Net.Sockets;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
@@ -11,6 +11,13 @@ namespace NzbDrone.Console
{
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(ConsoleApp));
private enum ExitCodes : int
{
Normal = 0,
UnknownFailure = 1,
RecoverableFailure = 2
}
public static void Main(string[] args)
{
try
@@ -19,30 +26,41 @@ namespace NzbDrone.Console
NzbDroneLogger.Register(startupArgs, false, true);
Bootstrap.Start(startupArgs, new ConsoleAlerts());
}
catch (SocketException exception)
catch (SocketException e)
{
System.Console.WriteLine("");
System.Console.WriteLine("");
Logger.Fatal(exception.Message + ". This can happen if another instance of Radarr is already running another application is using the same port (default: 7878) or the user has insufficient permissions");
System.Console.WriteLine("Press enter to exit...");
System.Console.ReadLine();
Environment.Exit(1);
Logger.Fatal(e.Message + ". This can happen if another instance of Radarr is already running another application is using the same port (default: 7878) or the user has insufficient permissions");
Exit(ExitCodes.RecoverableFailure);
}
catch (Exception e)
{
System.Console.WriteLine("");
System.Console.WriteLine("");
Logger.Fatal(e, "EPIC FAIL!");
System.Console.WriteLine("Press enter to exit...");
System.Console.ReadLine();
Environment.Exit(1);
Exit(ExitCodes.UnknownFailure);
}
Logger.Info("Exiting main.");
//Need this to terminate on mono (thanks nlog)
LogManager.Configuration = null;
Environment.Exit(0);
Exit(ExitCodes.Normal);
}
private static void Exit(ExitCodes exitCode)
{
LogManager.Shutdown();
if (exitCode != ExitCodes.Normal)
{
System.Console.WriteLine("Press enter to exit...");
System.Threading.Thread.Sleep(1000);
// Please note that ReadLine silently succeeds if there is no console, KeyAvailable does not.
System.Console.ReadLine();
}
Environment.Exit((int)exitCode);
}
}
}

View File

@@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
Port = 2222,
Username = "admin",
Password = "pass",
TvCategory = "tv",
MovieCategory = "movie",
RecentTvPriority = (int)NzbgetPriority.High
};
@@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
{
FileSizeLo = 1000,
RemainingSizeLo = 10,
Category = "tv",
Category = "movie",
NzbName = "Droned.1998.1080p.WEB-DL-DRONE",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } }
};
@@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
_failed = new NzbgetHistoryItem
{
FileSizeLo = 1000,
Category = "tv",
Category = "movie",
Name = "Droned.1998.1080p.WEB-DL-DRONE",
DestDir = "somedirectory",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
@@ -61,7 +61,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
_completed = new NzbgetHistoryItem
{
FileSizeLo = 1000,
Category = "tv",
Category = "movie",
Name = "Droned.1998.1080p.WEB-DL-DRONE",
DestDir = "/remote/mount/tv/Droned.1998.1080p.WEB-DL-DRONE",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
@@ -81,8 +81,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
});
var configItems = new Dictionary<string, string>();
configItems.Add("Category1.Name", "tv");
configItems.Add("Category1.DestDir", @"/remote/mount/tv");
configItems.Add("Category1.Name", "movie");
configItems.Add("Category1.DestDir", @"/remote/mount/movie");
Mocker.GetMock<INzbgetProxy>()
.Setup(v => v.GetConfig(It.IsAny<NzbgetSettings>()))

View File

@@ -36,7 +36,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
ApiKey = "5c770e3197e4fe763423ee7c392c25d1",
Username = "admin",
Password = "pass",
TvCategory = "tv",
MovieCategory = "movie",
RecentTvPriority = (int)SabnzbdPriority.High
};
_queued = new SabnzbdQueue
@@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
Size = 1000,
Sizeleft = 10,
Timeleft = TimeSpan.FromSeconds(10),
Category = "tv",
Category = "movie",
Id = "sabnzbd_nzb12345",
Title = "Droned.1998.1080p.WEB-DL-DRONE"
}
@@ -66,7 +66,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{
Status = SabnzbdDownloadStatus.Failed,
Size = 1000,
Category = "tv",
Category = "movie",
Id = "sabnzbd_nzb12345",
Title = "Droned.1998.1080p.WEB-DL-DRONE"
}
@@ -81,7 +81,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{
Status = SabnzbdDownloadStatus.Completed,
Size = 1000,
Category = "tv",
Category = "movie",
Id = "sabnzbd_nzb12345",
Title = "Droned.1998.1080p.WEB-DL-DRONE",
Storage = "/remote/mount/vv/Droned.1998.1080p.WEB-DL-DRONE"
@@ -97,7 +97,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
},
Categories = new List<SabnzbdCategory>
{
new SabnzbdCategory { Name = "tv", Dir = "vv" }
new SabnzbdCategory { Name = "movie", Dir = "vv" }
}
};
@@ -111,7 +111,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
_fullStatus = new SabnzbdFullStatus
{
CompleteDir = @"Y:\nzbget\root\complete".AsOsAgnostic()
CompleteDir = @"Y:\sabnzbd\root\complete".AsOsAgnostic()
};
Mocker.GetMock<ISabnzbdProxy>()
@@ -408,10 +408,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
result.OutputPath.Should().Be(@"C:\sorted\somewhere\asdfasdf\asdfasdf.mkv".AsOsAgnostic());
}
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads", @"Y:\nzbget\root\completed\downloads\vv")]
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed", @"Y:\nzbget\root\completed\vv")]
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads", @"/nzbget/root/completed/downloads/vv")]
[TestCase(@"/nzbget/root", @"completed", @"vv", @"/nzbget/root/completed", @"/nzbget/root/completed/vv")]
[TestCase(@"Y:\sabnzbd\root", @"completed\downloads", @"vv", @"Y:\sabnzbd\root\completed\downloads", @"Y:\sabnzbd\root\completed\downloads\vv")]
[TestCase(@"Y:\sabnzbd\root", @"completed", @"vv", @"Y:\sabnzbd\root\completed", @"Y:\sabnzbd\root\completed\vv")]
[TestCase(@"/sabnzbd/root", @"completed/downloads", @"vv", @"/sabnzbd/root/completed/downloads", @"/sabnzbd/root/completed/downloads/vv")]
[TestCase(@"/sabnzbd/root", @"completed", @"vv", @"/sabnzbd/root/completed", @"/sabnzbd/root/completed/vv")]
public void should_return_status_with_outputdir_for_version_lt_2(string rootFolder, string completeDir, string categoryDir, string fullCompleteDir, string fullCategoryDir)
{
_fullStatus.CompleteDir = null;
@@ -429,10 +429,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
result.OutputRootFolders.First().Should().Be(fullCategoryDir);
}
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads", @"Y:\nzbget\root\completed\downloads\vv")]
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed", @"Y:\nzbget\root\completed\vv")]
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads", @"/nzbget/root/completed/downloads/vv")]
[TestCase(@"/nzbget/root", @"completed", @"vv", @"/nzbget/root/completed", @"/nzbget/root/completed/vv")]
[TestCase(@"Y:\sabnzbd\root", @"completed\downloads", @"vv", @"Y:\sabnzbd\root\completed\downloads", @"Y:\sabnzbd\root\completed\downloads\vv")]
[TestCase(@"Y:\sabnzbd\root", @"completed", @"vv", @"Y:\sabnzbd\root\completed", @"Y:\sabnzbd\root\completed\vv")]
[TestCase(@"/sabnzbd/root", @"completed/downloads", @"vv", @"/sabnzbd/root/completed/downloads", @"/sabnzbd/root/completed/downloads/vv")]
[TestCase(@"/sabnzbd/root", @"completed", @"vv", @"/sabnzbd/root/completed", @"/sabnzbd/root/completed/vv")]
public void should_return_status_with_outputdir_for_version_gte_2(string rootFolder, string completeDir, string categoryDir, string fullCompleteDir, string fullCategoryDir)
{
_fullStatus.CompleteDir = fullCompleteDir;
@@ -554,7 +554,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
[Test]
public void should_test_failed_if_tv_sorting_default_category()
{
Subject.Definition.Settings.As<SabnzbdSettings>().TvCategory = null;
Subject.Definition.Settings.As<SabnzbdSettings>().MovieCategory = null;
_config.Misc.enable_tv_sorting = true;
_config.Misc.tv_categories = new[] { "Default" };

View File

@@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Port = 2222,
Username = "admin",
Password = "pass",
TvCategory = "tv"
MovieCategory = "movie"
};
_queued = new UTorrentTorrent
@@ -41,7 +41,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000,
Remaining = 1000,
Progress = 0,
Label = "tv",
Label = "movie",
DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath"
};
@@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000,
Remaining = 100,
Progress = 0.9,
Label = "tv",
Label = "movie",
DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath"
};
@@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000,
Remaining = 100,
Progress = 0.9,
Label = "tv",
Label = "movie",
DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath"
};
@@ -80,7 +80,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000,
Remaining = 0,
Progress = 1.0,
Label = "tv",
Label = "movie",
DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath"
};

View File

@@ -19,29 +19,29 @@ namespace NzbDrone.Core.Test.NotificationTests
[SetUp]
public void SetUp()
{
_movie = new Movie()
_movie = new Movie
{
Path = @"C:\Test\".AsOsAgnostic()
};
_upgrade = new DownloadMessage()
_upgrade = new DownloadMessage
{
Movie = _movie,
MovieFile = new MovieFile
{
RelativePath = "file1.S01E01E02.mkv"
RelativePath = "moviefile1.mkv"
},
OldMovieFiles = new List<MovieFile>
{
new MovieFile
{
RelativePath = "file1.S01E01.mkv"
RelativePath = "oldmoviefile1.mkv"
},
new MovieFile
{
RelativePath = "file1.S01E02.mkv"
RelativePath = "oldmoviefile2.mkv"
}
}
};
@@ -63,37 +63,37 @@ namespace NzbDrone.Core.Test.NotificationTests
Subject.OnMovieRename(_movie);
Mocker.GetMock<ISynologyIndexerProxy>()
.Verify(v => v.UpdateFolder(_movie.Path), Times.Never());
.Verify(v => v.UpdateFolder(_movie.Path), Times.Never());
}
[Test]
public void should_remove_old_episodes_on_upgrade()
public void should_remove_old_movie_on_upgrade()
{
Subject.OnDownload(_upgrade);
Mocker.GetMock<ISynologyIndexerProxy>()
.Verify(v => v.DeleteFile(@"C:\Test\file1.S01E01.mkv".AsOsAgnostic()), Times.Once());
.Verify(v => v.DeleteFile(@"C:\Test\oldmoviefile1.mkv".AsOsAgnostic()), Times.Once());
Mocker.GetMock<ISynologyIndexerProxy>()
.Verify(v => v.DeleteFile(@"C:\Test\file1.S01E02.mkv".AsOsAgnostic()), Times.Once());
.Verify(v => v.DeleteFile(@"C:\Test\oldmoviefile2.mkv".AsOsAgnostic()), Times.Once());
}
[Test]
public void should_add_new_episode_on_upgrade()
public void should_add_new_movie_on_upgrade()
{
Subject.OnDownload(_upgrade);
Mocker.GetMock<ISynologyIndexerProxy>()
.Verify(v => v.AddFile(@"C:\Test\file1.S01E01E02.mkv".AsOsAgnostic()), Times.Once());
.Verify(v => v.AddFile(@"C:\Test\moviefile1.mkv".AsOsAgnostic()), Times.Once());
}
[Test]
public void should_update_entire_series_folder_on_rename()
public void should_update_entire_movie_folder_on_rename()
{
Subject.OnMovieRename(_movie);
Mocker.GetMock<ISynologyIndexerProxy>()
.Verify(v => v.UpdateFolder(@"C:\Test\".AsOsAgnostic()), Times.Once());
.Verify(v => v.UpdateFolder(@"C:\Test\".AsOsAgnostic()), Times.Once());
}
}
}

View File

@@ -1,70 +0,0 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Notifications.Xbmc;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Http
{
[TestFixture]
public class ActivePlayersFixture : CoreTest<HttpApiProvider>
{
private XbmcSettings _settings;
private string _expectedUrl;
private void WithNoActivePlayers()
{
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(_expectedUrl, _settings.Username, _settings.Password))
.Returns("<html><li>Filename:[Nothing Playing]</html>");
}
private void WithVideoPlayerActive()
{
var activePlayers = @"<html><li>Filename:C:\Test\TV\2 Broke Girls\Season 01\2 Broke Girls - S01E01 - Pilot [SDTV].avi" +
"<li>PlayStatus:Playing<li>VideoNo:0<li>Type:Video<li>Thumb:special://masterprofile/Thumbnails/Video/a/auto-a664d5a2.tbn" +
"<li>Time:00:06<li>Duration:21:35<li>Percentage:0<li>File size:183182590<li>Changed:True</html>";
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(_expectedUrl, _settings.Username, _settings.Password))
.Returns(activePlayers);
}
[SetUp]
public void Setup()
{
_settings = new XbmcSettings
{
Host = "localhost",
Port = 8080,
Username = "xbmc",
Password = "xbmc",
AlwaysUpdate = false,
CleanLibrary = false,
UpdateLibrary = true
};
_expectedUrl = string.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", _settings.Address, "getcurrentlyplaying");
}
[Test]
public void _should_be_empty_when_no_active_players()
{
WithNoActivePlayers();
Subject.GetActivePlayers(_settings).Should().BeEmpty();
}
[Test]
public void should_have_active_video_player()
{
WithVideoPlayerActive();
var result = Subject.GetActivePlayers(_settings);
result.Should().HaveCount(1);
result.First().Type.Should().Be("video");
}
}
}

View File

@@ -1,35 +0,0 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Notifications.Xbmc;
using NzbDrone.Core.Test.Framework;
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Http
{
[TestFixture]
public class CheckForErrorFixture : CoreTest<HttpApiProvider>
{
[Test]
public void should_be_true_when_the_response_contains_an_error()
{
const string response = "html><li>Error:Unknown command</html>";
Subject.CheckForError(response).Should().BeTrue();
}
[Test]
public void JsonError_true_empty_response()
{
var response = string.Empty;
Subject.CheckForError(response).Should().BeTrue();
}
[Test]
public void JsonError_false()
{
const string response = "html><li>Filename:[Nothing Playing]</html>";
Subject.CheckForError(response).Should().BeFalse();
}
}
}

View File

@@ -1,94 +0,0 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Notifications.Xbmc;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Http
{
[TestFixture]
public class GetSeriesPathFixture : CoreTest<HttpApiProvider>
{
private XbmcSettings _settings;
private Series _series;
[SetUp]
public void Setup()
{
_settings = new XbmcSettings
{
Host = "localhost",
Port = 8080,
Username = "xbmc",
Password = "xbmc",
AlwaysUpdate = false,
CleanLibrary = false,
UpdateLibrary = true
};
_series = new Series
{
TvdbId = 79488,
Title = "30 Rock"
};
const string setResponseUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=SetResponseFormat(webheader;false;webfooter;false;header;<xml>;footer;</xml>;opentag;<tag>;closetag;</tag>;closefinaltag;false)";
const string resetResponseUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=SetResponseFormat()";
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(setResponseUrl, _settings.Username, _settings.Password))
.Returns("<xml><tag>OK</xml>");
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(resetResponseUrl, _settings.Username, _settings.Password))
.Returns(@"<html>
<li>OK
</html>");
}
[Test]
public void should_get_series_path()
{
const string queryResult = @"<xml><record><field>smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/</field></record></xml>";
var query = string.Format("http://localhost:8080/xbmcCmds/xbmcHttp?command=QueryVideoDatabase(select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = 79488 and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath)");
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(query, _settings.Username, _settings.Password))
.Returns(queryResult);
Subject.GetSeriesPath(_settings, _series)
.Should().Be("smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/");
}
[Test]
public void should_get_null_for_series_path()
{
const string queryResult = @"<xml></xml>";
var query = string.Format("http://localhost:8080/xbmcCmds/xbmcHttp?command=QueryVideoDatabase(select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = 79488 and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath)");
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(query, _settings.Username, _settings.Password))
.Returns(queryResult);
Subject.GetSeriesPath(_settings, _series)
.Should().BeNull();
}
[Test]
public void should_get_series_path_with_special_characters_in_it()
{
const string queryResult = @"<xml><record><field>smb://xbmc:xbmc@HOMESERVER/TV/Law & Order- Special Victims Unit/</field></record></xml>";
var query = string.Format("http://localhost:8080/xbmcCmds/xbmcHttp?command=QueryVideoDatabase(select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = 79488 and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath)");
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(query, _settings.Username, _settings.Password))
.Returns(queryResult);
Subject.GetSeriesPath(_settings, _series)
.Should().Be("smb://xbmc:xbmc@HOMESERVER/TV/Law & Order- Special Victims Unit/");
}
}
}

View File

@@ -1,75 +0,0 @@
using FizzWare.NBuilder;
using NUnit.Framework;
using NzbDrone.Common.Http;
using NzbDrone.Core.Notifications.Xbmc;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Http
{
[TestFixture]
public class UpdateFixture : CoreTest<HttpApiProvider>
{
private XbmcSettings _settings;
private string _seriesQueryUrl = "http://localhost:8080/xbmcCmds/xbmcHttp?command=QueryVideoDatabase(select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = 79488 and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath)";
private Series _fakeSeries;
[SetUp]
public void Setup()
{
_settings = new XbmcSettings
{
Host = "localhost",
Port = 8080,
Username = "xbmc",
Password = "xbmc",
AlwaysUpdate = false,
CleanLibrary = false,
UpdateLibrary = true
};
_fakeSeries = Builder<Series>.CreateNew()
.With(s => s.TvdbId = 79488)
.With(s => s.Title = "30 Rock")
.Build();
}
private void WithSeriesPath()
{
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(_seriesQueryUrl, _settings.Username, _settings.Password))
.Returns("<xml><record><field>smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/</field></record></xml>");
}
private void WithoutSeriesPath()
{
Mocker.GetMock<IHttpProvider>()
.Setup(s => s.DownloadString(_seriesQueryUrl, _settings.Username, _settings.Password))
.Returns("<xml></xml>");
}
[Test]
public void should_update_using_series_path()
{
WithSeriesPath();
const string url = "http://localhost:8080/xbmcCmds/xbmcHttp?command=ExecBuiltIn(UpdateLibrary(video,smb://xbmc:xbmc@HOMESERVER/TV/30 Rock/))";
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadString(url, _settings.Username, _settings.Password));
Subject.Update(_settings, _fakeSeries);
Mocker.VerifyAllMocks();
}
[Test]
public void should_update_all_paths_when_series_path_not_found()
{
WithoutSeriesPath();
const string url = "http://localhost:8080/xbmcCmds/xbmcHttp?command=ExecBuiltIn(UpdateLibrary(video))";
Mocker.GetMock<IHttpProvider>().Setup(s => s.DownloadString(url, _settings.Username, _settings.Password));
Subject.Update(_settings, _fakeSeries);
Mocker.VerifyAllMocks();
}
}
}

View File

@@ -0,0 +1,91 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Notifications.Xbmc;
using NzbDrone.Core.Notifications.Xbmc.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Json
{
[TestFixture]
public class GetMoviePathFixture : CoreTest<JsonApiProvider>
{
private const string IMDB_ID = "tt67890";
private XbmcSettings _settings;
private Movie _movie;
private List<XbmcMovie> _xbmcMovies;
[SetUp]
public void Setup()
{
_settings = Builder<XbmcSettings>.CreateNew()
.Build();
_xbmcMovies = Builder<XbmcMovie>.CreateListOfSize(3)
.All()
.With(s => s.ImdbNumber = "tt00000")
.TheFirst(1)
.With(s => s.ImdbNumber = IMDB_ID)
.Build()
.ToList();
Mocker.GetMock<IXbmcJsonApiProxy>()
.Setup(s => s.GetMovies(_settings))
.Returns(_xbmcMovies);
}
private void GivenMatchingImdbId()
{
_movie = new Movie
{
ImdbId = IMDB_ID,
Title = "Movie"
};
}
private void GivenMatchingTitle()
{
_movie = new Movie
{
ImdbId = "tt01000",
Title = _xbmcMovies.First().Label
};
}
private void GivenMatchingMovie()
{
_movie = new Movie
{
ImdbId = "tt01000",
Title = "Does not exist"
};
}
[Test]
public void should_return_null_when_movie_is_not_found()
{
GivenMatchingMovie();
Subject.GetMoviePath(_settings, _movie).Should().BeNull();
}
[Test]
public void should_return_path_when_tvdbId_matches()
{
GivenMatchingImdbId();
Subject.GetMoviePath(_settings, _movie).Should().Be(_xbmcMovies.First().File);
}
[Test]
public void should_return_path_when_title_matches()
{
GivenMatchingTitle();
Subject.GetMoviePath(_settings, _movie).Should().Be(_xbmcMovies.First().File);
}
}
}

View File

@@ -1,106 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Notifications.Xbmc;
using NzbDrone.Core.Notifications.Xbmc.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Json
{
[TestFixture]
public class GetSeriesPathFixture : CoreTest<JsonApiProvider>
{
private const int TVDB_ID = 5;
private XbmcSettings _settings;
private Series _series;
private List<TvShow> _xbmcSeries;
[SetUp]
public void Setup()
{
_settings = Builder<XbmcSettings>.CreateNew()
.Build();
_xbmcSeries = Builder<TvShow>.CreateListOfSize(3)
.All()
.With(s => s.ImdbNumber = "0")
.TheFirst(1)
.With(s => s.ImdbNumber = TVDB_ID.ToString())
.Build()
.ToList();
Mocker.GetMock<IXbmcJsonApiProxy>()
.Setup(s => s.GetSeries(_settings))
.Returns(_xbmcSeries);
}
private void GivenMatchingTvdbId()
{
_series = new Series
{
TvdbId = TVDB_ID,
Title = "TV Show"
};
}
private void GivenMatchingTitle()
{
_series = new Series
{
TvdbId = 1000,
Title = _xbmcSeries.First().Label
};
}
private void GivenMatchingSeries()
{
_series = new Series
{
TvdbId = 1000,
Title = "Does not exist"
};
}
[Test]
public void should_return_null_when_series_is_not_found()
{
GivenMatchingSeries();
Subject.GetSeriesPath(_settings, _series).Should().BeNull();
}
[Test]
public void should_return_path_when_tvdbId_matches()
{
GivenMatchingTvdbId();
Subject.GetSeriesPath(_settings, _series).Should().Be(_xbmcSeries.First().File);
}
[Test]
public void should_return_path_when_title_matches()
{
GivenMatchingTitle();
Subject.GetSeriesPath(_settings, _series).Should().Be(_xbmcSeries.First().File);
}
[Test]
public void should_not_throw_when_imdb_number_is_not_a_number()
{
GivenMatchingTvdbId();
_xbmcSeries.ForEach(s => s.ImdbNumber = "tt12345");
_xbmcSeries.Last().ImdbNumber = TVDB_ID.ToString();
Mocker.GetMock<IXbmcJsonApiProxy>()
.Setup(s => s.GetSeries(_settings))
.Returns(_xbmcSeries);
Subject.GetSeriesPath(_settings, _series).Should().NotBeNull();
}
}
}

View File

@@ -1,68 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Notifications.Xbmc;
using NzbDrone.Core.Notifications.Xbmc.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Json
{
[TestFixture]
public class UpdateFixture : CoreTest<JsonApiProvider>
{
private const int TVDB_ID = 5;
private XbmcSettings _settings;
private List<TvShow> _xbmcSeries;
[SetUp]
public void Setup()
{
_settings = Builder<XbmcSettings>.CreateNew()
.Build();
_xbmcSeries = Builder<TvShow>.CreateListOfSize(3)
.TheFirst(1)
.With(s => s.ImdbNumber = TVDB_ID.ToString())
.Build()
.ToList();
Mocker.GetMock<IXbmcJsonApiProxy>()
.Setup(s => s.GetSeries(_settings))
.Returns(_xbmcSeries);
Mocker.GetMock<IXbmcJsonApiProxy>()
.Setup(s => s.GetActivePlayers(_settings))
.Returns(new List<ActivePlayer>());
}
[Test]
public void should_update_using_series_path()
{
var series = Builder<Series>.CreateNew()
.With(s => s.TvdbId = TVDB_ID)
.Build();
Subject.Update(_settings, series);
Mocker.GetMock<IXbmcJsonApiProxy>()
.Verify(v => v.UpdateLibrary(_settings, It.IsAny<string>()), Times.Once());
}
[Test]
public void should_update_all_paths_when_series_path_not_found()
{
var fakeSeries = Builder<Series>.CreateNew()
.With(s => s.TvdbId = 1000)
.With(s => s.Title = "Not 30 Rock")
.Build();
Subject.Update(_settings, fakeSeries);
Mocker.GetMock<IXbmcJsonApiProxy>()
.Verify(v => v.UpdateLibrary(_settings, null), Times.Once());
}
}
}

View File

@@ -0,0 +1,68 @@
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Notifications.Xbmc;
using NzbDrone.Core.Notifications.Xbmc.Model;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.NotificationTests.Xbmc.Json
{
[TestFixture]
public class UpdateMovieFixture : CoreTest<JsonApiProvider>
{
private const string IMDB_ID = "tt67890";
private XbmcSettings _settings;
private List<XbmcMovie> _xbmcMovies;
[SetUp]
public void Setup()
{
_settings = Builder<XbmcSettings>.CreateNew()
.Build();
_xbmcMovies = Builder<XbmcMovie>.CreateListOfSize(3)
.TheFirst(1)
.With(s => s.ImdbNumber = IMDB_ID)
.Build()
.ToList();
Mocker.GetMock<IXbmcJsonApiProxy>()
.Setup(s => s.GetMovies(_settings))
.Returns(_xbmcMovies);
Mocker.GetMock<IXbmcJsonApiProxy>()
.Setup(s => s.GetActivePlayers(_settings))
.Returns(new List<ActivePlayer>());
}
[Test]
public void should_update_using_movie_path()
{
var movie = Builder<Movie>.CreateNew()
.With(s => s.ImdbId = IMDB_ID)
.Build();
Subject.UpdateMovie(_settings, movie);
Mocker.GetMock<IXbmcJsonApiProxy>()
.Verify(v => v.UpdateLibrary(_settings, It.IsAny<string>()), Times.Once());
}
[Test]
public void should_update_all_paths_when_movie_path_not_found()
{
var fakeMovie = Builder<Movie>.CreateNew()
.With(s => s.ImdbId = "tt01000")
.With(s => s.Title = "Not A Real Movie")
.Build();
Subject.UpdateMovie(_settings, fakeMovie);
Mocker.GetMock<IXbmcJsonApiProxy>()
.Verify(v => v.UpdateLibrary(_settings, null), Times.Once());
}
}
}

View File

@@ -41,8 +41,8 @@ namespace NzbDrone.Core.Test.NotificationTests.Xbmc
private void GivenOldFiles()
{
_downloadMessage.OldMovieFiles = Builder<MovieFile>.CreateListOfSize(1)
.Build()
.ToList();
.Build()
.ToList();
Subject.Definition.Settings = new XbmcSettings
{
@@ -52,7 +52,7 @@ namespace NzbDrone.Core.Test.NotificationTests.Xbmc
}
[Test]
public void should_not_clean_if_no_episode_was_replaced()
public void should_not_clean_if_no_movie_was_replaced()
{
Subject.OnDownload(_downloadMessage);
@@ -60,7 +60,7 @@ namespace NzbDrone.Core.Test.NotificationTests.Xbmc
}
[Test]
public void should_clean_if_episode_was_replaced()
public void should_clean_if_movie_was_replaced()
{
GivenOldFiles();
Subject.OnDownload(_downloadMessage);

View File

@@ -317,12 +317,6 @@
<Compile Include="Metadata\Consumers\Wdtv\FindMetadataFileFixture.cs" />
<Compile Include="NotificationTests\PlexClientServiceTest.cs" />
<Compile Include="NotificationTests\ProwlProviderTest.cs" />
<Compile Include="NotificationTests\Xbmc\Http\ActivePlayersFixture.cs" />
<Compile Include="NotificationTests\Xbmc\Http\CheckForErrorFixture.cs" />
<Compile Include="NotificationTests\Xbmc\Http\GetSeriesPathFixture.cs" />
<Compile Include="NotificationTests\Xbmc\Http\UpdateFixture.cs" />
<Compile Include="NotificationTests\Xbmc\Json\GetSeriesPathFixture.cs" />
<Compile Include="NotificationTests\Xbmc\Json\UpdateFixture.cs" />
<Compile Include="NotificationTests\Xbmc\OnDownloadFixture.cs" />
<Compile Include="OrganizerTests\BuildFilePathFixture.cs" />
<Compile Include="OrganizerTests\GetSeasonFolderFixture.cs" />
@@ -395,6 +389,8 @@
<None Include="Files\Indexers\PTP\imdbsearch.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Compile Include="NotificationTests\Xbmc\Json\GetMoviePathFixture.cs" />
<Compile Include="NotificationTests\Xbmc\Json\UpdateMovieFixture.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Marr.Data\Marr.Data.csproj">

View File

@@ -14,6 +14,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("Ouija.Origin.of.Evil.2016.MULTi.TRUEFRENCH.1080p.BluRay.x264-MELBA", Language.French)]
[TestCase("Everest.2015.FRENCH.VFQ.BDRiP.x264-CNF30", Language.French)]
[TestCase("Showdown.In.Little.Tokyo.1991.MULTI.VFQ.VFF.DTSHD-MASTER.1080p.BluRay.x264-ZombiE", Language.French)]
[TestCase("The.Polar.Express.2004.MULTI.VF2.1080p.BluRay.x264-PopHD", Language.French)]
[TestCase("Castle.2009.S01E14.Spanish.HDTV.XviD-LOL", Language.Spanish)]
[TestCase("Castle.2009.S01E14.German.HDTV.XviD-LOL", Language.German)]
[TestCase("Castle.2009.S01E14.Germany.HDTV.XviD-LOL", Language.English)]

View File

@@ -144,7 +144,7 @@ namespace NzbDrone.Core.Datastore
.Ignore(s => s.RootFolderPath)
.Ignore(m => m.Actors)
.Ignore(m => m.Genres)
.Ignore(m => m.Tags)
// .Ignore(m => m.Tags)
.Relationship()
.HasOne(s => s.Profile, s => s.ProfileId);
//.HasOne(m => m.MovieFile, m => m.MovieFileId);

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
@@ -38,7 +38,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContents)
{
var category = Settings.TvCategory; // TODO: Update this to MovieCategory?
var category = Settings.MovieCategory;
var priority = Settings.RecentTvPriority;
@@ -204,7 +204,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
public override IEnumerable<DownloadClientItem> GetItems()
{
return GetQueue().Concat(GetHistory()).Where(downloadClientItem => downloadClientItem.Category == Settings.TvCategory);
return GetQueue().Concat(GetHistory()).Where(downloadClientItem => downloadClientItem.Category == Settings.MovieCategory);
}
public override void RemoveItem(string downloadId, bool deleteData)
@@ -221,7 +221,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
var config = _proxy.GetConfig(Settings);
var category = GetCategories(config).FirstOrDefault(v => v.Name == Settings.TvCategory);
var category = GetCategories(config).FirstOrDefault(v => v.Name == Settings.MovieCategory);
var status = new DownloadClientStatus
{
@@ -283,7 +283,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
if (Version.Parse(version) < Version.Parse("12.0"))
{
return new ValidationFailure(string.Empty, "Nzbget version too low, need 12.0 or higher");
return new ValidationFailure(string.Empty, "NZBGet version too low, need 12.0 or higher");
}
}
catch (Exception ex)
@@ -304,12 +304,12 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var config = _proxy.GetConfig(Settings);
var categories = GetCategories(config);
if (!Settings.TvCategory.IsNullOrWhiteSpace() && !categories.Any(v => v.Name == Settings.TvCategory))
if (!Settings.MovieCategory.IsNullOrWhiteSpace() && !categories.Any(v => v.Name == Settings.MovieCategory))
{
return new NzbDroneValidationFailure("TvCategory", "Category does not exist")
return new NzbDroneValidationFailure("MovieCategory", "Category does not exist")
{
InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port),
DetailedDescription = "The Category your entered doesn't exist in NzbGet. Go to NzbGet to create it."
DetailedDescription = "The category you entered doesn't exist in NZBGet. Go to NZBGet to create it."
};
}
@@ -323,10 +323,10 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var keepHistory = config.GetValueOrDefault("KeepHistory");
if (keepHistory == "0")
{
return new NzbDroneValidationFailure(string.Empty, "NzbGet setting KeepHistory should be greater than 0")
return new NzbDroneValidationFailure(string.Empty, "NZBGet setting KeepHistory should be greater than 0")
{
InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port),
DetailedDescription = "NzbGet setting KeepHistory is set to 0. Which prevents Radarr from seeing completed downloads."
DetailedDescription = "NZBGet setting KeepHistory is set to 0. Which prevents Radarr from seeing completed downloads."
};
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
@@ -88,7 +88,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var editResult = EditQueue("GroupSetParameter", 0, "drone=" + droneId, item.NzbId, settings);
if (editResult)
{
_logger.Debug("Nzbget download drone parameter set to: {0}", droneId);
_logger.Debug("NZBGet download drone parameter set to: {0}", droneId);
}
return droneId;
@@ -114,7 +114,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
if (editResult)
{
_logger.Debug("Nzbget download drone parameter set to: {0}", droneId);
_logger.Debug("NZBGet download drone parameter set to: {0}", droneId);
}
return droneId;
@@ -175,7 +175,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
if (!EditQueue("GroupFinalDelete", 0, "", queueItem.NzbId, settings))
{
_logger.Warn("Failed to remove item from nzbget queue, {0} [{1}]", queueItem.NzbName, queueItem.NzbId);
_logger.Warn("Failed to remove item from NZBGet, {0} [{1}]", queueItem.NzbName, queueItem.NzbId);
}
}
@@ -183,13 +183,13 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
if (!EditQueue("HistoryDelete", 0, "", historyItem.Id, settings))
{
_logger.Warn("Failed to remove item from nzbget history, {0} [{1}]", historyItem.Name, historyItem.Id);
_logger.Warn("Failed to remove item from NZBGet history, {0} [{1}]", historyItem.Name, historyItem.Id);
}
}
else
{
_logger.Warn("Unable to remove item from nzbget, Unknown ID: {0}", id);
_logger.Warn("Unable to remove item from NZBGet, Unknown ID: {0}", id);
return;
}
}
@@ -235,21 +235,21 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{
throw new DownloadClientException("Authentication failed for NzbGet, please check your settings", ex);
throw new DownloadClientException("Authentication failed for NZBGet, please check your settings", ex);
}
throw new DownloadClientException("Unable to connect to NzbGet. " + ex.Message, ex);
throw new DownloadClientException("Unable to connect to NZBGet. " + ex.Message, ex);
}
catch (WebException ex)
{
throw new DownloadClientException("Unable to connect to NzbGet. " + ex.Message, ex);
throw new DownloadClientException("Unable to connect to NZBGet. " + ex.Message, ex);
}
var result = Json.Deserialize<JsonRpcResponse<T>>(response.Content);
if (result.Error != null)
{
throw new DownloadClientException("Error response received from nzbget: {0}", result.Error.ToString());
throw new DownloadClientException("Error response received from NZBGet: {0}", result.Error.ToString());
}
return result.Result;

View File

@@ -1,4 +1,4 @@
namespace NzbDrone.Core.Download.Clients.Nzbget
namespace NzbDrone.Core.Download.Clients.Nzbget
{
public class NzbgetResponse<T>
{

View File

@@ -1,4 +1,4 @@
using FluentValidation;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@@ -14,7 +14,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
RuleFor(c => c.Username).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Password));
RuleFor(c => c.Password).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Username));
RuleFor(c => c.TvCategory).NotEmpty().WithMessage("A category is recommended").AsWarning();
RuleFor(c => c.MovieCategory).NotEmpty().WithMessage("A category is recommended").AsWarning();
}
}
@@ -26,7 +26,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{
Host = "localhost";
Port = 6789;
TvCategory = "Movies";
MovieCategory = "Movies";
Username = "nzbget";
Password = "tegbzn6789";
RecentTvPriority = (int)NzbgetPriority.Normal;
@@ -46,7 +46,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
public string Password { get; set; }
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; }
public string MovieCategory { get; set; }
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing releases that aired within the last 14 days")]
public int RecentTvPriority { get; set; }
@@ -57,7 +57,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
[FieldDefinition(7, Label = "Use SSL", Type = FieldType.Checkbox)]
public bool UseSsl { get; set; }
[FieldDefinition(8, Label = "Add Paused", Type = FieldType.Checkbox, HelpText = "This option requires at least NzbGet version 16.0")]
[FieldDefinition(8, Label = "Add Paused", Type = FieldType.Checkbox, HelpText = "This option requires at least NZBGet version 16.0")]
public bool AddPaused { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -50,6 +50,8 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
_proxy.SetTorrentLabel(hash.ToLower(), Settings.MovieCategory, Settings);
}
SetInitialState(hash.ToLower());
return hash;
}
@@ -62,6 +64,8 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
_proxy.SetTorrentLabel(hash.ToLower(), Settings.MovieCategory, Settings);
}
SetInitialState(hash);
return hash;
}
@@ -261,5 +265,28 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
return null;
}
private void SetInitialState(string hash)
{
try
{
switch ((QBittorrentState)Settings.InitialState)
{
case QBittorrentState.ForceStart:
_proxy.SetForceStart(hash, true, Settings);
break;
case QBittorrentState.Start:
_proxy.ResumeTorrent(hash, Settings);
break;
case QBittorrentState.Pause:
_proxy.PauseTorrent(hash, Settings);
break;
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Failed to set inital state for {0}.", hash);
}
}
}
}

View File

@@ -23,6 +23,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
void RemoveTorrent(string hash, Boolean removeData, QBittorrentSettings settings);
void SetTorrentLabel(string hash, string label, QBittorrentSettings settings);
void MoveTorrentToTopInQueue(string hash, QBittorrentSettings settings);
void PauseTorrent(string hash, QBittorrentSettings settings);
void ResumeTorrent(string hash, QBittorrentSettings settings);
void SetForceStart(string hash, bool enabled, QBittorrentSettings settings);
}
public class QBittorrentProxy : IQBittorrentProxy
@@ -154,6 +157,34 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
}
public void PauseTorrent(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/command/pause")
.Post()
.AddFormParameter("hash", hash);
ProcessRequest(request, settings);
}
public void ResumeTorrent(string hash, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/command/resume")
.Post()
.AddFormParameter("hash", hash);
ProcessRequest(request, settings);
}
public void SetForceStart(string hash, bool enabled, QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/command/setForceStart")
.Post()
.AddFormParameter("hashes", hash)
.AddFormParameter("value", enabled ? "true": "false");
ProcessRequest(request, settings);
}
private HttpRequestBuilder BuildRequest(QBittorrentSettings settings)
{
var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port);

View File

@@ -1,4 +1,4 @@
using FluentValidation;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@@ -21,7 +21,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
public QBittorrentSettings()
{
Host = "localhost";
Port = 9091;
Port = 8080;
MovieCategory = "radarr";
}
@@ -40,7 +40,10 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string MovieCategory { get; set; }
[FieldDefinition(5, Label = "Use SSL", Type = FieldType.Checkbox, HelpText = "Use a secure connection. See Options -> Web UI -> 'Use HTTPS instead of HTTP' in qBittorrent.")]
[FieldDefinition(5, Label = "Initial State", Type = FieldType.Select, SelectOptions = typeof(QBittorrentState), HelpText = "Initial state for torrents added to qBittorrent")]
public int InitialState { get; set; }
[FieldDefinition(6, Label = "Use SSL", Type = FieldType.Checkbox, HelpText = "Use a secure connection. See Options -> Web UI -> 'Use HTTPS instead of HTTP' in qBittorrent.")]
public bool UseSsl { get; set; }
public NzbDroneValidationResult Validate()

View File

@@ -0,0 +1,9 @@
namespace NzbDrone.Core.Download.Clients.QBittorrent
{
public enum QBittorrentState
{
Start = 0,
ForceStart = 1,
Pause = 2
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
@@ -39,7 +39,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContents)
{
var category = Settings.TvCategory;
var category = Settings.MovieCategory;
var priority = Settings.RecentTvPriority;
var response = _proxy.DownloadNzb(fileContents, filename, category, priority, Settings);
@@ -119,7 +119,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
try
{
sabHistory = _proxy.GetHistory(0, _configService.DownloadClientHistoryLimit, Settings.TvCategory, Settings);
sabHistory = _proxy.GetHistory(0, _configService.DownloadClientHistoryLimit, Settings.MovieCategory, Settings);
}
catch (DownloadClientException ex)
{
@@ -200,7 +200,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
foreach (var downloadClientItem in GetQueue().Concat(GetHistory()))
{
if (downloadClientItem.Category == Settings.TvCategory || downloadClientItem.Category == "*" && Settings.TvCategory.IsNullOrWhiteSpace())
if (downloadClientItem.Category == Settings.MovieCategory || downloadClientItem.Category == "*" && Settings.MovieCategory.IsNullOrWhiteSpace())
{
yield return downloadClientItem;
}
@@ -254,7 +254,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
var config = _proxy.GetConfig(Settings);
var categories = GetCategories(config).ToArray();
var category = categories.FirstOrDefault(v => v.Name == Settings.TvCategory);
var category = categories.FirstOrDefault(v => v.Name == Settings.MovieCategory);
if (category == null)
{
@@ -366,7 +366,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
if (rawVersion.Equals("develop", StringComparison.InvariantCultureIgnoreCase))
{
return new NzbDroneValidationFailure("Version", "Sabnzbd develop version, assuming version 1.1.0 or higher.")
return new NzbDroneValidationFailure("Version", "SABnzbd develop version, assuming version 1.1.0 or higher.")
{
IsWarning = true,
DetailedDescription = "Radarr may not be able to support new features added to SABnzbd when running develop versions."
@@ -419,10 +419,10 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
var config = _proxy.GetConfig(Settings);
if (config.Misc.pre_check && !HasVersion(1, 1))
{
return new NzbDroneValidationFailure("", "Disable 'Check before download' option in Sabnbzd")
return new NzbDroneValidationFailure("", "Disable 'Check before download' option in SABnzbd")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/switches/", Settings.Host, Settings.Port),
DetailedDescription = "Using Check before download affects Radarr ability to track new downloads. Also Sabnzbd recommends 'Abort jobs that cannot be completed' instead since it's more effective."
DetailedDescription = "Using Check before download affects Radarr ability to track new downloads. Also SABnzbd recommends 'Abort jobs that cannot be completed' instead since it's more effective."
};
}
@@ -432,52 +432,52 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
private ValidationFailure TestCategory()
{
var config = _proxy.GetConfig(Settings);
var category = GetCategories(config).FirstOrDefault((SabnzbdCategory v) => v.Name == Settings.TvCategory);
var category = GetCategories(config).FirstOrDefault((SabnzbdCategory v) => v.Name == Settings.MovieCategory);
if (category != null)
{
if (category.Dir.EndsWith("*"))
{
return new NzbDroneValidationFailure("TvCategory", "Enable Job folders")
return new NzbDroneValidationFailure("MovieCategory", "Enable Job folders")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port),
DetailedDescription = "Radarr prefers each download to have a separate folder. With * appended to the Folder/Path Sabnzbd will not create these job folders. Go to Sabnzbd to fix it."
DetailedDescription = "Radarr prefers each download to have a separate folder. With * appended to the Folder/Path SABnzbd will not create these job folders. Go to SABnzbd to fix it."
};
}
}
else
{
if (!Settings.TvCategory.IsNullOrWhiteSpace())
if (!Settings.MovieCategory.IsNullOrWhiteSpace())
{
return new NzbDroneValidationFailure("TvCategory", "Category does not exist")
return new NzbDroneValidationFailure("MovieCategory", "Category does not exist")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port),
DetailedDescription = "The Category your entered doesn't exist in Sabnzbd. Go to Sabnzbd to create it."
DetailedDescription = "The category you entered doesn't exist in SABnzbd. Go to SABnzbd to create it."
};
}
}
if (config.Misc.enable_tv_sorting && ContainsCategory(config.Misc.tv_categories, Settings.TvCategory))
if (config.Misc.enable_tv_sorting && ContainsCategory(config.Misc.tv_categories, Settings.MovieCategory))
{
return new NzbDroneValidationFailure("TvCategory", "Disable TV Sorting")
return new NzbDroneValidationFailure("MovieCategory", "Disable TV Sorting")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
DetailedDescription = "You must disable Sabnzbd TV Sorting for the category Radarr uses to prevent import issues. Go to Sabnzbd to fix it."
DetailedDescription = "You must disable SABnzbd TV Sorting for the category Radarr uses to prevent import issues. Go to SABnzbd to fix it."
};
}
if (config.Misc.enable_movie_sorting && ContainsCategory(config.Misc.movie_categories, Settings.TvCategory))
if (config.Misc.enable_movie_sorting && ContainsCategory(config.Misc.movie_categories, Settings.MovieCategory))
{
return new NzbDroneValidationFailure("TvCategory", "Disable Movie Sorting")
return new NzbDroneValidationFailure("MovieCategory", "Disable Movie Sorting")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
DetailedDescription = "You must disable Sabnzbd Movie Sorting for the category Radarr uses to prevent import issues. Go to Sabnzbd to fix it."
DetailedDescription = "You must disable SABnzbd Movie Sorting for the category Radarr uses to prevent import issues. Go to SABnzbd to fix it."
};
}
if (config.Misc.enable_date_sorting && ContainsCategory(config.Misc.date_categories, Settings.TvCategory))
if (config.Misc.enable_date_sorting && ContainsCategory(config.Misc.date_categories, Settings.MovieCategory))
{
return new NzbDroneValidationFailure("TvCategory", "Disable Date Sorting")
return new NzbDroneValidationFailure("MovieCategory", "Disable Date Sorting")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
DetailedDescription = "You must disable Sabnzbd Date Sorting for the category Radarr uses to prevent import issues. Go to Sabnzbd to fix it."
DetailedDescription = "You must disable SABnzbd Date Sorting for the category Radarr uses to prevent import issues. Go to SABnzbd to fix it."
};
}

View File

@@ -1,4 +1,4 @@
using FluentValidation;
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
@@ -24,7 +24,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
.WithMessage("Password is required when API key is not configured")
.When(c => string.IsNullOrWhiteSpace(c.ApiKey));
RuleFor(c => c.TvCategory).NotEmpty()
RuleFor(c => c.MovieCategory).NotEmpty()
.WithMessage("A category is recommended")
.AsWarning();
}
@@ -38,7 +38,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{
Host = "localhost";
Port = 8080;
TvCategory = "movies";
MovieCategory = "movies";
RecentTvPriority = (int)SabnzbdPriority.Default;
OlderTvPriority = (int)SabnzbdPriority.Default;
}
@@ -59,7 +59,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
public string Password { get; set; }
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; }
public string MovieCategory { get; set; }
[FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing releases that aired within the last 14 days")]
public int RecentTvPriority { get; set; }

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq;
using System.Collections.Generic;
using NzbDrone.Common.Disk;
@@ -49,7 +49,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
{
_proxy.AddTorrentFromUrl(magnetLink, Settings);
_proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings);
_proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
@@ -59,13 +59,15 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
_proxy.MoveTorrentToTopInQueue(hash, Settings);
}*/
_proxy.SetState(hash, (UTorrentState)Settings.IntialState, Settings);
return hash;
}
protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, byte[] fileContent)
{
_proxy.AddTorrentFromFile(filename, fileContent, Settings);
_proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings);
_proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
@@ -75,6 +77,8 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
_proxy.MoveTorrentToTopInQueue(hash, Settings);
}*/
_proxy.SetState(hash, (UTorrentState)Settings.IntialState, Settings);
return hash;
}
@@ -86,7 +90,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
try
{
var cacheKey = string.Format("{0}:{1}:{2}", Settings.Host, Settings.Port, Settings.TvCategory);
var cacheKey = string.Format("{0}:{1}:{2}", Settings.Host, Settings.Port, Settings.MovieCategory);
var cache = _torrentCache.Find(cacheKey);
var response = _proxy.GetTorrents(cache == null ? null : cache.CacheID, Settings);
@@ -123,7 +127,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
foreach (var torrent in torrents)
{
if (torrent.Label != Settings.TvCategory)
if (torrent.Label != Settings.MovieCategory)
{
continue;
}
@@ -205,7 +209,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
if (config.GetValueOrDefault("dir_add_label") == "true")
{
destDir = destDir + Settings.TvCategory;
destDir = destDir + Settings.MovieCategory;
}
}

View File

@@ -22,6 +22,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
void RemoveTorrent(string hash, bool removeData, UTorrentSettings settings);
void SetTorrentLabel(string hash, string label, UTorrentSettings settings);
void MoveTorrentToTopInQueue(string hash, UTorrentSettings settings);
void SetState(string hash, UTorrentState state, UTorrentSettings settings);
}
public class UTorrentProxy : IUTorrentProxy
@@ -157,6 +158,15 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
ProcessRequest(requestBuilder, settings);
}
public void SetState(string hash, UTorrentState state, UTorrentSettings settings)
{
var requestBuilder = BuildRequest(settings)
.AddQueryParam("action", state.ToString().ToLowerInvariant())
.AddQueryParam("hash", hash);
ProcessRequest(requestBuilder, settings);
}
private HttpRequestBuilder BuildRequest(UTorrentSettings settings)
{
var requestBuilder = new HttpRequestBuilder(false, settings.Host, settings.Port)

View File

@@ -11,7 +11,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
{
RuleFor(c => c.Host).ValidHost();
RuleFor(c => c.Port).InclusiveBetween(1, 65535);
RuleFor(c => c.TvCategory).NotEmpty();
RuleFor(c => c.MovieCategory).NotEmpty();
}
}
@@ -22,8 +22,8 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
public UTorrentSettings()
{
Host = "localhost";
Port = 9091;
TvCategory = "radarr";
Port = 8080;
MovieCategory = "radarr";
}
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]
@@ -39,7 +39,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
public string Password { get; set; }
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; }
public string MovieCategory { get; set; }
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing releases that aired within the last 14 days")]
public int RecentTvPriority { get; set; }
@@ -47,6 +47,9 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing releases that aired over 14 days ago")]
public int OlderTvPriority { get; set; }
[FieldDefinition(7, Label = "Initial State", Type = FieldType.Select, SelectOptions = typeof(UTorrentState), HelpText = "Initial state for torrents added to uTorrent")]
public int IntialState { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -0,0 +1,10 @@
namespace NzbDrone.Core.Download.Clients.UTorrent
{
public enum UTorrentState
{
Start = 0,
ForceStart = 1,
Pause = 2,
Stop = 3
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -131,7 +131,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
if (newDownload)
{
_eventAggregator.PublishEvent(new MovieDownloadedEvent(localMovie, movieFile, oldFiles));
_eventAggregator.PublishEvent(new MovieDownloadedEvent(localMovie, movieFile, oldFiles, downloadClientItem));
}
}
catch (Exception e)

View File

@@ -136,10 +136,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
_logger.Debug("Size: {0}", localMovie.Size);
var current = localMovie.Quality;
localMovie.MediaInfo = _videoFileInfoReader.GetMediaInfo(file);
//TODO: make it so media info doesn't ruin the import process of a new series
if (sceneSource && ShouldCheckQualityForParsedQuality(current.Quality))
{
localMovie.MediaInfo = _videoFileInfoReader.GetMediaInfo(file);
if (shouldCheckQuality)
{
_logger.Debug("Checking quality for this video file to make sure nothing mismatched.");

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Common.Messaging;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Download;
namespace NzbDrone.Core.MediaFiles.Events
{
@@ -9,12 +10,17 @@ namespace NzbDrone.Core.MediaFiles.Events
public LocalMovie Movie { get; private set; }
public MovieFile MovieFile { get; private set; }
public List<MovieFile> OldFiles { get; private set; }
public string DownloadId { get; private set; }
public MovieDownloadedEvent(LocalMovie episode, MovieFile episodeFile, List<MovieFile> oldFiles)
public MovieDownloadedEvent(LocalMovie episode, MovieFile episodeFile, List<MovieFile> oldFiles, DownloadClientItem downloadClientItem)
{
Movie = episode;
MovieFile = episodeFile;
OldFiles = oldFiles;
if (downloadClientItem != null)
{
DownloadId = downloadClientItem.DownloadId;
}
}
}
}
}

View File

@@ -34,10 +34,6 @@ namespace NzbDrone.Core.Notifications.Boxcar
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Boxcar";
public override bool SupportsOnRename => false;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
@@ -31,6 +31,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
{
var movie = message.Movie;
var remoteMovie = message.RemoteMovie;
var quality = message.Quality;
var environmentVariables = new StringDictionary();
environmentVariables.Add("Radarr_EventType", "Grab");
@@ -42,6 +43,8 @@ namespace NzbDrone.Core.Notifications.CustomScript
environmentVariables.Add("Radarr_Release_Indexer", remoteMovie.Release.Indexer);
environmentVariables.Add("Radarr_Release_Size", remoteMovie.Release.Size.ToString());
environmentVariables.Add("Radarr_Release_ReleaseGroup", remoteMovie.ParsedMovieInfo.ReleaseGroup ?? string.Empty);
environmentVariables.Add("Radarr_Release_Quality", quality.Quality.Name);
environmentVariables.Add("Radarr_Release_QualityVersion", quality.Revision.Version.ToString());
ExecuteScript(environmentVariables);
}
@@ -54,6 +57,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
var environmentVariables = new StringDictionary();
environmentVariables.Add("Radarr_EventType", "Download");
environmentVariables.Add("Radarr_IsUpgrade", message.OldMovieFiles.Any().ToString());
environmentVariables.Add("Radarr_Movie_Id", movie.Id.ToString());
environmentVariables.Add("Radarr_Movie_Title", movie.Title);
environmentVariables.Add("Radarr_Movie_Path", movie.Path);
@@ -68,7 +72,13 @@ namespace NzbDrone.Core.Notifications.CustomScript
environmentVariables.Add("Radarr_MovieFile_SceneName", movieFile.SceneName ?? string.Empty);
environmentVariables.Add("Radarr_MovieFile_SourcePath", sourcePath);
environmentVariables.Add("Radarr_MovieFile_SourceFolder", Path.GetDirectoryName(sourcePath));
environmentVariables.Add("Radarr_Download_Id", message.DownloadId ?? string.Empty);
if (message.OldMovieFiles.Any())
{
environmentVariables.Add("Radarr_DeletedRelativePaths", string.Join("|", message.OldMovieFiles.Select(e => e.RelativePath)));
environmentVariables.Add("Radarr_DeletedPaths", string.Join("|", message.OldMovieFiles.Select(e => Path.Combine(movie.Path, e.RelativePath))));
}
ExecuteScript(environmentVariables);
}
@@ -86,10 +96,6 @@ namespace NzbDrone.Core.Notifications.CustomScript
ExecuteScript(environmentVariables);
}
public override void OnRename(Series series)
{
}
public override string Name => "Custom Script";
public override ValidationResult Test()

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Tv;
@@ -7,13 +7,11 @@ namespace NzbDrone.Core.Notifications
public class DownloadMessage
{
public string Message { get; set; }
public Series Series { get; set; }
public Movie Movie { get; set; }
public EpisodeFile EpisodeFile { get; set; }
public List<EpisodeFile> OldFiles { get; set; }
public MovieFile MovieFile { get; set; }
public List<MovieFile> OldMovieFiles { get; set; }
public string SourcePath { get; set; }
public string DownloadId { get; set; }
public override string ToString()
{

View File

@@ -36,10 +36,6 @@ namespace NzbDrone.Core.Notifications.Email
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Email";
public override bool SupportsOnRename => false;

View File

@@ -7,10 +7,8 @@ namespace NzbDrone.Core.Notifications
public class GrabMessage
{
public string Message { get; set; }
public Series Series { get; set; }
public Movie Movie { get; set; }
public RemoteMovie RemoteMovie { get; set; }
public RemoteEpisode Episode { get; set; }
public QualityModel Quality { get; set; }
public override string ToString()

View File

@@ -34,10 +34,6 @@ namespace NzbDrone.Core.Notifications.Growl
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Growl";
public override bool SupportsOnRename => false;

View File

@@ -133,8 +133,8 @@ namespace NzbDrone.Core.Notifications.Growl
{
var notificationTypes = new List<NotificationType>();
notificationTypes.Add(new NotificationType("TEST", "Test"));
notificationTypes.Add(new NotificationType("GRAB", "Episode Grabbed"));
notificationTypes.Add(new NotificationType("DOWNLOAD", "Episode Complete"));
notificationTypes.Add(new NotificationType("GRAB", "Movie Grabbed"));
notificationTypes.Add(new NotificationType("DOWNLOAD", "Movie Complete"));
return notificationTypes.ToArray();
}

View File

@@ -9,7 +9,6 @@ namespace NzbDrone.Core.Notifications
void OnGrab(GrabMessage grabMessage);
void OnDownload(DownloadMessage message);
void OnRename(Series series);
void OnMovieRename(Movie movie);
bool SupportsOnGrab { get; }
bool SupportsOnDownload { get; }

View File

@@ -34,10 +34,6 @@ namespace NzbDrone.Core.Notifications.Join
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Join";
public override bool SupportsOnRename => false;

View File

@@ -49,14 +49,6 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
}
}
public override void OnRename(Series series)
{
if (Settings.UpdateLibrary)
{
_mediaBrowserService.Update(Settings, series);
}
}
public override string Name => "Emby (Media Browser)";
public override ValidationResult Test()

View File

@@ -31,16 +31,6 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
ProcessRequest(request, settings);
}
public void Update(MediaBrowserSettings settings, int tvdbId)
{
var path = string.Format("/Library/Series/Updated?tvdbid={0}", tvdbId);
var request = BuildRequest(path, settings);
request.Headers.Add("Content-Length", "0");
ProcessRequest(request, settings);
}
public void UpdateMovies(MediaBrowserSettings settings, string imdbid)
{
var path = string.Format("/Library/Movies/Updated?ImdbId={0}", imdbid);

View File

@@ -10,7 +10,6 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
public interface IMediaBrowserService
{
void Notify(MediaBrowserSettings settings, string title, string message);
void Update(MediaBrowserSettings settings, Series series);
void UpdateMovies(MediaBrowserSettings settings, Movie movie);
ValidationFailure Test(MediaBrowserSettings settings);
}
@@ -31,12 +30,6 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
_proxy.Notify(settings, title, message);
}
public void Update(MediaBrowserSettings settings, Series series)
{
_proxy.Update(settings, series.TvdbId);
}
public void UpdateMovies(MediaBrowserSettings settings, Movie movie)
{
_proxy.UpdateMovies(settings, movie.ImdbId);

View File

@@ -26,7 +26,6 @@ namespace NzbDrone.Core.Notifications
public abstract void OnGrab(GrabMessage grabMessage);
public abstract void OnDownload(DownloadMessage message);
public abstract void OnRename(Series series);
public abstract void OnMovieRename(Movie movie);
public virtual bool SupportsOnGrab => true;

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
@@ -30,47 +30,6 @@ namespace NzbDrone.Core.Notifications
_logger = logger;
}
private string GetMessage(Series series, List<Episode> episodes, QualityModel quality)
{
var qualityString = quality.Quality.ToString();
if (quality.Revision.Version > 1)
{
if (series.SeriesType == SeriesTypes.Anime)
{
qualityString += " v" + quality.Revision.Version;
}
else
{
qualityString += " Proper";
}
}
if (series.SeriesType == SeriesTypes.Daily)
{
var episode = episodes.First();
return string.Format("{0} - {1} - {2} [{3}]",
series.Title,
episode.AirDate,
episode.Title,
qualityString);
}
var episodeNumbers = string.Concat(episodes.Select(e => e.EpisodeNumber)
.Select(i => string.Format("x{0:00}", i)));
var episodeTitles = string.Join(" + ", episodes.Select(e => e.Title));
return string.Format("{0} - {1}{2} - {3} [{4}]",
series.Title,
episodes.First().SeasonNumber,
episodeNumbers,
episodeTitles,
qualityString);
}
private string GetMessage(Movie movie, QualityModel quality)
{
var qualityString = quality.Quality.ToString();
@@ -100,7 +59,7 @@ namespace NzbDrone.Core.Notifications
if (notificationDefinition.Tags.Intersect(movie.Tags).Any())
{
_logger.Debug("Notification and series have one or more matching tags.");
_logger.Debug("Notification and movie have one or more matching tags.");
return true;
}
@@ -109,49 +68,9 @@ namespace NzbDrone.Core.Notifications
return false;
}
private bool ShouldHandleSeries(ProviderDefinition definition, Series series)
{
var notificationDefinition = (NotificationDefinition) definition;
if (notificationDefinition.Tags.Empty())
{
_logger.Debug("No tags set for this notification.");
return true;
}
if (notificationDefinition.Tags.Intersect(series.Tags).Any())
{
_logger.Debug("Notification and series have one or more matching tags.");
return true;
}
//TODO: this message could be more clear
_logger.Debug("{0} does not have any tags that match {1}'s tags", notificationDefinition.Name, series.Title);
return false;
}
public void Handle(EpisodeGrabbedEvent message)
{
var grabMessage = new GrabMessage {
Message = GetMessage(message.Episode.Series, message.Episode.Episodes, message.Episode.ParsedEpisodeInfo.Quality),
Series = message.Episode.Series,
Quality = message.Episode.ParsedEpisodeInfo.Quality,
Episode = message.Episode
};
foreach (var notification in _notificationFactory.OnGrabEnabled())
{
try
{
if (!ShouldHandleSeries(notification.Definition, message.Episode.Series)) continue;
notification.OnGrab(grabMessage);
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send OnGrab notification to: " + notification.Definition.Name);
}
}
throw new NotImplementedException("Remove Series/Season/Episode");
}
public void Handle(MovieGrabbedEvent message)
@@ -159,9 +78,7 @@ namespace NzbDrone.Core.Notifications
var grabMessage = new GrabMessage
{
Message = GetMessage(message.Movie.Movie, message.Movie.ParsedMovieInfo.Quality),
Series = null,
Quality = message.Movie.ParsedMovieInfo.Quality,
Episode = null,
Movie = message.Movie.Movie,
RemoteMovie = message.Movie
};
@@ -183,44 +100,18 @@ namespace NzbDrone.Core.Notifications
public void Handle(EpisodeDownloadedEvent message)
{
var downloadMessage = new DownloadMessage();
downloadMessage.Message = GetMessage(message.Episode.Series, message.Episode.Episodes, message.Episode.Quality);
downloadMessage.Series = message.Episode.Series;
downloadMessage.EpisodeFile = message.EpisodeFile;
downloadMessage.OldFiles = message.OldFiles;
downloadMessage.SourcePath = message.Episode.Path;
foreach (var notification in _notificationFactory.OnDownloadEnabled())
{
try
{
if (ShouldHandleSeries(notification.Definition, message.Episode.Series))
{
if (downloadMessage.OldFiles.Empty() || ((NotificationDefinition)notification.Definition).OnUpgrade)
{
notification.OnDownload(downloadMessage);
}
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to send OnDownload notification to: " + notification.Definition.Name);
}
}
throw new NotImplementedException("Remove Series/Season/Episode");
}
public void Handle(MovieDownloadedEvent message)
{
var downloadMessage = new DownloadMessage();
downloadMessage.Message = GetMessage(message.Movie.Movie, message.Movie.Quality);
downloadMessage.Series = null;
downloadMessage.EpisodeFile = null;
downloadMessage.MovieFile = message.MovieFile;
downloadMessage.Movie = message.Movie.Movie;
downloadMessage.OldFiles = null;
downloadMessage.OldMovieFiles = message.OldFiles;
downloadMessage.SourcePath = message.Movie.Path;
downloadMessage.DownloadId = message.DownloadId;
foreach (var notification in _notificationFactory.OnDownloadEnabled())
{
@@ -244,21 +135,7 @@ namespace NzbDrone.Core.Notifications
public void Handle(SeriesRenamedEvent message)
{
foreach (var notification in _notificationFactory.OnRenameEnabled())
{
try
{
if (ShouldHandleSeries(notification.Definition, message.Series))
{
notification.OnRename(message.Series);
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to send OnRename notification to: " + notification.Definition.Name);
}
}
throw new NotImplementedException("Remove Series/Season/Episode");
}
public void Handle(MovieRenamedEvent message)

View File

@@ -35,10 +35,6 @@ namespace NzbDrone.Core.Notifications.NotifyMyAndroid
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Notify My Android";
public override bool SupportsOnRename => false;

View File

@@ -32,10 +32,6 @@ namespace NzbDrone.Core.Notifications.Plex
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Plex Media Center";
public override bool SupportsOnRename => false;

View File

@@ -39,11 +39,6 @@ namespace NzbDrone.Core.Notifications.Plex
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Plex Home Theater";
public override bool SupportsOnRename => false;

View File

@@ -30,11 +30,6 @@ namespace NzbDrone.Core.Notifications.Plex
UpdateIfEnabled(movie);
}
public override void OnRename(Series series)
{
//UpdateIfEnabled(movie);
}
private void UpdateIfEnabled(Movie movie)
{
if (Settings.UpdateLibrary)

View File

@@ -19,10 +19,10 @@ namespace NzbDrone.Core.Notifications.Plex
List<PlexSection> GetTvSections(PlexServerSettings settings);
List<PlexSection> GetMovieSections(PlexServerSettings settings);
void Update(int sectionId, PlexServerSettings settings);
void UpdateSeries(int metadataId, PlexServerSettings settings);
void UpdateItem(int metadataId, PlexServerSettings settings);
string Version(PlexServerSettings settings);
List<PlexPreference> Preferences(PlexServerSettings settings);
int? GetMetadataId(int sectionId, int tvdbId, string language, PlexServerSettings settings);
int? GetMetadataId(int sectionId, string imdbId, string language, PlexServerSettings settings);
}
public class PlexServerProxy : IPlexServerProxy
@@ -109,14 +109,14 @@ namespace NzbDrone.Core.Notifications.Plex
CheckForError(response, settings);
}
public void UpdateSeries(int metadataId, PlexServerSettings settings)
public void UpdateItem(int metadataId, PlexServerSettings settings)
{
var resource = string.Format("library/metadata/{0}/refresh", metadataId);
var request = GetPlexServerRequest(resource, Method.PUT, settings);
var client = GetPlexServerClient(settings);
var response = client.Execute(request);
_logger.Trace("Update Series response: {0}", response.Content);
_logger.Trace("Update Item response: {0}", response.Content);
CheckForError(response, settings);
}
@@ -160,9 +160,9 @@ namespace NzbDrone.Core.Notifications.Plex
.Preferences;
}
public int? GetMetadataId(int sectionId, int tvdbId, string language, PlexServerSettings settings)
public int? GetMetadataId(int sectionId, string imdbId, string language, PlexServerSettings settings)
{
var guid = string.Format("com.plexapp.agents.thetvdb://{0}?lang={1}", tvdbId, language);
var guid = string.Format("com.plexapp.agents.imdb://{0}?lang={1}", imdbId, language);
var resource = string.Format("library/sections/{0}/all?guid={1}", sectionId, System.Web.HttpUtility.UrlEncode(guid));
var request = GetPlexServerRequest(resource, Method.GET, settings);
var client = GetPlexServerClient(settings);

View File

@@ -13,7 +13,6 @@ namespace NzbDrone.Core.Notifications.Plex
{
public interface IPlexServerService
{
void UpdateLibrary(Series series, PlexServerSettings settings);
void UpdateMovieSections(Movie movie, PlexServerSettings settings);
ValidationFailure Test(PlexServerSettings settings);
}
@@ -33,7 +32,7 @@ namespace NzbDrone.Core.Notifications.Plex
_logger = logger;
}
public void UpdateLibrary(Series series, PlexServerSettings settings)
public void UpdateMovieSections(Movie movie, PlexServerSettings settings)
{
try
{
@@ -47,7 +46,7 @@ namespace NzbDrone.Core.Notifications.Plex
if (partialUpdates)
{
UpdatePartialSection(series, sections, settings);
UpdatePartialSection(movie, sections, settings);
}
else
@@ -56,38 +55,6 @@ namespace NzbDrone.Core.Notifications.Plex
}
}
catch(Exception ex)
{
_logger.Warn(ex, "Failed to Update Plex host: " + settings.Host);
throw;
}
}
public void UpdateMovieSections(Movie movie, PlexServerSettings settings)
{
try
{
_logger.Debug("Sending Update Request to Plex Server");
var version = _versionCache.Get(settings.Host, () => GetVersion(settings), TimeSpan.FromHours(2));
ValidateVersion(version);
var sections = GetSections(settings);
var partialUpdates = _partialUpdateCache.Get(settings.Host, () => PartialUpdatesAllowed(settings, version), TimeSpan.FromHours(2));
// TODO: Investiate partial updates later, for now just update all movie sections...
//if (partialUpdates)
//{
// UpdatePartialSection(series, sections, settings);
//}
//else
//{
sections.ForEach(s => UpdateSection(s.Id, settings));
//}
}
catch (Exception ex)
{
_logger.Warn(ex, "Failed to Update Plex host: " + settings.Host);
@@ -163,18 +130,18 @@ namespace NzbDrone.Core.Notifications.Plex
_plexServerProxy.Update(sectionId, settings);
}
private void UpdatePartialSection(Series series, List<PlexSection> sections, PlexServerSettings settings)
private void UpdatePartialSection(Movie movie, List<PlexSection> sections, PlexServerSettings settings)
{
var partiallyUpdated = false;
foreach (var section in sections)
{
var metadataId = GetMetadataId(section.Id, series, section.Language, settings);
var metadataId = GetMetadataId(section.Id, movie, section.Language, settings);
if (metadataId.HasValue)
{
_logger.Debug("Updating Plex host: {0}, Section: {1}, Series: {2}", settings.Host, section.Id, series);
_plexServerProxy.UpdateSeries(metadataId.Value, settings);
_logger.Debug("Updating Plex host: {0}, Section: {1}, Movie: {2}", settings.Host, section.Id, movie);
_plexServerProxy.UpdateItem(metadataId.Value, settings);
partiallyUpdated = true;
}
@@ -188,11 +155,11 @@ namespace NzbDrone.Core.Notifications.Plex
}
}
private int? GetMetadataId(int sectionId, Series series, string language, PlexServerSettings settings)
private int? GetMetadataId(int sectionId, Movie movie, string language, PlexServerSettings settings)
{
_logger.Debug("Getting metadata from Plex host: {0} for series: {1}", settings.Host, series);
_logger.Debug("Getting metadata from Plex host: {0} for movie: {1}", settings.Host, movie);
return _plexServerProxy.GetMetadataId(sectionId, series.TvdbId, language, settings);
return _plexServerProxy.GetMetadataId(sectionId, movie.ImdbId, language, settings);
}
public ValidationFailure Test(PlexServerSettings settings)

View File

@@ -35,10 +35,6 @@ namespace NzbDrone.Core.Notifications.Prowl
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Prowl";
public override bool SupportsOnRename => false;

View File

@@ -33,10 +33,6 @@ namespace NzbDrone.Core.Notifications.PushBullet
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Pushbullet";

View File

@@ -34,10 +34,6 @@ namespace NzbDrone.Core.Notifications.Pushalot
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Pushalot";
public override bool SupportsOnRename => false;

View File

@@ -34,10 +34,6 @@ namespace NzbDrone.Core.Notifications.Pushover
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Pushover";
public override bool SupportsOnRename => false;

View File

@@ -15,6 +15,8 @@ namespace NzbDrone.Core.Notifications.Slack.Payloads
[JsonProperty("icon_url")]
public string IconUrl { get; set; }
public string Channel { get; set; }
public List<Attachment> Attachments { get; set; }
}
}

View File

@@ -78,21 +78,6 @@ namespace NzbDrone.Core.Notifications.Slack
_proxy.SendPayload(payload, Settings);
}
public override void OnRename(Series series)
{
var attachments = new List<Attachment>
{
new Attachment
{
Title = series.Title,
}
};
var payload = CreatePayload("Renamed", attachments);
_proxy.SendPayload(payload, Settings);
}
public override ValidationResult Test()
{
var failures = new List<ValidationFailure>();
@@ -124,6 +109,7 @@ namespace NzbDrone.Core.Notifications.Slack
private SlackPayload CreatePayload(string message, List<Attachment> attachments = null)
{
var icon = Settings.Icon;
var channel = Settings.Channel;
var payload = new SlackPayload
{
@@ -145,6 +131,11 @@ namespace NzbDrone.Core.Notifications.Slack
}
}
if (channel.IsNotNullOrWhiteSpace())
{
payload.Channel = channel;
}
return payload;
}
}

View File

@@ -27,6 +27,9 @@ namespace NzbDrone.Core.Notifications.Slack
[FieldDefinition(2, Label = "Icon", HelpText = "Change the icon that is used for messages from this integration (Emoji or URL)", Type = FieldType.Textbox, HelpLink = "http://www.emoji-cheat-sheet.com/")]
public string Icon { get; set; }
[FieldDefinition(3, Label = "Channel", HelpText = "Overrides the default channel for the incoming webhook (#other-channel)", Type = FieldType.Textbox)]
public string Channel { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -50,14 +50,6 @@ namespace NzbDrone.Core.Notifications.Synology
}
}
public override void OnRename(Series series)
{
if (Settings.UpdateLibrary)
{
_indexerProxy.UpdateFolder(series.Path);
}
}
public override string Name => "Synology Indexer";
public override ValidationResult Test()

View File

@@ -34,10 +34,6 @@ namespace NzbDrone.Core.Notifications.Telegram
{
}
public override void OnRename(Series series)
{
}
public override string Name => "Telegram";
public override bool SupportsOnRename => false;

View File

@@ -33,10 +33,6 @@ namespace NzbDrone.Core.Notifications.Twitter
{
}
public override void OnRename(Series series)
{
}
public override object RequestAction(string action, IDictionary<string, string> query)
{
if (action == "startOAuth")

89
src/NzbDrone.Core/Notifications/Webhook/Webhook.cs Normal file → Executable file
View File

@@ -1,39 +1,64 @@

using System.Collections.Generic;
using System.Linq;
using FluentValidation.Results;
using NzbDrone.Core.Tv;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Notifications.Webhook
{
public class Webhook : NotificationBase<WebhookSettings>
{
private readonly IWebhookService _service;
private readonly IWebhookProxy _proxy;
public Webhook(IWebhookService service)
public Webhook(IWebhookProxy proxy)
{
_service = service;
_proxy = proxy;
}
public override string Link => "https://github.com/Radarr/Radarr/wiki/Webhook";
public override void OnGrab(GrabMessage message)
{
_service.OnGrab(message.Movie, message.RemoteMovie, message.Quality, Settings);
var remoteMovie = message.RemoteMovie;
var quality = message.Quality;
var payload = new WebhookGrabPayload
{
EventType = "Grab",
Movie = new WebhookMovie(message.Movie),
RemoteMovie = new WebhookRemoteMovie(remoteMovie),
Release = new WebhookRelease(quality, remoteMovie)
};
_proxy.SendWebhook(payload, Settings);
}
public override void OnDownload(DownloadMessage message)
{
_service.OnDownload(message.Movie, message.MovieFile, Settings);
var movieFile = message.MovieFile;
var payload = new WebhookImportPayload
{
EventType = "Download",
Movie = new WebhookMovie(message.Movie),
RemoteMovie = new WebhookRemoteMovie(message.Movie),
MovieFile = new WebhookMovieFile(movieFile),
IsUpgrade = message.OldMovieFiles.Any()
};
_proxy.SendWebhook(payload, Settings);
}
public override void OnMovieRename(Movie movie)
{
_service.OnRename(movie, Settings);
}
var payload = new WebhookPayload
{
EventType = "Rename",
Movie = new WebhookMovie(movie)
};
public override void OnRename(Series series)
{
_proxy.SendWebhook(payload, Settings);
}
public override string Name => "Webhook";
@@ -42,9 +67,51 @@ namespace NzbDrone.Core.Notifications.Webhook
{
var failures = new List<ValidationFailure>();
failures.AddIfNotNull(_service.Test(Settings));
failures.AddIfNotNull(SendWebhookTest());
return new ValidationResult(failures);
}
private ValidationFailure SendWebhookTest()
{
try
{
var payload = new WebhookGrabPayload
{
EventType = "Test",
Movie = new WebhookMovie
{
Id = 1,
Title = "Test Title",
FolderPath = "C:\\testpath",
ReleaseDate = "1970-01-01"
},
RemoteMovie = new WebhookRemoteMovie
{
TmdbId = 1234,
ImdbId = "5678",
Title = "Test title",
Year = 1970
},
Release = new WebhookRelease
{
Indexer = "Test Indexer",
Quality = "Test Quality",
QualityVersion = 1,
ReleaseGroup = "Test Group",
ReleaseTitle = "Test Title",
Size = 9999999
}
};
_proxy.SendWebhook(payload, Settings);
}
catch (WebhookException ex)
{
return new NzbDroneValidationFailure("Url", ex.Message);
}
return null;
}
}
}

View File

@@ -1,32 +0,0 @@
using NzbDrone.Core.Tv;
using System;
namespace NzbDrone.Core.Notifications.Webhook
{
public class WebhookEpisode
{
public WebhookEpisode() { }
public WebhookEpisode(Episode episode)
{
Id = episode.Id;
SeasonNumber = episode.SeasonNumber;
EpisodeNumber = episode.EpisodeNumber;
Title = episode.Title;
AirDate = episode.AirDate;
AirDateUtc = episode.AirDateUtc;
}
public int Id { get; set; }
public int EpisodeNumber { get; set; }
public int SeasonNumber { get; set; }
public string Title { get; set; }
public string AirDate { get; set; }
public DateTime? AirDateUtc { get; set; }
public string Quality { get; set; }
public int QualityVersion { get; set; }
public string ReleaseGroup { get; set; }
public string SceneName { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
namespace NzbDrone.Core.Notifications.Webhook
{
class WebhookGrabPayload : WebhookPayload
{
public WebhookRemoteMovie RemoteMovie { get; set; }
public WebhookRelease Release { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace NzbDrone.Core.Notifications.Webhook
{
class WebhookImportPayload : WebhookPayload
{
public WebhookRemoteMovie RemoteMovie { get; set; }
public WebhookMovieFile MovieFile { get; set; }
public bool IsUpgrade { get; set; }
}
}

View File

@@ -1,8 +1,10 @@
namespace NzbDrone.Core.Notifications.Webhook
using NzbDrone.Common.Http;
namespace NzbDrone.Core.Notifications.Webhook
{
public enum WebhookMethod
{
POST = RestSharp.Method.POST,
PUT = RestSharp.Method.PUT
POST = HttpMethod.POST,
PUT = HttpMethod.PUT
}
}
}

View File

@@ -9,6 +9,8 @@ namespace NzbDrone.Core.Notifications.Webhook
public int Id { get; set; }
public string Title { get; set; }
public string FilePath { get; set; }
public string ReleaseDate { get; set; }
public string FolderPath { get; set; }
public WebhookMovie() { }
@@ -16,12 +18,12 @@ namespace NzbDrone.Core.Notifications.Webhook
{
Id = movie.Id;
Title = movie.Title;
ReleaseDate = movie.PhysicalReleaseDate().ToString("yyyy-MM-dd");
FolderPath = movie.Path;
}
public WebhookMovie(Movie movie, MovieFile movieFile)
public WebhookMovie(Movie movie, MovieFile movieFile) : this(movie)
{
Id = movie.Id;
Title = movie.Title;
FilePath = Path.Combine(movie.Path, movieFile.RelativePath);
}
}

View File

@@ -0,0 +1,28 @@
using NzbDrone.Core.MediaFiles;
namespace NzbDrone.Core.Notifications.Webhook
{
class WebhookMovieFile
{
public WebhookMovieFile() { }
public WebhookMovieFile(MovieFile movieFile)
{
Id = movieFile.Id;
RelativePath = movieFile.RelativePath;
Path = movieFile.Path;
Quality = movieFile.Quality.Quality.Name;
QualityVersion = movieFile.Quality.Revision.Version;
ReleaseGroup = movieFile.ReleaseGroup;
SceneName = movieFile.SceneName;
}
public int Id { get; set; }
public string RelativePath { get; set; }
public string Path { get; set; }
public string Quality { get; set; }
public int QualityVersion { get; set; }
public string ReleaseGroup { get; set; }
public string SceneName { get; set; }
}
}

View File

@@ -1,11 +1,8 @@
using System.Collections.Generic;
namespace NzbDrone.Core.Notifications.Webhook
{
public class WebhookPayload
{
public string EventType { get; set; }
public WebhookMovie Movie { get; set; }
public WebhookRemoteMovie RemoteMovie { get; set; }
}
}

View File

@@ -0,0 +1,50 @@
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Rest;
using System;
using System.Text;
namespace NzbDrone.Core.Notifications.Webhook
{
public interface IWebhookProxy
{
void SendWebhook(WebhookPayload payload, WebhookSettings settings);
}
class WebhookProxy : IWebhookProxy
{
private readonly IHttpClient _httpClient;
public WebhookProxy(IHttpClient httpClient)
{
_httpClient = httpClient;
}
public void SendWebhook(WebhookPayload body, WebhookSettings settings)
{
try
{
var request = new HttpRequestBuilder(settings.Url)
.Accept(HttpAccept.Json)
.Build();
request.Method = (HttpMethod)settings.Method;
request.Headers.ContentType = "application/json";
request.SetContent(body.ToJson());
if (!String.IsNullOrEmpty(settings.Username) || !String.IsNullOrEmpty(settings.Password))
{
var authInfo = settings.Username + ":" + settings.Password;
authInfo = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(authInfo));
request.Headers.Set("Authorization", "Basic " + authInfo);
}
_httpClient.Execute(request);
}
catch (RestException ex)
{
throw new WebhookException("Unable to post to webhook: {0}", ex, ex.Message);
}
}
}
}

View File

@@ -0,0 +1,27 @@
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Notifications.Webhook
{
public class WebhookRelease
{
public WebhookRelease() { }
public WebhookRelease(QualityModel quality, RemoteMovie remoteMovie)
{
Quality = quality.Quality.Name;
QualityVersion = quality.Revision.Version;
ReleaseGroup = remoteMovie.ParsedMovieInfo.ReleaseGroup;
ReleaseTitle = remoteMovie.Release.Title;
Indexer = remoteMovie.Release.Indexer;
Size = remoteMovie.Release.Size;
}
public string Quality { get; set; }
public int QualityVersion { get; set; }
public string ReleaseGroup { get; set; }
public string ReleaseTitle { get; set; }
public string Indexer { get; set; }
public long Size { get; set; }
}
}

View File

@@ -1,22 +0,0 @@
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.Webhook
{
public class WebhookSeries
{
public int Id { get; set; }
public string Title { get; set; }
public string Path { get; set; }
public int TvdbId { get; set; }
public WebhookSeries() { }
public WebhookSeries(Series series)
{
Id = series.Id;
Title = series.Title;
Path = series.Path;
TvdbId = series.TvdbId;
}
}
}

View File

@@ -1,103 +0,0 @@
using FluentValidation.Results;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Validation;
using NzbDrone.Core.Rest;
using RestSharp;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Parser.Model;
using System.Collections.Generic;
namespace NzbDrone.Core.Notifications.Webhook
{
public interface IWebhookService
{
void OnDownload(Movie movie, MovieFile movieFile, WebhookSettings settings);
void OnRename(Movie movie, WebhookSettings settings);
void OnGrab(Movie movie, RemoteMovie remoteMovie, QualityModel quality, WebhookSettings settings);
ValidationFailure Test(WebhookSettings settings);
}
public class WebhookService : IWebhookService
{
public void OnDownload(Movie movie, MovieFile movieFile, WebhookSettings settings)
{
var payload = new WebhookPayload
{
EventType = "Download",
Movie = new WebhookMovie(movie, movieFile),
RemoteMovie = new WebhookRemoteMovie(movie)
};
NotifyWebhook(payload, settings);
}
public void OnRename(Movie movie, WebhookSettings settings)
{
var payload = new WebhookPayload
{
EventType = "Rename",
Movie = new WebhookMovie(movie)
};
NotifyWebhook(payload, settings);
}
public void OnGrab(Movie movie, RemoteMovie remoteMovie, QualityModel quality, WebhookSettings settings)
{
var payload = new WebhookPayload
{
EventType = "Grab",
Movie = new WebhookMovie(movie),
RemoteMovie = new WebhookRemoteMovie(remoteMovie)
};
NotifyWebhook(payload, settings);
}
public void NotifyWebhook(WebhookPayload body, WebhookSettings settings)
{
try {
var client = RestClientFactory.BuildClient(settings.Url);
var request = new RestRequest((Method) settings.Method);
request.RequestFormat = DataFormat.Json;
request.AddBody(body);
client.ExecuteAndValidate(request);
}
catch (RestException ex)
{
throw new WebhookException("Unable to post to webhook: {0}", ex, ex.Message);
}
}
public ValidationFailure Test(WebhookSettings settings)
{
try
{
NotifyWebhook(
new WebhookPayload
{
EventType = "Test",
Movie = new WebhookMovie()
{
Id = 1,
Title = "Test Title",
FilePath = "C:\\testpath",
},
RemoteMovie = new WebhookRemoteMovie(){
ImdbId = "tt012345",
Title = "My Awesome Movie!"
}
},
settings
);
}
catch (WebhookException ex)
{
return new NzbDroneValidationFailure("Url", ex.Message);
}
return null;
}
}
}

View File

@@ -29,6 +29,12 @@ namespace NzbDrone.Core.Notifications.Webhook
[FieldDefinition(1, Label = "Method", Type = FieldType.Select, SelectOptions = typeof(WebhookMethod), HelpText = "Which HTTP method to use submit to the Webservice")]
public int Method { get; set; }
[FieldDefinition(2, Label = "Username")]
public string Username { get; set; }
[FieldDefinition(3, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

View File

@@ -1,236 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Notifications.Xbmc.Model;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.Xbmc
{
public class HttpApiProvider : IApiProvider
{
private readonly IHttpProvider _httpProvider;
private readonly Logger _logger;
public HttpApiProvider(IHttpProvider httpProvider, Logger logger)
{
_httpProvider = httpProvider;
_logger = logger;
}
public bool CanHandle(XbmcVersion version)
{
return version < new XbmcVersion(5);
}
public void Notify(XbmcSettings settings, string title, string message)
{
var notification = string.Format("Notification({0},{1},{2},{3})", title, message, settings.DisplayTime * 1000, "https://raw.github.com/Radarr/Radarr/develop/Logo/64.png");
var command = BuildExecBuiltInCommand(notification);
SendCommand(settings, command);
}
public void Update(XbmcSettings settings, Series series)
{
if (!settings.AlwaysUpdate)
{
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
var activePlayers = GetActivePlayers(settings);
if (activePlayers.Any(a => a.Type.Equals("video")))
{
_logger.Debug("Video is currently playing, skipping library update");
return;
}
}
UpdateLibrary(settings, series);
}
public void UpdateMovie(XbmcSettings settings, Movie movie)
{
if (!settings.AlwaysUpdate)
{
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
var activePlayers = GetActivePlayers(settings);
if (activePlayers.Any(a => a.Type.Equals("video")))
{
_logger.Debug("Video is currently playing, skipping library update");
return;
}
}
UpdateMovieLibrary(settings, movie);
}
public void Clean(XbmcSettings settings)
{
const string cleanVideoLibrary = "CleanLibrary(video)";
var command = BuildExecBuiltInCommand(cleanVideoLibrary);
SendCommand(settings, command);
}
internal List<ActivePlayer> GetActivePlayers(XbmcSettings settings)
{
try
{
var result = new List<ActivePlayer>();
var response = SendCommand(settings, "getcurrentlyplaying");
if (response.Contains("<li>Filename:[Nothing Playing]")) return new List<ActivePlayer>();
if (response.Contains("<li>Type:Video")) result.Add(new ActivePlayer(1, "video"));
return result;
}
catch (Exception ex)
{
_logger.Debug(ex, ex.Message);
}
return new List<ActivePlayer>();
}
internal string GetSeriesPath(XbmcSettings settings, Series series)
{
var query =
string.Format(
"select path.strPath from path, tvshow, tvshowlinkpath where tvshow.c12 = {0} and tvshowlinkpath.idShow = tvshow.idShow and tvshowlinkpath.idPath = path.idPath",
series.TvdbId);
var command = string.Format("QueryVideoDatabase({0})", query);
const string setResponseCommand =
"SetResponseFormat(webheader;false;webfooter;false;header;<xml>;footer;</xml>;opentag;<tag>;closetag;</tag>;closefinaltag;false)";
const string resetResponseCommand = "SetResponseFormat()";
SendCommand(settings, setResponseCommand);
var response = SendCommand(settings, command);
SendCommand(settings, resetResponseCommand);
if (string.IsNullOrEmpty(response))
return string.Empty;
var xDoc = XDocument.Load(new StringReader(response.Replace("&", "&amp;")));
var xml = xDoc.Descendants("xml").Select(x => x).FirstOrDefault();
if (xml == null)
return null;
var field = xml.Descendants("field").FirstOrDefault();
if (field == null)
return null;
return field.Value;
}
internal bool CheckForError(string response)
{
_logger.Debug("Looking for error in response: {0}", response);
if (string.IsNullOrWhiteSpace(response))
{
_logger.Debug("Invalid response from XBMC, the response is not valid JSON");
return true;
}
var errorIndex = response.IndexOf("Error", StringComparison.InvariantCultureIgnoreCase);
if (errorIndex > -1)
{
var errorMessage = response.Substring(errorIndex + 6);
errorMessage = errorMessage.Substring(0, errorMessage.IndexOfAny(new char[] { '<', ';' }));
_logger.Debug("Error found in response: {0}", errorMessage);
return true;
}
return false;
}
private void UpdateLibrary(XbmcSettings settings, Series series)
{
try
{
_logger.Debug("Sending Update DB Request to XBMC Host: {0}", settings.Address);
var xbmcSeriesPath = GetSeriesPath(settings, series);
//If the path is found update it, else update the whole library
if (!string.IsNullOrEmpty(xbmcSeriesPath))
{
_logger.Debug("Updating series [{0}] on XBMC host: {1}", series, settings.Address);
var command = BuildExecBuiltInCommand(string.Format("UpdateLibrary(video,{0})", xbmcSeriesPath));
SendCommand(settings, command);
}
else
{
//Update the entire library
_logger.Debug("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", series, settings.Address);
var command = BuildExecBuiltInCommand("UpdateLibrary(video)");
SendCommand(settings, command);
}
}
catch (Exception ex)
{
_logger.Debug(ex, ex.Message);
}
}
private void UpdateMovieLibrary(XbmcSettings settings, Movie movie)
{
try
{
//_logger.Debug("Sending Update DB Request to XBMC Host: {0}", settings.Address);
//var xbmcSeriesPath = GetSeriesPath(settings, series);
////If the path is found update it, else update the whole library
//if (!string.IsNullOrEmpty(xbmcSeriesPath))
//{
// _logger.Debug("Updating series [{0}] on XBMC host: {1}", series, settings.Address);
// var command = BuildExecBuiltInCommand(string.Format("UpdateLibrary(video,{0})", xbmcSeriesPath));
// SendCommand(settings, command);
//}
//else
//{
//Update the entire library
_logger.Debug("Series [{0}] doesn't exist on XBMC host: {1}, Updating Entire Library", movie, settings.Address);
var command = BuildExecBuiltInCommand("UpdateLibrary(video)");
SendCommand(settings, command);
//}
}
catch (Exception ex)
{
_logger.Debug(ex, ex.Message);
}
}
private string SendCommand(XbmcSettings settings, string command)
{
var url = string.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", settings.Address, command);
if (!string.IsNullOrEmpty(settings.Username))
{
return _httpProvider.DownloadString(url, settings.Username, settings.Password);
}
return _httpProvider.DownloadString(url);
}
private string BuildExecBuiltInCommand(string command)
{
return string.Format("ExecBuiltIn({0})", command);
}
}
}

View File

@@ -6,7 +6,6 @@ namespace NzbDrone.Core.Notifications.Xbmc
public interface IApiProvider
{
void Notify(XbmcSettings settings, string title, string message);
void Update(XbmcSettings settings, Series series);
void UpdateMovie(XbmcSettings settings, Movie movie);
void Clean(XbmcSettings settings);
bool CanHandle(XbmcVersion version);

View File

@@ -28,23 +28,6 @@ namespace NzbDrone.Core.Notifications.Xbmc
_proxy.Notify(settings, title, message);
}
public void Update(XbmcSettings settings, Series series)
{
if (!settings.AlwaysUpdate)
{
_logger.Debug("Determining if there are any active players on XBMC host: {0}", settings.Address);
var activePlayers = _proxy.GetActivePlayers(settings);
if (activePlayers.Any(a => a.Type.Equals("video")))
{
_logger.Debug("Video is currently playing, skipping library update");
return;
}
}
UpdateLibrary(settings, series);
}
public void UpdateMovie(XbmcSettings settings, Movie movie)
{
if (!settings.AlwaysUpdate)
@@ -73,65 +56,45 @@ namespace NzbDrone.Core.Notifications.Xbmc
return _proxy.GetActivePlayers(settings);
}
public string GetSeriesPath(XbmcSettings settings, Series series)
public string GetMoviePath(XbmcSettings settings, Movie movie)
{
var allSeries = _proxy.GetSeries(settings);
var allMovies = _proxy.GetMovies(settings);
if (!allSeries.Any())
if (!allMovies.Any())
{
_logger.Debug("No TV shows returned from XBMC");
_logger.Debug("No Movies returned from XBMC");
return null;
}
var matchingSeries = allSeries.FirstOrDefault(s =>
var matchingMovies = allMovies.FirstOrDefault(s =>
{
var tvdbId = 0;
int.TryParse(s.ImdbNumber, out tvdbId);
return s.ImdbNumber == movie.ImdbId || s.Label == movie.Title;
return tvdbId == series.TvdbId || s.Label == series.Title;
});
if (matchingSeries != null) return matchingSeries.File;
if (matchingMovies != null) return matchingMovies.File;
return null;
}
private void UpdateLibrary(XbmcSettings settings, Series series)
{
try
{
var seriesPath = GetSeriesPath(settings, series);
if (seriesPath != null)
{
_logger.Debug("Updating series {0} (Path: {1}) on XBMC host: {2}", series, seriesPath, settings.Address);
}
else
{
_logger.Debug("Series {0} doesn't exist on XBMC host: {1}, Updating Entire Library", series,
settings.Address);
}
var response = _proxy.UpdateLibrary(settings, seriesPath);
if (!response.Equals("OK", StringComparison.InvariantCultureIgnoreCase))
{
_logger.Debug("Failed to update library for: {0}", settings.Address);
}
}
catch (Exception ex)
{
_logger.Debug(ex, ex.Message);
}
}
private void UpdateMovieLibrary(XbmcSettings settings, Movie movie)
{
try
{
var response = _proxy.UpdateLibrary(settings, null);
var moviePath = GetMoviePath(settings, movie);
if (moviePath != null)
{
_logger.Debug("Updating movie {0} (Path: {1}) on XBMC host: {2}", movie, moviePath, settings.Address);
}
else
{
_logger.Debug("Movie {0} doesn't exist on XBMC host: {1}, Updating Entire Library", movie,
settings.Address);
}
var response = _proxy.UpdateLibrary(settings, moviePath);
if (!response.Equals("OK", StringComparison.InvariantCultureIgnoreCase))
{

Some files were not shown because too many files have changed in this diff Show More