1
0
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:
Leonardo Galli 2017-06-06 22:40:44 +02:00 committed by GitHub
parent b70ed720c5
commit accf8a9efa
30 changed files with 479 additions and 138 deletions

View File

@ -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)

View File

@ -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)
{

View File

@ -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; }

View File

@ -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; }

View File

@ -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; }

View File

@ -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)

View File

@ -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)

View File

@ -8,5 +8,7 @@ public interface ISearchForNewMovie
List<Movie> SearchForNewMovie(string title);
Movie MapMovieToTmdbMovie(Movie movie);
Movie MapMovie(SkyHook.Resource.MovieResult result);
}
}

View File

@ -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)

View File

@ -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; }

View File

@ -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;

View File

@ -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; }

View File

@ -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)

View File

@ -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()

View 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;
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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));
}
}
}

View File

@ -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);
}
}
}

View File

@ -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));
}
}

View File

@ -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();

View File

@ -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" />

View File

@ -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);

View File

@ -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();

View File

@ -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;
}
});

View File

@ -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:

View 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;
}
});

View File

@ -0,0 +1,3 @@
{{#each this}}
<li value="{{id}}" class="clickable discoverable-list-item">{{name}}</option>
{{/each}}

View File

@ -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;

View File

@ -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;