mirror of
https://github.com/Radarr/Radarr.git
synced 2024-09-11 12:02:35 +02:00
New: Movie Discovery/Recommendations Reworked
This commit is contained in:
parent
3e3b2a7784
commit
2d59192a9e
@ -0,0 +1,14 @@
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(176)]
|
||||
public class movie_recommendations : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("Movies").AddColumn("Recommendations").AsString().WithDefaultValue("[]");
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,8 @@ public interface IProvideMovieInfo
|
||||
{
|
||||
Movie GetMovieByImdbId(string imdbId);
|
||||
Tuple<Movie, List<Credit>> GetMovieInfo(int tmdbId);
|
||||
List<Movie> GetBulkMovieInfo(List<int> tmdbIds);
|
||||
|
||||
HashSet<int> GetChangedMovies(DateTime startTime);
|
||||
}
|
||||
}
|
||||
|
@ -33,5 +33,6 @@ public class MovieResource
|
||||
public CollectionResource Collection { get; set; }
|
||||
public string OriginalLanguage { get; set; }
|
||||
public string Homepage { get; set; }
|
||||
public List<RecommendationResource> Recommendations { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
namespace NzbDrone.Core.MetadataSource.SkyHook.Resource
|
||||
{
|
||||
public class RecommendationResource
|
||||
{
|
||||
public int TmdbId { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@
|
||||
using NzbDrone.Common.Cloud;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Exceptions;
|
||||
using NzbDrone.Core.Languages;
|
||||
@ -97,6 +98,31 @@ public Tuple<Movie, List<Credit>> GetMovieInfo(int tmdbId)
|
||||
return new Tuple<Movie, List<Credit>>(movie, credits.ToList());
|
||||
}
|
||||
|
||||
public List<Movie> GetBulkMovieInfo(List<int> tmdbIds)
|
||||
{
|
||||
var httpRequest = _radarrMetadata.Create()
|
||||
.SetSegment("route", "movie/bulk")
|
||||
.Build();
|
||||
|
||||
httpRequest.Headers.ContentType = "application/json";
|
||||
|
||||
httpRequest.SetContent(tmdbIds.ToJson());
|
||||
|
||||
httpRequest.AllowAutoRedirect = true;
|
||||
httpRequest.SuppressHttpError = true;
|
||||
|
||||
var httpResponse = _httpClient.Post<List<MovieResource>>(httpRequest);
|
||||
|
||||
if (httpResponse.HasHttpError || httpResponse.Resource.Count == 0)
|
||||
{
|
||||
throw new HttpException(httpRequest, httpResponse);
|
||||
}
|
||||
|
||||
var movies = httpResponse.Resource.Select(MapMovie).ToList();
|
||||
|
||||
return movies;
|
||||
}
|
||||
|
||||
public Movie GetMovieByImdbId(string imdbId)
|
||||
{
|
||||
var httpRequest = _radarrMetadata.Create()
|
||||
@ -165,6 +191,7 @@ public Movie MapMovie(MovieResource resource)
|
||||
movie.Certification = resource.Certifications.FirstOrDefault(m => m.Country == certificationCountry)?.Certification;
|
||||
movie.Ratings = resource.Ratings.Select(MapRatings).FirstOrDefault() ?? new Ratings();
|
||||
movie.Genres = resource.Genres;
|
||||
movie.Recommendations = resource.Recommendations.Select(r => r.TmdbId).ToList();
|
||||
|
||||
var now = DateTime.Now;
|
||||
|
||||
|
@ -16,6 +16,7 @@ public Movie()
|
||||
Genres = new List<string>();
|
||||
Tags = new HashSet<int>();
|
||||
AlternativeTitles = new List<AlternativeTitle>();
|
||||
Recommendations = new List<int>();
|
||||
}
|
||||
|
||||
public int TmdbId { get; set; }
|
||||
@ -59,6 +60,7 @@ public Movie()
|
||||
public int SecondaryYearSourceId { get; set; }
|
||||
public string YouTubeTrailerId { get; set; }
|
||||
public string Studio { get; set; }
|
||||
public List<int> Recommendations { get; set; }
|
||||
|
||||
public bool IsRecentMovie
|
||||
{
|
||||
|
@ -43,6 +43,7 @@ public interface IMovieService
|
||||
Movie UpdateMovie(Movie movie);
|
||||
List<Movie> UpdateMovie(List<Movie> movie, bool useExistingRelativeFolder);
|
||||
List<Movie> FilterExistingMovies(List<Movie> movies);
|
||||
List<Movie> GetRecommendedMovies();
|
||||
bool MoviePathExists(string folder);
|
||||
void RemoveAddOptions(Movie movie);
|
||||
}
|
||||
@ -393,6 +394,28 @@ public List<Movie> FilterExistingMovies(List<Movie> movies)
|
||||
return ret;
|
||||
}
|
||||
|
||||
public List<Movie> GetRecommendedMovies()
|
||||
{
|
||||
// Get all recommended movies, plus all movies on enabled lists
|
||||
var netImportMovies = new List<Movie>();
|
||||
|
||||
var allMovies = GetAllMovies();
|
||||
|
||||
// Ensure we only return distinct ids that do not exist in DB already, first 100 that are from latest movies add first
|
||||
var distinctRecommendations = allMovies.OrderByDescending(x => x.Added)
|
||||
.SelectMany(m => m.Recommendations.Select(c => c))
|
||||
.Where(r => !allMovies.Any(m => m.TmdbId == r))
|
||||
.Distinct()
|
||||
.Take(100);
|
||||
|
||||
foreach (var recommendation in distinctRecommendations)
|
||||
{
|
||||
netImportMovies.Add(new Movie { TmdbId = recommendation });
|
||||
}
|
||||
|
||||
return netImportMovies;
|
||||
}
|
||||
|
||||
public void Handle(MovieFileAddedEvent message)
|
||||
{
|
||||
var movie = message.MovieFile.Movie;
|
||||
|
@ -107,6 +107,7 @@ private void RefreshMovieInfo(Movie movie)
|
||||
movie.YouTubeTrailerId = movieInfo.YouTubeTrailerId;
|
||||
movie.Studio = movieInfo.Studio;
|
||||
movie.HasPreDBEntry = movieInfo.HasPreDBEntry;
|
||||
movie.Recommendations = movieInfo.Recommendations;
|
||||
|
||||
try
|
||||
{
|
||||
|
64
src/Radarr.Api.V3/Movies/DiscoverMoviesModule.cs
Normal file
64
src/Radarr.Api.V3/Movies/DiscoverMoviesModule.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.NetImport.ImportExclusions;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using Radarr.Http;
|
||||
|
||||
namespace NzbDrone.Api.V3.Movies
|
||||
{
|
||||
public class DiscoverMoviesModule : RadarrRestModule<DiscoverMoviesResource>
|
||||
{
|
||||
private readonly IMovieService _movieService;
|
||||
private readonly IProvideMovieInfo _movieInfo;
|
||||
private readonly IBuildFileNames _fileNameBuilder;
|
||||
private readonly IImportExclusionsService _importExclusionService;
|
||||
|
||||
public DiscoverMoviesModule(IMovieService movieService, IProvideMovieInfo movieInfo, IBuildFileNames fileNameBuilder, IImportExclusionsService importExclusionsService)
|
||||
: base("/movies/discover")
|
||||
{
|
||||
_movieService = movieService;
|
||||
_movieInfo = movieInfo;
|
||||
_fileNameBuilder = fileNameBuilder;
|
||||
_importExclusionService = importExclusionsService;
|
||||
Get("/", x => GetDiscoverMovies());
|
||||
}
|
||||
|
||||
private object GetDiscoverMovies()
|
||||
{
|
||||
var results = _movieService.GetRecommendedMovies();
|
||||
|
||||
var mapped = new List<Movie>();
|
||||
|
||||
if (results.Count > 0)
|
||||
{
|
||||
mapped = _movieInfo.GetBulkMovieInfo(results.Select(m => m.TmdbId).ToList());
|
||||
}
|
||||
|
||||
var realResults = new List<Movie>();
|
||||
|
||||
realResults.AddRange(mapped.Where(x => x != null));
|
||||
|
||||
return MapToResource(realResults);
|
||||
}
|
||||
|
||||
private IEnumerable<DiscoverMoviesResource> MapToResource(IEnumerable<Movie> movies)
|
||||
{
|
||||
foreach (var currentMovie in movies)
|
||||
{
|
||||
var resource = currentMovie.ToResource(_movieService, _importExclusionService);
|
||||
var poster = currentMovie.Images.FirstOrDefault(c => c.CoverType == MediaCoverTypes.Poster);
|
||||
if (poster != null)
|
||||
{
|
||||
resource.RemotePoster = poster.Url;
|
||||
}
|
||||
|
||||
resource.Folder = _fileNameBuilder.GetMovieFolder(currentMovie);
|
||||
|
||||
yield return resource;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
78
src/Radarr.Api.V3/Movies/DiscoverMoviesResource.cs
Normal file
78
src/Radarr.Api.V3/Movies/DiscoverMoviesResource.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.NetImport.ImportExclusions;
|
||||
using Radarr.Http.REST;
|
||||
|
||||
namespace NzbDrone.Api.V3.Movies
|
||||
{
|
||||
public class DiscoverMoviesResource : RestResource
|
||||
{
|
||||
//View Only
|
||||
public string Title { get; set; }
|
||||
public string SortTitle { get; set; }
|
||||
public string TitleSlug { get; set; }
|
||||
public MovieStatusType Status { get; set; }
|
||||
public string Overview { get; set; }
|
||||
public DateTime? InCinemas { get; set; }
|
||||
public DateTime? PhysicalRelease { get; set; }
|
||||
public List<MediaCover> Images { get; set; }
|
||||
public string Website { get; set; }
|
||||
public string RemotePoster { get; set; }
|
||||
public int Year { get; set; }
|
||||
public string YouTubeTrailerId { get; set; }
|
||||
public string Studio { get; set; }
|
||||
|
||||
public int Runtime { get; set; }
|
||||
public string ImdbId { get; set; }
|
||||
public int TmdbId { get; set; }
|
||||
public string Folder { get; set; }
|
||||
public string Certification { get; set; }
|
||||
public List<string> Genres { get; set; }
|
||||
public Ratings Ratings { get; set; }
|
||||
public MovieCollection Collection { get; set; }
|
||||
public bool IsExcluded { get; set; }
|
||||
public bool IsExisting { get; set; }
|
||||
}
|
||||
|
||||
public static class DiscoverMoviesResourceMapper
|
||||
{
|
||||
public static DiscoverMoviesResource ToResource(this Movie model, IMovieService movieService, IImportExclusionsService importExclusionService)
|
||||
{
|
||||
if (model == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DiscoverMoviesResource
|
||||
{
|
||||
TmdbId = model.TmdbId,
|
||||
Title = model.Title,
|
||||
SortTitle = model.SortTitle,
|
||||
TitleSlug = model.TitleSlug,
|
||||
InCinemas = model.InCinemas,
|
||||
PhysicalRelease = model.PhysicalRelease,
|
||||
|
||||
Status = model.Status,
|
||||
Overview = model.Overview,
|
||||
|
||||
Images = model.Images,
|
||||
|
||||
Year = model.Year,
|
||||
|
||||
Runtime = model.Runtime,
|
||||
ImdbId = model.ImdbId,
|
||||
Certification = model.Certification,
|
||||
Website = model.Website,
|
||||
Genres = model.Genres,
|
||||
Ratings = model.Ratings,
|
||||
YouTubeTrailerId = model.YouTubeTrailerId,
|
||||
Studio = model.Studio,
|
||||
Collection = model.Collection,
|
||||
IsExcluded = importExclusionService.IsMovieExcluded(model.TmdbId),
|
||||
IsExisting = movieService.FindByTmdbId(model.TmdbId) != null,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user