mirror of
https://github.com/Radarr/Radarr.git
synced 2024-09-17 15:02:34 +02:00
Added: Ability to see TMDB and lists going through the Radarr API on the discovery page.
Added: More lists (specifically presets for IMDB Top 250 and IMDB Popular) Added: Ability to set Radarr API endpoint as list.
This commit is contained in:
parent
b70ed720c5
commit
accf8a9efa
@ -6,17 +6,22 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.NetImport;
|
||||
using NzbDrone.Api.NetImport;
|
||||
|
||||
namespace NzbDrone.Api.Movie
|
||||
{
|
||||
public class MovieDiscoverModule : NzbDroneRestModule<MovieResource>
|
||||
{
|
||||
private readonly IDiscoverNewMovies _searchProxy;
|
||||
private readonly INetImportFactory _netImportFactory;
|
||||
|
||||
public MovieDiscoverModule(IDiscoverNewMovies searchProxy)
|
||||
public MovieDiscoverModule(IDiscoverNewMovies searchProxy, INetImportFactory netImportFactory)
|
||||
: base("/movies/discover")
|
||||
{
|
||||
_searchProxy = searchProxy;
|
||||
_netImportFactory = netImportFactory;
|
||||
Get["/lists"] = x => GetLists();
|
||||
Get["/{action?recommendations}"] = x => Search(x.action);
|
||||
}
|
||||
|
||||
@ -26,6 +31,20 @@ private Response Search(string action)
|
||||
return MapToResource(imdbResults).AsResponse();
|
||||
}
|
||||
|
||||
private Response GetLists()
|
||||
{
|
||||
var lists = _netImportFactory.Discoverable();
|
||||
|
||||
return lists.Select(definition => {
|
||||
var resource = new NetImportResource();
|
||||
resource.Id = definition.Definition.Id;
|
||||
|
||||
resource.Name = definition.Definition.Name;
|
||||
|
||||
return resource;
|
||||
}).AsResponse();
|
||||
}
|
||||
|
||||
private static IEnumerable<MovieResource> MapToResource(IEnumerable<Core.Tv.Movie> movies)
|
||||
{
|
||||
foreach (var currentSeries in movies)
|
||||
|
@ -20,7 +20,7 @@ public class RSSImportFixture : CoreTest<RSSImport>
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
Subject.Definition = Subject.DefaultDefinitions.First();
|
||||
Subject.Definition = Subject.GetDefaultDefinitions().First();
|
||||
}
|
||||
private void GivenRecentFeedResponse(string rssXmlFile)
|
||||
{
|
||||
|
@ -28,7 +28,10 @@ public abstract class DownloadClientBase<TSettings> : IDownloadClient
|
||||
|
||||
public virtual ProviderMessage Message => null;
|
||||
|
||||
public IEnumerable<ProviderDefinition> DefaultDefinitions => new List<ProviderDefinition>();
|
||||
public IEnumerable<ProviderDefinition> GetDefaultDefinitions()
|
||||
{
|
||||
return new List<ProviderDefinition>();
|
||||
}
|
||||
|
||||
public ProviderDefinition Definition { get; set; }
|
||||
|
||||
|
@ -17,7 +17,10 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||
|
||||
public virtual ProviderMessage Message => null;
|
||||
|
||||
public IEnumerable<ProviderDefinition> DefaultDefinitions => new List<ProviderDefinition>();
|
||||
public IEnumerable<ProviderDefinition> GetDefaultDefinitions()
|
||||
{
|
||||
return new List<ProviderDefinition>();
|
||||
}
|
||||
|
||||
public ProviderDefinition Definition { get; set; }
|
||||
|
||||
|
@ -38,21 +38,18 @@ public IndexerBase(IIndexerStatusService indexerStatusService, IConfigService co
|
||||
|
||||
public virtual ProviderMessage Message => null;
|
||||
|
||||
public virtual IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||
public virtual IEnumerable<ProviderDefinition> GetDefaultDefinitions()
|
||||
{
|
||||
get
|
||||
{
|
||||
var config = (IProviderConfig)new TSettings();
|
||||
var config = (IProviderConfig)new TSettings();
|
||||
|
||||
yield return new IndexerDefinition
|
||||
{
|
||||
Name = GetType().Name,
|
||||
EnableRss = config.Validate().IsValid && SupportsRss,
|
||||
EnableSearch = config.Validate().IsValid && SupportsSearch,
|
||||
Implementation = GetType().Name,
|
||||
Settings = config
|
||||
};
|
||||
}
|
||||
yield return new IndexerDefinition
|
||||
{
|
||||
Name = GetType().Name,
|
||||
EnableRss = config.Validate().IsValid && SupportsRss,
|
||||
EnableSearch = config.Validate().IsValid && SupportsSearch,
|
||||
Implementation = GetType().Name,
|
||||
Settings = config
|
||||
};
|
||||
}
|
||||
|
||||
public virtual ProviderDefinition Definition { get; set; }
|
||||
|
@ -35,25 +35,22 @@ public override IParseIndexerResponse GetParser()
|
||||
return new NewznabRssParser(Settings);
|
||||
}
|
||||
|
||||
public override IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||
public override IEnumerable<ProviderDefinition> GetDefaultDefinitions()
|
||||
{
|
||||
get
|
||||
{
|
||||
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"));
|
||||
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"));
|
||||
yield return GetDefinition("omgwtfnzbs", GetSettings("https://api.omgwtfnzbs.me"));
|
||||
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"));
|
||||
yield return GetDefinition("Usenet Crawler", GetSettings("https://www.usenet-crawler.com"));
|
||||
}
|
||||
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"));
|
||||
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"));
|
||||
yield return GetDefinition("omgwtfnzbs", GetSettings("https://api.omgwtfnzbs.me"));
|
||||
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"));
|
||||
yield return GetDefinition("Usenet Crawler", GetSettings("https://www.usenet-crawler.com"));
|
||||
}
|
||||
|
||||
public Newznab(INewznabCapabilitiesProvider capabilitiesProvider, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
|
||||
|
@ -37,13 +37,10 @@ public override IParseIndexerResponse GetParser()
|
||||
return new TorznabRssParser();
|
||||
}
|
||||
|
||||
public override IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||
public override IEnumerable<ProviderDefinition> GetDefaultDefinitions()
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return GetDefinition("Jackett", GetSettings("http://localhost:9117/torznab/YOURINDEXER"));
|
||||
yield return GetDefinition("HD4Free.xyz", GetSettings("http://hd4free.xyz"));
|
||||
}
|
||||
yield return GetDefinition("Jackett", GetSettings("http://localhost:9117/torznab/YOURINDEXER"));
|
||||
yield return GetDefinition("HD4Free.xyz", GetSettings("http://hd4free.xyz"));
|
||||
}
|
||||
|
||||
public Torznab(INewznabCapabilitiesProvider capabilitiesProvider, IHttpClient httpClient, IIndexerStatusService indexerStatusService, IConfigService configService, IParsingService parsingService, Logger logger)
|
||||
|
@ -8,5 +8,7 @@ public interface ISearchForNewMovie
|
||||
List<Movie> SearchForNewMovie(string title);
|
||||
|
||||
Movie MapMovieToTmdbMovie(Movie movie);
|
||||
|
||||
Movie MapMovie(SkyHook.Resource.MovieResult result);
|
||||
}
|
||||
}
|
@ -11,27 +11,30 @@ public interface IRadarrAPIClient
|
||||
{
|
||||
IHttpRequestBuilderFactory RadarrAPI { get; }
|
||||
List<MovieResult> DiscoverMovies(string action, Func<HttpRequest, HttpRequest> enhanceRequest);
|
||||
string APIURL { get; }
|
||||
}
|
||||
|
||||
public class RadarrAPIClient : IRadarrAPIClient
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
|
||||
public string APIURL { get; private set; }
|
||||
|
||||
public RadarrAPIClient(IConfigFileProvider configFile, IHttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
|
||||
if (configFile.Branch == "nightly")
|
||||
{
|
||||
RadarrAPI = new HttpRequestBuilder("https://staging.api.radarr.video/{route}/{action}")
|
||||
.CreateFactory();
|
||||
APIURL = "https://staging.api.radarr.video";
|
||||
}
|
||||
else
|
||||
{
|
||||
RadarrAPI = new HttpRequestBuilder("https://api.radarr.video/v2/{route}/{action}")
|
||||
.CreateFactory();
|
||||
APIURL = "https://api.radarr.video/v2";
|
||||
}
|
||||
|
||||
RadarrAPI = new HttpRequestBuilder(APIURL+"/{route}/{action}")
|
||||
.CreateFactory();
|
||||
}
|
||||
|
||||
private HttpResponse Execute(HttpRequest request)
|
||||
|
@ -168,23 +168,9 @@ public class ListResponseRoot
|
||||
public object poster_path { get; set; }
|
||||
}
|
||||
|
||||
public class Item
|
||||
public class Item : MovieResult
|
||||
{
|
||||
public string poster_path { get; set; }
|
||||
public bool adult { get; set; }
|
||||
public string overview { get; set; }
|
||||
public string release_date { get; set; }
|
||||
public string original_title { get; set; }
|
||||
public int[] genre_ids { get; set; }
|
||||
public int id { get; set; }
|
||||
public string media_type { get; set; }
|
||||
public string original_language { get; set; }
|
||||
public string title { get; set; }
|
||||
public string backdrop_path { get; set; }
|
||||
public float popularity { get; set; }
|
||||
public int vote_count { get; set; }
|
||||
public bool video { get; set; }
|
||||
public float vote_average { get; set; }
|
||||
public string first_air_date { get; set; }
|
||||
public string[] origin_country { get; set; }
|
||||
public string name { get; set; }
|
||||
|
@ -546,7 +546,7 @@ public List<Series> SearchForNewSeries(string title)
|
||||
}
|
||||
}
|
||||
|
||||
private Movie MapMovie(MovieResult result)
|
||||
public Movie MapMovie(MovieResult result)
|
||||
{
|
||||
var imdbMovie = new Movie();
|
||||
imdbMovie.TmdbId = result.id;
|
||||
|
@ -32,23 +32,21 @@ public NetImportBase(IConfigService configService, IParsingService parsingServic
|
||||
public Type ConfigContract => typeof(TSettings);
|
||||
|
||||
public virtual ProviderMessage Message => null;
|
||||
public virtual IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||
{
|
||||
get
|
||||
{
|
||||
var config = (IProviderConfig)new TSettings();
|
||||
|
||||
yield return new NetImportDefinition
|
||||
{
|
||||
Name = this.Name,
|
||||
Enabled = config.Validate().IsValid && Enabled,
|
||||
EnableAuto = true,
|
||||
ProfileId = 1,
|
||||
MinimumAvailability = MovieStatusType.Announced,
|
||||
Implementation = GetType().Name,
|
||||
Settings = config
|
||||
};
|
||||
}
|
||||
public virtual IEnumerable<ProviderDefinition> GetDefaultDefinitions()
|
||||
{
|
||||
var config = (IProviderConfig)new TSettings();
|
||||
|
||||
yield return new NetImportDefinition
|
||||
{
|
||||
Name = this.Name,
|
||||
Enabled = config.Validate().IsValid && Enabled,
|
||||
EnableAuto = true,
|
||||
ProfileId = 1,
|
||||
MinimumAvailability = MovieStatusType.Announced,
|
||||
Implementation = GetType().Name,
|
||||
Settings = config
|
||||
};
|
||||
}
|
||||
|
||||
public virtual ProviderDefinition Definition { get; set; }
|
||||
|
@ -10,6 +10,8 @@ namespace NzbDrone.Core.NetImport
|
||||
public interface INetImportFactory : IProviderFactory<INetImport, NetImportDefinition>
|
||||
{
|
||||
List<INetImport> Enabled();
|
||||
|
||||
List<INetImport> Discoverable();
|
||||
}
|
||||
|
||||
public class NetImportFactory : ProviderFactory<INetImport, NetImportDefinition>, INetImportFactory
|
||||
@ -46,6 +48,13 @@ public List<INetImport> Enabled()
|
||||
return indexers.ToList();
|
||||
}
|
||||
|
||||
public List<INetImport> Discoverable()
|
||||
{
|
||||
var enabledImporters = GetAvailableProviders().Where(n => (n.GetType() == typeof(Radarr.RadarrProxied) || n.GetType() == typeof(TMDb.TMDbImport)));
|
||||
var indexers = FilterBlockedIndexers(enabledImporters);
|
||||
return indexers.ToList();
|
||||
}
|
||||
|
||||
private IEnumerable<INetImport> FilterBlockedIndexers(IEnumerable<INetImport> importers)
|
||||
{
|
||||
foreach (var importer in importers)
|
||||
|
@ -17,33 +17,30 @@ public RSSImport(IHttpClient httpClient, IConfigService configService, IParsingS
|
||||
: base(httpClient, configService, parsingService, logger)
|
||||
{ }
|
||||
|
||||
public override IEnumerable<ProviderDefinition> DefaultDefinitions
|
||||
public override IEnumerable<ProviderDefinition> GetDefaultDefinitions()
|
||||
{
|
||||
get
|
||||
foreach (var def in base.GetDefaultDefinitions())
|
||||
{
|
||||
foreach (var def in base.DefaultDefinitions)
|
||||
{
|
||||
yield return def;
|
||||
}
|
||||
yield return new NetImportDefinition
|
||||
{
|
||||
Name = "IMDb List",
|
||||
Enabled = Enabled,
|
||||
EnableAuto = true,
|
||||
ProfileId = 1,
|
||||
Implementation = GetType().Name,
|
||||
Settings = new RSSImportSettings { Link = "http://rss.imdb.com/list/YOURLISTID" },
|
||||
};
|
||||
yield return new NetImportDefinition
|
||||
{
|
||||
Name = "IMDb Watchlist",
|
||||
Enabled = Enabled,
|
||||
EnableAuto = true,
|
||||
ProfileId = 1,
|
||||
Implementation = GetType().Name,
|
||||
Settings = new RSSImportSettings { Link = "http://rss.imdb.com/user/IMDBUSERID/watchlist" },
|
||||
};
|
||||
yield return def;
|
||||
}
|
||||
yield return new NetImportDefinition
|
||||
{
|
||||
Name = "IMDb List",
|
||||
Enabled = Enabled,
|
||||
EnableAuto = true,
|
||||
ProfileId = 1,
|
||||
Implementation = GetType().Name,
|
||||
Settings = new RSSImportSettings { Link = "http://rss.imdb.com/list/YOURLISTID" },
|
||||
};
|
||||
yield return new NetImportDefinition
|
||||
{
|
||||
Name = "IMDb Watchlist",
|
||||
Enabled = Enabled,
|
||||
EnableAuto = true,
|
||||
ProfileId = 1,
|
||||
Implementation = GetType().Name,
|
||||
Settings = new RSSImportSettings { Link = "http://rss.imdb.com/user/IMDBUSERID/watchlist" },
|
||||
};
|
||||
}
|
||||
|
||||
public override INetImportRequestGenerator GetRequestGenerator()
|
||||
|
78
src/NzbDrone.Core/NetImport/Radarr/RadarrParser.cs
Normal file
78
src/NzbDrone.Core/NetImport/Radarr/RadarrParser.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using Newtonsoft.Json;
|
||||
using NzbDrone.Core.NetImport.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MetadataSource.SkyHook.Resource;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.MetadataSource.RadarrAPI;
|
||||
using NzbDrone.Common.Http;
|
||||
|
||||
namespace NzbDrone.Core.NetImport.Radarr
|
||||
{
|
||||
public class RadarrParser : IParseNetImportResponse
|
||||
{
|
||||
private readonly RadarrSettings _settings;
|
||||
private NetImportResponse _importResponse;
|
||||
private readonly ISearchForNewMovie _skyhookProxy;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public RadarrParser(RadarrSettings settings, ISearchForNewMovie skyhookProxy)
|
||||
{
|
||||
_skyhookProxy = skyhookProxy;//TinyIoC.TinyIoCContainer.Current.Resolve<ISearchForNewMovie>();
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
public IList<Tv.Movie> ParseResponse(NetImportResponse importResponse)
|
||||
{
|
||||
_importResponse = importResponse;
|
||||
|
||||
var movies = new List<Tv.Movie>();
|
||||
|
||||
if (!PreProcess(_importResponse))
|
||||
{
|
||||
return movies;
|
||||
}
|
||||
|
||||
var jsonResponse = JsonConvert.DeserializeObject<List<MovieResult>>(_importResponse.Content);
|
||||
|
||||
// no movies were return
|
||||
if (jsonResponse == null)
|
||||
{
|
||||
return movies;
|
||||
}
|
||||
|
||||
return jsonResponse.SelectList(_skyhookProxy.MapMovie);
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected virtual bool PreProcess(NetImportResponse indexerResponse)
|
||||
{
|
||||
try
|
||||
{
|
||||
var error = JsonConvert.DeserializeObject<RadarrError>(indexerResponse.HttpResponse.Content);
|
||||
|
||||
if (error != null && error.Errors != null && error.Errors.Count != 0)
|
||||
{
|
||||
throw new RadarrAPIException(error);
|
||||
}
|
||||
}
|
||||
catch (JsonSerializationException)
|
||||
{
|
||||
//No error!
|
||||
}
|
||||
|
||||
|
||||
if (indexerResponse.HttpResponse.StatusCode != System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
throw new HttpException(indexerResponse.HttpRequest, indexerResponse.HttpResponse);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
84
src/NzbDrone.Core/NetImport/Radarr/RadarrProxied.cs
Normal file
84
src/NzbDrone.Core/NetImport/Radarr/RadarrProxied.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
|
||||
|
||||
namespace NzbDrone.Core.NetImport.Radarr
|
||||
{
|
||||
public class RadarrProxied : HttpNetImportBase<RadarrSettings>
|
||||
{
|
||||
public override string Name => "Radarr Proxied Lists";
|
||||
public override bool Enabled => true;
|
||||
public override bool EnableAuto => false;
|
||||
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly Logger _logger;
|
||||
private readonly ISearchForNewMovie _skyhookProxy;
|
||||
|
||||
public RadarrProxied(IHttpClient httpClient, IConfigService configService, IParsingService parsingService, ISearchForNewMovie skyhookProxy,
|
||||
Logger logger)
|
||||
: base(httpClient, configService, parsingService, logger)
|
||||
{
|
||||
_skyhookProxy = skyhookProxy;
|
||||
_logger = logger;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public override IEnumerable<ProviderDefinition> GetDefaultDefinitions()
|
||||
{
|
||||
foreach (var def in base.GetDefaultDefinitions())
|
||||
{
|
||||
yield return def;
|
||||
}
|
||||
|
||||
yield return new NetImportDefinition
|
||||
{
|
||||
Name = "IMDb Top 250",
|
||||
Enabled = Enabled,
|
||||
EnableAuto = true,
|
||||
ProfileId = 1,
|
||||
Implementation = GetType().Name,
|
||||
Settings = new RadarrSettings { Path = "/imdb/top250" },
|
||||
};
|
||||
yield return new NetImportDefinition
|
||||
{
|
||||
Name = "IMDb Popular Movies",
|
||||
Enabled = Enabled,
|
||||
EnableAuto = true,
|
||||
ProfileId = 1,
|
||||
Implementation = GetType().Name,
|
||||
Settings = new RadarrSettings { Path = "/imdb/popular" },
|
||||
};
|
||||
yield return new NetImportDefinition
|
||||
{
|
||||
Name = "IMDb List",
|
||||
Enabled = Enabled,
|
||||
EnableAuto = true,
|
||||
ProfileId = 1,
|
||||
Implementation = GetType().Name,
|
||||
Settings = new RadarrSettings { Path = "/imdb/list?listId=LISTID" },
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override INetImportRequestGenerator GetRequestGenerator()
|
||||
{
|
||||
return new RadarrRequestGenerator()
|
||||
{
|
||||
Settings = Settings,
|
||||
Logger = _logger,
|
||||
HttpClient = _httpClient
|
||||
};
|
||||
}
|
||||
|
||||
public override IParseNetImportResponse GetParser()
|
||||
{
|
||||
return new RadarrParser(Settings, _skyhookProxy);
|
||||
}
|
||||
}
|
||||
}
|
38
src/NzbDrone.Core/NetImport/Radarr/RadarrRequestGenerator.cs
Normal file
38
src/NzbDrone.Core/NetImport/Radarr/RadarrRequestGenerator.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using NzbDrone.Common.Http;
|
||||
using System.Collections.Generic;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.MetadataSource.SkyHook.Resource;
|
||||
|
||||
namespace NzbDrone.Core.NetImport.Radarr
|
||||
{
|
||||
public class RadarrRequestGenerator : INetImportRequestGenerator
|
||||
{
|
||||
public RadarrSettings Settings { get; set; }
|
||||
public IHttpClient HttpClient { get; set; }
|
||||
public Logger Logger { get; set; }
|
||||
|
||||
public int MaxPages { get; set; }
|
||||
|
||||
public RadarrRequestGenerator()
|
||||
{
|
||||
MaxPages = 3;
|
||||
}
|
||||
|
||||
public virtual NetImportPageableRequestChain GetMovies()
|
||||
{
|
||||
var pageableRequests = new NetImportPageableRequestChain();
|
||||
|
||||
var baseUrl = $"{Settings.APIURL.TrimEnd("/")}";
|
||||
|
||||
var request = new NetImportRequest($"{baseUrl}{Settings.Path}", HttpAccept.Json);
|
||||
|
||||
request.HttpRequest.SuppressHttpError = true;
|
||||
|
||||
pageableRequests.Add(new List<NetImportRequest> { request });
|
||||
return pageableRequests;
|
||||
}
|
||||
}
|
||||
}
|
42
src/NzbDrone.Core/NetImport/Radarr/RadarrSettings.cs
Normal file
42
src/NzbDrone.Core/NetImport/Radarr/RadarrSettings.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using FluentValidation;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Annotations;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
using NzbDrone.Core.Validation;
|
||||
using System.Text.RegularExpressions;
|
||||
using NzbDrone.Core.MetadataSource.RadarrAPI;
|
||||
|
||||
namespace NzbDrone.Core.NetImport.Radarr
|
||||
{
|
||||
|
||||
public class RadarrSettingsValidator : AbstractValidator<RadarrSettings>
|
||||
{
|
||||
public RadarrSettingsValidator()
|
||||
{
|
||||
RuleFor(c => c.APIURL).ValidRootUrl();
|
||||
}
|
||||
}
|
||||
|
||||
public class RadarrSettings : IProviderConfig
|
||||
{
|
||||
private static readonly RadarrSettingsValidator Validator = new RadarrSettingsValidator();
|
||||
|
||||
public RadarrSettings()
|
||||
{
|
||||
APIURL = "https://api.radarr.video";
|
||||
Path = "";
|
||||
}
|
||||
|
||||
[FieldDefinition(0, Label = "Radarr API URL", HelpText = "Link to to Radarr API URL.Use https://staging.api.radarr.video if you are on nightly.")]
|
||||
public string APIURL { get; set; }
|
||||
|
||||
[FieldDefinition(1, Label = "Path to list", HelpText = "Path to the list proxied by the Radarr API. Check the wiki for available lists.")]
|
||||
public string Path { get; set; }
|
||||
|
||||
public NzbDroneValidationResult Validate()
|
||||
{
|
||||
return new NzbDroneValidationResult(Validator.Validate(this));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using NLog;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Parser;
|
||||
|
||||
|
||||
@ -14,13 +15,15 @@ public class TMDbImport : HttpNetImportBase<TMDbSettings>
|
||||
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly Logger _logger;
|
||||
private readonly ISearchForNewMovie _skyhookProxy;
|
||||
|
||||
public TMDbImport(IHttpClient httpClient, IConfigService configService, IParsingService parsingService,
|
||||
public TMDbImport(IHttpClient httpClient, IConfigService configService, IParsingService parsingService, ISearchForNewMovie skyhookProxy,
|
||||
Logger logger)
|
||||
: base(httpClient, configService, parsingService, logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_httpClient = httpClient;
|
||||
_skyhookProxy = skyhookProxy;
|
||||
}
|
||||
|
||||
public override INetImportRequestGenerator GetRequestGenerator()
|
||||
@ -35,7 +38,7 @@ public override INetImportRequestGenerator GetRequestGenerator()
|
||||
|
||||
public override IParseNetImportResponse GetParser()
|
||||
{
|
||||
return new TMDbParser(Settings);
|
||||
return new TMDbParser(Settings, _skyhookProxy);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,8 @@
|
||||
using NLog;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.MetadataSource.SkyHook.Resource;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using TinyIoC;
|
||||
|
||||
namespace NzbDrone.Core.NetImport.TMDb
|
||||
{
|
||||
@ -13,10 +15,12 @@ public class TMDbParser : IParseNetImportResponse
|
||||
{
|
||||
private readonly TMDbSettings _settings;
|
||||
private NetImportResponse _importResponse;
|
||||
private readonly ISearchForNewMovie _skyhookProxy;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public TMDbParser(TMDbSettings settings)
|
||||
public TMDbParser(TMDbSettings settings, ISearchForNewMovie skyhookProxy)
|
||||
{
|
||||
_skyhookProxy = skyhookProxy;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
@ -41,22 +45,7 @@ public TMDbParser(TMDbSettings settings)
|
||||
return movies;
|
||||
}
|
||||
|
||||
foreach (var movie in jsonResponse.results)
|
||||
{
|
||||
// Movies with no Year Fix
|
||||
if (string.IsNullOrWhiteSpace(movie.release_date))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
movies.AddIfNotNull(new Tv.Movie()
|
||||
{
|
||||
Title = movie.title,
|
||||
TmdbId = movie.id,
|
||||
ImdbId = null,
|
||||
Year = DateTime.Parse(movie.release_date).Year
|
||||
});
|
||||
}
|
||||
return jsonResponse.results.SelectList(_skyhookProxy.MapMovie);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -82,13 +71,7 @@ public TMDbParser(TMDbSettings settings)
|
||||
continue;
|
||||
}
|
||||
|
||||
movies.AddIfNotNull(new Tv.Movie()
|
||||
{
|
||||
Title = movie.title,
|
||||
TmdbId = movie.id,
|
||||
ImdbId = null,
|
||||
Year = DateTime.Parse(movie.release_date).Year
|
||||
});
|
||||
movies.AddIfNotNull(_skyhookProxy.MapMovie(movie));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,10 @@ namespace NzbDrone.Core.Notifications
|
||||
|
||||
public virtual ProviderMessage Message => null;
|
||||
|
||||
public IEnumerable<ProviderDefinition> DefaultDefinitions => new List<ProviderDefinition>();
|
||||
public IEnumerable<ProviderDefinition> GetDefaultDefinitions()
|
||||
{
|
||||
return new List<ProviderDefinition>();
|
||||
}
|
||||
|
||||
public ProviderDefinition Definition { get; set; }
|
||||
public abstract ValidationResult Test();
|
||||
|
@ -1285,6 +1285,10 @@
|
||||
<Compile Include="NetImport\ImportExclusions\ImportExclusionsRepository.cs" />
|
||||
<Compile Include="NetImport\ImportExclusions\ImportExclusionsService.cs" />
|
||||
<Compile Include="Datastore\Migration\138_add_physical_release_note.cs" />
|
||||
<Compile Include="NetImport\Radarr\RadarrProxied.cs" />
|
||||
<Compile Include="NetImport\Radarr\RadarrParser.cs" />
|
||||
<Compile Include="NetImport\Radarr\RadarrRequestGenerator.cs" />
|
||||
<Compile Include="NetImport\Radarr\RadarrSettings.cs" />
|
||||
<Compile Include="MetadataSource\RadarrAPI\RadarrResources.cs" />
|
||||
<Compile Include="MetadataSource\RadarrAPI\RadarrAPIClient.cs" />
|
||||
</ItemGroup>
|
||||
@ -1358,6 +1362,7 @@
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<Folder Include="NetImport\ImportExclusions\" />
|
||||
<Folder Include="NetImport\Radarr\" />
|
||||
<Folder Include="MetadataSource\RadarrAPI\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
|
@ -9,7 +9,9 @@ public interface IProvider
|
||||
string Name { get; }
|
||||
Type ConfigContract { get; }
|
||||
ProviderMessage Message { get; }
|
||||
IEnumerable<ProviderDefinition> DefaultDefinitions { get; }
|
||||
|
||||
IEnumerable<ProviderDefinition> GetDefaultDefinitions();
|
||||
|
||||
ProviderDefinition Definition { get; set; }
|
||||
ValidationResult Test();
|
||||
object RequestAction(string stage, IDictionary<string, string> query);
|
||||
|
@ -43,7 +43,7 @@ public IEnumerable<TProviderDefinition> GetDefaultDefinitions()
|
||||
{
|
||||
foreach (var provider in _providers)
|
||||
{
|
||||
var definition = provider.DefaultDefinitions
|
||||
var definition = provider.GetDefaultDefinitions()
|
||||
.OfType<TProviderDefinition>()
|
||||
.FirstOrDefault(v => v.Name == null || v.Name == provider.Name);
|
||||
|
||||
@ -68,7 +68,7 @@ public IEnumerable<TProviderDefinition> GetPresetDefinitions(TProviderDefinition
|
||||
{
|
||||
var provider = _providers.First(v => v.GetType().Name == providerDefinition.Implementation);
|
||||
|
||||
var definitions = provider.DefaultDefinitions
|
||||
var definitions = provider.GetDefaultDefinitions()
|
||||
.OfType<TProviderDefinition>()
|
||||
.Where(v => v.Name != null && v.Name != provider.Name)
|
||||
.ToList();
|
||||
|
@ -3,7 +3,12 @@ var $ = require('jquery');
|
||||
var vent = require('vent');
|
||||
var Marionette = require('marionette');
|
||||
var AddMoviesCollection = require('./AddMoviesCollection');
|
||||
var AddFromListCollection = require('./List/AddFromListCollection');
|
||||
var SearchResultCollectionView = require('./SearchResultCollectionView');
|
||||
var DiscoverableListDropdownView = require("./DiscoverableListDropdownView");
|
||||
var DiscoverableListCollection = require("./DiscoverableListCollection");
|
||||
var DiscoverableListCollectionView = require("./DiscoverableListCollectionView");
|
||||
var DiscoverMoviesCollection = require("./DiscoverMoviesCollection");
|
||||
var EmptyView = require('./EmptyView');
|
||||
var NotFoundView = require('./NotFoundView');
|
||||
var DiscoverEmptyView = require('./DiscoverEmptyView');
|
||||
@ -15,7 +20,8 @@ module.exports = Marionette.Layout.extend({
|
||||
template : 'AddMovies/AddMoviesViewTemplate',
|
||||
|
||||
regions : {
|
||||
searchResult : '#search-result'
|
||||
myRegion : '#my-region',
|
||||
searchResult : '#search-result',
|
||||
},
|
||||
|
||||
ui : {
|
||||
@ -26,14 +32,17 @@ module.exports = Marionette.Layout.extend({
|
||||
discoverBefore : ".x-discover-before",
|
||||
discoverRecos : ".x-recommendations-tab",
|
||||
discoverPopular : ".x-popular-tab" ,
|
||||
discoverUpcoming : ".x-upcoming-tab"
|
||||
discoverUpcoming : ".x-upcoming-tab",
|
||||
discoverLists : ".x-lists-tab"
|
||||
},
|
||||
|
||||
events : {
|
||||
'click .x-load-more' : '_onLoadMore',
|
||||
"click .x-recommendations-tab" : "_discoverRecos",
|
||||
"click .x-popular-tab" : "_discoverPopular",
|
||||
"click .x-upcoming-tab" : "_discoverUpcoming"
|
||||
"click .x-upcoming-tab" : "_discoverUpcoming",
|
||||
"click .x-lists-tab" : "_discoverLists",
|
||||
"click .discoverable-list-item" : "_discoverList"
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
@ -58,6 +67,15 @@ module.exports = Marionette.Layout.extend({
|
||||
isExisting : this.isExisting
|
||||
});
|
||||
|
||||
/*this.listsDropdown = new DiscoverableListCollectionView({
|
||||
collection : DiscoverableListCollection
|
||||
});*/
|
||||
|
||||
this.listenTo(DiscoverableListCollection, 'sync', this._showListDropdown);
|
||||
this.listsDropdown = new DiscoverableListCollectionView({
|
||||
collection : DiscoverableListCollection
|
||||
})
|
||||
|
||||
this.throttledSearch = _.debounce(this.search, 1000, { trailing : true }).bind(this);
|
||||
|
||||
if (options.action === "search") {
|
||||
@ -125,6 +143,8 @@ module.exports = Marionette.Layout.extend({
|
||||
this.ui.moviesSearch.focus();
|
||||
this.ui.loadMore.hide();
|
||||
|
||||
this._showListDropdown();
|
||||
|
||||
if (this.isDiscover) {
|
||||
this.ui.discoverBefore.show();
|
||||
}
|
||||
@ -208,6 +228,14 @@ module.exports = Marionette.Layout.extend({
|
||||
}
|
||||
},
|
||||
|
||||
_showListDropdown : function() {
|
||||
this.listsDropdown = new DiscoverableListDropdownView(DiscoverableListCollection.toJSON());
|
||||
this.listsDropdown.render();
|
||||
$("#list-dropdown").html(this.listsDropdown.$el.html());
|
||||
//debugger;
|
||||
//this.myRegion.show(new DiscoverableListDropdownView(DiscoverableListCollection.toJSON()));
|
||||
},
|
||||
|
||||
_abortExistingSearch : function() {
|
||||
if (this.currentSearchPromise && this.currentSearchPromise.readyState > 0 && this.currentSearchPromise.readyState < 4) {
|
||||
console.log('aborting previous pending search request.');
|
||||
@ -229,7 +257,14 @@ module.exports = Marionette.Layout.extend({
|
||||
if (this.collection.action === action) {
|
||||
return
|
||||
}
|
||||
this.collection.reset();
|
||||
|
||||
if (this.collection.specialProperty === "special") {
|
||||
this.collection.reset();
|
||||
this.collection = new DiscoverMoviesCollection();
|
||||
this.resultCollectionView.collection = this.collection;
|
||||
}
|
||||
|
||||
this.listenTo(this.collection, 'sync', this._showResults);
|
||||
this.searchResult.show(new LoadingView());
|
||||
this.collection.action = action;
|
||||
this.currentSearchPromise = this.collection.fetch();
|
||||
@ -253,5 +288,22 @@ module.exports = Marionette.Layout.extend({
|
||||
this._discover("upcoming");
|
||||
},
|
||||
|
||||
_discoverLists : function() {
|
||||
/*this.ui.discoverLists.tab("show");
|
||||
this.ui.discoverHeader.html("");*/
|
||||
},
|
||||
|
||||
_discoverList : function(options) {
|
||||
this.ui.discoverLists.tab("show");
|
||||
this.ui.discoverHeader.html("Showing movies from list: "+options.target.textContent);
|
||||
|
||||
this.collection.reset();
|
||||
this.collection = new AddFromListCollection();
|
||||
this.listenTo(this.collection, 'sync', this._showResults);
|
||||
this.searchResult.show(new LoadingView());
|
||||
this.currentSearchPromise = this.collection.fetch({ data: { listId: options.target.value } });
|
||||
this.resultCollectionView.collection = this.collection;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
@ -10,6 +10,13 @@
|
||||
<li><a href="#media-management" class="x-recommendations-tab no-router">Recommendations</a></li>
|
||||
<li><a href="#popular" class="x-popular-tab no-router">Popular</a></li>
|
||||
<li><a href="#upcoming" class="x-upcoming-tab no-router">Upcoming</a></li>
|
||||
<li role="presentation" class="dropdown">
|
||||
<a class="dropdown-toggle x-lists-tab" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
Lists <span class="caret"></span>
|
||||
</a>
|
||||
<ul id="list-dropdown" class="dropdown-menu">
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 class="x-discover-header">
|
||||
Recommendations by The Movie Database based on your library:
|
||||
|
13
src/UI/AddMovies/DiscoverableListDropdownView.js
Normal file
13
src/UI/AddMovies/DiscoverableListDropdownView.js
Normal file
@ -0,0 +1,13 @@
|
||||
var Marionette = require('marionette');
|
||||
|
||||
module.exports = Marionette.CompositeView.extend({
|
||||
template : 'AddMovies/DiscoverableListDropdownViewTemplate',
|
||||
|
||||
initialize : function(lists) {
|
||||
this.lists = lists;
|
||||
},
|
||||
|
||||
templateHelpers : function() {
|
||||
return this.lists;
|
||||
}
|
||||
});
|
@ -0,0 +1,3 @@
|
||||
{{#each this}}
|
||||
<li value="{{id}}" class="clickable discoverable-list-item">{{name}}</option>
|
||||
{{/each}}
|
@ -5,6 +5,7 @@ var _ = require('underscore');
|
||||
module.exports = Backbone.Collection.extend({
|
||||
url : window.NzbDrone.ApiRoot + '/netimport/movies',
|
||||
model : MovieModel,
|
||||
specialProperty: "special",
|
||||
|
||||
parse : function(response) {
|
||||
var self = this;
|
||||
|
@ -6,9 +6,9 @@
|
||||
}
|
||||
|
||||
.page-size {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
float: right;
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
float: right;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
@ -148,6 +148,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
#list-dropdown {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.discoverable-list-item {
|
||||
font-size: 14px;
|
||||
padding-top: 5px;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.discoverable-list-item:hover {
|
||||
background-color: rgb(237, 237, 237);
|
||||
}
|
||||
|
||||
li.add-new {
|
||||
.clickable;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user