merge from Develop

pull/2/head
Tim Turner 8 years ago
commit f9c6ffcdaa

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 811 B

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 37 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 31 KiB

@ -12,7 +12,9 @@
| 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.
A fork of [Sonarr](https://github.com/Sonarr/Sonarr) to work with movies à la Couchpotato.
**This fork works independently of Sonarr and will not interfere with it.**
## Downloads
@ -34,33 +36,33 @@ To connect to the UI, fire up your browser and open <http://localhost:7878> or <
## Features
### Currently Working
### Current Features
* Adding new movies
* Manually searching for releases of movies
* Automatically searching for releases
* Adding new movies with lots of information, such as trailers, ratings, etc.
* 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
* Automatically searching for releases as well as RSS Sync
* 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)
* All indexers supported by Sonarr also supported
* New PassThePopcorn Indexer
* QBittorrent, Deluge, rTorrent, Transmission and uTorrent download client (Other clients are coming)
* New TorrentPotato Indexer (Works well with [Jackett](https://github.com/Jackett/Jackett))
* And a beautiful UI
### 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
* Importing movies from various online sources, such as IMDb Watchlists (A complete list can be found [here](https://github.com/Radarr/Radarr/issues/114))
* Full integration with Kodi, Plex (notification, library update, metadata)
* And a beautiful UI
##Feature Requests
[![Feature Requests](http://feathub.com/Radarr/Radarr?format=svg)](http://feathub.com/Radarr/Radarr)
## Configuring Development Environment

@ -64,6 +64,8 @@ namespace NzbDrone.Api.Authentication
new DefaultHmacProvider(new PassphraseKeyGenerator(_configService.HmacPassphrase, Encoding.ASCII.GetBytes(_configService.HmacSalt)))
);
FormsAuthentication.FormsAuthenticationCookieName = "_ncfaradarr"; //For those people that both have sonarr and radarr.
FormsAuthentication.Enable(pipelines, new FormsAuthenticationConfiguration
{
RedirectUrl = _configFileProvider.UrlBase + "/login",

@ -5,7 +5,7 @@ namespace NzbDrone.Api.Validation
public class RssSyncIntervalValidator : PropertyValidator
{
public RssSyncIntervalValidator()
: base("Must be between 10 and 120 or 0 to disable")
: base("Must be between 10 and 720 or 0 to disable")
{
}
@ -23,7 +23,7 @@ namespace NzbDrone.Api.Validation
return true;
}
if (value >= 10 && value <= 120)
if (value >= 10 && value <= 720)
{
return true;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 81 KiB

@ -32,7 +32,7 @@ namespace NzbDrone.Core.Test.Configuration
[Test]
public void Get_value_should_return_default_when_no_value()
{
Subject.RssSyncInterval.Should().Be(15);
Subject.RssSyncInterval.Should().Be(60);
}
[Test]
@ -47,7 +47,7 @@ namespace NzbDrone.Core.Test.Configuration
public void get_value_with_out_persist_should_not_store_default_value()
{
var interval = Subject.RssSyncInterval;
interval.Should().Be(15);
interval.Should().Be(60);
Mocker.GetMock<IConfigRepository>().Verify(c => c.Insert(It.IsAny<Config>()), Times.Never());
}

@ -100,7 +100,7 @@ namespace NzbDrone.Core.Configuration
public int RssSyncInterval
{
get { return GetValueInt("RssSyncInterval", 15); }
get { return GetValueInt("RssSyncInterval", 60); }
set { SetValue("RssSyncInterval", value); }
}

@ -19,7 +19,21 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
public Decision IsSatisfiedBy(RemoteMovie subject, SearchCriteriaBase searchCriteria)
{
throw new NotImplementedException();
if (searchCriteria != null)
{
if (searchCriteria.UserInvokedSearch)
{
_logger.Debug("Skipping monitored check during search");
return Decision.Accept();
}
}
if (!subject.Movie.Monitored)
{
return Decision.Reject("Movie is not monitored");
}
return Decision.Accept();
}
public virtual Decision IsSatisfiedBy(RemoteEpisode subject, SearchCriteriaBase searchCriteria)

@ -5,6 +5,7 @@ using NzbDrone.Core.IndexerSearch;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Tv;
using System.Collections.Generic;
namespace NzbDrone.Core.Download
{
@ -38,7 +39,7 @@ namespace NzbDrone.Core.Download
{
_logger.Debug("Failed download contains a movie, searching again.");
_commandQueueManager.Push(new MoviesSearchCommand { MovieId = message.MovieId });
_commandQueueManager.Push(new MoviesSearchCommand { MovieIds = new List<int> { message.MovieId } });
return;
}

@ -102,13 +102,13 @@ namespace NzbDrone.Core.Extras
public void Handle(MediaCoversUpdatedEvent message)
{
var series = message.Series;
var episodeFiles = GetEpisodeFiles(series.Id);
//var series = message.Series;
//var episodeFiles = GetEpisodeFiles(series.Id);
foreach (var extraFileManager in _extraFileManagers)
{
extraFileManager.CreateAfterSeriesScan(series, episodeFiles);
}
//foreach (var extraFileManager in _extraFileManagers)
//{
// extraFileManager.CreateAfterSeriesScan(series, episodeFiles);
//}
}
//TODO: Implementing this will fix a lot of our warning exceptions

@ -0,0 +1,13 @@
using NzbDrone.Core.Messaging.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.IndexerSearch
{
public class MissingMoviesSearchCommand : Command
{
public override bool SendUpdatesToClient => true;
}
}

@ -1,10 +1,11 @@
using NzbDrone.Core.Messaging.Commands;
using System.Collections.Generic;
namespace NzbDrone.Core.IndexerSearch
{
public class MoviesSearchCommand : Command
{
public int MovieId { get; set; }
public List<int> MovieIds { get; set; }
public override bool SendUpdatesToClient => true;
}

@ -4,22 +4,23 @@ using NzbDrone.Common.Instrumentation.Extensions;
using NzbDrone.Core.Download;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.IndexerSearch
{
public class MovieSearchService : IExecute<MoviesSearchCommand>
public class MovieSearchService : IExecute<MoviesSearchCommand>, IExecute<MissingMoviesSearchCommand>
{
private readonly IMovieService _seriesService;
private readonly IMovieService _movieService;
private readonly ISearchForNzb _nzbSearchService;
private readonly IProcessDownloadDecisions _processDownloadDecisions;
private readonly Logger _logger;
public MovieSearchService(IMovieService seriesService,
public MovieSearchService(IMovieService movieService,
ISearchForNzb nzbSearchService,
IProcessDownloadDecisions processDownloadDecisions,
Logger logger)
{
_seriesService = seriesService;
_movieService = movieService;
_nzbSearchService = nzbSearchService;
_processDownloadDecisions = processDownloadDecisions;
_logger = logger;
@ -27,20 +28,35 @@ namespace NzbDrone.Core.IndexerSearch
public void Execute(MoviesSearchCommand message)
{
var series = _seriesService.GetMovie(message.MovieId);
var downloadedCount = 0;
foreach (var movieId in message.MovieIds)
{
var series = _movieService.GetMovie(movieId);
if (!series.Monitored)
{
_logger.Debug("Movie {0} is not monitored, skipping search", series.Title);
}
var decisions = _nzbSearchService.MovieSearch(message.MovieId, false);//_nzbSearchService.SeasonSearch(message.MovieId, season.SeasonNumber, false, message.Trigger == CommandTrigger.Manual);
var decisions = _nzbSearchService.MovieSearch(movieId, false);//_nzbSearchService.SeasonSearch(message.MovieId, season.SeasonNumber, false, message.Trigger == CommandTrigger.Manual);
downloadedCount += _processDownloadDecisions.ProcessDecisions(decisions).Grabbed.Count;
}
_logger.ProgressInfo("Movie search completed. {0} reports downloaded.", downloadedCount);
}
public void Execute(MissingMoviesSearchCommand message)
{
var movies = _movieService.MoviesWithoutFiles(new PagingSpec<Movie>
{
Page = 1,
PageSize = 100000,
SortDirection = SortDirection.Ascending,
SortKey = "Id",
FilterExpression =
v =>
v.Monitored == true
}).Records.ToList();
}
}
}

@ -54,13 +54,19 @@ namespace NzbDrone.Core.Indexers.AwesomeHD
private IEnumerable<IndexerRequest> GetRequest(string searchParameters)
{
var onlyInternal = "";
if (Settings.Internal)
{
onlyInternal = "&internal=true";
}
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);
yield return new IndexerRequest($"{Settings.BaseUrl.Trim().TrimEnd('/')}/searchapi.php?action=imdbsearch&passkey={Settings.Passkey.Trim()}&imdb={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);
yield return new IndexerRequest($"{Settings.BaseUrl.Trim().TrimEnd('/')}/searchapi.php?action=latestmovies&passkey={Settings.Passkey.Trim()}{onlyInternal}", HttpAccept.Rss);
}
}

@ -29,6 +29,9 @@ namespace NzbDrone.Core.Indexers.AwesomeHD
[FieldDefinition(1, Label = "Passkey")]
public string Passkey { get; set; }
[FieldDefinition(2, Type = FieldType.Checkbox, Label = "Require Internal", HelpText = "Will only include internal releases for RSS Sync.")]
public bool Internal { get; set; }
public NzbDroneValidationResult Validate()
{
return new NzbDroneValidationResult(Validator.Validate(this));

@ -30,12 +30,14 @@ namespace NzbDrone.Core.Jobs
{
private readonly IScheduledTaskRepository _scheduledTaskRepository;
private readonly IConfigService _configService;
private readonly IConfigFileProvider _configFileProvider;
private readonly Logger _logger;
public TaskManager(IScheduledTaskRepository scheduledTaskRepository, IConfigService configService, Logger logger)
public TaskManager(IScheduledTaskRepository scheduledTaskRepository, IConfigService configService, IConfigFileProvider configFileProvider, Logger logger)
{
_scheduledTaskRepository = scheduledTaskRepository;
_configService = configService;
_configFileProvider = configFileProvider;
_logger = logger;
}
@ -59,11 +61,18 @@ namespace NzbDrone.Core.Jobs
public void Handle(ApplicationStartedEvent message)
{
float updateInterval = 6 * 60;
if (_configFileProvider.Branch == "nightly")
{
updateInterval = 30;
}
var defaultTasks = new[]
{
new ScheduledTask{ Interval = 0.25f, TypeName = typeof(CheckForFinishedDownloadCommand).FullName},
new ScheduledTask{ Interval = 5, TypeName = typeof(MessagingCleanupCommand).FullName},
new ScheduledTask{ Interval = 6*60, TypeName = typeof(ApplicationUpdateCommand).FullName},
new ScheduledTask{ Interval = updateInterval, TypeName = typeof(ApplicationUpdateCommand).FullName},
// new ScheduledTask{ Interval = 3*60, TypeName = typeof(UpdateSceneMappingCommand).FullName},
new ScheduledTask{ Interval = 6*60, TypeName = typeof(CheckHealthCommand).FullName},
new ScheduledTask{ Interval = 24*60, TypeName = typeof(RefreshMovieCommand).FullName},

@ -1,5 +1,8 @@
using NzbDrone.Common.Disk;
using System;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Http;
using System.Drawing;
using NLog;
namespace NzbDrone.Core.MediaCover
{
@ -12,11 +15,13 @@ namespace NzbDrone.Core.MediaCover
{
private readonly IDiskProvider _diskProvider;
private readonly IHttpClient _httpClient;
private readonly Logger _logger;
public CoverAlreadyExistsSpecification(IDiskProvider diskProvider, IHttpClient httpClient)
public CoverAlreadyExistsSpecification(IDiskProvider diskProvider, IHttpClient httpClient, Logger logger)
{
_diskProvider = diskProvider;
_httpClient = httpClient;
_logger = logger;
}
public bool AlreadyExists(string url, string path)
@ -26,9 +31,38 @@ namespace NzbDrone.Core.MediaCover
return false;
}
if (!IsValidGDIPlusImage(path))
{
_diskProvider.DeleteFile(path);
return false;
}
var headers = _httpClient.Head(new HttpRequest(url)).Headers;
var fileSize = _diskProvider.GetFileSize(path);
return fileSize == headers.ContentLength;
}
private bool IsValidGDIPlusImage(string filename)
{
try
{
GdiPlusInterop.CheckGdiPlus();
using (var bmp = new Bitmap(filename))
{
}
return true;
}
catch (DllNotFoundException ex)
{
_logger.Error(ex, "Could not find libgdiplus. Cannot test if image is corrupt.");
return true;
}
catch (Exception ex)
{
_logger.Debug(ex, "Corrupted image found at: {0}. Redownloading...", filename);
return false;
}
}
}
}

@ -48,11 +48,12 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
return AudioChannelPositionsText.ContainsIgnoreCase("LFE") ? AudioChannels - 1 + 0.1m : AudioChannels;
}
decimal channels = 0;
decimal.TryParse(AudioChannelPositions.Split('/').First(), out channels);
return channels;
return
AudioChannelPositions.Replace("Object Based /", "").Replace(" / ", "$")
.Split('$')
.First()
.Split('/')
.Sum(s => decimal.Parse(s, CultureInfo.InvariantCulture));
}
}
}

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using NzbDrone.Core.Profiles;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.MetadataSource
@ -7,6 +8,6 @@ namespace NzbDrone.Core.MetadataSource
public interface IProvideMovieInfo
{
Movie GetMovieInfo(string ImdbId);
Movie GetMovieInfo(int TmdbId);
Movie GetMovieInfo(int TmdbId, Profile profile);
}
}

@ -14,6 +14,8 @@ using NzbDrone.Core.Tv;
using Newtonsoft.Json;
using System.Text.RegularExpressions;
using System.Text;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Profiles;
namespace NzbDrone.Core.MetadataSource.SkyHook
{
@ -67,25 +69,39 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
return new Tuple<Series, List<Episode>>(series, episodes.ToList());
}
public Movie GetMovieInfo(int TmdbId)
public Movie GetMovieInfo(int TmdbId, Profile profile = null)
{
var langCode = profile != null ? IsoLanguages.Get(profile.Language).TwoLetterCode : "us";
var request = _movieBuilder.Create()
.SetSegment("route", "movie")
.SetSegment("id", TmdbId.ToString())
.SetSegment("secondaryRoute", "")
.AddQueryParam("append_to_response", "alternative_titles,release_dates,videos")
.AddQueryParam("country", "US")
.AddQueryParam("language", langCode.ToUpper())
// .AddQueryParam("country", "US")
.Build();
request.AllowAutoRedirect = true;
request.SuppressHttpError = true;
var response = _httpClient.Get<MovieResourceRoot>(request);
var resource = response.Resource;
var movie = new Movie();
foreach (var alternativeTitle in resource.alternative_titles.titles)
{
if (alternativeTitle.iso_3166_1.ToLower() == langCode)
{
movie.AlternativeTitles.Add(alternativeTitle.title);
}
else if (alternativeTitle.iso_3166_1.ToLower() == "us")
{
movie.AlternativeTitles.Add(alternativeTitle.title);
}
}
movie.TmdbId = TmdbId;
movie.ImdbId = resource.imdb_id;
movie.Title = resource.title;
@ -106,10 +122,10 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
movie.Images.Add(_configService.GetCoverForURL(resource.backdrop_path, MediaCoverTypes.Banner));
movie.Runtime = resource.runtime;
foreach(Title title in resource.alternative_titles.titles)
{
movie.AlternativeTitles.Add(title.title);
}
//foreach(Title title in resource.alternative_titles.titles)
//{
// movie.AlternativeTitles.Add(title.title);
//}
foreach(ReleaseDates releaseDates in resource.release_dates.results)
{

@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Boxcar
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Episode Grabbed";
const string title = "Movie Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Episode Downloaded";
const string title = "Movie Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
}

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
@ -24,77 +25,67 @@ namespace NzbDrone.Core.Notifications.CustomScript
_logger = logger;
}
public override string Link => "https://github.com/Sonarr/Sonarr/wiki/Custom-Post-Processing-Scripts";
public override string Link => "https://github.com/Radarr/Radarr/wiki/Custom-Post-Processing-Scripts";
public override void OnGrab(GrabMessage message)
{
var series = message.Series;
var remoteEpisode = message.Episode;
var releaseGroup = remoteEpisode.ParsedEpisodeInfo.ReleaseGroup;
var movie = message.Movie;
var remoteMovie = message.RemoteMovie;
var releaseGroup = remoteMovie.ParsedMovieInfo.ReleaseGroup;
var environmentVariables = new StringDictionary();
environmentVariables.Add("Sonarr_EventType", "Grab");
environmentVariables.Add("Sonarr_Series_Id", series.Id.ToString());
environmentVariables.Add("Sonarr_Series_Title", series.Title);
environmentVariables.Add("Sonarr_Series_TvdbId", series.TvdbId.ToString());
environmentVariables.Add("Sonarr_Series_Type", series.SeriesType.ToString());
environmentVariables.Add("Sonarr_Release_EpisodeCount", remoteEpisode.Episodes.Count.ToString());
environmentVariables.Add("Sonarr_Release_SeasonNumber", remoteEpisode.ParsedEpisodeInfo.SeasonNumber.ToString());
environmentVariables.Add("Sonarr_Release_EpisodeNumbers", string.Join(",", remoteEpisode.Episodes.Select(e => e.EpisodeNumber)));
environmentVariables.Add("Sonarr_Release_Title", remoteEpisode.Release.Title);
environmentVariables.Add("Sonarr_Release_Indexer", remoteEpisode.Release.Indexer);
environmentVariables.Add("Sonarr_Release_Size", remoteEpisode.Release.Size.ToString());
environmentVariables.Add("Sonarr_Release_ReleaseGroup", releaseGroup);
environmentVariables.Add("Radarr_EventType", "Grab");
environmentVariables.Add("Radarr_Movie_Id", movie.Id.ToString());
environmentVariables.Add("Radarr_Movie_Title", movie.Title);
environmentVariables.Add("Radarr_Movie_ImdbId", movie.ImdbId.ToString());
environmentVariables.Add("Radarr_Release_Title", remoteMovie.Release.Title);
environmentVariables.Add("Radarr_Release_Indexer", remoteMovie.Release.Indexer);
environmentVariables.Add("Radarr_Release_Size", remoteMovie.Release.Size.ToString());
environmentVariables.Add("Radarr_Release_ReleaseGroup", releaseGroup);
ExecuteScript(environmentVariables);
}
public override void OnDownload(DownloadMessage message)
{
var series = message.Series;
var episodeFile = message.EpisodeFile;
var movie = message.Movie;
var movieFile = message.MovieFile;
var sourcePath = message.SourcePath;
var environmentVariables = new StringDictionary();
environmentVariables.Add("Sonarr_EventType", "Download");
environmentVariables.Add("Sonarr_Series_Id", series.Id.ToString());
environmentVariables.Add("Sonarr_Series_Title", series.Title);
environmentVariables.Add("Sonarr_Series_Path", series.Path);
environmentVariables.Add("Sonarr_Series_TvdbId", series.TvdbId.ToString());
environmentVariables.Add("Sonarr_Series_Type", series.SeriesType.ToString());
environmentVariables.Add("Sonarr_EpisodeFile_Id", episodeFile.Id.ToString());
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeCount", episodeFile.Episodes.Value.Count.ToString());
environmentVariables.Add("Sonarr_EpisodeFile_RelativePath", episodeFile.RelativePath);
environmentVariables.Add("Sonarr_EpisodeFile_Path", Path.Combine(series.Path, episodeFile.RelativePath));
environmentVariables.Add("Sonarr_EpisodeFile_SeasonNumber", episodeFile.SeasonNumber.ToString());
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeNumbers", string.Join(",", episodeFile.Episodes.Value.Select(e => e.EpisodeNumber)));
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeAirDates", string.Join(",", episodeFile.Episodes.Value.Select(e => e.AirDate)));
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeAirDatesUtc", string.Join(",", episodeFile.Episodes.Value.Select(e => e.AirDateUtc)));
environmentVariables.Add("Sonarr_EpisodeFile_EpisodeTitles", string.Join("|", episodeFile.Episodes.Value.Select(e => e.Title)));
environmentVariables.Add("Sonarr_EpisodeFile_Quality", episodeFile.Quality.Quality.Name);
environmentVariables.Add("Sonarr_EpisodeFile_QualityVersion", episodeFile.Quality.Revision.Version.ToString());
environmentVariables.Add("Sonarr_EpisodeFile_ReleaseGroup", episodeFile.ReleaseGroup ?? string.Empty);
environmentVariables.Add("Sonarr_EpisodeFile_SceneName", episodeFile.SceneName ?? string.Empty);
environmentVariables.Add("Sonarr_EpisodeFile_SourcePath", sourcePath);
environmentVariables.Add("Sonarr_EpisodeFile_SourceFolder", Path.GetDirectoryName(sourcePath));
environmentVariables.Add("Radarr_EventType", "Download");
environmentVariables.Add("Radarr_Movie_Id", movie.Id.ToString());
environmentVariables.Add("Radarr_Movie_Title", movie.Title);
environmentVariables.Add("Radarr_Movie_ImdbId", movie.ImdbId.ToString());
environmentVariables.Add("Radarr_MovieFile_Id", movieFile.Id.ToString());
environmentVariables.Add("Radarr_MovieFile_RelativePath", movieFile.RelativePath);
environmentVariables.Add("Radarr_MovieFile_Path", Path.Combine(movie.Path, movieFile.RelativePath));
environmentVariables.Add("Radarr_MovieFile_Quality", movieFile.Quality.Quality.Name);
environmentVariables.Add("Radarr_MovieFile_QualityVersion", movieFile.Quality.Revision.Version.ToString());
environmentVariables.Add("Radarr_MovieFile_ReleaseGroup", movieFile.ReleaseGroup ?? string.Empty);
environmentVariables.Add("Radarr_MovieFile_SceneName", movieFile.SceneName ?? string.Empty);
environmentVariables.Add("Radarr_MovieFile_SourcePath", sourcePath);
environmentVariables.Add("Radarr_MovieFile_SourceFolder", Path.GetDirectoryName(sourcePath));
ExecuteScript(environmentVariables);
}
public override void OnRename(Series series)
public override void OnMovieRename(Movie movie)
{
var environmentVariables = new StringDictionary();
environmentVariables.Add("Sonarr_EventType", "Rename");
environmentVariables.Add("Sonarr_Series_Id", series.Id.ToString());
environmentVariables.Add("Sonarr_Series_Title", series.Title);
environmentVariables.Add("Sonarr_Series_Path", series.Path);
environmentVariables.Add("Sonarr_Series_TvdbId", series.TvdbId.ToString());
environmentVariables.Add("Sonarr_Series_Type", series.SeriesType.ToString());
environmentVariables.Add("Radarr_EventType", "Rename");
environmentVariables.Add("Radarr_Movie_Id", movie.Id.ToString());
environmentVariables.Add("Radarr_Movie_Title", movie.Title);
environmentVariables.Add("Radarr_Movie_Path", movie.Path);
environmentVariables.Add("Radarr_Movie_TvdbId", movie.ImdbId.ToString());
ExecuteScript(environmentVariables);
}
public override void OnRename(Series series)
{
}
public override string Name => "Custom Script";
public override ValidationResult Test()

@ -8,8 +8,11 @@ namespace NzbDrone.Core.Notifications
{
public string Message { get; set; }
public Series Series { get; set; }
public Movie Movie { get; set; }
public EpisodeFile EpisodeFile { get; set; }
public List<EpisodeFile> OldFiles { get; set; }
public MovieFile MovieFile { get; set; }
public List<MovieFile> OldMovieFiles { get; set; }
public string SourcePath { get; set; }
public override string ToString()

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

@ -8,6 +8,8 @@ namespace NzbDrone.Core.Notifications
{
public string Message { get; set; }
public Series Series { get; set; }
public Movie Movie { get; set; }
public RemoteMovie RemoteMovie { get; set; }
public RemoteEpisode Episode { get; set; }
public QualityModel Quality { get; set; }

@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Growl
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Episode Grabbed";
const string title = "Movie Grabbed";
_growlService.SendNotification(title, grabMessage.Message, "GRAB", Settings.Host, Settings.Port, Settings.Password);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Episode Downloaded";
const string title = "Movie Downloaded";
_growlService.SendNotification(title, message.Message, "DOWNLOAD", Settings.Host, Settings.Port, Settings.Password);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
}

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

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

@ -87,7 +87,7 @@ namespace NzbDrone.Core.Notifications.Join
request.AddParameter("apikey", settings.ApiKey);
request.AddParameter("title", title);
request.AddParameter("text", message);
request.AddParameter("icon", "https://cdn.rawgit.com/Sonarr/Sonarr/develop/Logo/256.png"); // Use the Sonarr logo.
request.AddParameter("icon", "https://cdn.rawgit.com/Radarr/Radarr/develop/Logo/256.png"); // Use the Radarr logo.
var response = client.ExecuteAndValidate(request);
var res = Json.Deserialize<JoinResponseModel>(response.Content);

@ -18,7 +18,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Radarr - Grabbed";
const string title = "Radarr - Movie Grabbed";
if (Settings.Notify)
{
@ -28,7 +28,7 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
public override void OnDownload(DownloadMessage message)
{
const string title = "Radarr - Downloaded";
const string title = "Radarr - Movie Downloaded";
if (Settings.Notify)
{
@ -41,6 +41,10 @@ namespace NzbDrone.Core.Notifications.MediaBrowser
}
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
if (Settings.UpdateLibrary)

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

@ -15,7 +15,11 @@ namespace NzbDrone.Core.Notifications
public class NotificationService
: IHandle<EpisodeGrabbedEvent>,
IHandle<EpisodeDownloadedEvent>,
IHandle<SeriesRenamedEvent>
IHandle<SeriesRenamedEvent>,
IHandle<MovieRenamedEvent>,
IHandle<MovieGrabbedEvent>,
IHandle<MovieDownloadedEvent>
{
private readonly INotificationFactory _notificationFactory;
private readonly Logger _logger;
@ -67,6 +71,41 @@ namespace NzbDrone.Core.Notifications
qualityString);
}
private string GetMessage(Movie movie, QualityModel quality)
{
var qualityString = quality.Quality.ToString();
if (quality.Revision.Version > 1)
{
qualityString += " Proper";
}
return string.Format("{0} [{1}]",
movie.Title,
qualityString);
}
private bool ShouldHandleMovie(ProviderDefinition definition, Movie movie)
{
var notificationDefinition = (NotificationDefinition)definition;
if (notificationDefinition.Tags.Empty())
{
_logger.Debug("No tags set for this notification.");
return true;
}
if (notificationDefinition.Tags.Intersect(movie.Tags).Any())
{
_logger.Debug("Notification and series have one or more matching tags.");
return true;
}
//TODO: this message could be more clear
_logger.Debug("{0} does not have any tags that match {1}'s tags", notificationDefinition.Name, movie.Title);
return false;
}
private bool ShouldHandleSeries(ProviderDefinition definition, Series series)
{
var notificationDefinition = (NotificationDefinition) definition;
@ -112,6 +151,33 @@ namespace NzbDrone.Core.Notifications
}
}
public void Handle(MovieGrabbedEvent message)
{
var grabMessage = new GrabMessage
{
Message = GetMessage(message.Movie.Movie, message.Movie.ParsedMovieInfo.Quality),
Series = null,
Quality = message.Movie.ParsedMovieInfo.Quality,
Episode = null,
Movie = message.Movie.Movie,
RemoteMovie = message.Movie
};
foreach (var notification in _notificationFactory.OnGrabEnabled())
{
try
{
if (!ShouldHandleMovie(notification.Definition, message.Movie.Movie)) continue;
notification.OnGrab(grabMessage);
}
catch (Exception ex)
{
_logger.Error(ex, "Unable to send OnGrab notification to: " + notification.Definition.Name);
}
}
}
public void Handle(EpisodeDownloadedEvent message)
{
var downloadMessage = new DownloadMessage();
@ -141,6 +207,38 @@ namespace NzbDrone.Core.Notifications
}
}
public void Handle(MovieDownloadedEvent message)
{
var downloadMessage = new DownloadMessage();
downloadMessage.Message = GetMessage(message.Movie.Movie, message.Movie.Quality);
downloadMessage.Series = null;
downloadMessage.EpisodeFile = null;
downloadMessage.MovieFile = message.MovieFile;
downloadMessage.Movie = message.Movie.Movie;
downloadMessage.OldFiles = null;
downloadMessage.OldMovieFiles = message.OldFiles;
downloadMessage.SourcePath = message.Movie.Path;
foreach (var notification in _notificationFactory.OnDownloadEnabled())
{
try
{
if (ShouldHandleMovie(notification.Definition, message.Movie.Movie))
{
if (downloadMessage.OldMovieFiles.Empty() || ((NotificationDefinition)notification.Definition).OnUpgrade)
{
notification.OnDownload(downloadMessage);
}
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to send OnDownload notification to: " + notification.Definition.Name);
}
}
}
public void Handle(SeriesRenamedEvent message)
{
foreach (var notification in _notificationFactory.OnRenameEnabled())
@ -159,5 +257,24 @@ namespace NzbDrone.Core.Notifications
}
}
}
public void Handle(MovieRenamedEvent message)
{
foreach (var notification in _notificationFactory.OnRenameEnabled())
{
try
{
if (ShouldHandleMovie(notification.Definition, message.Movie))
{
notification.OnMovieRename(message.Movie);
}
}
catch (Exception ex)
{
_logger.Warn(ex, "Unable to send OnRename notification to: " + notification.Definition.Name);
}
}
}
}
}

@ -19,18 +19,22 @@ namespace NzbDrone.Core.Notifications.NotifyMyAndroid
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Episode Grabbed";
const string title = "Movie Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings.ApiKey, (NotifyMyAndroidPriority)Settings.Priority);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Episode Downloaded";
const string title = "Movie Downloaded";
_proxy.SendNotification(title, message.Message, Settings.ApiKey, (NotifyMyAndroidPriority)Settings.Priority);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
}

@ -28,6 +28,10 @@ namespace NzbDrone.Core.Notifications.Plex
_plexClientService.Notify(Settings, header, message.Message);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
}

@ -35,6 +35,10 @@ namespace NzbDrone.Core.Notifications.Plex
Notify(Settings, header, message.Message);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{

@ -22,19 +22,24 @@ namespace NzbDrone.Core.Notifications.Plex
public override void OnDownload(DownloadMessage message)
{
UpdateIfEnabled(message.Series);
UpdateIfEnabled(message.Movie);
}
public override void OnMovieRename(Movie movie)
{
UpdateIfEnabled(movie);
}
public override void OnRename(Series series)
{
UpdateIfEnabled(series);
//UpdateIfEnabled(movie);
}
private void UpdateIfEnabled(Series series)
private void UpdateIfEnabled(Movie movie)
{
if (Settings.UpdateLibrary)
{
_plexServerService.UpdateLibrary(series, Settings);
_plexServerService.UpdateMovieSections(movie, Settings);
}
}

@ -17,6 +17,7 @@ namespace NzbDrone.Core.Notifications.Plex
public interface IPlexServerProxy
{
List<PlexSection> GetTvSections(PlexServerSettings settings);
List<PlexSection> GetMovieSections(PlexServerSettings settings);
void Update(int sectionId, PlexServerSettings settings);
void UpdateSeries(int metadataId, PlexServerSettings settings);
string Version(PlexServerSettings settings);
@ -66,6 +67,37 @@ namespace NzbDrone.Core.Notifications.Plex
.ToList();
}
public List<PlexSection> GetMovieSections(PlexServerSettings settings)
{
var request = GetPlexServerRequest("library/sections", Method.GET, settings);
var client = GetPlexServerClient(settings);
var response = client.Execute(request);
_logger.Trace("Sections response: {0}", response.Content);
CheckForError(response, settings);
if (response.Content.Contains("_children"))
{
return Json.Deserialize<PlexMediaContainerLegacy>(response.Content)
.Sections
.Where(d => d.Type == "movie")
.Select(s => new PlexSection
{
Id = s.Id,
Language = s.Language,
Locations = s.Locations,
Type = s.Type
})
.ToList();
}
return Json.Deserialize<PlexResponse<PlexSectionsContainer>>(response.Content)
.MediaContainer
.Sections
.Where(d => d.Type == "movie")
.ToList();
}
public void Update(int sectionId, PlexServerSettings settings)
{
var resource = string.Format("library/sections/{0}/refresh", sectionId);

@ -14,6 +14,7 @@ namespace NzbDrone.Core.Notifications.Plex
public interface IPlexServerService
{
void UpdateLibrary(Series series, PlexServerSettings settings);
void UpdateMovieSections(Movie movie, PlexServerSettings settings);
ValidationFailure Test(PlexServerSettings settings);
}
@ -62,11 +63,43 @@ namespace NzbDrone.Core.Notifications.Plex
}
}
public void UpdateMovieSections(Movie movie, PlexServerSettings settings)
{
try
{
_logger.Debug("Sending Update Request to Plex Server");
var version = _versionCache.Get(settings.Host, () => GetVersion(settings), TimeSpan.FromHours(2));
ValidateVersion(version);
var sections = GetSections(settings);
var partialUpdates = _partialUpdateCache.Get(settings.Host, () => PartialUpdatesAllowed(settings, version), TimeSpan.FromHours(2));
// TODO: Investiate partial updates later, for now just update all movie sections...
//if (partialUpdates)
//{
// UpdatePartialSection(series, sections, settings);
//}
//else
//{
sections.ForEach(s => UpdateSection(s.Id, settings));
//}
}
catch (Exception ex)
{
_logger.Warn(ex, "Failed to Update Plex host: " + settings.Host);
throw;
}
}
private List<PlexSection> GetSections(PlexServerSettings settings)
{
_logger.Debug("Getting sections from Plex host: {0}", settings.Host);
return _plexServerProxy.GetTvSections(settings).ToList();
return _plexServerProxy.GetMovieSections(settings).ToList();
}
private bool PartialUpdatesAllowed(PlexServerSettings settings, Version version)

@ -19,18 +19,22 @@ namespace NzbDrone.Core.Notifications.Prowl
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Episode Grabbed";
const string title = "Movie Grabbed";
_prowlService.SendNotification(title, grabMessage.Message, Settings.ApiKey, (NotificationPriority)Settings.Priority);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Episode Downloaded";
const string title = "Movie Downloaded";
_prowlService.SendNotification(title, message.Message, Settings.ApiKey, (NotificationPriority)Settings.Priority);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
}

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

@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Pushalot
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Episode Grabbed";
const string title = "Movie Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Episode Downloaded";
const string title = "Movie Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
}

@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Pushover
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Episode Grabbed";
const string title = "Movie Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Episode Downloaded";
const string title = "Movie Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
}

@ -37,7 +37,7 @@ namespace NzbDrone.Core.Notifications.Slack
new Attachment
{
Fallback = message.Message,
Title = message.Series.Title,
Title = message.Movie.Title,
Text = message.Message,
Color = "warning"
}
@ -59,7 +59,7 @@ namespace NzbDrone.Core.Notifications.Slack
new Attachment
{
Fallback = message.Message,
Title = message.Series.Title,
Title = message.Movie.Title,
Text = message.Message,
Color = "good"
}
@ -69,6 +69,25 @@ namespace NzbDrone.Core.Notifications.Slack
NotifySlack(payload);
}
public override void OnMovieRename(Movie movie)
{
var payload = new SlackPayload
{
IconEmoji = Settings.Icon,
Username = Settings.Username,
Text = "Renamed",
Attachments = new List<Attachment>
{
new Attachment
{
Title = movie.Title,
}
}
};
NotifySlack(payload);
}
public override void OnRename(Series series)
{
var payload = new SlackPayload

@ -42,6 +42,10 @@ namespace NzbDrone.Core.Notifications.Synology
}
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
if (Settings.UpdateLibrary)

@ -18,18 +18,22 @@ namespace NzbDrone.Core.Notifications.Telegram
public override void OnGrab(GrabMessage grabMessage)
{
const string title = "Episode Grabbed";
const string title = "Movie Grabbed";
_proxy.SendNotification(title, grabMessage.Message, Settings);
}
public override void OnDownload(DownloadMessage message)
{
const string title = "Episode Downloaded";
const string title = "Movie Downloaded";
_proxy.SendNotification(title, message.Message, Settings);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
}

@ -29,6 +29,10 @@ namespace NzbDrone.Core.Notifications.Twitter
_twitterService.SendNotification($"Imported: {message.Message}", Settings);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
}

@ -27,6 +27,10 @@ namespace NzbDrone.Core.Notifications.Webhook
_service.OnDownload(message.Series, message.EpisodeFile, Settings);
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
_service.OnRename(series, Settings);

@ -36,6 +36,10 @@ namespace NzbDrone.Core.Notifications.Xbmc
UpdateAndClean(message.Series, message.OldFiles.Any());
}
public override void OnMovieRename(Movie movie)
{
}
public override void OnRename(Series series)
{
UpdateAndClean(series);

@ -583,6 +583,7 @@
<Compile Include="Http\HttpProxySettingsProvider.cs" />
<Compile Include="Http\TorcacheHttpInterceptor.cs" />
<Compile Include="IndexerSearch\Definitions\MovieSearchCriteria.cs" />
<Compile Include="IndexerSearch\MissingMoviesSearchCommand.cs" />
<Compile Include="IndexerSearch\MoviesSearchCommand.cs" />
<Compile Include="IndexerSearch\MoviesSearchService.cs" />
<Compile Include="Indexers\AwesomeHD\AwesomeHDRssParser.cs" />

@ -125,7 +125,8 @@ namespace NzbDrone.Core.Organizer
RelativePath = "Movie.Title.2010.1080p.BluRay.DTS.x264-EVOLVE.mkv",
SceneName = "Movie.Title.2010.1080p.BluRay.DTS.x264-EVOLVE",
ReleaseGroup = "RlsGrp",
MediaInfo = mediaInfo
MediaInfo = mediaInfo,
Edition = "Ultimate extended edition",
};
_singleEpisodeFile = new EpisodeFile

@ -12,5 +12,6 @@
ThreeLetterCode = threeLetterCode;
Language = language;
}
}
}

@ -18,20 +18,20 @@ 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>(\.?((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+|_|$)(?!\\)",
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>((Extended.|Ultimate.)?(Director.?s|Collector.?s|Theatrical|Ultimate|Final|Extended|Rogue|Special|Despecialized).(Cut|Edition|Version)|Extended|Uncensored|Remastered|Unrated|Uncut|IMAX))",
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
new Regex(@"^(?<title>.+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)\[!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\]|\W\d+)))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//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+|_|$)(?!\\)",
new Regex(@"^(?<title>(?![(\[]).+?)?(?:(?:[-_\W](?<![)!]))*(?<year>(19|20)\d{2}(?!p|i|\d+|\W\d+)))+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
};
@ -268,7 +268,7 @@ namespace NzbDrone.Core.Parser
private static readonly Regex ReportImdbId = new Regex(@"(?<imdbid>tt\d{9})", RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex SimpleTitleRegex = new Regex(@"(?:480[ip]|576[ip]|720[ip]|1080[ip]|[xh][\W_]?26[45]|DD\W?5\W1|[<>?*:|]|848x480|1280x720|1920x1080|(8|10)b(it)?)\s*",
private static readonly Regex SimpleTitleRegex = new Regex(@"(?:480[ip]|576[ip]|720[ip]|1080[ip]|2160[ip]|[xh][\W_]?26[45]|DD\W?5\W1|[<>?*:|]|848x480|1280x720|1920x1080|(8|10)b(it)?)\s*",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex WebsitePrefixRegex = new Regex(@"^\[\s*[a-z]+(\.[a-z]+)+\s*\][- ]*",
@ -696,6 +696,12 @@ namespace NzbDrone.Core.Parser
private static ParsedMovieInfo ParseMovieMatchCollection(MatchCollection matchCollection)
{
if (!matchCollection[0].Groups["title"].Success)
{
return null;
}
var seriesName = matchCollection[0].Groups["title"].Value.Replace('.', ' ').Replace('_', ' ');
seriesName = RequestInfoRegex.Replace(seriesName, "").Trim(' ');

@ -396,9 +396,15 @@ namespace NzbDrone.Core.Parser
if (searchCriteria == null)
{
if (parsedEpisodeInfo.Year > 1900)
{
movie = _movieService.FindByTitle(parsedEpisodeInfo.MovieTitle, parsedEpisodeInfo.Year);
//Todo: same as above!
}
else
{
movie = _movieService.FindByTitle(parsedEpisodeInfo.MovieTitle); //Todo: same as above!
}
return movie;
}

@ -3,6 +3,7 @@ using NzbDrone.Core.IndexerSearch;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Messaging.Events;
using System.Collections.Generic;
namespace NzbDrone.Core.Tv
{
@ -37,7 +38,7 @@ namespace NzbDrone.Core.Tv
if (movie.AddOptions.SearchForMovie)
{
_commandQueueManager.Push(new MoviesSearchCommand { MovieId = movie.Id});
_commandQueueManager.Push(new MoviesSearchCommand { MovieIds = new List<int> { movie.Id } });
}
movie.AddOptions = null;

@ -51,7 +51,7 @@ namespace NzbDrone.Core.Tv
try
{
movieInfo = _movieInfo.GetMovieInfo(movie.TmdbId);
movieInfo = _movieInfo.GetMovieInfo(movie.TmdbId, movie.Profile);
}
catch (MovieNotFoundException)
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 81 KiB

@ -1,7 +1,7 @@
var Marionette = require('marionette');
var Backgrid = require('backgrid');
var QueueCollection = require('./QueueCollection');
var SeriesTitleCell = require('../../Cells/MovieTitleCell');
var MovieTitleCell = require('../../Cells/MovieTitleCell');
var EpisodeNumberCell = require('../../Cells/EpisodeNumberCell');
var EpisodeTitleCell = require('../../Cells/EpisodeTitleCell');
var QualityCell = require('../../Cells/QualityCell');
@ -30,7 +30,7 @@ module.exports = Marionette.Layout.extend({
{
name : 'movie',
label : 'Movie',
cell : SeriesTitleCell
cell : MovieTitleCell
},
/*{
name : 'episode',

@ -6,9 +6,7 @@ module.exports = TemplatedCell.extend({
render : function() {
this.$el.html(this.model.get("movie").get("title")); //Hack, but somehow handlebar helper does not work.
debugger;
this.$el.html('<a href="movies/' + this.model.get("movie").get("titleSlug") +'">' + this.model.get("movie").get("title") + '</a>'); //Hack, but somehow handlebar helper does not work.
return this;
}
});

@ -2,23 +2,26 @@ var $ = require('jquery');
var vent = require('./vent');
module.exports = {
ConfigNamespace : 'Radarr.',
Events : {
ConfigUpdatedEvent : 'ConfigUpdatedEvent'
},
Keys : {
DefaultProfileId : 'DefaultProfileId',
DefaultRootFolderId : 'DefaultRootFolderId',
UseSeasonFolder : 'UseSeasonFolder',
DefaultSeriesType : 'DefaultSeriesType',
MonitorEpisodes : 'MonitorEpisodes',
AdvancedSettings : 'advancedSettings'
DefaultProfileId : 'RadarrDefaultProfileId',
DefaultRootFolderId : 'RadarrDefaultRootFolderId',
UseSeasonFolder : 'RadarrUseSeasonFolder',
DefaultSeriesType : 'RadarrDefaultSeriesType',
MonitorEpisodes : 'RadarrMonitorEpisodes',
AdvancedSettings : 'RadarradvancedSettings'
},
getValueJson : function (key, defaultValue) {
var storeKey = this.ConfigNamespace + key;
defaultValue = defaultValue || {};
var storeValue = window.localStorage.getItem(key);
var storeValue = window.localStorage.getItem(storeKey);
if (!storeValue) {
return defaultValue;
@ -34,7 +37,8 @@ module.exports = {
},
getValue : function(key, defaultValue) {
var storeValue = window.localStorage.getItem(key);
var storeKey = this.ConfigNamespace + key;
var storeValue = window.localStorage.getItem(storeKey);
if (!storeValue) {
return defaultValue;
@ -48,22 +52,22 @@ module.exports = {
},
setValue : function(key, value) {
console.log('Config: [{0}] => [{1}]'.format(key, value));
var storeKey = this.ConfigNamespace + key;
console.log('Config: [{0}] => [{1}]'.format(storeKey, value));
if (this.getValue(key) === value.toString()) {
return;
}
try {
window.localStorage.setItem(key, value);
window.localStorage.setItem(storeKey, value);
vent.trigger(this.Events.ConfigUpdatedEvent, {
key : key,
value : value
});
}
catch (error) {
console.error('Unable to save config: [{0}] => [{1}]'.format(key, value));
console.error('Unable to save config: [{0}] => [{1}]'.format(storeKey, value));
}
}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

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

Loading…
Cancel
Save