Merge branch 'develop' into feature/net-import

pull/497/head
Devin Buhl 8 years ago
commit 47824426c6

26
.gitignore vendored

@ -101,16 +101,21 @@ App_Data/*.ldf
_NCrunch_*
_TeamCity*
# Sonarr
config.xml
nzbdrone.log*txt
# Radarr
Backups/
logs/
MediaCover/
UpdateLogs/
xdg/
config.xml
logs.db*
nzbdrone.db*
nzbdrone.pid
*workspace.xml
*.test-cache
*.userprefs
*/test-results/*
src/UI/.idea/*
*log.txt
node_modules/
_output*
_rawPackage/
@ -122,23 +127,26 @@ setup/Output/
UI.Phantom/
#VS outout folders
# VS outout folders
bin
obj
output/*
#Packages
# Packages
Radarr_*/
Radarr_*.zip
Radarr_*.gz
#OS X metadata files
# macOS metadata files
._*
.DS_Store
_start
_temp_*/**/*
#AppVeyor
# Windows thumbnail cache files
Thumbs.db
# AppVeyor
/tools-cake/
/_artifacts/
/_artifacts/

@ -1,12 +1,14 @@
language: csharp
solution: src/NzbDrone.sln
script: # the following commands are just examples, use whatever your build process requires
addons:
apt:
packages:
- nodejs
- npm
script:
- ./build.sh
- chmod +x test.sh
# - ./test.sh Linux Unit Takes far too long, maybe even crashes travis :/
install:
- sudo apt-get install nodejs
- sudo apt-get install npm
after_success:
- chmod +x package.sh
- ./package.sh

@ -1,6 +1,6 @@
# Sonarr Individual Contributor License Agreement #
# Radarr Individual Contributor License Agreement #
Thank you for your interest in contributing to Sonarr ("We" or "Us").
Thank you for your interest in contributing to Radarr ("We" or "Us").
This contributor agreement ("Agreement") documents the rights granted by contributors to Us. To make this document effective, please complete the form below. This is a legally binding document, so please read it carefully before agreeing to it. The Agreement may cover more than one software project managed by Us.
## 1. Definitions ##

@ -1,6 +1,6 @@
# How to Contribute #
We're always looking for people to help make Sonarr even better, there are a number of ways to contribute.
We're always looking for people to help make Radarr even better, there are a number of ways to contribute.
## Documentation ##
Setup guides, FAQ, the more information we have on the wiki the better.
@ -15,7 +15,7 @@ Setup guides, FAQ, the more information we have on the wiki the better.
### Getting started ###
1. Fork Sonarr
1. Fork Radarr
2. Clone (develop branch) *you may need pull in submodules separately if you client doesn't clone them automatically (CurlSharp)*
3. Run `npm install`
4. Run `npm start` - Used to compile the UI components and copy them.
@ -24,8 +24,8 @@ Setup guides, FAQ, the more information we have on the wiki the better.
5. Compile in Visual Studio
### Contributing Code ###
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Sonarr/Sonarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
- Rebase from Sonarr's develop branch, don't merge
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Radarr/Radarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
- Rebase from Radarr's develop branch, don't merge
- Make meaningful commits, or squash them
- Feel free to make a pull request before work is complete, this will let us see where its at and make comments/suggest improvements
- Reach out to us on the forums or on IRC if you have any questions

Binary file not shown.

@ -0,0 +1,85 @@
## Status
[![GitHub issues](https://img.shields.io/github/issues/radarr/radarr.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/issues)
[![GitHub pull requests](https://img.shields.io/github/issues-pr/radarr/radarr.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/pulls)
[![GNU GPL v3](https://img.shields.io/badge/license-GNU%20GPL%20v3-blue.svg?maxAge=60&style=flat-square)](http://www.gnu.org/licenses/gpl.html)
[![Copyright 2010-2017](https://img.shields.io/badge/copyright-2017-blue.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr)
| Service | Master | Develop |
|----------|:---------------------------:|:----------------------------:|
| 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) |
This fork of Sonarr aims to turn it into something like CouchPotato.
## Downloads
[![GitHub Releases](https://img.shields.io/badge/downloads-releases-brightgreen.svg?maxAge=60&style=flat-square)](https://github.com/Radarr/Radarr/releases)
[![AppVeyor Builds](https://img.shields.io/badge/downloads-continuous-green.svg?maxAge=60&style=flat-square)](https://ci.appveyor.com/project/galli-leo/radarr-usby1/build/artifacts)
[![Docker x64](https://img.shields.io/badge/docker-x64-blue.svg?maxAge=60&style=flat-square)](https://store.docker.com/community/images/linuxserver/radarr)
[![Docker armhf](https://img.shields.io/badge/docker-armhf-blue.svg?maxAge=60&style=flat-square)](https://store.docker.com/community/images/lsioarmhf/radarr)
[![Docker aarch64](https://img.shields.io/badge/docker-aarch64-blue.svg?maxAge=60&style=flat-square)](https://store.docker.com/community/images/lsioarmhf/radarr-aarch64)
To connect to the UI, fire up your browser and open <http://localhost:7878> or <http://your-ip:7878>.
## Features
### Currently Working
* Adding new movies
* Manually searching for releases of movies
* Automatically searching for releases
* Automatically importing downloaded movies
* Recognizing Special Editions, Director's Cut, etc.
* Identifying releases with hardcoded subs
* Rarbg.to, Torznab and Newznab Indexer
* QBittorrent and Deluge download client (Other clients are coming)
* New TorrentPotato Indexer (Works well with [Jackett](https://github.com/Jackett/Jackett))
### Planned Features
* Scanning PreDB to know when a new release is available
* Fixing the other Indexers and download clients
* Importing of Sonarr config
### Major Features
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
* Can watch for better quality of the movies you have and do an automatic upgrade. *eg. from DVD to Blu-Ray*
* Automatic failed download handling will try another release if one fails
* Manual search so you can pick any release or to see why a release was not downloaded automatically
* Full integration with SABnzbd and NZBGet
* Full integration with Kodi, Plex (notification, library update, metadata)
* And a beautiful UI
## Configuring Development Environment
### Requirements
* [Visual Studio Community](https://www.visualstudio.com/vs/community/) or [MonoDevelop](http://www.monodevelop.com)
* [Git](https://git-scm.com/downloads)
* [Node.js](https://nodejs.org/en/download/)
### Setup
* Make sure all the required software mentioned above are installed
* Clone the repository into your development machine ([*info*](https://help.github.com/desktop/guides/contributing/working-with-your-remote-repository-on-github-or-github-enterprise))
* Grab the submodules `git submodule init && git submodule update`
* Install the required Node Packages `npm install`
* Start gulp to monitor your dev environment for any changes that need post processing using `npm start` command.
*Please note: gulp must be running at all times while you are working with Radarr client source files.*
### 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
## Sponsors
[JetBrains](http://www.jetbrains.com) for providing us with free licenses to their great tools:
* [ReSharper](http://www.jetbrains.com/resharper)
* [WebStorm](http://www.jetbrains.com/webstorm)
* [TeamCity](http://www.jetbrains.com/teamcity)

@ -36,6 +36,9 @@ artifacts:
cache:
- '%USERPROFILE%\.nuget\packages'
- node_modules
pull_requests:
do_not_increment_build_number: true
only_commits:
files:

@ -1,81 +0,0 @@
# Radarr
| Service | Master | Develop |
|----------|:---------------------------:|:----------------------------:|
| 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/galli-leo/Radarr/master.svg?maxAge=60&style=flat-square)](https://travis-ci.org/galli-leo/Radarr) | [![Travis](https://img.shields.io/travis/galli-leo/Radarr/develop.svg?maxAge=60&style=flat-square)](https://travis-ci.org/galli-leo/Radarr) |
This fork of Sonarr aims to turn it into something like Couchpotato.
## Currently working:
* Adding new movies
* Manually searching for releases of movies.
* Automatically searching for releases.
* Automatically importing downloaded movies.
* Recognizing Special Editions, Director's Cut, etc.
* Identifying releases with hardcoded subs.
* Rarbg.to, Torznab and Newznab Indexer.
* QBittorrent and Deluge download client (Other clients are coming)
* New TorrentPotato Indexer (Works well with [Jackett](https://github.com/Jackett/Jackett))
## Planned Features:
* Scanning PreDB to know when a new release is available.
* Fixing the other Indexers and download clients.
* Importing of Sonarr config.
## Download
The latest precompiled binary versions can be found here: https://github.com/galli-leo/Radarr/releases.
Docker containers from [linuxserver.io](https://linuxserver.io) can be found here.
* [Radarr (x64)](https://hub.docker.com/r/linuxserver/radarr/)
* [Radarr (armhf)](https://hub.docker.com/r/lsioarmhf/radarr/)
* [Radarr (aarch64)](https://hub.docker.com/r/lsioarmhf/radarr-aarch64/)
For more up to date versions (but also sometimes broken), daily builds can be found here:
* [OSX](https://leonardogalli.ch/radarr/builds/latest.php?os=osx)
* [Windows](https://leonardogalli.ch/radarr/builds/latest.php?os=windows)
* [Linux](https://leonardogalli.ch/radarr/builds/latest.php?os=mono)
## Major Features Include: ##
* Support for major platforms: Windows, Linux, OSX, Raspberry Pi, etc.
* Can watch for better quality of the movies you have and do an upgrade.
* Automatic failed download handling will try another release if one fails
* Manual search so you can pick any release or to see why a release was not downloaded automatically.
* Full integration with SABNzbd and NzbGet.
* Full integration with XBMC, Plex (notification, library update, metadata).
* And a beautiful UI
## Configuring Development Environment: ##
### Requirements ###
- Visual Studio 2015 [Free Community Edition](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) or Mono
- [Git](http://git-scm.com/downloads)
- [NodeJS](http://nodejs.org/download/)
### Setup ###
- Make sure all the required software mentioned above are installed.
- Clone the repository into your development machine. [*info*](https://help.github.com/articles/working-with-repositories)
- Grab the submodules `git submodule init && git submodule update`
- install the required Node Packages `npm install`
- start gulp to monitor your dev environment for any changes that need post processing using `npm start` command.
*Please note gulp must be running at all times while you are working with Sonarr client source files.*
### 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
### License ###
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
Copyright 2010-2016
### Sponsors ###
- [JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools
- [ReSharper](http://www.jetbrains.com/resharper/)
- [WebStorm](http://www.jetbrains.com/webstorm/)
- [TeamCity](http://www.jetbrains.com/teamcity/)

@ -27,6 +27,7 @@ namespace NzbDrone.Api.Calendar
Get["/NzbDrone.ics"] = options => GetCalendarFeed();
Get["/Sonarr.ics"] = options => GetCalendarFeed();
Get["/Radarr.ics"] = options => GetCalendarFeed();
}
private Response GetCalendarFeed()

@ -97,7 +97,7 @@ namespace NzbDrone.Api.Indexers
{
Guid = releaseInfo.Guid,
Quality = parsedMovieInfo.Quality,
//QualityWeight
QualityWeight = parsedMovieInfo.Quality.Quality.Id, //Id kinda hacky for wheight, but what you gonna do? TODO: Fix this shit!
Age = releaseInfo.Age,
AgeHours = releaseInfo.AgeHours,
AgeMinutes = releaseInfo.AgeMinutes,

@ -0,0 +1,89 @@
using System.Collections.Generic;
using System.IO;
using NLog;
using NzbDrone.Api.REST;
using NzbDrone.Api.Movie;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Tv;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.SignalR;
namespace NzbDrone.Api.EpisodeFiles
{
public class MovieFileModule : NzbDroneRestModuleWithSignalR<MovieFileResource, MovieFile>
//IHandle<EpisodeFileAddedEvent>
{
private readonly IMediaFileService _mediaFileService;
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly IMovieService _seriesService;
private readonly IQualityUpgradableSpecification _qualityUpgradableSpecification;
private readonly Logger _logger;
public MovieFileModule(IBroadcastSignalRMessage signalRBroadcaster,
IMediaFileService mediaFileService,
IRecycleBinProvider recycleBinProvider,
IMovieService seriesService,
IQualityUpgradableSpecification qualityUpgradableSpecification,
Logger logger)
: base(signalRBroadcaster)
{
_mediaFileService = mediaFileService;
_recycleBinProvider = recycleBinProvider;
_seriesService = seriesService;
_qualityUpgradableSpecification = qualityUpgradableSpecification;
_logger = logger;
/*GetResourceById = GetEpisodeFile;
GetResourceAll = GetEpisodeFiles;
UpdateResource = SetQuality;*/
DeleteResource = DeleteEpisodeFile;
}
/*private EpisodeFileResource GetEpisodeFile(int id)
{
var episodeFile = _mediaFileService.Get(id);
var series = _seriesService.GetSeries(episodeFile.SeriesId);
return episodeFile.ToResource(series, _qualityUpgradableSpecification);
}
private List<EpisodeFileResource> GetEpisodeFiles()
{
if (!Request.Query.SeriesId.HasValue)
{
throw new BadRequestException("seriesId is missing");
}
var seriesId = (int)Request.Query.SeriesId;
var series = _seriesService.GetSeries(seriesId);
return _mediaFileService.GetFilesBySeries(seriesId).ConvertAll(f => f.ToResource(series, _qualityUpgradableSpecification));
}
private void SetQuality(EpisodeFileResource episodeFileResource)
{
var episodeFile = _mediaFileService.Get(episodeFileResource.Id);
episodeFile.Quality = episodeFileResource.Quality;
_mediaFileService.Update(episodeFile);
}*/
private void DeleteEpisodeFile(int id)
{
var episodeFile = _mediaFileService.GetMovie(id);
var series = _seriesService.GetMovie(episodeFile.MovieId);
var fullPath = Path.Combine(series.Path, episodeFile.RelativePath);
_logger.Info("Deleting episode file: {0}", fullPath);
_recycleBinProvider.DeleteFile(fullPath);
_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual);
}
public void Handle(EpisodeFileAddedEvent message)
{
BroadcastResourceChange(ModelAction.Updated, message.EpisodeFile.Id);
}
}
}

@ -116,6 +116,7 @@
<Compile Include="Frontend\Mappers\RobotsTxtMapper.cs" />
<Compile Include="Indexers\ReleaseModuleBase.cs" />
<Compile Include="Indexers\ReleasePushModule.cs" />
<Compile Include="Movies\MovieFileModule.cs" />
<Compile Include="Movies\MovieModule.cs" />
<Compile Include="Movies\RenameMovieModule.cs" />
<Compile Include="Movies\RenameMovieResource.cs" />

@ -30,8 +30,8 @@ namespace NzbDrone.Api.Movie
public string ReleaseGroup { get; set; }
public QualityModel Quality { get; set; }
public MovieResource Movie { get; set; }
public string Edition { get; set; }
public Core.MediaFiles.MediaInfo.MediaInfoModel MediaInfo { get; set; }
//TODO: Add series statistics as a property of the series (instead of individual properties)
}
@ -63,7 +63,8 @@ namespace NzbDrone.Api.Movie
ReleaseGroup = model.ReleaseGroup,
Quality = model.Quality,
Movie = movie,
MediaInfo = model.MediaInfo,
Edition = model.Edition
};
}

@ -23,7 +23,7 @@ namespace NzbDrone.Common
Console.WriteLine(" Commands:");
Console.WriteLine(" /{0} Install the application as a Windows Service ({1}).", StartupContext.INSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME);
Console.WriteLine(" /{0} Uninstall already installed Windows Service ({1}).", StartupContext.UNINSTALL_SERVICE, ServiceProvider.NZBDRONE_SERVICE_NAME);
Console.WriteLine(" /{0} Don't open Sonarr in a browser", StartupContext.NO_BROWSER);
Console.WriteLine(" /{0} Don't open Radarr in a browser", StartupContext.NO_BROWSER);
Console.WriteLine(" <No Arguments> Run application in console mode.");
}

@ -9,12 +9,12 @@ namespace NzbDrone.Common.Http
static UserAgentBuilder()
{
UserAgent = string.Format("Sonarr/{0} ({1} {2})",
UserAgent = string.Format("Radarr/{0} ({1} {2})",
BuildInfo.Version,
OsInfo.Os, OsInfo.Version.ToString(2));
UserAgentSimplified = string.Format("Sonarr/{0}",
UserAgentSimplified = string.Format("Radarr/{0}",
BuildInfo.Version.ToString(2));
}
}
}
}

@ -103,9 +103,9 @@ namespace NzbDrone.Common.Instrumentation
private static void RegisterAppFile(IAppFolderInfo appFolderInfo)
{
RegisterAppFile(appFolderInfo, "appFileInfo", "sonarr.txt", 5, LogLevel.Info);
RegisterAppFile(appFolderInfo, "appFileDebug", "sonarr.debug.txt", 50, LogLevel.Off);
RegisterAppFile(appFolderInfo, "appFileTrace", "sonarr.trace.txt", 50, LogLevel.Off);
RegisterAppFile(appFolderInfo, "appFileInfo", "radarr.txt", 5, LogLevel.Info);
RegisterAppFile(appFolderInfo, "appFileDebug", "radarr.debug.txt", 50, LogLevel.Off);
RegisterAppFile(appFolderInfo, "appFileTrace", "radarr.trace.txt", 50, LogLevel.Off);
}
private static LoggingRule RegisterAppFile(IAppFolderInfo appFolderInfo, string name, string fileName, int maxArchiveFiles, LogLevel minLogLevel)

@ -26,7 +26,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.DelugeTests
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new DelugeSettings()
{
TvCategory = null
MovieCategory = null
};
_queued = new DelugeTorrent

@ -25,7 +25,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.QBittorrentTests
Port = 2222,
Username = "admin",
Password = "pass",
TvCategory = "tv"
MovieCategory = "movies-radarr"
};
Mocker.GetMock<ITorrentFileInfoReader>()

@ -21,7 +21,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.RTorrentTests
Subject.Definition = new DownloadClientDefinition();
Subject.Definition.Settings = new RTorrentSettings()
{
TvCategory = null
MovieCategory = null
};
_downloading = new RTorrentTorrent

@ -112,12 +112,12 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests
protected void GivenTvCategory()
{
_settings.TvCategory = "sonarr";
_settings.MovieCategory = "radarr";
}
protected void GivenTvDirectory()
{
_settings.TvDirectory = @"C:/Downloads/Finished/sonarr";
_settings.MovieDirectory = @"C:/Downloads/Finished/radarr";
}
protected void GivenFailedDownload()

@ -42,14 +42,14 @@ namespace NzbDrone.Core.Test.IndexerTests.OmgwtfnzbsTests
var releaseInfo = releases.First();
releaseInfo.Title.Should().Be("Stephen.Fry.Gadget.Man.S01E05.HDTV.x264-C4TV");
releaseInfo.Title.Should().Be("Un.Petit.Boulot.2016.FRENCH.720p.BluRay.DTS.x264-LOST");
releaseInfo.DownloadProtocol.Should().Be(DownloadProtocol.Usenet);
releaseInfo.DownloadUrl.Should().Be("http://api.omgwtfnzbs.org/sn.php?id=OAl4g&user=nzbdrone&api=nzbdrone");
releaseInfo.InfoUrl.Should().Be("http://omgwtfnzbs.org/details.php?id=OAl4g");
releaseInfo.DownloadUrl.Should().Be("https://api.omgwtfnzbs.me/nzb/?id=8a2Bw&user=nzbdrone&api=nzbdrone");
releaseInfo.InfoUrl.Should().Be("https://omgwtfnzbs.me/details.php?id=8a2Bw");
releaseInfo.CommentUrl.Should().BeNullOrEmpty();
releaseInfo.Indexer.Should().Be(Subject.Definition.Name);
releaseInfo.PublishDate.Should().Be(DateTime.Parse("2012/12/17 23:30:13"));
releaseInfo.Size.Should().Be(236822906);
releaseInfo.PublishDate.Should().Be(DateTime.Parse("2017/01/09 00:16:54"));
releaseInfo.Size.Should().Be(5354909355);
}
}
}

@ -0,0 +1,45 @@
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(115)]
public class update_movie_sorttitle : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
// Create.Column("SortTitle").OnTable("Series").AsString().Nullable();
Execute.WithConnection(SetSortTitles);
}
private void SetSortTitles(IDbConnection conn, IDbTransaction tran)
{
using (IDbCommand getSeriesCmd = conn.CreateCommand())
{
getSeriesCmd.Transaction = tran;
getSeriesCmd.CommandText = @"SELECT Id, Title FROM Movies";
using (IDataReader seriesReader = getSeriesCmd.ExecuteReader())
{
while (seriesReader.Read())
{
var id = seriesReader.GetInt32(0);
var title = seriesReader.GetString(1);
var sortTitle = Parser.Parser.NormalizeTitle(title).ToLower();
using (IDbCommand updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "UPDATE Movies SET SortTitle = ? WHERE Id = ?";
updateCmd.AddParameter(sortTitle);
updateCmd.AddParameter(id);
updateCmd.ExecuteNonQuery();
}
}
}
}
}
}
}

@ -0,0 +1,44 @@
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(116)]
public class update_movie_sorttitle_again : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(SetSortTitles);
}
private void SetSortTitles(IDbConnection conn, IDbTransaction tran)
{
using (IDbCommand getSeriesCmd = conn.CreateCommand())
{
getSeriesCmd.Transaction = tran;
getSeriesCmd.CommandText = @"SELECT Id, Title FROM Movies";
using (IDataReader seriesReader = getSeriesCmd.ExecuteReader())
{
while (seriesReader.Read())
{
var id = seriesReader.GetInt32(0);
var title = seriesReader.GetString(1);
var sortTitle = Parser.Parser.NormalizeTitle(title).ToLower();
using (IDbCommand updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "UPDATE Movies SET SortTitle = ? WHERE Id = ?";
updateCmd.AddParameter(sortTitle);
updateCmd.AddParameter(id);
updateCmd.ExecuteNonQuery();
}
}
}
}
}
}
}

@ -0,0 +1,52 @@
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(117)]
public class update_movie_file : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Create.Column("Edition").OnTable("MovieFiles").AsString().Nullable();
//Execute.WithConnection(SetSortTitles);
}
private void SetSortTitles(IDbConnection conn, IDbTransaction tran)
{
using (IDbCommand getSeriesCmd = conn.CreateCommand())
{
getSeriesCmd.Transaction = tran;
getSeriesCmd.CommandText = @"SELECT Id, RelativePath FROM MovieFiles";
using (IDataReader seriesReader = getSeriesCmd.ExecuteReader())
{
while (seriesReader.Read())
{
var id = seriesReader.GetInt32(0);
var relativePath = seriesReader.GetString(1);
var result = Parser.Parser.ParseMovieTitle(relativePath);
var edition = "";
if (result != null)
{
edition = Parser.Parser.ParseMovieTitle(relativePath).Edition;
}
using (IDbCommand updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "UPDATE MovieFiles SET Edition = ? WHERE Id = ?";
updateCmd.AddParameter(edition);
updateCmd.AddParameter(id);
updateCmd.ExecuteNonQuery();
}
}
}
}
}
}
}

@ -0,0 +1,71 @@
using System.Data;
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
using System.Text;
using System.Text.RegularExpressions;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(118)]
public class update_movie_slug : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.WithConnection(SetTitleSlug);
}
private void SetTitleSlug(IDbConnection conn, IDbTransaction tran)
{
using (IDbCommand getSeriesCmd = conn.CreateCommand())
{
getSeriesCmd.Transaction = tran;
getSeriesCmd.CommandText = @"SELECT Id, Title, Year FROM Movies";
using (IDataReader seriesReader = getSeriesCmd.ExecuteReader())
{
while (seriesReader.Read())
{
var id = seriesReader.GetInt32(0);
var title = seriesReader.GetString(1);
var year = seriesReader.GetInt32(2);
var titleSlug = ToUrlSlug(title + "-" + year);
using (IDbCommand updateCmd = conn.CreateCommand())
{
updateCmd.Transaction = tran;
updateCmd.CommandText = "UPDATE Movies SET TitleSlug = ? WHERE Id = ?";
updateCmd.AddParameter(titleSlug);
updateCmd.AddParameter(id);
updateCmd.ExecuteNonQuery();
}
}
}
}
}
public static string ToUrlSlug(string value)
{
//First to lower case
value = value.ToLowerInvariant();
//Remove all accents
var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(value);
value = Encoding.ASCII.GetString(bytes);
//Replace spaces
value = Regex.Replace(value, @"\s", "-", RegexOptions.Compiled);
//Remove invalid chars
value = Regex.Replace(value, @"[^a-z0-9\s-_]", "", RegexOptions.Compiled);
//Trim dashes from end
value = value.Trim('-', '_');
//Replace double occurences of - or _
value = Regex.Replace(value, @"([-_]){2,}", "$1", RegexOptions.Compiled);
return value;
}
}
}

@ -24,8 +24,6 @@ namespace NzbDrone.Core.DecisionEngine
{
CompareQuality,
CompareProtocol,
CompareEpisodeCount,
CompareEpisodeNumber,
ComparePeersIfTorrent,
CompareAgeIfUsenet,
CompareSize
@ -56,6 +54,12 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareQuality(DownloadDecision x, DownloadDecision y)
{
if (x.IsForMovie && y.IsForMovie)
{
return CompareAll(CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode => remoteEpisode.Movie.Profile.Value.Items.FindIndex(v => v.Quality == remoteEpisode.ParsedMovieInfo.Quality.Quality)),
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode => remoteEpisode.ParsedMovieInfo.Quality.Revision.Real),
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode => remoteEpisode.ParsedMovieInfo.Quality.Revision.Version));
}
return CompareAll(CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Series.Profile.Value.Items.FindIndex(v => v.Quality == remoteEpisode.ParsedEpisodeInfo.Quality.Quality)),
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Real),
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.Quality.Revision.Version));
@ -63,6 +67,7 @@ namespace NzbDrone.Core.DecisionEngine
private int CompareProtocol(DownloadDecision x, DownloadDecision y)
{
var result = CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
{
var delayProfile = _delayProfileService.BestForTags(remoteEpisode.Series.Tags);
@ -70,13 +75,22 @@ namespace NzbDrone.Core.DecisionEngine
return downloadProtocol == delayProfile.PreferredProtocol;
});
if (x.IsForMovie)
{
result = CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode =>
{
var delayProfile = _delayProfileService.BestForTags(remoteEpisode.Movie.Tags);
var downloadProtocol = remoteEpisode.Release.DownloadProtocol;
return downloadProtocol == delayProfile.PreferredProtocol;
});
}
return result;
}
private int CompareEpisodeCount(DownloadDecision x, DownloadDecision y)
{
return CompareAll(CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.ParsedEpisodeInfo.FullSeason),
CompareByReverse(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Episodes.Count));
return 0;
}
private int CompareEpisodeNumber(DownloadDecision x, DownloadDecision y)
@ -88,20 +102,20 @@ namespace NzbDrone.Core.DecisionEngine
{
// Different protocols should get caught when checking the preferred protocol,
// since we're dealing with the same series in our comparisions
if (x.RemoteEpisode.Release.DownloadProtocol != DownloadProtocol.Torrent ||
y.RemoteEpisode.Release.DownloadProtocol != DownloadProtocol.Torrent)
if (x.RemoteMovie.Release.DownloadProtocol != DownloadProtocol.Torrent ||
y.RemoteMovie.Release.DownloadProtocol != DownloadProtocol.Torrent)
{
return 0;
}
return CompareAll(
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode =>
{
var seeders = TorrentInfo.GetSeeders(remoteEpisode.Release);
return seeders.HasValue && seeders.Value > 0 ? Math.Round(Math.Log10(seeders.Value)) : 0;
}),
CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode =>
{
var peers = TorrentInfo.GetPeers(remoteEpisode.Release);
@ -117,7 +131,7 @@ namespace NzbDrone.Core.DecisionEngine
return 0;
}
return CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode =>
return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode =>
{
var ageHours = remoteEpisode.Release.AgeHours;
var age = remoteEpisode.Release.Age;
@ -145,7 +159,7 @@ namespace NzbDrone.Core.DecisionEngine
{
// TODO: Is smaller better? Smaller for usenet could mean no par2 files.
return CompareBy(x.RemoteEpisode, y.RemoteEpisode, remoteEpisode => remoteEpisode.Release.Size.Round(200.Megabytes()));
return CompareBy(x.RemoteMovie, y.RemoteMovie, remoteEpisode => remoteEpisode.Release.Size.Round(200.Megabytes()));
}
}
}

@ -265,7 +265,6 @@ namespace NzbDrone.Core.DecisionEngine
e.Data.Add("parsed", remoteEpisode.ParsedEpisodeInfo.ToJson());
_logger.Error(e, "Couldn't evaluate decision on " + remoteEpisode.Release.Title + ", with spec: " + spec.GetType().Name);
return new Rejection(string.Format("{0}: {1}", spec.GetType().Name, e.Message));//TODO UPDATE SPECS!
return null;
}
return null;

@ -64,7 +64,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
if (!_qualityUpgradableSpecification.CutoffNotMet(subject.Movie.Profile, remoteEpisode.ParsedMovieInfo.Quality, subject.ParsedMovieInfo.Quality))
{
return Decision.Reject("Quality for release in queue already meets cutoff: {0}", remoteEpisode.ParsedEpisodeInfo.Quality);
return Decision.Reject("Quality for release in queue already meets cutoff: {0}", remoteEpisode.ParsedMovieInfo.Quality);
}
_logger.Debug("Checking if release is higher quality than queued release. Queued quality is: {0}", remoteEpisode.ParsedMovieInfo.Quality);

@ -26,10 +26,10 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
private static readonly TorrentBlackholeSettingsValidator Validator = new TorrentBlackholeSettingsValidator();
[FieldDefinition(0, Label = "Torrent Folder", Type = FieldType.Path, HelpText = "Folder in which Sonarr will store the .torrent file")]
[FieldDefinition(0, Label = "Torrent Folder", Type = FieldType.Path, HelpText = "Folder in which Radarr will store the .torrent file")]
public string TorrentFolder { get; set; }
[FieldDefinition(1, Label = "Watch Folder", Type = FieldType.Path, HelpText = "Folder from which Sonarr should import completed downloads")]
[FieldDefinition(1, Label = "Watch Folder", Type = FieldType.Path, HelpText = "Folder from which Radarr should import completed downloads")]
public string WatchFolder { get; set; }
[DefaultValue(false)]
@ -39,7 +39,7 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
[DefaultValue(false)]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[FieldDefinition(3, Label = "Read Only", Type = FieldType.Checkbox, HelpText = "Instead of moving files this will instruct Sonarr to Copy or Hardlink (depending on settings/system configuration)")]
[FieldDefinition(3, Label = "Read Only", Type = FieldType.Checkbox, HelpText = "Instead of moving files this will instruct Radarr to Copy or Hardlink (depending on settings/system configuration)")]
public bool ReadOnly { get; set; }
public NzbDroneValidationResult Validate()

@ -19,10 +19,10 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
{
private static readonly UsenetBlackholeSettingsValidator Validator = new UsenetBlackholeSettingsValidator();
[FieldDefinition(0, Label = "Nzb Folder", Type = FieldType.Path, HelpText = "Folder in which Sonarr will store the .nzb file")]
[FieldDefinition(0, Label = "Nzb Folder", Type = FieldType.Path, HelpText = "Folder in which Radarr will store the .nzb file")]
public string NzbFolder { get; set; }
[FieldDefinition(1, Label = "Watch Folder", Type = FieldType.Path, HelpText = "Folder from which Sonarr should import completed downloads")]
[FieldDefinition(1, Label = "Watch Folder", Type = FieldType.Path, HelpText = "Folder from which Radarr should import completed downloads")]
public string WatchFolder { get; set; }
public NzbDroneValidationResult Validate()

@ -31,25 +31,17 @@ namespace NzbDrone.Core.Download.Clients.Deluge
_proxy = proxy;
}
protected override string AddFromMagnetLink(RemoteMovie remoteEpisode, string hash, string magnetLink)
protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
{
var actualHash = _proxy.AddTorrentFromMagnet(magnetLink, Settings);
if (!Settings.TvCategory.IsNullOrWhiteSpace())
if (!Settings.MovieCategory.IsNullOrWhiteSpace())
{
_proxy.SetLabel(actualHash, Settings.TvCategory, Settings);
_proxy.SetLabel(actualHash, Settings.MovieCategory, Settings);
}
_proxy.SetTorrentConfiguration(actualHash, "remove_at_ratio", false, Settings);
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)DelugePriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)DelugePriority.First)
{
_proxy.MoveTorrentToTopInQueue(actualHash, Settings);
}*/
return actualHash.ToUpper();
}
@ -57,66 +49,24 @@ namespace NzbDrone.Core.Download.Clients.Deluge
{
var actualHash = _proxy.AddTorrentFromFile(filename, fileContent, Settings);
if (!Settings.TvCategory.IsNullOrWhiteSpace())
if (!Settings.MovieCategory.IsNullOrWhiteSpace())
{
_proxy.SetLabel(actualHash, Settings.TvCategory, Settings);
_proxy.SetLabel(actualHash, Settings.MovieCategory, Settings);
}
_proxy.SetTorrentConfiguration(actualHash, "remove_at_ratio", false, Settings);
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)DelugePriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)DelugePriority.First)
{
_proxy.MoveTorrentToTopInQueue(actualHash, Settings);
}*/
return actualHash.ToUpper();
}
protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink)
{
var actualHash = _proxy.AddTorrentFromMagnet(magnetLink, Settings);
if (!Settings.TvCategory.IsNullOrWhiteSpace())
{
_proxy.SetLabel(actualHash, Settings.TvCategory, Settings);
}
_proxy.SetTorrentConfiguration(actualHash, "remove_at_ratio", false, Settings);
var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)DelugePriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)DelugePriority.First)
{
_proxy.MoveTorrentToTopInQueue(actualHash, Settings);
}
return actualHash.ToUpper();
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent)
{
var actualHash = _proxy.AddTorrentFromFile(filename, fileContent, Settings);
if (!Settings.TvCategory.IsNullOrWhiteSpace())
{
_proxy.SetLabel(actualHash, Settings.TvCategory, Settings);
}
_proxy.SetTorrentConfiguration(actualHash, "remove_at_ratio", false, Settings);
var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)DelugePriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)DelugePriority.First)
{
_proxy.MoveTorrentToTopInQueue(actualHash, Settings);
}
return actualHash.ToUpper();
throw new NotImplementedException("Episodes are not working with Radarr");
}
public override string Name => "Deluge";
@ -127,9 +77,9 @@ namespace NzbDrone.Core.Download.Clients.Deluge
try
{
if (!Settings.TvCategory.IsNullOrWhiteSpace())
if (!Settings.MovieCategory.IsNullOrWhiteSpace())
{
torrents = _proxy.GetTorrentsByLabel(Settings.TvCategory, Settings);
torrents = _proxy.GetTorrentsByLabel(Settings.MovieCategory, Settings);
}
else
{
@ -149,7 +99,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge
var item = new DownloadClientItem();
item.DownloadId = torrent.Hash.ToUpper();
item.Title = torrent.Name;
item.Category = Settings.TvCategory;
item.Category = Settings.MovieCategory;
item.DownloadClient = Definition.Name;
@ -280,7 +230,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge
private ValidationFailure TestCategory()
{
if (Settings.TvCategory.IsNullOrWhiteSpace())
if (Settings.MovieCategory.IsNullOrWhiteSpace())
{
return null;
}
@ -297,16 +247,16 @@ namespace NzbDrone.Core.Download.Clients.Deluge
var labels = _proxy.GetAvailableLabels(Settings);
if (!labels.Contains(Settings.TvCategory))
if (!labels.Contains(Settings.MovieCategory))
{
_proxy.AddLabel(Settings.TvCategory, Settings);
_proxy.AddLabel(Settings.MovieCategory, Settings);
labels = _proxy.GetAvailableLabels(Settings);
if (!labels.Contains(Settings.TvCategory))
if (!labels.Contains(Settings.MovieCategory))
{
return new NzbDroneValidationFailure("TvCategory", "Configuration of label failed")
return new NzbDroneValidationFailure("MovieCategory", "Configuration of label failed")
{
DetailedDescription = "Sonarr as unable to add the label to Deluge."
DetailedDescription = "Radarr as unable to add the label to Deluge."
};
}
}

@ -12,7 +12,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge
RuleFor(c => c.Host).ValidHost();
RuleFor(c => c.Port).GreaterThan(0);
RuleFor(c => c.TvCategory).Matches("^[-a-z]*$").WithMessage("Allowed characters a-z and -");
RuleFor(c => c.MovieCategory).Matches("^[-a-z]*$").WithMessage("Allowed characters a-z and -");
}
}
@ -25,7 +25,7 @@ namespace NzbDrone.Core.Download.Clients.Deluge
Host = "localhost";
Port = 8112;
Password = "deluge";
TvCategory = "movie-radarr";
MovieCategory = "movie-radarr";
}
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]
@ -41,15 +41,9 @@ namespace NzbDrone.Core.Download.Clients.Deluge
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(DelugePriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]
public int RecentTvPriority { get; set; }
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(DelugePriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")]
public int OlderTvPriority { get; set; }
[FieldDefinition(7, Label = "Use SSL", Type = FieldType.Checkbox)]
[FieldDefinition(5, Label = "Use SSL", Type = FieldType.Checkbox)]
public bool UseSsl { get; set; }
public NzbDroneValidationResult Validate()

@ -43,7 +43,7 @@ namespace NzbDrone.Core.Download.Clients.NzbVortex
[FieldDefinition(2, Label = "API Key", Type = FieldType.Textbox)]
public string ApiKey { get; set; }
[FieldDefinition(3, Label = "Group", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")]
[FieldDefinition(3, Label = "Group", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; }
[FieldDefinition(4, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbVortexPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]

@ -337,7 +337,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
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 Sonarr from seeing completed downloads."
DetailedDescription = "NzbGet setting KeepHistory is set to 0. Which prevents Radarr from seeing completed downloads."
};
}

@ -45,7 +45,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
[FieldDefinition(3, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")]
[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; }
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]

@ -33,81 +33,35 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink)
{
_proxy.AddTorrentFromUrl(magnetLink, Settings);
if (Settings.TvCategory.IsNotNullOrWhiteSpace())
{
_proxy.SetTorrentLabel(hash.ToLower(), Settings.TvCategory, Settings);
}
var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)QBittorrentPriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)QBittorrentPriority.First)
{
_proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
}
return hash;
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, Byte[] fileContent)
{
_proxy.AddTorrentFromFile(filename, fileContent, Settings);
if (Settings.TvCategory.IsNotNullOrWhiteSpace())
{
_proxy.SetTorrentLabel(hash.ToLower(), Settings.TvCategory, Settings);
}
var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)QBittorrentPriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)QBittorrentPriority.First)
{
_proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
}
return hash;
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromMagnetLink(RemoteMovie remoteEpisode, string hash, string magnetLink)
protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
{
_proxy.AddTorrentFromUrl(magnetLink, Settings);
if (Settings.TvCategory.IsNotNullOrWhiteSpace())
if (Settings.MovieCategory.IsNotNullOrWhiteSpace())
{
_proxy.SetTorrentLabel(hash.ToLower(), Settings.TvCategory, Settings);
_proxy.SetTorrentLabel(hash.ToLower(), Settings.MovieCategory, Settings);
}
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)QBittorrentPriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)QBittorrentPriority.First)
{
_proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
}*/ //TODO: Maybe reimplement for movies
return hash;
}
protected override string AddFromTorrentFile(RemoteMovie remoteEpisode, string hash, string filename, Byte[] fileContent)
protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, Byte[] fileContent)
{
_proxy.AddTorrentFromFile(filename, fileContent, Settings);
if (Settings.TvCategory.IsNotNullOrWhiteSpace())
if (Settings.MovieCategory.IsNotNullOrWhiteSpace())
{
_proxy.SetTorrentLabel(hash.ToLower(), Settings.TvCategory, Settings);
_proxy.SetTorrentLabel(hash.ToLower(), Settings.MovieCategory, Settings);
}
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)QBittorrentPriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)QBittorrentPriority.First)
{
_proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
}*/
return hash;
}
@ -236,7 +190,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
else if (version < 6)
{
// API version 6 introduced support for labels
if (Settings.TvCategory.IsNotNullOrWhiteSpace())
if (Settings.MovieCategory.IsNotNullOrWhiteSpace())
{
return new NzbDroneValidationFailure("Category", "Category is not supported")
{
@ -244,7 +198,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
};
}
}
else if (Settings.TvCategory.IsNullOrWhiteSpace())
else if (Settings.MovieCategory.IsNullOrWhiteSpace())
{
// warn if labels are supported, but category is not provided
return new NzbDroneValidationFailure("TvCategory", "Category is recommended")

@ -58,8 +58,8 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
public List<QBittorrentTorrent> GetTorrents(QBittorrentSettings settings)
{
var request = BuildRequest(settings).Resource("/query/torrents")
.AddQueryParam("label", settings.TvCategory)
.AddQueryParam("category", settings.TvCategory);
.AddQueryParam("label", settings.MovieCategory)
.AddQueryParam("category", settings.MovieCategory);
var response = ProcessRequest<List<QBittorrentTorrent>>(request, settings);

@ -22,7 +22,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
{
Host = "localhost";
Port = 9091;
TvCategory = "movie-radarr";
MovieCategory = "movie-radarr";
}
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]
@ -38,16 +38,9 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
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; }
//Todo: update this shit.
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(QBittorrentPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]
public int RecentTvPriority { get; set; }
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(QBittorrentPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")]
public int OlderTvPriority { get; set; }
[FieldDefinition(7, 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 = "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()

@ -30,13 +30,13 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
}
// patch can be a number (releases) or 'x' (git)
private static readonly Regex VersionRegex = new Regex(@"(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+|x)(?<candidate>.*)", RegexOptions.Compiled);
private static readonly Regex VersionRegex = new Regex(@"(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+|x)", RegexOptions.Compiled);
protected override string AddFromNzbFile(RemoteEpisode remoteEpisode, string filename, byte[] fileContents)
{
var category = Settings.TvCategory;
var priority = remoteEpisode.IsRecentEpisode() ? Settings.RecentTvPriority : Settings.OlderTvPriority;
var response = _proxy.DownloadNzb(fileContents, filename, category, priority, Settings);
if (response != null && response.Ids.Any())
@ -284,110 +284,103 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
failures.AddIfNotNull(TestCategory());
}
private bool HasVersion(int major, int minor, int patch = 0, string candidate = null)
private bool HasVersion(int major, int minor, int patch = 0)
{
candidate = candidate ?? string.Empty;
var version = _proxy.GetVersion(Settings);
var parsed = VersionRegex.Match(version);
var rawVersion = _proxy.GetVersion(Settings);
var version = ParseVersion(rawVersion);
int actualMajor;
int actualMinor;
int actualPatch;
string actualCandidate;
if (!parsed.Success)
if (version == null)
{
if (!version.Equals("develop", StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
actualMajor = 1;
actualMinor = 1;
actualPatch = 0;
actualCandidate = null;
}
else
{
actualMajor = Convert.ToInt32(parsed.Groups["major"].Value);
actualMinor = Convert.ToInt32(parsed.Groups["minor"].Value);
actualPatch = Convert.ToInt32(parsed.Groups["patch"].Value.Replace("x", ""));
actualCandidate = parsed.Groups["candidate"].Value.ToUpper();
return false;
}
if (actualMajor > major)
if (version.Major > major)
{
return true;
}
else if (actualMajor < major)
else if (version.Major < major)
{
return false;
}
if (actualMinor > minor)
if (version.Minor > minor)
{
return true;
}
else if (actualMinor < minor)
else if (version.Minor < minor)
{
return false;
}
if (actualPatch > patch)
if (version.Build > patch)
{
return true;
}
else if (actualPatch < patch)
else if (version.Build < patch)
{
return false;
}
if (actualCandidate.IsNullOrWhiteSpace())
{
return true;
}
else if (candidate.IsNullOrWhiteSpace())
return true;
}
private Version ParseVersion(string version)
{
var parsed = VersionRegex.Match(version);
int major;
int minor;
int patch;
if (parsed.Success)
{
return false;
major = Convert.ToInt32(parsed.Groups["major"].Value);
minor = Convert.ToInt32(parsed.Groups["minor"].Value);
patch = Convert.ToInt32(parsed.Groups["patch"].Value.Replace("x", "0"));
}
else
{
return actualCandidate.CompareTo(candidate) > 0;
if (!version.Equals("develop", StringComparison.InvariantCultureIgnoreCase))
{
return null;
}
major = 1;
minor = 1;
patch = 0;
}
return new Version(major, minor, patch);
}
private ValidationFailure TestConnectionAndVersion()
{
try
{
var version = _proxy.GetVersion(Settings);
var parsed = VersionRegex.Match(version);
var rawVersion = _proxy.GetVersion(Settings);
var version = ParseVersion(rawVersion);
if (!parsed.Success)
if (version == null)
{
if (version.Equals("develop", StringComparison.InvariantCultureIgnoreCase))
{
return new NzbDroneValidationFailure("Version", "Sabnzbd develop version, assuming version 1.1.0 or higher.")
{
IsWarning = true,
DetailedDescription = "Sonarr may not be able to support new features added to SABnzbd when running develop versions."
};
}
return new ValidationFailure("Version", "Unknown Version: " + version);
}
var major = Convert.ToInt32(parsed.Groups["major"].Value);
var minor = Convert.ToInt32(parsed.Groups["minor"].Value);
if (rawVersion.Equals("develop", StringComparison.InvariantCultureIgnoreCase))
{
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."
};
}
if (major >= 1)
if (version.Major >= 1)
{
return null;
}
if (minor >= 7)
if (version.Minor >= 7)
{
return null;
}
@ -431,7 +424,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("", "Disable 'Check before download' option in Sabnbzd")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/switches/", Settings.Host, Settings.Port),
DetailedDescription = "Using Check before download affects Sonarr 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."
};
}
@ -450,7 +443,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("TvCategory", "Enable Job folders")
{
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port),
DetailedDescription = "Sonarr 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."
};
}
}
@ -475,7 +468,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("TvCategory", "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 Sonarr 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."
};
}
}
@ -489,7 +482,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("TvCategory", "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 Sonarr 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."
};
}
}
@ -503,7 +496,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
return new NzbDroneValidationFailure("TvCategory", "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 Sonarr 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."
};
}
}

@ -58,7 +58,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
[FieldDefinition(4, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")]
[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; }
[FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]

@ -54,21 +54,21 @@ namespace NzbDrone.Core.Download.Clients.Transmission
var outputPath = new OsPath(torrent.DownloadDir);
if (Settings.TvDirectory.IsNotNullOrWhiteSpace())
if (Settings.MovieDirectory.IsNotNullOrWhiteSpace())
{
if (!new OsPath(Settings.TvDirectory).Contains(outputPath)) continue;
if (!new OsPath(Settings.MovieDirectory).Contains(outputPath)) continue;
}
else if (Settings.TvCategory.IsNotNullOrWhiteSpace())
else if (Settings.MovieCategory.IsNotNullOrWhiteSpace())
{
var directories = outputPath.FullPath.Split('\\', '/');
if (!directories.Contains(Settings.TvCategory)) continue;
if (!directories.Contains(Settings.MovieCategory)) continue;
}
outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, outputPath);
var item = new DownloadClientItem();
item.DownloadId = torrent.HashString.ToUpper();
item.Category = Settings.TvCategory;
item.Category = Settings.MovieCategory;
item.Title = torrent.Name;
item.DownloadClient = Definition.Name;
@ -123,9 +123,9 @@ namespace NzbDrone.Core.Download.Clients.Transmission
var config = _proxy.GetConfig(Settings);
var destDir = config.GetValueOrDefault("download-dir") as string;
if (Settings.TvCategory.IsNotNullOrWhiteSpace())
if (Settings.MovieCategory.IsNotNullOrWhiteSpace())
{
destDir = string.Format("{0}/.{1}", destDir, Settings.TvCategory);
destDir = string.Format("{0}/.{1}", destDir, Settings.MovieCategory);
}
return new DownloadClientStatus
@ -137,56 +137,23 @@ namespace NzbDrone.Core.Download.Clients.Transmission
protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink)
{
_proxy.AddTorrentFromUrl(magnetLink, GetDownloadDirectory(), Settings);
var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)TransmissionPriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)TransmissionPriority.First)
{
_proxy.MoveTorrentToTopInQueue(hash, Settings);
}
return hash;
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent)
{
_proxy.AddTorrentFromData(fileContent, GetDownloadDirectory(), Settings);
var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)TransmissionPriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)TransmissionPriority.First)
{
_proxy.MoveTorrentToTopInQueue(hash, Settings);
}
return hash;
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
{
_proxy.AddTorrentFromUrl(magnetLink, GetDownloadDirectory(), Settings);
if (remoteMovie.Release.Age < 14 && Settings.RecentTvPriority == (int)TransmissionPriority.First ||
remoteMovie.Release.Age > 14 && Settings.OlderTvPriority == (int)TransmissionPriority.First)
{
_proxy.MoveTorrentToTopInQueue(hash, Settings);
}
return hash;
}
protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, byte[] fileContent)
{
_proxy.AddTorrentFromData(fileContent, GetDownloadDirectory(), Settings);
if (remoteMovie.Release.Age < 14 && Settings.RecentTvPriority == (int)TransmissionPriority.First ||
remoteMovie.Release.Age > 14 && Settings.OlderTvPriority == (int)TransmissionPriority.First)
{
_proxy.MoveTorrentToTopInQueue(hash, Settings);
}
return hash;
}
@ -204,16 +171,16 @@ namespace NzbDrone.Core.Download.Clients.Transmission
protected string GetDownloadDirectory()
{
if (Settings.TvDirectory.IsNotNullOrWhiteSpace())
if (Settings.MovieDirectory.IsNotNullOrWhiteSpace())
{
return Settings.TvDirectory;
return Settings.MovieDirectory;
}
else if (Settings.TvCategory.IsNotNullOrWhiteSpace())
else if (Settings.MovieCategory.IsNotNullOrWhiteSpace())
{
var config = _proxy.GetConfig(Settings);
var destDir = (string)config.GetValueOrDefault("download-dir");
return string.Format("{0}/{1}", destDir.TrimEnd('/'), Settings.TvCategory);
return string.Format("{0}/{1}", destDir.TrimEnd('/'), Settings.MovieCategory);
}
else
{
@ -232,7 +199,7 @@ namespace NzbDrone.Core.Download.Clients.Transmission
_logger.Error(ex, ex.Message);
return new NzbDroneValidationFailure("Username", "Authentication failure")
{
DetailedDescription = string.Format("Please verify your username and password. Also verify if the host running Sonarr isn't blocked from accessing {0} by WhiteList limitations in the {0} configuration.", Name)
DetailedDescription = string.Format("Please verify your username and password. Also verify if the host running Radarr isn't blocked from accessing {0} by WhiteList limitations in the {0} configuration.", Name)
};
}
catch (WebException ex)

@ -16,10 +16,10 @@ namespace NzbDrone.Core.Download.Clients.Transmission
RuleFor(c => c.UrlBase).ValidUrlBase();
RuleFor(c => c.TvCategory).Matches(@"^\.?[-a-z]*$", RegexOptions.IgnoreCase).WithMessage("Allowed characters a-z and -");
RuleFor(c => c.MovieCategory).Matches(@"^\.?[-a-z]*$", RegexOptions.IgnoreCase).WithMessage("Allowed characters a-z and -");
RuleFor(c => c.TvCategory).Empty()
.When(c => c.TvDirectory.IsNotNullOrWhiteSpace())
RuleFor(c => c.MovieCategory).Empty()
.When(c => c.MovieDirectory.IsNotNullOrWhiteSpace())
.WithMessage("Cannot use Category and Directory");
}
}
@ -50,19 +50,13 @@ namespace NzbDrone.Core.Download.Clients.Transmission
[FieldDefinition(4, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional. Creates a [category] subdirectory in the output directory.")]
public string TvCategory { 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. Creates a [category] subdirectory in the output directory.")]
public string MovieCategory { get; set; }
[FieldDefinition(6, Label = "Directory", Type = FieldType.Textbox, Advanced = true, HelpText = "Optional location to put downloads in, leave blank to use the default Transmission location")]
public string TvDirectory { get; set; }
public string MovieDirectory { get; set; }
[FieldDefinition(7, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(TransmissionPriority), HelpText = "Priority to use when grabbing movies that we're released within the last 14 days")]
public int RecentTvPriority { get; set; }
[FieldDefinition(8, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(TransmissionPriority), HelpText = "Priority to use when grabbing movies that we're released over 14 days ago")]
public int OlderTvPriority { get; set; }
[FieldDefinition(9, Label = "Use SSL", Type = FieldType.Checkbox)]
[FieldDefinition(7, Label = "Use SSL", Type = FieldType.Checkbox)]
public bool UseSsl { get; set; }
public NzbDroneValidationResult Validate()

@ -37,51 +37,23 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
_rTorrentDirectoryValidator = rTorrentDirectoryValidator;
}
protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink)
{
_proxy.AddTorrentFromUrl(magnetLink, Settings);
// Download the magnet to the appropriate directory.
_proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings);
//SetPriority(remoteEpisode, hash);
SetDownloadDirectory(hash);
// Once the magnet meta download finishes, rTorrent replaces it with the actual torrent download with default settings.
// Schedule an event to apply the appropriate settings when that happens.
// var priority = (RTorrentPriority)(remoteEpisode.IsRecentEpisode() ? Settings.RecentTvPriority : Settings.OlderTvPriority);
//_proxy.SetDeferredMagnetProperties(hash, Settings.TvCategory, Settings.TvDirectory, priority, Settings);
_proxy.StartTorrent(hash, Settings);
// Wait for the magnet to be resolved.
var tries = 10;
var retryDelay = 500;
if (WaitForTorrent(hash, tries, retryDelay))
{
return hash;
}
else
{
_logger.Warn("rTorrent could not resolve magnet within {0} seconds, download may remain stuck: {1}.", tries * retryDelay / 1000, magnetLink);
throw new NotImplementedException("Episodes are not working with Radarr");
}
return hash;
}
protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent)
{
throw new NotImplementedException("Episodes are not working with Radarr");
}
protected override string AddFromMagnetLink(RemoteEpisode remoteEpisode, string hash, string magnetLink)
protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
{
_proxy.AddTorrentFromUrl(magnetLink, Settings);
// Download the magnet to the appropriate directory.
_proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings);
SetPriority(remoteEpisode, hash);
_proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
SetDownloadDirectory(hash);
// Once the magnet meta download finishes, rTorrent replaces it with the actual torrent download with default settings.
// Schedule an event to apply the appropriate settings when that happens.
var priority = (RTorrentPriority)(remoteEpisode.IsRecentEpisode() ? Settings.RecentTvPriority : Settings.OlderTvPriority);
_proxy.SetDeferredMagnetProperties(hash, Settings.TvCategory, Settings.TvDirectory, priority, Settings);
_proxy.StartTorrent(hash, Settings);
// Wait for the magnet to be resolved.
@ -107,13 +79,9 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
var retryDelay = 100;
if (WaitForTorrent(hash, tries, retryDelay))
{
_proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings);
//SetPriority(remoteEpisode, hash);
_proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
SetDownloadDirectory(hash);
_proxy.StartTorrent(hash, Settings);
return hash;
}
else
@ -125,32 +93,6 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
}
}
protected override string AddFromTorrentFile(RemoteEpisode remoteEpisode, string hash, string filename, byte[] fileContent)
{
_proxy.AddTorrentFromFile(filename, fileContent, Settings);
var tries = 2;
var retryDelay = 100;
if (WaitForTorrent(hash, tries, retryDelay))
{
_proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings);
SetPriority(remoteEpisode, hash);
SetDownloadDirectory(hash);
_proxy.StartTorrent(hash, Settings);
return hash;
}
else
{
_logger.Debug("rTorrent could not add file");
RemoveItem(hash, true);
throw new ReleaseDownloadException(remoteEpisode.Release, "Downloading torrent failed");
}
}
public override string Name => "rTorrent";
public override ProviderMessage Message => new ProviderMessage("Radarr is unable to remove torrents that have finished seeding when using rTorrent", ProviderMessageType.Warning);
@ -167,7 +109,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
foreach (RTorrentTorrent torrent in torrents)
{
// Don't concern ourselves with categories other than specified
if (torrent.Category != Settings.TvCategory) continue;
if (torrent.Category != Settings.MovieCategory) continue;
if (torrent.Path.StartsWith("."))
{
@ -287,17 +229,11 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
return result.Errors.First();
}
private void SetPriority(RemoteEpisode remoteEpisode, string hash)
{
var priority = (RTorrentPriority)(remoteEpisode.IsRecentEpisode() ? Settings.RecentTvPriority : Settings.OlderTvPriority);
_proxy.SetTorrentPriority(hash, priority, Settings);
}
private void SetDownloadDirectory(string hash)
{
if (Settings.TvDirectory.IsNotNullOrWhiteSpace())
if (Settings.MovieDirectory.IsNotNullOrWhiteSpace())
{
_proxy.SetTorrentDownloadDirectory(hash, Settings.TvDirectory, Settings);
_proxy.SetTorrentDownloadDirectory(hash, Settings.MovieDirectory, Settings);
}
}

@ -18,13 +18,13 @@ namespace NzbDrone.Core.Download.Clients.rTorrent
DroneFactoryValidator droneFactoryValidator,
MappedNetworkDriveValidator mappedNetworkDriveValidator)
{
RuleFor(c => c.TvDirectory).Cascade(CascadeMode.StopOnFirstFailure)
RuleFor(c => c.MovieDirectory).Cascade(CascadeMode.StopOnFirstFailure)
.IsValidPath()
.SetValidator(rootFolderValidator)
.SetValidator(droneFactoryValidator)
.SetValidator(mappedNetworkDriveValidator)
.SetValidator(pathExistsValidator)
.When(c => c.TvDirectory.IsNotNullOrWhiteSpace())
.When(c => c.MovieDirectory.IsNotNullOrWhiteSpace())
.When(c => c.Host == "localhost" || c.Host == "127.0.0.1");
}
}

@ -11,7 +11,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
{
RuleFor(c => c.Host).ValidHost();
RuleFor(c => c.Port).InclusiveBetween(0, 65535);
RuleFor(c => c.TvCategory).NotEmpty()
RuleFor(c => c.MovieCategory).NotEmpty()
.WithMessage("A category is recommended")
.AsWarning();
}
@ -26,9 +26,7 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
Host = "localhost";
Port = 8080;
UrlBase = "RPC2";
TvCategory = "movies-radarr";
OlderTvPriority = (int)RTorrentPriority.Normal;
RecentTvPriority = (int)RTorrentPriority.Normal;
MovieCategory = "movies-radarr";
}
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]
@ -49,17 +47,11 @@ namespace NzbDrone.Core.Download.Clients.RTorrent
[FieldDefinition(5, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(6, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional.")]
public string TvCategory { get; set; }
[FieldDefinition(6, 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(7, Label = "Directory", Type = FieldType.Textbox, Advanced = true, HelpText = "Optional location to put downloads in, leave blank to use the default rTorrent location")]
public string TvDirectory { get; set; }
[FieldDefinition(8, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(RTorrentPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]
public int RecentTvPriority { get; set; }
[FieldDefinition(9, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(RTorrentPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")]
public int OlderTvPriority { get; set; }
public string MovieDirectory { get; set; }
public NzbDroneValidationResult Validate()
{

@ -68,6 +68,38 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
return hash;
}
protected override string AddFromMagnetLink(RemoteMovie remoteEpisode, string hash, string magnetLink)
{
_proxy.AddTorrentFromUrl(magnetLink, Settings);
_proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings);
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)UTorrentPriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)UTorrentPriority.First)
{
_proxy.MoveTorrentToTopInQueue(hash, Settings);
}*/
return hash;
}
protected override string AddFromTorrentFile(RemoteMovie remoteEpisode, string hash, string filename, byte[] fileContent)
{
_proxy.AddTorrentFromFile(filename, fileContent, Settings);
_proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings);
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
if (isRecentEpisode && Settings.RecentTvPriority == (int)UTorrentPriority.First ||
!isRecentEpisode && Settings.OlderTvPriority == (int)UTorrentPriority.First)
{
_proxy.MoveTorrentToTopInQueue(hash, Settings);
}*/
return hash;
}
public override string Name => "uTorrent";
public override IEnumerable<DownloadClientItem> GetItems()

@ -38,7 +38,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
[FieldDefinition(3, Label = "Password", Type = FieldType.Password)]
public string Password { get; set; }
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional")]
[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; }
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")]

@ -94,30 +94,18 @@ namespace NzbDrone.Core.Download
return;
}
var series = _parsingService.GetSeries(trackedDownload.DownloadItem.Title);
if (series == null)
var movie = _parsingService.GetMovie(trackedDownload.DownloadItem.Title);
if (movie == null)
{
if (historyItem != null)
{
//series = _seriesService.GetSeries(historyItem.SeriesId);
movie = _movieService.GetMovie(historyItem.MovieId);
}
if (series == null)
if (movie == null)
{
var movie = _parsingService.GetMovie(trackedDownload.DownloadItem.Title);
if (movie == null)
{
movie = _movieService.GetMovie(historyItem.MovieId);
if (movie == null)
{
trackedDownload.Warn("Movie title mismatch, automatic import is not possible.");
}
}
//trackedDownload.Warn("Series title mismatch, automatic import is not possible.");
//return;
trackedDownload.Warn("Movie title mismatch, automatic import is not possible.");
return;
}
}
}
@ -128,61 +116,30 @@ namespace NzbDrone.Core.Download
private void Import(TrackedDownload trackedDownload)
{
var outputPath = trackedDownload.DownloadItem.OutputPath.FullPath;
if (trackedDownload.RemoteMovie.Movie != null)
{
var importResults = _downloadedMovieImportService.ProcessPath(outputPath, ImportMode.Auto, trackedDownload.RemoteMovie.Movie, trackedDownload.DownloadItem);
if (importResults.Empty())
{
trackedDownload.Warn("No files found are eligible for import in {0}", outputPath);
return;
}
var importResults = _downloadedMovieImportService.ProcessPath(outputPath, ImportMode.Auto, trackedDownload.RemoteMovie.Movie, trackedDownload.DownloadItem);
if (importResults.Count(c => c.Result == ImportResultType.Imported) >= 1)
{
trackedDownload.State = TrackedDownloadStage.Imported;
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
return;
}
if (importResults.Any(c => c.Result != ImportResultType.Imported))
{
var statusMessages = importResults
.Where(v => v.Result != ImportResultType.Imported)
.Select(v => new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.LocalEpisode.Path), v.Errors))
.ToArray();
trackedDownload.Warn(statusMessages);
}
}
else if (trackedDownload.RemoteEpisode.Series != null)
if (importResults.Empty())
{
var importResults = _downloadedEpisodesImportService.ProcessPath(outputPath, ImportMode.Auto, trackedDownload.RemoteEpisode.Series, trackedDownload.DownloadItem);
if (importResults.Empty())
{
trackedDownload.Warn("No files found are eligible for import in {0}", outputPath);
return;
}
trackedDownload.Warn("No files found are eligible for import in {0}", outputPath);
return;
}
if (importResults.Count(c => c.Result == ImportResultType.Imported) >= Math.Max(1, trackedDownload.RemoteEpisode.Episodes.Count))
{
trackedDownload.State = TrackedDownloadStage.Imported;
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
return;
}
if (importResults.Count(c => c.Result == ImportResultType.Imported) >= 1)
{
trackedDownload.State = TrackedDownloadStage.Imported;
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
return;
}
if (importResults.Any(c => c.Result != ImportResultType.Imported))
{
var statusMessages = importResults
.Where(v => v.Result != ImportResultType.Imported)
.Select(v => new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.LocalEpisode.Path), v.Errors))
.ToArray();
if (importResults.Any(c => c.Result != ImportResultType.Imported))
{
var statusMessages = importResults
.Where(v => v.Result != ImportResultType.Imported)
.Select(v => new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.LocalMovie.Path), v.Errors))
.ToArray();
trackedDownload.Warn(statusMessages);
}
trackedDownload.Warn(statusMessages);
}
}
}
}

@ -72,7 +72,7 @@ namespace NzbDrone.Core.Download
if (grabbedItems.Empty())
{
trackedDownload.Warn("Download wasn't grabbed by sonarr, skipping");
trackedDownload.Warn("Download wasn't grabbed by Radarr, skipping");
return;
}

@ -13,8 +13,9 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
public void Clean()
{
CleanupOrphanedBySeries();
CleanupOrphanedByEpisode();
//CleanupOrphanedBySeries();
//CleanupOrphanedByEpisode();
CleanupOrphanedByMovie();
}
private void CleanupOrphanedBySeries()
@ -29,6 +30,18 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
WHERE Series.Id IS NULL)");
}
private void CleanupOrphanedByMovie()
{
var mapper = _database.GetDataMapper();
mapper.ExecuteNonQuery(@"DELETE FROM History
WHERE Id IN (
SELECT History.Id FROM History
LEFT OUTER JOIN Movies
ON History.MovieId = Movies.Id
WHERE Movies.Id IS NULL)");
}
private void CleanupOrphanedByEpisode()
{
var mapper = _database.GetDataMapper();

@ -0,0 +1,30 @@
using NLog;
using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Parser;
namespace NzbDrone.Core.Indexers.AwesomeHD
{
public class AwesomeHD : HttpIndexerBase<AwesomeHDSettings>
{
public override string Name => "AwesomeHD";
public override DownloadProtocol Protocol => DownloadProtocol.Torrent;
public override bool SupportsRss => true;
public override bool SupportsSearch => true;
public override int PageSize => 50;
public AwesomeHD(IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
: base(httpClient, indexerStatusService, configService, parsingService, logger)
{ }
public override IIndexerRequestGenerator GetRequestGenerator()
{
return new AwesomeHDRequestGenerator() { Settings = Settings };
}
public override IParseIndexerResponse GetParser()
{
return new AwesomeHDRssParser(Settings);
}
}
}

@ -0,0 +1,80 @@
using System;
using Newtonsoft.Json;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace NzbDrone.Core.Indexers.AwesomeHD
{
public class Torrent
{
[XmlElement(ElementName = "id")]
public string Id { get; set; }
[XmlElement(ElementName = "groupid")]
public string GroupId { get; set; }
[XmlElement(ElementName = "time")]
public DateTime Time { get; set; }
[XmlElement(ElementName = "userid")]
public string Userid { get; set; }
[XmlElement(ElementName = "size")]
public long Size { get; set; }
[XmlElement(ElementName = "snatched")]
public string Snatched { get; set; }
[XmlElement(ElementName = "seeders")]
public string Seeders { get; set; }
[XmlElement(ElementName = "leechers")]
public string Leechers { get; set; }
[XmlElement(ElementName = "releasegroup")]
public string Releasegroup { get; set; }
[XmlElement(ElementName = "resolution")]
public string Resolution { get; set; }
[XmlElement(ElementName = "media")]
public string Media { get; set; }
[XmlElement(ElementName = "format")]
public string Format { get; set; }
[XmlElement(ElementName = "encoding")]
public string Encoding { get; set; }
[XmlElement(ElementName = "audioformat")]
public string Audioformat { get; set; }
[XmlElement(ElementName = "audiobitrate")]
public string Audiobitrate { get; set; }
[XmlElement(ElementName = "audiochannels")]
public string Audiochannels { get; set; }
[XmlElement(ElementName = "subtitles")]
public string Subtitles { get; set; }
[XmlElement(ElementName = "encodestatus")]
public string Encodestatus { get; set; }
[XmlElement(ElementName = "freeleech")]
public string Freeleech { get; set; }
[XmlElement(ElementName = "cover")]
public string Cover { get; set; }
[XmlElement(ElementName = "smallcover")]
public string Smallcover { get; set; }
[XmlElement(ElementName = "year")]
public string Year { get; set; }
[XmlElement(ElementName = "name")]
public string Name { get; set; }
[XmlElement(ElementName = "imdb")]
public string Imdb { get; set; }
[XmlElement(ElementName = "type")]
public string Type { get; set; }
[XmlElement(ElementName = "plotoutline")]
public string Plotoutline { get; set; }
}
public class SearchResults
{
[XmlElement(ElementName = "authkey")]
public string AuthKey { get; set; }
[XmlElement(ElementName = "torrent")]
public List<Torrent> Torrent { get; set; }
}
public class AwesomeHDSearchResponse
{
[XmlElement(ElementName = "?xml")]
public string Xml { get; set; }
[XmlElement(ElementName = "searchresults")]
public SearchResults SearchResults { get; set; }
}
}

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.IndexerSearch.Definitions;
namespace NzbDrone.Core.Indexers.AwesomeHD
{
public class AwesomeHDRequestGenerator : IIndexerRequestGenerator
{
public AwesomeHDSettings Settings { get; set; }
public virtual IndexerPageableRequestChain GetRecentRequests()
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetRequest(null));
return pageableRequests;
}
public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria)
{
return new IndexerPageableRequestChain();
}
public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria)
{
var pageableRequests = new IndexerPageableRequestChain();
pageableRequests.Add(GetRequest(searchCriteria.Movie.ImdbId));
return pageableRequests;
}
private IEnumerable<IndexerRequest> GetRequest(string searchParameters)
{
if (searchParameters != null)
{
yield return new IndexerRequest(string.Format("{0}/searchapi.php?action=imdbsearch&passkey={1}&imdb={2}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.Passkey.Trim(), searchParameters), HttpAccept.Rss);
}
else
{
yield return new IndexerRequest(string.Format("{0}/searchapi.php?action=latestmovies&passkey={1}", Settings.BaseUrl.Trim().TrimEnd('/'), Settings.Passkey.Trim()), HttpAccept.Rss);
}
}
}
}

@ -0,0 +1,92 @@
using System.Collections.Generic;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NzbDrone.Common.Http;
using NzbDrone.Core.Indexers.Exceptions;
using NzbDrone.Core.Parser.Model;
using System;
using System.Linq;
using System.Xml;
namespace NzbDrone.Core.Indexers.AwesomeHD
{
public class AwesomeHDRssParser : IParseIndexerResponse
{
private readonly AwesomeHDSettings _settings;
public AwesomeHDRssParser(AwesomeHDSettings settings)
{
_settings = settings;
}
public IList<ReleaseInfo> ParseResponse(IndexerResponse indexerResponse)
{
var torrentInfos = new List<ReleaseInfo>();
if (indexerResponse.HttpResponse.StatusCode != HttpStatusCode.OK)
{
throw new IndexerException(indexerResponse,
"Unexpected response status {0} code from API request",
indexerResponse.HttpResponse.StatusCode);
}
// Hacky ¯\_(ツ)_/¯
XmlDocument doc = new XmlDocument();
doc.LoadXml(indexerResponse.Content);
var json = JsonConvert.SerializeXmlNode(doc);
Console.WriteLine(json);
var jsonResponse = JsonConvert.DeserializeObject<AwesomeHDSearchResponse>(json);
if (jsonResponse == null)
{
throw new IndexerException(indexerResponse, "Unexpected response from request");
}
foreach (var torrent in jsonResponse.SearchResults.Torrent)
{
var id = torrent.Id;
var title = $"{torrent.Name}.{torrent.Year}.{torrent.Resolution}.{torrent.Media}.{torrent.Encoding}.{torrent.Audioformat}-{torrent.Releasegroup}";
torrentInfos.Add(new TorrentInfo()
{
Guid = string.Format("AwesomeHD-{0}", id),
Title = title,
Size = torrent.Size,
DownloadUrl = GetDownloadUrl(id, jsonResponse.SearchResults.AuthKey, _settings.Passkey),
InfoUrl = GetInfoUrl(torrent.GroupId, id),
Seeders = int.Parse(torrent.Seeders),
Peers = int.Parse(torrent.Leechers) + int.Parse(torrent.Seeders),
PublishDate = torrent.Time.ToUniversalTime()
});
}
return torrentInfos.OrderByDescending(o => ((dynamic)o).Seeders).ToArray();
}
private string GetDownloadUrl(string torrentId, string authKey, string passKey)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/torrents.php")
.AddQueryParam("action", "download")
.AddQueryParam("id", torrentId)
.AddQueryParam("authkey", authKey)
.AddQueryParam("torrent_pass", passKey);
return url.FullUri;
}
private string GetInfoUrl(string groupId, string torrentId)
{
var url = new HttpUri(_settings.BaseUrl)
.CombinePath("/torrents.php")
.AddQueryParam("id", groupId)
.AddQueryParam("torrentid", torrentId);
return url.FullUri;
}
}
}

@ -0,0 +1,37 @@
using FluentValidation;
using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Indexers.AwesomeHD
{
public class AwesomeHDSettingsValidator : AbstractValidator<AwesomeHDSettings>
{
public AwesomeHDSettingsValidator()
{
RuleFor(c => c.BaseUrl).ValidRootUrl();
RuleFor(c => c.Passkey).NotEmpty();
}
}
public class AwesomeHDSettings : IProviderConfig
{
private static readonly AwesomeHDSettingsValidator Validator = new AwesomeHDSettingsValidator();
public AwesomeHDSettings()
{
BaseUrl = "https://awesome-hd.me";
}
[FieldDefinition(0, Label = "API URL", Advanced = true, HelpText = "Do not change this unless you know what you're doing. Since you Passkey will be sent to that host.")]
public string BaseUrl { get; set; }
[FieldDefinition(1, Label = "Passkey")]
public string Passkey { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));
}
}
}

@ -39,14 +39,15 @@ namespace NzbDrone.Core.Indexers.Newznab
{
get
{
yield return GetDefinition("Dognzb.cr", GetSettings("https://api.dognzb.cr"));
yield return GetDefinition("DOGnzb", GetSettings("https://api.dognzb.cr"));
yield return GetDefinition("DrunkenSlug", GetSettings("https://api.drunkenslug.com"));
yield return GetDefinition("Nzb-Tortuga", GetSettings("https://www.nzb-tortuga.com"));
yield return GetDefinition("Nzb.su", GetSettings("https://api.nzb.su"));
yield return GetDefinition("NZBCat", GetSettings("https://nzb.cat"));
yield return GetDefinition("NZBFinder.ws", GetSettings("https://nzbfinder.ws", 5010, 5030, 5040, 5045));
yield return GetDefinition("NZBFinder.ws", GetSettings("https://nzbfinder.ws"));
yield return GetDefinition("NZBgeek", GetSettings("https://api.nzbgeek.info"));
yield return GetDefinition("nzbplanet.net", GetSettings("https://api.nzbplanet.net"));
yield return GetDefinition("Nzbs.org", GetSettings("http://nzbs.org", 2000));
yield return GetDefinition("Nzbs.org", GetSettings("http://nzbs.org"));
yield return GetDefinition("OZnzb.com", GetSettings("https://api.oznzb.com"));
yield return GetDefinition("PFmonkey", GetSettings("https://www.pfmonkey.com"));
yield return GetDefinition("SimplyNZBs", GetSettings("https://simplynzbs.com"));

@ -124,7 +124,7 @@ namespace NzbDrone.Core.Indexers.Newznab
{
var pageableRequests = new IndexerPageableRequestChain();
if (SupportsMovieSearch)
if (false)
{
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "movie",
string.Format("&imdbid={0}", searchCriteria.Movie.ImdbId.Substring(2)))); //strip off the "tt" - VERY HACKY
@ -133,7 +133,7 @@ namespace NzbDrone.Core.Indexers.Newznab
{
//Let's try anyways with q parameter, worst case nothing found.
pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "search",
string.Format("&q={0}", searchCriteria.Movie.Title)));
string.Format("&q={0}", Parser.Parser.NormalizeTitle(searchCriteria.Movie.Title))));
}
return pageableRequests;

@ -60,7 +60,7 @@ namespace NzbDrone.Core.Indexers.Newznab
public NewznabSettings()
{
Categories = new[] { 2030, 2035, 2040, 2050 };
Categories = new[] { 2000, 2010, 2020, 2030, 2035, 2040, 2045, 2050, 2060 };
AnimeCategories = Enumerable.Empty<int>();
}

@ -29,7 +29,7 @@ namespace NzbDrone.Core.Indexers.Omgwtfnzbs
protected override string GetInfoUrl(XElement item)
{
//Todo: Me thinks I need to parse details to get this...
var match = Regex.Match(item.Description(), @"(?:\<b\>View NZB\:\<\/b\>\s\<a\shref\=\"")(?<URL>.+)(?:\""\starget)",
var match = Regex.Match(item.Description(), @"(?:\<b\>View NZB\:\<\/b\>\s\<a\shref\=\"")(?<URL>.+)(?:\"")",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
if (match.Success)

@ -40,6 +40,7 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
torrentInfo.Seeders = torrent.seeders;
torrentInfo.Peers = torrent.leechers + torrent.seeders;
torrentInfo.Freeleech = torrent.freeleech;
torrentInfo.PublishDate = torrent.publishdate.ToUniversalTime();
results.Add(torrentInfo);
}

@ -78,9 +78,16 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
.Accept(HttpAccept.Json);
requestBuilder.AddQueryParam("passkey", Settings.Passkey);
requestBuilder.AddQueryParam("user", Settings.User);
// requestBuilder.AddQueryParam("imdbid", "tt0076759"); //For now just search for Star Wars.
requestBuilder.AddQueryParam("search", "the"); // there has to be movies with 'the' in the title on any indexer
if (!string.IsNullOrWhiteSpace(Settings.User))
{
requestBuilder.AddQueryParam("user", Settings.User);
}
else
{
requestBuilder.AddQueryParam("user", "");
}
requestBuilder.AddQueryParam("search", "the");
yield return new IndexerRequest(requestBuilder.Build());
}
@ -91,7 +98,15 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
.Accept(HttpAccept.Json);
requestBuilder.AddQueryParam("passkey", Settings.Passkey);
requestBuilder.AddQueryParam("user", Settings.User);
if (!string.IsNullOrWhiteSpace(Settings.User))
{
requestBuilder.AddQueryParam("user", Settings.User);
}
else
{
requestBuilder.AddQueryParam("user", "");
}
if (searchCriteria.Movie.ImdbId.IsNotNullOrWhiteSpace())
{

@ -21,6 +21,7 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
public int size { get; set; }
public int leechers { get; set; }
public int seeders { get; set; }
public DateTime publishdate { get; set; }
}
}

@ -19,7 +19,7 @@ namespace NzbDrone.Core.Indexers.TorrentPotato
public TorrentPotatoSettings()
{
BaseUrl = "";
BaseUrl = "http://127.0.0.1";
}
[FieldDefinition(0, Label = "API URL", HelpText = "URL to TorrentPotato api.")]

@ -97,8 +97,7 @@ namespace NzbDrone.Core.Indexers.Torznab
}
if (capabilities.SupportedTvSearchParameters != null &&
new[] { "q", "tvdbid", "rid" }.Any(v => capabilities.SupportedTvSearchParameters.Contains(v)) &&
new[] { "season", "ep" }.All(v => capabilities.SupportedTvSearchParameters.Contains(v)))
new[] { "q", "imdbid" }.Any(v => capabilities.SupportedTvSearchParameters.Contains(v)))
{
return null;
}

@ -39,10 +39,7 @@ namespace NzbDrone.Core.Indexers.Torznab
protected override ReleaseInfo ProcessItem(XElement item, ReleaseInfo releaseInfo)
{
var torrentInfo = base.ProcessItem(item, releaseInfo) as TorrentInfo;
torrentInfo.TvdbId = GetTvdbId(item);
torrentInfo.TvRageId = GetTvRageId(item);
torrentInfo.ImdbId = int.Parse(GetImdbId(item).Substring(2));
return torrentInfo;
}
@ -100,31 +97,12 @@ namespace NzbDrone.Core.Indexers.Torznab
return url;
}
protected virtual int GetTvdbId(XElement item)
protected virtual string GetImdbId(XElement item)
{
var tvdbIdString = TryGetTorznabAttribute(item, "tvdbid");
int tvdbId;
if (!tvdbIdString.IsNullOrWhiteSpace() && int.TryParse(tvdbIdString, out tvdbId))
{
return tvdbId;
}
return 0;
var imdbIdString = TryGetTorznabAttribute(item, "imdbid");
return (!imdbIdString.IsNullOrWhiteSpace() ? imdbIdString.Substring(2) : null);
}
protected virtual int GetTvRageId(XElement item)
{
var tvRageIdString = TryGetTorznabAttribute(item, "rageid");
int tvRageId;
if (!tvRageIdString.IsNullOrWhiteSpace() && int.TryParse(tvRageIdString, out tvRageId))
{
return tvRageId;
}
return 0;
}
protected override string GetInfoHash(XElement item)
{
return TryGetTorznabAttribute(item, "infohash");

@ -178,7 +178,7 @@ namespace NzbDrone.Core.MediaFiles
_mediaFileTableCleanupService.Clean(movie, mediaFileList);
var decisionsStopwatch = Stopwatch.StartNew();
var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, movie);
var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, movie, true);
decisionsStopwatch.Stop();
_logger.Trace("Import decisions complete for: {0} [{1}]", movie, decisionsStopwatch.Elapsed);

@ -183,7 +183,7 @@ namespace NzbDrone.Core.MediaFiles
}
}
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), movie, folderInfo, true);
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), movie, folderInfo, true, false);
var importResults = _importApprovedMovie.Import(decisions, true, downloadClientItem, importMode);
if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) &&
@ -237,7 +237,7 @@ namespace NzbDrone.Core.MediaFiles
}
}
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, movie, null, true);
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, movie, null, true, false);
return _importApprovedMovie.Import(decisions, true, downloadClientItem, importMode);
}

@ -83,6 +83,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
episodeFile.MediaInfo = localMovie.MediaInfo;
episodeFile.Movie = localMovie.Movie;
episodeFile.ReleaseGroup = localMovie.ParsedMovieInfo.ReleaseGroup;
episodeFile.Edition = localMovie.ParsedMovieInfo.Edition;
bool copyOnly;
switch (importMode)

@ -19,7 +19,8 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
{
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series);
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie);
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource); //TODO: Needs changing to ParsedMovieInfo!!
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, bool shouldCheckQuality);
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldCheckQuality); //TODO: Needs changing to ParsedMovieInfo!!
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource);
}
@ -31,6 +32,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
private readonly IDiskProvider _diskProvider;
private readonly IVideoFileInfoReader _videoFileInfoReader;
private readonly IDetectSample _detectSample;
private readonly IQualityDefinitionService _qualitiesService;
private readonly Logger _logger;
public ImportDecisionMaker(IEnumerable<IImportDecisionEngineSpecification> specifications,
@ -39,6 +41,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
IDiskProvider diskProvider,
IVideoFileInfoReader videoFileInfoReader,
IDetectSample detectSample,
IQualityDefinitionService qualitiesService,
Logger logger)
{
_specifications = specifications;
@ -47,6 +50,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
_diskProvider = diskProvider;
_videoFileInfoReader = videoFileInfoReader;
_detectSample = detectSample;
_qualitiesService = qualitiesService;
_logger = logger;
}
@ -57,7 +61,12 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie)
{
return GetImportDecisions(videoFiles, movie, null, false);
return GetImportDecisions(videoFiles, movie, null, true, false);
}
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, bool shouldCheckQuality = false)
{
return GetImportDecisions(videoFiles, movie, null, true, shouldCheckQuality);
}
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource)
@ -77,7 +86,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
return decisions;
}
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource)
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldCheckQuality = false)
{
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), movie);
@ -88,13 +97,13 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
foreach (var file in newFiles)
{
decisions.AddIfNotNull(GetDecision(file, movie, folderInfo, sceneSource, shouldUseFolderName));
decisions.AddIfNotNull(GetDecision(file, movie, folderInfo, sceneSource, shouldUseFolderName, shouldCheckQuality));
}
return decisions;
}
private ImportDecision GetDecision(string file, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldUseFolderName)
private ImportDecision GetDecision(string file, Movie movie, ParsedMovieInfo folderInfo, bool sceneSource, bool shouldUseFolderName, bool shouldCheckQuality = false)
{
ImportDecision decision = null;
@ -113,6 +122,106 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
if (sceneSource)
{
localMovie.MediaInfo = _videoFileInfoReader.GetMediaInfo(file);
if (shouldCheckQuality)
{
var width = localMovie.MediaInfo.Width;
var current = localMovie.Quality;
var qualityName = current.Quality.Name.ToLower();
QualityModel updated = null;
if (width > 1400)
{
if (qualityName.Contains("bluray"))
{
updated = new QualityModel(Quality.Bluray1080p);
}
else if (qualityName.Contains("webdl"))
{
updated = new QualityModel(Quality.WEBDL1080p);
}
else if (qualityName.Contains("hdtv"))
{
updated = new QualityModel(Quality.HDTV1080p);
}
else
{
var def = _qualitiesService.Get(Quality.HDTV1080p);
if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size)
{
updated = new QualityModel(Quality.HDTV1080p);
}
def = _qualitiesService.Get(Quality.WEBDL1080p);
if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size)
{
updated = new QualityModel(Quality.WEBDL1080p);
}
def = _qualitiesService.Get(Quality.Bluray1080p);
if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size)
{
updated = new QualityModel(Quality.Bluray1080p);
}
if (updated == null)
{
updated = new QualityModel(Quality.Bluray1080p);
}
}
}
else
if (width > 900)
{
if (qualityName.Contains("bluray"))
{
updated = new QualityModel(Quality.Bluray720p);
}
else if (qualityName.Contains("webdl"))
{
updated = new QualityModel(Quality.WEBDL720p);
}
else if (qualityName.Contains("hdtv"))
{
updated = new QualityModel(Quality.HDTV720p);
}
else
{
var def = _qualitiesService.Get(Quality.HDTV720p);
if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size)
{
updated = new QualityModel(Quality.HDTV720p);
}
def = _qualitiesService.Get(Quality.WEBDL720p);
if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size)
{
updated = new QualityModel(Quality.WEBDL720p);
}
def = _qualitiesService.Get(Quality.Bluray720p);
if (localMovie.Size > def.MinSize && def.MaxSize > localMovie.Size)
{
updated = new QualityModel(Quality.Bluray720p);
}
if (updated == null)
{
updated = new QualityModel(Quality.Bluray720p);
}
}
}
if (updated != null && updated != current)
{
updated.QualitySource = QualitySource.MediaInfo;
localMovie.Quality = updated;
}
}
decision = GetDecision(localMovie);
}
else

@ -161,7 +161,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
}
var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> { file },
movie, null, SceneSource(movie, folder));
movie, null, SceneSource(movie, folder), true);
return importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : null;
}

@ -26,6 +26,7 @@ namespace NzbDrone.Core.MediaFiles
List<string> FilterExistingFiles(List<string> files, Series series);
List<string> FilterExistingFiles(List<string> files, Movie movie);
EpisodeFile Get(int id);
MovieFile GetMovie(int id);
List<EpisodeFile> Get(IEnumerable<int> ids);
List<MovieFile> GetMovies(IEnumerable<int> ids);
@ -150,5 +151,9 @@ namespace NzbDrone.Core.MediaFiles
_movieFileRepository.Update(episodeFile);
}
public MovieFile GetMovie(int id)
{
return _movieFileRepository.Get(id);
}
}
}

@ -19,6 +19,7 @@ namespace NzbDrone.Core.MediaFiles
public string ReleaseGroup { get; set; }
public QualityModel Quality { get; set; }
public MediaInfoModel MediaInfo { get; set; }
public string Edition { get; set; }
public LazyLoaded<Movie> Movie { get; set; }
public override string ToString()

@ -55,7 +55,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
public Production_Companies[] production_companies { get; set; }
public Production_Countries[] production_countries { get; set; }
public string release_date { get; set; }
public int revenue { get; set; }
public long revenue { get; set; }
public int runtime { get; set; }
public Spoken_Languages[] spoken_languages { get; set; }
public string status { get; set; }

@ -13,6 +13,7 @@ using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Tv;
using Newtonsoft.Json;
using System.Text.RegularExpressions;
using System.Text;
namespace NzbDrone.Core.MetadataSource.SkyHook
{
@ -88,8 +89,9 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
movie.TmdbId = TmdbId;
movie.ImdbId = resource.imdb_id;
movie.Title = resource.title;
movie.TitleSlug = movie.Title.ToLower().Replace(" ", "-");
movie.TitleSlug = ToUrlSlug(movie.Title);
movie.CleanTitle = Parser.Parser.CleanSeriesTitle(movie.Title);
movie.SortTitle = Parser.Parser.NormalizeTitle(movie.Title);
movie.Overview = resource.overview;
movie.Website = resource.homepage;
if (resource.release_date.IsNotNullOrWhiteSpace())
@ -98,11 +100,6 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
movie.Year = movie.InCinemas.Value.Year;
}
var slugResult = _movieService.FindByTitleSlug(movie.TitleSlug);
if (slugResult != null)
{
_logger.Debug("Movie with this title slug already exists. Adding year...");
}
movie.TitleSlug += "-" + movie.Year.ToString();
movie.Images.Add(_configService.GetCoverForURL(resource.poster_path, MediaCoverTypes.Poster));//TODO: Update to load image specs from tmdb page!
@ -189,7 +186,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
{
var lowerTitle = title.ToLower();
var parserResult = Parser.Parser.ParseMovieTitle(title);
var parserResult = Parser.Parser.ParseMovieTitle(title, true);
var yearTerm = "";
@ -327,23 +324,20 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
imdbMovie.TmdbId = result.id;
try
{
imdbMovie.SortTitle = result.title;
imdbMovie.SortTitle = Parser.Parser.NormalizeTitle(result.title);
imdbMovie.Title = result.title;
string titleSlug = result.title;
string titleSlug = ToUrlSlug(result.title);
imdbMovie.TitleSlug = titleSlug.ToLower().Replace(" ", "-");
if (result.release_date.IsNotNullOrWhiteSpace())
{
imdbMovie.Year = DateTime.Parse(result.release_date).Year;
}
var slugResult = _movieService.FindByTitleSlug(imdbMovie.TitleSlug);
if (slugResult != null)
{
_logger.Debug("Movie with this title slug already exists. Adding year...");
}
//var slugResult = _movieService.FindByTitleSlug(imdbMovie.TitleSlug);
//if (slugResult != null)
//{
// _logger.Debug("Movie with this title slug already exists. Adding year...");
//}
imdbMovie.TitleSlug += "-" + imdbMovie.Year.ToString();
imdbMovie.Images = new List<MediaCover.MediaCover>();
@ -524,5 +518,29 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
return MediaCoverTypes.Unknown;
}
}
public static string ToUrlSlug(string value)
{
//First to lower case
value = value.ToLowerInvariant();
//Remove all accents
var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(value);
value = Encoding.ASCII.GetString(bytes);
//Replace spaces
value = Regex.Replace(value, @"\s", "-", RegexOptions.Compiled);
//Remove invalid chars
value = Regex.Replace(value, @"[^a-z0-9\s-_]", "", RegexOptions.Compiled);
//Trim dashes from end
value = value.Trim('-', '_');
//Replace double occurences of - or _
value = Regex.Replace(value, @"([-_]){2,}", "$1", RegexOptions.Compiled);
return value;
}
}
}

@ -18,7 +18,7 @@ namespace NzbDrone.Core.Notifications.Email
public override void OnGrab(GrabMessage grabMessage)
{
const string subject = "Sonarr [TV] - Grabbed";
const string subject = "Radarr [TV] - Grabbed";
var body = string.Format("{0} sent to queue.", grabMessage.Message);
_emailService.SendEmail(Settings, subject, body);
@ -26,7 +26,7 @@ namespace NzbDrone.Core.Notifications.Email
public override void OnDownload(DownloadMessage message)
{
const string subject = "Sonarr [TV] - Downloaded";
const string subject = "Radarr [TV] - Downloaded";
var body = string.Format("{0} Downloaded and sorted.", message.Message);
_emailService.SendEmail(Settings, subject, body);

@ -64,7 +64,7 @@ namespace NzbDrone.Core.Notifications.Email
try
{
SendEmail(settings, "Sonarr - Test Notification", body);
SendEmail(settings, "Radarr - Test Notification", body);
}
catch (Exception ex)
{

@ -18,14 +18,14 @@ namespace NzbDrone.Core.Notifications.Join
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Sonarr - Episode Grabbed";
const string title = "Radarr - Episode Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Sonarr - Episode Downloaded";
const string title = "Radarr - Episode Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
}

@ -18,7 +18,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Sonarr - Grabbed";
const string title = "Radarr - Grabbed";
if (Settings.Notify)
{
@ -28,7 +28,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
public override void OnDownload(DownloadMessage message)
{
const string title = "Sonarr - Downloaded";
const string title = "Radarr - Downloaded";
if (Settings.Notify)
{

@ -18,13 +18,13 @@ namespace NzbDrone.Core.Notifications.Plex
public override void OnGrab(GrabMessage grabMessage)
{
const string header = "Sonarr [TV] - Grabbed";
const string header = "Radarr [TV] - Grabbed";
_plexClientService.Notify(Settings, header, grabMessage.Message);
}
public override void OnDownload(DownloadMessage message)
{
const string header = "Sonarr [TV] - Downloaded";
const string header = "Radarr [TV] - Downloaded";
_plexClientService.Notify(Settings, header, message.Message);
}

@ -23,14 +23,14 @@ namespace NzbDrone.Core.Notifications.Plex
public override void OnGrab(GrabMessage grabMessage)
{
const string header = "Sonarr - Grabbed";
const string header = "Radarr - Grabbed";
Notify(Settings, header, grabMessage.Message);
}
public override void OnDownload(DownloadMessage message)
{
const string header = "Sonarr - Downloaded";
const string header = "Radarr - Downloaded";
Notify(Settings, header, message.Message);
}

@ -98,7 +98,7 @@ namespace NzbDrone.Core.Notifications.Plex
{
if (version >= new Version(1, 3, 0) && version < new Version(1, 3, 1))
{
throw new PlexVersionException("Found version {0}, upgrade to PMS 1.3.1 to fix library updating and then restart Sonarr", version);
throw new PlexVersionException("Found version {0}, upgrade to PMS 1.3.1 to fix library updating and then restart Radarr", version);
}
}

@ -18,14 +18,14 @@ namespace NzbDrone.Core.Notifications.PushBullet
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Sonarr - Episode Grabbed";
const string title = "Radarr - Episode Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Sonarr - Episode Downloaded";
const string title = "Radarr - Episode Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
}

@ -92,7 +92,7 @@ namespace NzbDrone.Core.Notifications.PushBullet
{
try
{
const string title = "Sonarr - Test Notification";
const string title = "Radarr - Test Notification";
const string body = "This is a test message from Radarr";
SendNotification(title, body, settings);

@ -28,7 +28,7 @@ namespace NzbDrone.Core.Notifications.Pushalot
[FieldDefinition(1, Label = "Priority", Type = FieldType.Select, SelectOptions = typeof(PushalotPriority))]
public int Priority { get; set; }
[FieldDefinition(2, Label = "Image", Type = FieldType.Checkbox, HelpText = "Include Sonarr logo with notifications")]
[FieldDefinition(2, Label = "Image", Type = FieldType.Checkbox, HelpText = "Include Radarr logo with notifications")]
public bool Image { get; set; }
public bool IsValid => !string.IsNullOrWhiteSpace(AuthToken);

@ -101,7 +101,7 @@ namespace NzbDrone.Core.Notifications.Slack
{
try
{
var message = $"Test message from Sonarr posted at {DateTime.Now}";
var message = $"Test message from Radarr posted at {DateTime.Now}";
var payload = new SlackPayload
{
IconEmoji = Settings.Icon,

@ -125,7 +125,7 @@ namespace NzbDrone.Core.Notifications.Twitter
{
try
{
var body = "Sonarr: Test Message @ " + DateTime.Now;
var body = "Radarr: Test Message @ " + DateTime.Now;
SendNotification(body, settings);
}

@ -23,14 +23,14 @@ namespace NzbDrone.Core.Notifications.Xbmc
public override void OnGrab(GrabMessage grabMessage)
{
const string header = "Sonarr - Grabbed";
const string header = "Radarr - Grabbed";
Notify(Settings, header, grabMessage.Message);
}
public override void OnDownload(DownloadMessage message)
{
const string header = "Sonarr - Downloaded";
const string header = "Radarr - Downloaded";
Notify(Settings, header, message.Message);
UpdateAndClean(message.Series, message.OldFiles.Any());

@ -193,6 +193,10 @@
<Compile Include="Datastore\Migration\002_remove_tvrage_imdb_unique_constraint.cs" />
<Compile Include="Datastore\Migration\003_remove_clean_title_from_scene_mapping.cs" />
<Compile Include="Datastore\Migration\004_updated_history.cs" />
<Compile Include="Datastore\Migration\118_update_movie_slug.cs" />
<Compile Include="Datastore\Migration\117_update_movie_file.cs" />
<Compile Include="Datastore\Migration\116_update_movie_sorttitle_again.cs" />
<Compile Include="Datastore\Migration\115_update_movie_sorttitle.cs" />
<Compile Include="Datastore\Migration\111_remove_bitmetv.cs" />
<Compile Include="Datastore\Migration\112_remove_torrentleech.cs" />
<Compile Include="Datastore\Migration\114_remove_fanzub.cs" />
@ -587,6 +591,7 @@
<Compile Include="IndexerSearch\Definitions\MovieSearchCriteria.cs" />
<Compile Include="IndexerSearch\MoviesSearchCommand.cs" />
<Compile Include="IndexerSearch\MoviesSearchService.cs" />
<Compile Include="Indexers\AwesomeHD\AwesomeHDRssParser.cs" />
<Compile Include="Indexers\DownloadProtocol.cs" />
<Compile Include="Indexers\Exceptions\ApiKeyException.cs" />
<Compile Include="Indexers\Exceptions\IndexerException.cs" />
@ -594,6 +599,10 @@
<Compile Include="Indexers\Exceptions\UnsupportedFeedException.cs" />
<Compile Include="Indexers\EzrssTorrentRssParser.cs" />
<Compile Include="Indexers\FetchAndParseRssService.cs" />
<Compile Include="Indexers\AwesomeHD\AwesomeHD.cs" />
<Compile Include="Indexers\AwesomeHD\AwesomeHDApi.cs" />
<Compile Include="Indexers\AwesomeHD\AwesomeHDRequestGenerator.cs" />
<Compile Include="Indexers\AwesomeHD\AwesomeHDSettings.cs" />
<Compile Include="Indexers\PassThePopcorn\PassThePopcorn.cs" />
<Compile Include="Indexers\PassThePopcorn\PassThePopcornApi.cs" />
<Compile Include="Indexers\PassThePopcorn\PassThePopcornInfo.cs" />

@ -58,7 +58,7 @@ namespace NzbDrone.Core.Organizer
public static readonly Regex SeriesTitleRegex = new Regex(@"(?<token>\{(?:Series)(?<separator>[- ._])(Clean)?Title\})",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{(?:Movie)(?<separator>[- ._])(Clean)?Title\})",
public static readonly Regex MovieTitleRegex = new Regex(@"(?<token>\{((?:(Movie|Original))(?<separator>[- ._])(Clean)?Title)\})",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex FileNameCleanupRegex = new Regex(@"([- ._])(\1)+", RegexOptions.Compiled);
@ -163,6 +163,7 @@ namespace NzbDrone.Core.Organizer
AddReleaseDateTokens(tokenHandlers, movie.Year); //In case we want to separate the year
AddQualityTokens(tokenHandlers, movie, movieFile);
AddMediaInfoTokens(tokenHandlers, movieFile);
AddMovieFileTokens(tokenHandlers, movieFile);
var fileName = ReplaceTokens(pattern, tokenHandlers, namingConfig).Trim();
fileName = FileNameCleanupRegex.Replace(fileName, match => match.Captures[0].Value[0].ToString());
@ -503,6 +504,13 @@ namespace NzbDrone.Core.Organizer
tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup ?? m.DefaultValue("Sonarr");
}
private void AddMovieFileTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, MovieFile episodeFile)
{
tokenHandlers["{Original Title}"] = m => GetOriginalTitle(episodeFile);
tokenHandlers["{Original Filename}"] = m => GetOriginalFileName(episodeFile);
tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup ?? m.DefaultValue("Sonarr");
}
private void AddQualityTokens(Dictionary<string, Func<TokenMatch, string>> tokenHandlers, Series series, EpisodeFile episodeFile)
{
var qualityTitle = _qualityDefinitionService.Get(episodeFile.Quality.Quality).Title;

@ -18,16 +18,10 @@ namespace NzbDrone.Core.Parser
private static readonly Regex[] ReportMovieTitleRegex = new[]
{
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.Special.Edition.2011
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<edition>(\w+\.?edition))\.(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<edition>(\.?((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final|Extended|Rogue|Special|Despecialized).(Cut|Edition|Version)|Extended|Uncensored|Remastered|Unrated|Uncut|IMAX)))\.(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Special, Despecialized, etc. Edition Movies, e.g: Mission.Impossible.3.2011.Special.Edition //TODO: Seems to slow down parsing heavily!
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((\w+\.?){1,3}edition))",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Cut Movies, e.g: Mission.Impossible.3.Directors.Cut.2011
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<edition>(\w+\.?cut))\.(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Cut Movies, e.g: Mission.Impossible.3.2011.Directors.Cut
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((\w+\.?){1,3}cut))",
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)(?<edition>((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final|Extended|Rogue|Special|Despecialized).(Cut|Edition|Version)|Extended|Uncensored|Remastered|Unrated|Uncut|IMAX))",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Normal movie format, e.g: Mission.Impossible.3.2011
@ -36,6 +30,15 @@ namespace NzbDrone.Core.Parser
//PassThePopcorn Torrent names: Star.Wars[PassThePopcorn]
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![()\[!]))*(?<year>(\[\w *\])))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//That did not work? Maybe some tool uses [] for years. Who would do that?
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\W\d+)))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
};
private static readonly Regex[] ReportMovieTitleFolderRegex = new[]
{
//When year comes first.
new Regex(@"^(?:(?:[-_\W](?<![)!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\W\d+)))+(\W+|_|$)(?<title>.+?)?$")
};
private static readonly Regex[] ReportTitleRegex = new[]
@ -327,7 +330,7 @@ namespace NzbDrone.Core.Parser
{
var fileInfo = new FileInfo(path);
var result = ParseMovieTitle(fileInfo.Name);
var result = ParseMovieTitle(fileInfo.Name, true);
if (result == null)
{
@ -345,7 +348,7 @@ namespace NzbDrone.Core.Parser
}
public static ParsedMovieInfo ParseMovieTitle(string title)
public static ParsedMovieInfo ParseMovieTitle(string title, bool isDir = false)
{
ParsedMovieInfo realResult = null;
@ -376,7 +379,14 @@ namespace NzbDrone.Core.Parser
simpleTitle = CleanTorrentSuffixRegex.Replace(simpleTitle, string.Empty);
foreach (var regex in ReportMovieTitleRegex)
var allRegexes = ReportMovieTitleRegex.ToList();
if (isDir)
{
allRegexes.AddRange(ReportMovieTitleFolderRegex);
}
foreach (var regex in allRegexes)
{
var match = regex.Matches(simpleTitle);

@ -44,14 +44,14 @@ namespace NzbDrone.Core.Queue
private IEnumerable<Queue> MapQueue(TrackedDownload trackedDownload)
{
if (trackedDownload.RemoteEpisode.Episodes != null && trackedDownload.RemoteEpisode.Episodes.Any())
if (trackedDownload.RemoteEpisode != null && trackedDownload.RemoteEpisode.Episodes != null && trackedDownload.RemoteEpisode.Episodes.Any())
{
foreach (var episode in trackedDownload.RemoteEpisode.Episodes)
{
yield return MapEpisode(trackedDownload, episode);
}
}
else if (trackedDownload.RemoteMovie.Movie != null)
else if (trackedDownload.RemoteMovie != null && trackedDownload.RemoteMovie.Movie != null)
{
yield return MapMovie(trackedDownload, trackedDownload.RemoteMovie.Movie);
}

@ -149,7 +149,11 @@ namespace NzbDrone.Core.RootFolders
foreach (string unmappedFolder in unmappedFolders)
{
var di = new DirectoryInfo(unmappedFolder.Normalize());
results.Add(new UnmappedFolder { Name = di.Name, Path = di.FullName });
if (!di.Attributes.HasFlag(FileAttributes.System) && !di.Attributes.HasFlag(FileAttributes.Hidden))
{
results.Add(new UnmappedFolder { Name = di.Name, Path = di.FullName });
}
}
var setToRemove = SpecialFolders;

@ -24,7 +24,7 @@ namespace Radarr.Host
SecurityProtocolPolicy.Register();
X509CertificateValidationPolicy.Register();
Logger.Info("Starting Sonarr - {0} - Version {1}", Assembly.GetCallingAssembly().Location, Assembly.GetExecutingAssembly().GetName().Version);
Logger.Info("Starting Radarr - {0} - Version {1}", Assembly.GetCallingAssembly().Location, Assembly.GetExecutingAssembly().GetName().Version);
if (!PlatformValidation.IsValidate(userAlert))
{

Binary file not shown.

Binary file not shown.

@ -91,7 +91,7 @@
{{/if_eq}}
{{#if_eq reason compare="MissingFromDisk"}}
Sonarr was unable to find the file on disk so it was removed
Radarr was unable to find the file on disk so it was removed
{{/if_eq}}
{{#if_eq reason compare="Upgrade"}}

@ -1,18 +1,6 @@
<dl class="monitor-tooltip-contents">
<dt>All</dt>
<dd>Monitor all episodes except specials</dd>
<dt>Future</dt>
<dd>Monitor episodes that have not aired yet</dd>
<dt>Missing</dt>
<dd>Monitor episodes that do not have files or have not aired yet</dd>
<dt>Existing</dt>
<dd>Monitor episodes that have files or have not aired yet</dd>
<dt>First Season</dt>
<dd>Monitor all episodes of the first season. All other seasons will be ignored</dd>
<dt>Latest Season</dt>
<dd>Monitor all episodes of the latest season and future seasons</dd>
<dt>None</dt>
<dd>No episodes will be monitored.</dd>
<!--<dt>Latest Season</dt>-->
<!--<dd>Monitor all episodes the latest season only, previous seasons will be ignored</dd>-->
<dt>Yes</dt>
<dd>Monitor for new releases</dd>
<dt>No</dt>
<dd>Do not monitor for new releases</dd>
</dl>

@ -84,7 +84,7 @@ var view = Marionette.ItemView.extend({
content : content,
html : true,
trigger : 'hover',
title : 'Episode Monitoring Options',
title : 'Movie Monitoring Options',
placement : 'right',
container : this.$el
});

@ -1,7 +1,7 @@
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h3>Sonarr Calendar feed</h3>
<h3>Radarr Calendar feed</h3>
</div>
<div class="modal-body edit-series-modal">
<div class="form-horizontal">

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

Loading…
Cancel
Save