using System; using AutoMapper; using Microsoft.Extensions.Logging; using Ombi.Api.TheMovieDb; using Ombi.Api.TheMovieDb.Models; using Ombi.Core.Models.Requests; using Ombi.Core.Models.Search; using System.Collections.Generic; using System.Linq; using System.Security.Principal; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Ombi.Core.Rule.Interfaces; using Microsoft.Extensions.Caching.Memory; using Ombi.Core.Authentication; using Ombi.Core.Settings; using Ombi.Helpers; using Ombi.Settings.Settings.Models; using Ombi.Store.Entities; using Ombi.Store.Repository; namespace Ombi.Core.Engine { public class MovieSearchEngine : BaseMediaEngine, IMovieEngine { public MovieSearchEngine(IPrincipal identity, IRequestServiceMain service, IMovieDbApi movApi, IMapper mapper, ILogger logger, IRuleEvaluator r, OmbiUserManager um, ICacheService mem, ISettingsService s, IRepository sub) : base(identity, service, r, um, mem, s, sub) { MovieApi = movApi; Mapper = mapper; Logger = logger; } private IMovieDbApi MovieApi { get; } private IMapper Mapper { get; } private ILogger Logger { get; } /// /// Lookups the imdb information. /// /// The movie database identifier. /// public async Task LookupImdbInformation(int theMovieDbId) { var movieInfo = await MovieApi.GetMovieInformationWithExtraInfo(theMovieDbId); var viewMovie = Mapper.Map(movieInfo); return await ProcessSingleMovie(viewMovie, true); } /// /// Searches the specified movie. /// /// The search. /// public async Task> Search(string search) { var result = await MovieApi.SearchMovie(search); if (result != null) { Logger.LogDebug("Search Result: {result}", result); return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API } return null; } /// /// Get similar movies to the id passed in /// /// /// public async Task> SimilarMovies(int theMovieDbId) { var result = await MovieApi.SimilarMovies(theMovieDbId); if (result != null) { Logger.LogDebug("Search Result: {result}", result); return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API } return null; } /// /// Gets popular movies. /// /// public async Task> PopularMovies() { var result = await Cache.GetOrAdd(CacheKeys.PopularMovies, async () => await MovieApi.PopularMovies(), DateTime.Now.AddHours(12)); if (result != null) { Logger.LogDebug("Search Result: {result}", result); return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API } return null; } /// /// Gets top rated movies. /// /// public async Task> TopRatedMovies() { var result = await Cache.GetOrAdd(CacheKeys.TopRatedMovies, async () => await MovieApi.TopRated(), DateTime.Now.AddHours(12)); if (result != null) { Logger.LogDebug("Search Result: {result}", result); return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API } return null; } /// /// Gets upcoming movies. /// /// public async Task> UpcomingMovies() { var result = await Cache.GetOrAdd(CacheKeys.UpcomingMovies, async () => await MovieApi.Upcoming(), DateTime.Now.AddHours(12)); if (result != null) { Logger.LogDebug("Search Result: {result}", result); return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API } return null; } /// /// Gets now playing movies. /// /// public async Task> NowPlayingMovies() { var result = await Cache.GetOrAdd(CacheKeys.NowPlayingMovies, async () => await MovieApi.NowPlaying(), DateTime.Now.AddHours(12)); if (result != null) { Logger.LogDebug("Search Result: {result}", result); return await TransformMovieResultsToResponse(result.Take(10)); // Take 10 to stop us overloading the API } return null; } private async Task> TransformMovieResultsToResponse( IEnumerable movies) { var viewMovies = new List(); foreach (var movie in movies) { viewMovies.Add(await ProcessSingleMovie(movie)); } return viewMovies; } private async Task ProcessSingleMovie(SearchMovieViewModel viewMovie, bool lookupExtraInfo = false) { if (lookupExtraInfo) { var showInfo = await MovieApi.GetMovieInformation(viewMovie.Id); viewMovie.Id = showInfo.Id; // TheMovieDbId viewMovie.ImdbId = showInfo.ImdbId; var usDates = viewMovie.ReleaseDates?.Results?.FirstOrDefault(x => x.IsoCode == "US"); viewMovie.DigitalReleaseDate = usDates?.ReleaseDate?.FirstOrDefault(x => x.Type == ReleaseDateType.Digital)?.ReleaseDate; } viewMovie.TheMovieDbId = viewMovie.Id.ToString(); await RunSearchRules(viewMovie); // This requires the rules to be run first to populate the RequestId property await CheckForSubscription(viewMovie); return viewMovie; } private async Task CheckForSubscription(SearchMovieViewModel viewModel) { // Check if this user requested it var user = await GetUser(); var request = await RequestService.MovieRequestService.GetAll() .AnyAsync(x => x.RequestedUserId.Equals(user.Id) && x.Id == viewModel.Id); if (request) { viewModel.ShowSubscribe = false; } else { viewModel.ShowSubscribe = true; var sub = await _subscriptionRepository.GetAll().FirstOrDefaultAsync(s => s.UserId == user.Id && s.RequestId == viewModel.RequestId && s.RequestType == RequestType.Movie); viewModel.Subscribed = sub != null; } } private async Task ProcessSingleMovie(MovieSearchResult movie) { var viewMovie = Mapper.Map(movie); return await ProcessSingleMovie(viewMovie); } } }