diff --git a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs index a1e869ad6..e9674bca7 100644 --- a/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs +++ b/src/NzbDrone.Core/Download/Clients/rTorrent/RTorrent.cs @@ -61,6 +61,10 @@ namespace NzbDrone.Core.Download.Clients.RTorrent var retryDelay = 500; if (WaitForTorrent(hash, tries, retryDelay)) { + _logger.Info("Resolved magnet for {0}", remoteMovie.Movie.CleanTitle); + SetDownloadDirectory(hash); + _proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings); + _proxy.StartTorrent(hash, Settings); return hash; } else diff --git a/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs index 8a25f064c..6dca9f998 100644 --- a/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Newznab/NewznabRequestGenerator.cs @@ -58,7 +58,8 @@ namespace NzbDrone.Core.Indexers.Newznab } else { - pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "search", $"&q={Parser.Parser.NormalizeTitle(searchCriteria.Movie.Title)}%20{searchCriteria.Movie.Year}")); + var searchTitle = Parser.Parser.ReplaceGermanUmlauts(Parser.Parser.NormalizeTitle(searchCriteria.Movie.Title)); + pageableRequests.Add(GetPagedRequests(MaxPages, Settings.Categories, "search", $"&q={searchTitle}%20{searchCriteria.Movie.Year}")); } return pageableRequests; diff --git a/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs b/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs index b3cb1d9d8..c75ab0595 100644 --- a/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs +++ b/src/NzbDrone.Core/Indexers/Rarbg/RarbgRequestGenerator.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using NzbDrone.Common.Extensions; using NzbDrone.Common.Http; using NzbDrone.Core.IndexerSearch.Definitions; @@ -20,60 +19,18 @@ namespace NzbDrone.Core.Indexers.Rarbg public virtual IndexerPageableRequestChain GetRecentRequests() { var pageableRequests = new IndexerPageableRequestChain(); - pageableRequests.Add(GetPagedRequests("list", null, null)); - return pageableRequests; } - public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria) + public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) { var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, "S{0:00}E{1:00}", searchCriteria.SeasonNumber, searchCriteria.EpisodeNumber)); - + pageableRequests.Add(GetMovieRequest(searchCriteria)); return pageableRequests; } - public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, "S{0:00}", searchCriteria.SeasonNumber)); - - return pageableRequests; - } - - public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, "\"{0:yyyy MM dd}\"", searchCriteria.AirDate)); - - return pageableRequests; - } - - public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria) - { - return new IndexerPageableRequestChain(); - } - - public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) - { - var pageableRequests = new IndexerPageableRequestChain(); - - foreach (var queryTitle in searchCriteria.EpisodeQueryTitles) - { - var query = queryTitle.Replace('+', ' '); - query = System.Web.HttpUtility.UrlEncode(query); - - pageableRequests.Add(GetPagedRequests("search", searchCriteria.Series.TvdbId, query)); - } - - return pageableRequests; - } - - private IEnumerable GetPagedRequests(string mode, int? tvdbId, string query, params object[] args) + private IEnumerable GetPagedRequests(string mode, int? imdbId, string query, params object[] args) { var requestBuilder = new HttpRequestBuilder(Settings.BaseUrl) .Resource("/pubapi_v2.php") @@ -87,9 +44,9 @@ namespace NzbDrone.Core.Indexers.Rarbg requestBuilder.AddQueryParam("mode", mode); - if (tvdbId.HasValue) + if (imdbId.HasValue) { - requestBuilder.AddQueryParam("search_tvdb", tvdbId.Value); + requestBuilder.AddQueryParam("search_imdb", imdbId.Value); } if (query.IsNotNullOrWhiteSpace()) @@ -102,11 +59,11 @@ namespace NzbDrone.Core.Indexers.Rarbg requestBuilder.AddQueryParam("ranked", "0"); } - requestBuilder.AddQueryParam("category", "tv"); + requestBuilder.AddQueryParam("category", "movies"); requestBuilder.AddQueryParam("limit", "100"); requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings)); requestBuilder.AddQueryParam("format", "json_extended"); - requestBuilder.AddQueryParam("app_id", "Sonarr"); + requestBuilder.AddQueryParam("app_id", "Radarr"); yield return new IndexerRequest(requestBuilder.Build()); } @@ -136,22 +93,34 @@ namespace NzbDrone.Core.Indexers.Rarbg requestBuilder.AddQueryParam("limit", "100"); requestBuilder.AddQueryParam("token", _tokenProvider.GetToken(Settings)); requestBuilder.AddQueryParam("format", "json_extended"); - requestBuilder.AddQueryParam("app_id", "Sonarr"); + requestBuilder.AddQueryParam("app_id", "Radarr"); yield return new IndexerRequest(requestBuilder.Build()); } - public IndexerPageableRequestChain GetSearchRequests(MovieSearchCriteria searchCriteria) + public virtual IndexerPageableRequestChain GetSearchRequests(SingleEpisodeSearchCriteria searchCriteria) { - + return new IndexerPageableRequestChain(); + } - var pageableRequests = new IndexerPageableRequestChain(); + public virtual IndexerPageableRequestChain GetSearchRequests(SeasonSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } - pageableRequests.Add(GetMovieRequest(searchCriteria)); + public virtual IndexerPageableRequestChain GetSearchRequests(DailyEpisodeSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } - return pageableRequests; + public virtual IndexerPageableRequestChain GetSearchRequests(AnimeEpisodeSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); + } - + public virtual IndexerPageableRequestChain GetSearchRequests(SpecialEpisodeSearchCriteria searchCriteria) + { + return new IndexerPageableRequestChain(); } } } diff --git a/src/NzbDrone.Core/Indexers/Rarbg/RarbgTokenProvider.cs b/src/NzbDrone.Core/Indexers/Rarbg/RarbgTokenProvider.cs index 628faac41..44aa87599 100644 --- a/src/NzbDrone.Core/Indexers/Rarbg/RarbgTokenProvider.cs +++ b/src/NzbDrone.Core/Indexers/Rarbg/RarbgTokenProvider.cs @@ -31,7 +31,7 @@ namespace NzbDrone.Core.Indexers.Rarbg { var requestBuilder = new HttpRequestBuilder(settings.BaseUrl.Trim('/')) .WithRateLimit(3.0) - .Resource("/pubapi_v2.php?get_token=get_token&app_id=Sonarr") + .Resource("/pubapi_v2.php?get_token=get_token&app_id=Radarr") .Accept(HttpAccept.Json); if (settings.CaptchaToken.IsNotNullOrWhiteSpace()) diff --git a/src/NzbDrone.Core/NetImport/NetImportFactory.cs b/src/NzbDrone.Core/NetImport/NetImportFactory.cs index 1e6ebf344..19a8eadee 100644 --- a/src/NzbDrone.Core/NetImport/NetImportFactory.cs +++ b/src/NzbDrone.Core/NetImport/NetImportFactory.cs @@ -30,7 +30,8 @@ namespace NzbDrone.Core.NetImport protected override List Active() { - return base.Active().Where(c => c.Enabled).ToList(); + // return base.Active().Where(c => c.Enabled).ToList(); // use this for when/if we add a setting to enable/disable lists + return base.Active().ToList(); } public override void SetProviderCharacteristics(INetImport provider, NetImportDefinition definition) diff --git a/src/NzbDrone.Core/NetImport/NetImportListLevels.cs b/src/NzbDrone.Core/NetImport/NetImportListLevels.cs new file mode 100644 index 000000000..3d8587da4 --- /dev/null +++ b/src/NzbDrone.Core/NetImport/NetImportListLevels.cs @@ -0,0 +1,11 @@ +namespace NzbDrone.Core.NetImport +{ + public enum NetImportCleanLibraryLevels + { + Disabled, + LogOnly, + KeepAndUnmonitor, + RemoveAndKeep, + RemoveAndDelete + } +} diff --git a/src/NzbDrone.Core/NetImport/NetImportSearchService.cs b/src/NzbDrone.Core/NetImport/NetImportSearchService.cs index 0bfe92b67..1f49a3f96 100644 --- a/src/NzbDrone.Core/NetImport/NetImportSearchService.cs +++ b/src/NzbDrone.Core/NetImport/NetImportSearchService.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System; using System.Linq; +using System.Text.RegularExpressions; using NLog; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.MetadataSource; @@ -8,6 +9,10 @@ using NzbDrone.Core.RootFolders; using NzbDrone.Core.Tv; using NzbDrone.Core.Configuration; using NzbDrone.Common.Extensions; +using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Core.DecisionEngine; +using NzbDrone.Core.Download; +using NzbDrone.Core.IndexerSearch; namespace NzbDrone.Core.NetImport { @@ -25,14 +30,19 @@ namespace NzbDrone.Core.NetImport private readonly ISearchForNewMovie _movieSearch; private readonly IRootFolderService _rootFolder; private readonly IConfigService _configService; - + private readonly ISearchForNzb _nzbSearchService; + private readonly IProcessDownloadDecisions _processDownloadDecisions; + public NetImportSearchService(INetImportFactory netImportFactory, IMovieService movieService, - ISearchForNewMovie movieSearch, IRootFolderService rootFolder, IConfigService configService, Logger logger) + ISearchForNewMovie movieSearch, IRootFolderService rootFolder, ISearchForNzb nzbSearchService, + IProcessDownloadDecisions processDownloadDecisions, IConfigService configService, Logger logger) { _netImportFactory = netImportFactory; _movieService = movieService; _movieSearch = movieSearch; + _nzbSearchService = nzbSearchService; + _processDownloadDecisions = processDownloadDecisions; _rootFolder = rootFolder; _logger = logger; _configService = configService; @@ -74,6 +84,8 @@ namespace NzbDrone.Core.NetImport return movies; } + + public void Execute(NetImportSyncCommand message) { //if there are no lists that are enabled for automatic import then dont do anything @@ -84,13 +96,69 @@ namespace NzbDrone.Core.NetImport } var listedMovies = Fetch(0, true); + + CleanLibrary(listedMovies); + + listedMovies = listedMovies.Where(x => !_movieService.MovieExists(x)).ToList(); + if (listedMovies.Any()) + { + _logger.Info($"Found {listedMovies.Count()} movies on your auto enabled lists not in your library"); + } + + + var importExclusions = new List(); + if (_configService.ImportExclusions != null) + { + // Replace `movie-title-tmdbid` with just tmdbid in exclusions + importExclusions = _configService.ImportExclusions.Split(',').Select(x => Regex.Replace(x, @"^.*\-(.*)$", "$1")).ToList(); + // listedMovies = listedMovies.Where(ah => importExclusions.Any(h => ah.TmdbId.ToString() != h)).ToList(); + } + + var downloadedCount = 0; + foreach (var movie in listedMovies) + { + var mapped = _movieSearch.MapMovieToTmdbMovie(movie); + if (mapped != null && !importExclusions.Any(x => x == mapped.TmdbId.ToString())) + { + List decisions; + mapped.AddOptions = new AddMovieOptions {SearchForMovie = true}; + _movieService.AddMovie(mapped); + + // Search for movie + try + { + decisions = _nzbSearchService.MovieSearch(mapped.Id, false); + } + catch (Exception ex) + { + _logger.Error(ex, $"Unable to search in list for movie {mapped.Id}"); + continue; + } + + var processed = _processDownloadDecisions.ProcessDecisions(decisions); + downloadedCount += processed.Grabbed.Count; + } + else + { + if (mapped != null) + { + _logger.Info($"{mapped.Title} ({mapped.TitleSlug}) will not be added since it was found on the exclusions list"); + } + } + } + + _logger.ProgressInfo("Movie search completed. {0} reports downloaded.", downloadedCount); + } + + private void CleanLibrary(List movies) + { if (_configService.ListSyncLevel != "disabled") { var moviesInLibrary = _movieService.GetAllMovies(); foreach (var movie in moviesInLibrary) - { + { bool foundMatch = false; - foreach (var listedMovie in listedMovies) + foreach (var listedMovie in movies) { if (movie.TmdbId == listedMovie.TmdbId) { @@ -101,7 +169,7 @@ namespace NzbDrone.Core.NetImport } if (!foundMatch) { - switch(_configService.ListSyncLevel) + switch (_configService.ListSyncLevel) { case "logOnly": _logger.Info("{0} was in your library, but not found in your lists --> You might want to unmonitor or remove it", movie); @@ -120,51 +188,10 @@ namespace NzbDrone.Core.NetImport //TODO: for some reason the files are not deleted in this case... any idea why? break; default: - break; - } - } - } - } - - List importExclusions = null; - if (_configService.ImportExclusions != String.Empty) - { - importExclusions = _configService.ImportExclusions.Split(',').ToList(); - } - - var movies = listedMovies.Where(x => !_movieService.MovieExists(x)).ToList(); - - if (movies.Count > 0) - { - _logger.Info("Found {0} movies on your auto enabled lists not in your library", movies.Count); - } - - foreach (var movie in movies) - { - bool shouldAdd = true; - if (importExclusions != null) - { - foreach (var exclusion in importExclusions) - { - //var excludedTmdbId = exclusion.Substring(exclusion.LastIndexOf('-')+1); - int excludedTmdbId; - if (Int32.TryParse(exclusion.Substring(exclusion.LastIndexOf('-') + 1), out excludedTmdbId)) - { - if (excludedTmdbId == movie.TmdbId) - { - _logger.Info("Movie: {0} was found but will not be added because {1} was found on your exclusion list", movie, exclusion); - shouldAdd = false; break; - } } } } - - var mapped = _movieSearch.MapMovieToTmdbMovie(movie); - if ((mapped != null) && shouldAdd) - { - _movieService.AddMovie(mapped); - } } } } diff --git a/src/NzbDrone.Core/NetImport/RSSImport/RSSImport.cs b/src/NzbDrone.Core/NetImport/RSSImport/RSSImport.cs index 60d6c6016..9b562b33f 100644 --- a/src/NzbDrone.Core/NetImport/RSSImport/RSSImport.cs +++ b/src/NzbDrone.Core/NetImport/RSSImport/RSSImport.cs @@ -11,7 +11,7 @@ namespace NzbDrone.Core.NetImport.RSSImport { public override string Name => "RSSList"; public override bool Enabled => true; - public override bool EnableAuto => true; + public override bool EnableAuto => false; public RSSImport(IHttpClient httpClient, IConfigService configService, IParsingService parsingService, Logger logger) : base(httpClient, configService, parsingService, logger) diff --git a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuImport.cs b/src/NzbDrone.Core/NetImport/StevenLu/StevenLuImport.cs index 80e69209f..643d4dd4a 100644 --- a/src/NzbDrone.Core/NetImport/StevenLu/StevenLuImport.cs +++ b/src/NzbDrone.Core/NetImport/StevenLu/StevenLuImport.cs @@ -9,7 +9,7 @@ namespace NzbDrone.Core.NetImport.StevenLu { public override string Name => "StevenLu"; public override bool Enabled => true; - public override bool EnableAuto => true; + public override bool EnableAuto => false; public StevenLuImport(IHttpClient httpClient, IConfigService configService, IParsingService parsingService, Logger logger) : base(httpClient, configService, parsingService, logger) diff --git a/src/NzbDrone.Core/NetImport/TMDb/TMDbImport.cs b/src/NzbDrone.Core/NetImport/TMDb/TMDbImport.cs index d7a20303c..1524e307c 100644 --- a/src/NzbDrone.Core/NetImport/TMDb/TMDbImport.cs +++ b/src/NzbDrone.Core/NetImport/TMDb/TMDbImport.cs @@ -11,6 +11,7 @@ namespace NzbDrone.Core.NetImport.TMDb public override string Name => "TMDb Lists"; public override bool Enabled => true; public override bool EnableAuto => false; + private readonly IHttpClient _httpClient; private readonly Logger _logger; diff --git a/src/NzbDrone.Core/NetImport/Trakt/TraktImport.cs b/src/NzbDrone.Core/NetImport/Trakt/TraktImport.cs index 94dc7f2ab..22dd15770 100644 --- a/src/NzbDrone.Core/NetImport/Trakt/TraktImport.cs +++ b/src/NzbDrone.Core/NetImport/Trakt/TraktImport.cs @@ -10,6 +10,7 @@ namespace NzbDrone.Core.NetImport.Trakt public override string Name => "Trakt List"; public override bool Enabled => true; public override bool EnableAuto => false; + private readonly IHttpClient _httpClient; public IConfigService _configService; diff --git a/src/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs b/src/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs index 8b851f24d..d983c96c4 100644 --- a/src/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs +++ b/src/NzbDrone.Core/Notifications/NotifyMyAndroid/NotifyMyAndroidProxy.cs @@ -32,7 +32,7 @@ namespace NzbDrone.Core.Notifications.NotifyMyAndroid var request = new RestRequest("notify", Method.POST); request.RequestFormat = DataFormat.Xml; request.AddParameter("apikey", apiKey); - request.AddParameter("application", "Sonarr"); + request.AddParameter("application", "Radarr"); request.AddParameter("event", title); request.AddParameter("description", message); request.AddParameter("priority", (int)priority); diff --git a/src/NzbDrone.Core/Notifications/Plex/PlexServerProxy.cs b/src/NzbDrone.Core/Notifications/Plex/PlexServerProxy.cs index aa9e660fd..0eb0002c3 100644 --- a/src/NzbDrone.Core/Notifications/Plex/PlexServerProxy.cs +++ b/src/NzbDrone.Core/Notifications/Plex/PlexServerProxy.cs @@ -224,8 +224,8 @@ namespace NzbDrone.Core.Notifications.Plex request.AddHeader("X-Plex-Platform-Version", "7"); request.AddHeader("X-Plex-Provides", "player"); request.AddHeader("X-Plex-Client-Identifier", "AB6CCCC7-5CF5-4523-826A-B969E0FFD8A0"); - request.AddHeader("X-Plex-Device-Name", "Sonarr"); - request.AddHeader("X-Plex-Product", "Sonarr"); + request.AddHeader("X-Plex-Device-Name", "Radarr"); + request.AddHeader("X-Plex-Product", "Radarr"); request.AddHeader("X-Plex-Version", BuildInfo.Version.ToString()); return request; diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 721130fdb..fe287ab33 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -132,6 +132,7 @@ + diff --git a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs index 52c9bb104..b6f953e61 100644 --- a/src/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/src/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -543,7 +543,7 @@ namespace NzbDrone.Core.Organizer { tokenHandlers["{Original Title}"] = m => GetOriginalTitle(episodeFile); tokenHandlers["{Original Filename}"] = m => GetOriginalFileName(episodeFile); - tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup ?? m.DefaultValue("Sonarr"); + tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup ?? m.DefaultValue("Radarr"); } private void AddMovieFileTokens(Dictionary> tokenHandlers, MovieFile episodeFile) @@ -551,7 +551,7 @@ namespace NzbDrone.Core.Organizer tokenHandlers["{Original Title}"] = m => GetOriginalTitle(episodeFile); tokenHandlers["{Original Filename}"] = m => GetOriginalFileName(episodeFile); //tokenHandlers["{IMDb Id}"] = m => - tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup ?? m.DefaultValue("Sonarr"); + tokenHandlers["{Release Group}"] = m => episodeFile.ReleaseGroup ?? m.DefaultValue("Radarr"); } private void AddQualityTokens(Dictionary> tokenHandlers, Series series, EpisodeFile episodeFile)