/// <summary> /// Get movies for a cast by its ImdbCode /// </summary> /// <param name="imdbCode"></param> /// <param name="ct"></param> /// <returns></returns> public async Task <IEnumerable <MovieLightJson> > GetMovieFromCast(string imdbCode, CancellationToken ct) { var timeoutPolicy = Policy.TimeoutAsync(Utils.Constants.DefaultRequestTimeoutInSecond, TimeoutStrategy.Pessimistic); try { return(await timeoutPolicy.ExecuteAsync(async cancellation => { var watch = Stopwatch.StartNew(); var wrapper = new MovieLightResponse(); var restClient = new RestClient(Utils.Constants.PopcornApi); var request = new RestRequest("/movies/cast/{segment}", Method.GET); request.AddUrlSegment("segment", imdbCode); try { var response = await restClient.ExecuteTaskAsync(request, cancellation) .ConfigureAwait(false); if (response.ErrorException != null) { throw response.ErrorException; } wrapper = JsonSerializer.Deserialize <MovieLightResponse>(response.RawBytes); foreach (var movie in wrapper.Movies) { movie.TranslationLanguage = TmdbClient.DefaultLanguage; } } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "GetMovieFromCast cancelled."); } catch (Exception exception) { Logger.Error( $"GetMovieFromCast: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"GetMovieFromCast ({imdbCode}) in {elapsedMs} milliseconds."); } var result = wrapper?.Movies ?? new List <MovieLightJson>(); ProcessTranslations(result); return result; }, ct).ConfigureAwait(false)); } catch (Exception ex) { Logger.Error(ex); return(new List <MovieLightJson>()); } }
public async Task <IActionResult> GetFromCast(string castId) { var hash = Convert.ToBase64String( Encoding.UTF8.GetBytes($"cast:{castId}")); try { var cachedMovie = await _cachingService.GetCache(hash); if (cachedMovie != null) { try { return(Content(cachedMovie, "application/json")); } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } } } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } using (var context = new PopcornContextFactory().CreateDbContext(new string[0])) { var imdbParameter = new SqlParameter("@imdbCode", castId); var query = @" SELECT Movie.Title, Movie.Year, Movie.Rating, Movie.PosterImage, Movie.ImdbCode, Movie.GenreNames FROM MovieSet AS Movie INNER JOIN CastSet AS Cast ON Cast.MovieId = Movie.Id WHERE Cast.ImdbCode = @imdbCode"; var movieQuery = await context.Database.ExecuteSqlQueryAsync(query, new CancellationToken(), imdbParameter); var reader = movieQuery.DbDataReader; var movies = new List <MovieLightJson>(); while (await reader.ReadAsync()) { var movie = new MovieLightJson { Title = !await reader.IsDBNullAsync(0) ? reader.GetString(0) : string.Empty, Year = !await reader.IsDBNullAsync(1) ? reader.GetInt32(1) : 0, Rating = !await reader.IsDBNullAsync(2) ? reader.GetDouble(2) : 0d, PosterImage = !await reader.IsDBNullAsync(3) ? reader.GetString(3) : string.Empty, ImdbCode = !await reader.IsDBNullAsync(4) ? reader.GetString(4) : string.Empty, Genres = !await reader.IsDBNullAsync(5) ? reader.GetString(5) : string.Empty }; movies.Add(movie); } var response = new MovieLightResponse { TotalMovies = movies.Count, Movies = movies }; var json = JsonSerializer.ToJsonString(response, StandardResolver.SnakeCase); await _cachingService.SetCache(hash, json, TimeSpan.FromDays(1)); return(Content(json, "application/json")); } }
public async Task <IActionResult> Get([RequiredFromQuery] int page, [FromQuery] int limit, [FromQuery] int minimum_rating, [FromQuery] string query_term, [FromQuery] string genre, [FromQuery] string sort_by) { var nbMoviesPerPage = 20; if (limit >= 20 && limit <= 50) { nbMoviesPerPage = limit; } var currentPage = 1; if (page >= 1) { currentPage = page; } var queryTerm = string.Empty; if (!string.IsNullOrWhiteSpace(query_term)) { queryTerm = query_term; } var genreFilter = string.Empty; if (!string.IsNullOrWhiteSpace(genre)) { genreFilter = genre; } var hash = Convert.ToBase64String( Encoding.UTF8.GetBytes( $@"type=movies&page={page}&limit={limit}&minimum_rating={minimum_rating}&query_term={ query_term }&genre={genre}&sort_by={sort_by}")); try { var cachedMovies = await _cachingService.GetCache(hash); if (cachedMovies != null) { try { return(Content(cachedMovies, "application/json")); } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } } } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } using (var context = new PopcornContextFactory().CreateDbContext(new string[0])) { var skipParameter = new SqlParameter("@skip", (currentPage - 1) * nbMoviesPerPage); var takeParameter = new SqlParameter("@take", nbMoviesPerPage); var ratingParameter = new SqlParameter("@rating", minimum_rating); var queryParameter = new SqlParameter("@Keywords", string.Format(@"""{0}""", queryTerm)); var genreParameter = new SqlParameter("@genre", genreFilter); var query = @" SELECT DISTINCT Movie.Title, Movie.Year, Movie.Rating, Movie.PosterImage, Movie.ImdbCode, Movie.GenreNames, Torrent.Peers, Torrent.Seeds, COUNT(*) OVER () as TotalCount, Movie.DateUploadedUnix, Movie.Id, Movie.DownloadCount, Movie.LikeCount FROM MovieSet AS Movie CROSS APPLY ( SELECT TOP 1 Torrent.MovieId, Torrent.Peers, Torrent.Seeds FROM TorrentMovieSet AS Torrent WHERE Torrent.MovieId = Movie.Id AND Torrent.Url <> '' AND Torrent.Url IS NOT NULL ) Torrent INNER JOIN CastSet AS Cast ON Cast.MovieId = Movie.Id WHERE 1 = 1"; if (minimum_rating > 0 && minimum_rating < 10) { query += @" AND Rating >= @rating"; } if (!string.IsNullOrWhiteSpace(query_term)) { query += @" AND (CONTAINS(Movie.Title, @Keywords) OR CONTAINS(Cast.Name, @Keywords) OR CONTAINS(Movie.ImdbCode, @Keywords) OR CONTAINS(Cast.ImdbCode, @Keywords))"; } if (!string.IsNullOrWhiteSpace(genre)) { query += @" AND CONTAINS(Movie.GenreNames, @genre)"; } query += " GROUP BY Movie.Id, Movie.Title, Movie.Year, Movie.Rating, Movie.PosterImage, Movie.ImdbCode, Movie.GenreNames, Torrent.Peers, Torrent.Seeds, Movie.DateUploadedUnix, Movie.Id, Movie.DownloadCount, Movie.LikeCount"; if (!string.IsNullOrWhiteSpace(sort_by)) { switch (sort_by) { case "title": query += " ORDER BY Movie.Title ASC"; break; case "year": query += " ORDER BY Movie.Year DESC"; break; case "rating": query += " ORDER BY Movie.Rating DESC"; break; case "peers": query += " ORDER BY Torrent.Peers DESC"; break; case "seeds": query += " ORDER BY Torrent.Seeds DESC"; break; case "download_count": query += " ORDER BY Movie.DownloadCount DESC"; break; case "like_count": query += " ORDER BY Movie.LikeCount DESC"; break; case "date_added": query += " ORDER BY Movie.DateUploadedUnix DESC"; break; default: query += " ORDER BY Movie.DateUploadedUnix DESC"; break; } } else { query += " ORDER BY Movie.DateUploadedUnix DESC"; } query += @" OFFSET @skip ROWS FETCH NEXT @take ROWS ONLY"; var moviesQuery = await context.Database.ExecuteSqlQueryAsync(query, new CancellationToken(), skipParameter, takeParameter, ratingParameter, queryParameter, genreParameter); var reader = moviesQuery.DbDataReader; var count = 0; var movies = new List <MovieLightJson>(); while (await reader.ReadAsync()) { var movie = new MovieLightJson { Title = !await reader.IsDBNullAsync(0) ? reader.GetString(0) : string.Empty, Year = !await reader.IsDBNullAsync(1) ? reader.GetInt32(1) : 0, Rating = !await reader.IsDBNullAsync(2) ? reader.GetDouble(2) : 0d, PosterImage = !await reader.IsDBNullAsync(3) ? reader.GetString(3) : string.Empty, ImdbCode = !await reader.IsDBNullAsync(4) ? reader.GetString(4) : string.Empty, Genres = !await reader.IsDBNullAsync(5) ? reader.GetString(5) : string.Empty }; movies.Add(movie); count = !await reader.IsDBNullAsync(8) ? reader.GetInt32(8) : 0; } var response = new MovieLightResponse { TotalMovies = count, Movies = movies }; var json = JsonSerializer.ToJsonString(response, StandardResolver.SnakeCase); await _cachingService.SetCache(hash, json, TimeSpan.FromDays(1)); return(Content(json, "application/json")); } }
public async Task <IActionResult> GetSimilar([FromBody] IEnumerable <string> imdbIds, [RequiredFromQuery] int page, [FromQuery] int limit, [FromQuery] int minimum_rating, [FromQuery] string query_term, [FromQuery] string genre, [FromQuery] string sort_by) { var nbMoviesPerPage = 20; if (limit >= 20 && limit <= 50) { nbMoviesPerPage = limit; } var currentPage = 1; if (page >= 1) { currentPage = page; } var queryTerm = string.Empty; if (!string.IsNullOrWhiteSpace(query_term)) { queryTerm = query_term; } var genreFilter = string.Empty; if (!string.IsNullOrWhiteSpace(genre)) { genreFilter = genre; } if (!imdbIds.Any()) { return(Json(new MovieLightResponse { Movies = new List <MovieLightJson>(), TotalMovies = 0 })); } var hash = Convert.ToBase64String( Encoding.UTF8.GetBytes( $@"type=movies&similar&imdbIds={string.Join(',', imdbIds)}&page={page}&limit={limit}&minimum_rating={minimum_rating}&query_term={ query_term }&genre={genre}&sort_by={sort_by}")); try { var cachedMovies = await _cachingService.GetCache(hash); if (cachedMovies != null) { try { return(Content(cachedMovies, "application/json")); } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } } } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } using (var context = new PopcornContextFactory().CreateDbContext(new string[0])) { var skipParameter = new SqlParameter("@skip", (currentPage - 1) * nbMoviesPerPage); var takeParameter = new SqlParameter("@take", nbMoviesPerPage); var ratingParameter = new SqlParameter("@rating", minimum_rating); var queryParameter = new SqlParameter("@Keywords", string.Format(@"""{0}""", queryTerm)); var genreParameter = new SqlParameter("@genre", genreFilter); var query = @" SELECT DISTINCT Movie.Title, Movie.Year, Movie.Rating, Movie.PosterImage, Movie.ImdbCode, Movie.GenreNames, COUNT(*) OVER () as TotalCount FROM MovieSet AS Movie WHERE Movie.ImdbCode IN (SELECT Similar.TmdbId FROM Similar AS Similar INNER JOIN ( SELECT Movie.ID FROM MovieSet AS Movie WHERE Movie.ImdbCode IN ({@imdbIds}) ) Movie ON Similar.MovieId = Movie.Id) AND 1 = 1"; if (minimum_rating > 0 && minimum_rating < 10) { query += @" AND Rating >= @rating"; } if (!string.IsNullOrWhiteSpace(query_term)) { query += @" AND (CONTAINS(Movie.Title, @Keywords) OR CONTAINS(Movie.ImdbCode, @Keywords))"; } if (!string.IsNullOrWhiteSpace(genre)) { query += @" AND CONTAINS(Movie.GenreNames, @genre)"; } query += " ORDER BY Movie.Rating DESC"; query += @" OFFSET @skip ROWS FETCH NEXT @take ROWS ONLY"; using (var cmd = new SqlCommand(query, new SqlConnection(context.Database.GetDbConnection().ConnectionString))) { cmd.AddArrayParameters(imdbIds, "@imdbIds"); cmd.Parameters.Add(skipParameter); cmd.Parameters.Add(takeParameter); cmd.Parameters.Add(ratingParameter); cmd.Parameters.Add(queryParameter); cmd.Parameters.Add(genreParameter); await cmd.Connection.OpenAsync(); var reader = await cmd.ExecuteReaderAsync(new CancellationToken()); var count = 0; var movies = new List <MovieLightJson>(); while (await reader.ReadAsync()) { var movie = new MovieLightJson { Title = !await reader.IsDBNullAsync(0) ? reader.GetString(0) : string.Empty, Year = !await reader.IsDBNullAsync(1) ? reader.GetInt32(1) : 0, Rating = !await reader.IsDBNullAsync(2) ? reader.GetDouble(2) : 0d, PosterImage = !await reader.IsDBNullAsync(3) ? reader.GetString(3) : string.Empty, ImdbCode = !await reader.IsDBNullAsync(4) ? reader.GetString(4) : string.Empty, Genres = !await reader.IsDBNullAsync(5) ? reader.GetString(5) : string.Empty }; movies.Add(movie); count = !await reader.IsDBNullAsync(6) ? reader.GetInt32(6) : 0; } var response = new MovieLightResponse { TotalMovies = count, Movies = movies }; var json = JsonSerializer.ToJsonString(response, StandardResolver.SnakeCase); await _cachingService.SetCache(hash, json, TimeSpan.FromDays(1)); return(Content(json, "application/json")); } } }
public async Task <IActionResult> GetMoviesByIds([FromBody] IEnumerable <string> imdbIds) { if (!imdbIds.Any()) { return(Json(new MovieLightResponse { Movies = new List <MovieLightJson>(), TotalMovies = 0 })); } var hash = Convert.ToBase64String( Encoding.UTF8.GetBytes( $@"type=movies&imdbIds={string.Join(',', imdbIds)}")); try { var cachedMovies = await _cachingService.GetCache(hash); if (cachedMovies != null) { try { return(Content(cachedMovies, "application/json")); } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } } } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } using (var context = new PopcornContextFactory().CreateDbContext(new string[0])) { var query = @" SELECT DISTINCT Movie.Title, Movie.Year, Movie.Rating, Movie.PosterImage, Movie.ImdbCode, Movie.GenreNames, COUNT(*) OVER () as TotalCount FROM MovieSet AS Movie WHERE Movie.ImdbCode IN ({@imdbIds}) ORDER BY Movie.Rating DESC"; using (var cmd = new SqlCommand(query, new SqlConnection(context.Database.GetDbConnection().ConnectionString))) { cmd.AddArrayParameters(imdbIds, "@imdbIds"); await cmd.Connection.OpenAsync(); var reader = await cmd.ExecuteReaderAsync(new CancellationToken()); var count = 0; var movies = new List <MovieLightJson>(); while (await reader.ReadAsync()) { var movie = new MovieLightJson { Title = !await reader.IsDBNullAsync(0) ? reader.GetString(0) : string.Empty, Year = !await reader.IsDBNullAsync(1) ? reader.GetInt32(1) : 0, Rating = !await reader.IsDBNullAsync(2) ? reader.GetDouble(2) : 0d, PosterImage = !await reader.IsDBNullAsync(3) ? reader.GetString(3) : string.Empty, ImdbCode = !await reader.IsDBNullAsync(4) ? reader.GetString(4) : string.Empty, Genres = !await reader.IsDBNullAsync(5) ? reader.GetString(5) : string.Empty }; movies.Add(movie); count = !await reader.IsDBNullAsync(6) ? reader.GetInt32(6) : 0; } var response = new MovieLightResponse { TotalMovies = count, Movies = movies }; var json = JsonSerializer.ToJsonString(response, StandardResolver.SnakeCase); await _cachingService.SetCache(hash, json, TimeSpan.FromDays(1)); return(Content(json, "application/json")); } } }
/// <summary> /// Search movies by criteria /// </summary> /// <param name="criteria">Criteria used for search</param> /// <param name="page">Page to return</param> /// <param name="limit">The maximum number of movies to return</param> /// <param name="genre">The genre to filter</param> /// <param name="ratingFilter">Used to filter by rating</param> /// <param name="ct">Cancellation token</param> /// <returns>Searched movies and the number of movies found</returns> public async Task <(IEnumerable <MovieLightJson> movies, int nbMovies)> SearchMoviesAsync(string criteria, int page, int limit, GenreJson genre, double ratingFilter, CancellationToken ct) { var timeoutPolicy = Policy.TimeoutAsync(Constants.DefaultRequestTimeoutInSecond, TimeoutStrategy.Optimistic); try { return(await timeoutPolicy.ExecuteAsync(async cancellation => { var watch = Stopwatch.StartNew(); var wrapper = new MovieLightResponse(); if (limit < 1 || limit > 50) { limit = Constants.MaxMoviesPerPage; } if (page < 1) { page = 1; } var restClient = new RestClient(Constants.PopcornApi); var request = new RestRequest("/{segment}", Method.GET); request.AddUrlSegment("segment", "movies"); request.AddParameter("limit", limit); request.AddParameter("page", page); request.AddParameter("genre", genre != null ? genre.EnglishName : string.Empty); request.AddParameter("minimum_rating", Convert.ToInt32(ratingFilter)); request.AddParameter("query_term", criteria); request.AddParameter("sort_by", "year"); try { var response = await restClient.ExecuteTaskAsync(request, cancellation); if (response.ErrorException != null) { throw response.ErrorException; } wrapper = JsonSerializer.Deserialize <MovieLightResponse>(response.RawBytes); foreach (var movie in wrapper.Movies) { movie.TranslationLanguage = (await _tmdbService.GetClient).DefaultLanguage; } } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "SearchMoviesAsync cancelled."); } catch (Exception exception) { Logger.Error( $"SearchMoviesAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Trace( $"SearchMoviesAsync ({criteria}, {page}, {limit}) in {elapsedMs} milliseconds."); } var result = wrapper?.Movies ?? new List <MovieLightJson>(); await ProcessTranslations(result); var nbResult = wrapper?.TotalMovies ?? 0; return (result, nbResult); }, ct)); } catch (Exception ex) { Logger.Error(ex); throw; } }
/// <summary> /// Get movies by ids /// </summary> /// <param name="imdbIds">The imdbIds of the movies, split by comma</param> /// <param name="ct">Cancellation token</param> /// <returns>Similar movies</returns> public async Task <(IEnumerable <MovieLightJson> movies, int nbMovies)> GetMoviesByIds( IEnumerable <string> imdbIds, CancellationToken ct) { var timeoutPolicy = Policy.TimeoutAsync(Constants.DefaultRequestTimeoutInSecond, TimeoutStrategy.Optimistic); try { return(await timeoutPolicy.ExecuteAsync(async cancellation => { var watch = Stopwatch.StartNew(); var wrapper = new MovieLightResponse(); var restClient = new RestClient(Constants.PopcornApi); var request = new RestRequest("/{segment}/{subsegment}", Method.POST); request.AddUrlSegment("segment", "movies"); request.AddUrlSegment("subsegment", "ids"); request.AddJsonBody(imdbIds); try { var response = await restClient.ExecuteTaskAsync(request, cancellation); if (response.ErrorException != null) { throw response.ErrorException; } wrapper = JsonSerializer.Deserialize <MovieLightResponse>(response.RawBytes); foreach (var movie in wrapper.Movies) { movie.TranslationLanguage = (await _tmdbService.GetClient).DefaultLanguage; } } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "GetMoviesByIds cancelled."); } catch (Exception exception) { Logger.Error( $"GetMoviesByIds: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Trace( $"GetMoviesByIds ({string.Join(",", imdbIds)}) in {elapsedMs} milliseconds."); } var result = wrapper?.Movies ?? new List <MovieLightJson>(); await ProcessTranslations(result); var nbResult = wrapper?.TotalMovies ?? 0; return (result, nbResult); }, ct)); } catch (Exception ex) { Logger.Error(ex); return(new List <MovieLightJson>(), 0); } }
/// <summary> /// Get similar movies /// </summary> /// <param name="page">Page to return</param> /// <param name="limit">The maximum number of movies to return</param> /// <param name="imdbIds">The imdbIds of the movies, split by comma</param> /// <param name="ct">Cancellation token</param> /// <returns>Similar movies</returns> public async Task <(IEnumerable <MovieLightJson> movies, int nbMovies)> GetSimilarAsync(int page, int limit, IEnumerable <string> imdbIds, CancellationToken ct) { var timeoutPolicy = Policy.TimeoutAsync(Utils.Constants.DefaultRequestTimeoutInSecond, TimeoutStrategy.Pessimistic); try { return(await timeoutPolicy.ExecuteAsync(async cancellation => { var watch = Stopwatch.StartNew(); var wrapper = new MovieLightResponse(); if (limit < 1 || limit > 50) { limit = Utils.Constants.MaxMoviesPerPage; } if (page < 1) { page = 1; } var restClient = new RestClient(Utils.Constants.PopcornApi); var request = new RestRequest("/{segment}/{subsegment}", Method.POST); request.AddUrlSegment("segment", "movies"); request.AddUrlSegment("subsegment", "similar"); request.AddQueryParameter("limit", limit.ToString()); request.AddQueryParameter("page", page.ToString()); request.AddJsonBody(imdbIds); try { var response = await restClient.ExecuteTaskAsync(request, cancellation); if (response.ErrorException != null) { throw response.ErrorException; } wrapper = JsonSerializer.Deserialize <MovieLightResponse>(response.RawBytes); foreach (var movie in wrapper.Movies) { movie.TranslationLanguage = TmdbClient.DefaultLanguage; } } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "GetSimilarAsync cancelled."); } catch (Exception exception) { Logger.Error( $"GetSimilarAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"GetSimilarAsync ({page}, {limit}, {string.Join(",", imdbIds)}) in {elapsedMs} milliseconds."); } var result = wrapper?.Movies ?? new List <MovieLightJson>(); ProcessTranslations(result); var nbResult = wrapper?.TotalMovies ?? 0; return (result, nbResult); }, ct).ConfigureAwait(false)); } catch (Exception ex) { Logger.Error(ex); return(new List <MovieLightJson>(), 0); } }
/// <summary> /// Search movies by criteria /// </summary> /// <param name="criteria">Criteria used for search</param> /// <param name="page">Page to return</param> /// <param name="limit">The maximum number of movies to return</param> /// <param name="genre">The genre to filter</param> /// <param name="ratingFilter">Used to filter by rating</param> /// <param name="ct">Cancellation token</param> /// <returns>Searched movies and the number of movies found</returns> public async Task <(IEnumerable <MovieLightJson> movies, int nbMovies)> SearchMoviesAsync(string criteria, int page, int limit, GenreJson genre, double ratingFilter, CancellationToken ct) { var watch = Stopwatch.StartNew(); var wrapper = new MovieLightResponse(); if (limit < 1 || limit > 50) { limit = Utils.Constants.MaxMoviesPerPage; } if (page < 1) { page = 1; } var restClient = new RestClient(Utils.Constants.PopcornApi); var request = new RestRequest("/{segment}", Method.GET); request.AddUrlSegment("segment", "movies"); request.AddParameter("limit", limit); request.AddParameter("page", page); if (genre != null) { request.AddParameter("genre", genre.EnglishName); } request.AddParameter("minimum_rating", Convert.ToInt32(ratingFilter)); request.AddParameter("query_term", criteria); try { var response = await restClient.ExecuteTaskAsync <MovieLightResponse>(request, ct); if (response.ErrorException != null) { throw response.ErrorException; } wrapper = response.Data; } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "SearchMoviesAsync cancelled."); } catch (Exception exception) { Logger.Error( $"SearchMoviesAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"SearchMoviesAsync ({criteria}, {page}, {limit}) in {elapsedMs} milliseconds."); } var result = wrapper?.Movies ?? new List <MovieLightJson>(); Task.Run(async() => { await ProcessTranslations(result).ConfigureAwait(false); }).ConfigureAwait(false); var nbResult = wrapper?.TotalMovies ?? 0; return(result, nbResult); }
public async Task <IActionResult> Get([RequiredFromQuery] int page, [FromQuery] int limit, [FromQuery] int minimum_rating, [FromQuery] string query_term, [FromQuery] string genre, [FromQuery] string sort_by) { var nbMoviesPerPage = 20; if (limit >= 20 && limit <= 50) { nbMoviesPerPage = limit; } var currentPage = 1; if (page >= 1) { currentPage = page; } var queryTerm = string.Empty; if (!string.IsNullOrWhiteSpace(query_term)) { queryTerm = query_term; } var genreFilter = string.Empty; if (!string.IsNullOrWhiteSpace(genre)) { genreFilter = genre; } var hash = Convert.ToBase64String( Encoding.UTF8.GetBytes( $@"type=movies&page={page}&limit={limit}&minimum_rating={minimum_rating}&query_term={ query_term }&genre={genre}&sort_by={sort_by}")); try { var cachedMovies = await _cachingService.GetCache(hash); if (cachedMovies != null) { try { return(Json(JsonConvert.DeserializeObject <MovieLightResponse>(cachedMovies))); } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } } } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } using (var context = new PopcornContextFactory().CreateDbContext(new string[0])) { var skipParameter = new SqlParameter("@skip", (currentPage - 1) * nbMoviesPerPage); var takeParameter = new SqlParameter("@take", nbMoviesPerPage); var ratingParameter = new SqlParameter("@rating", minimum_rating); var queryParameter = new SqlParameter("@Keywords", queryTerm); var genreParameter = new SqlParameter("@genre", genreFilter); var query = @" SELECT Movie.Title, Movie.Year, Movie.Rating, Movie.PosterImage, Movie.ImdbCode, Movie.GenreNames, Torrent.Peers, Torrent.Seeds, COUNT(*) OVER () as TotalCount FROM MovieSet AS Movie INNER JOIN TorrentMovieSet AS Torrent ON Torrent.MovieId = Movie.Id AND Torrent.Quality = '720p' WHERE 1 = 1"; if (minimum_rating > 0 && minimum_rating < 10) { query += @" AND Rating >= @rating"; } if (!string.IsNullOrWhiteSpace(query_term)) { query += @" AND FREETEXT(Title, @Keywords)"; } if (!string.IsNullOrWhiteSpace(genre)) { query += @" AND CONTAINS(GenreNames, @genre)"; } if (!string.IsNullOrWhiteSpace(sort_by)) { switch (sort_by) { case "title": query += " ORDER BY Movie.Title ASC"; break; case "year": query += " ORDER BY Movie.Year DESC"; break; case "rating": query += " ORDER BY Movie.Rating DESC"; break; case "peers": query += " ORDER BY Torrent.Peers DESC"; break; case "seeds": query += " ORDER BY Torrent.Seeds DESC"; break; case "download_count": query += " ORDER BY Movie.DownloadCount DESC"; break; case "like_count": query += " ORDER BY Movie.LikeCount DESC"; break; case "date_added": query += " ORDER BY Movie.DateUploadedUnix DESC"; break; default: query += " ORDER BY Movie.DateUploadedUnix DESC"; break; } } else { query += " ORDER BY Movie.DateUploadedUnix DESC"; } query += @" OFFSET @skip ROWS FETCH NEXT @take ROWS ONLY"; var moviesQuery = await context.Database.ExecuteSqlQueryAsync(query, new CancellationToken(), skipParameter, takeParameter, ratingParameter, queryParameter, genreParameter); var reader = moviesQuery.DbDataReader; var count = 0; var movies = new List <MovieLightJson>(); while (await reader.ReadAsync()) { var movie = new MovieLightJson { Title = reader[0].GetType() != typeof(DBNull) ? (string)reader[0] : string.Empty, Year = reader[1].GetType() != typeof(DBNull) ? (int)reader[1] : 0, Rating = reader[2].GetType() != typeof(DBNull) ? (double)reader[2] : 0d, PosterImage = reader[3].GetType() != typeof(DBNull) ? (string)reader[3] : string.Empty, ImdbCode = reader[4].GetType() != typeof(DBNull) ? (string)reader[4] : string.Empty, Genres = reader[5].GetType() != typeof(DBNull) ? (string)reader[5] : string.Empty }; movies.Add(movie); count = reader[8].GetType() != typeof(DBNull) ? (int)reader[8] : 0; } var response = new MovieLightResponse { TotalMovies = count, Movies = movies }; await _cachingService.SetCache(hash, JsonConvert.SerializeObject(response), TimeSpan.FromDays(1)); return (Json(response)); } }
public async Task <IActionResult> GetSimilar([FromBody] IEnumerable <string> imdbIds, [RequiredFromQuery] int page, [FromQuery] int limit) { if (!imdbIds.Any()) { return(Json(new MovieLightResponse { Movies = new List <MovieLightJson>(), TotalMovies = 0 })); } var nbMoviesPerPage = 20; if (limit >= 20 && limit <= 50) { nbMoviesPerPage = limit; } var currentPage = 1; if (page >= 1) { currentPage = page; } var hash = Convert.ToBase64String( Encoding.UTF8.GetBytes( $@"type=movies&page={page}&limit={limit}&imdbId={string.Join(',', imdbIds)}")); try { var cachedMovies = await _cachingService.GetCache(hash); if (cachedMovies != null) { try { return(Json(JsonConvert.DeserializeObject <MovieLightResponse>(cachedMovies))); } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } } } catch (Exception ex) { _loggingService.Telemetry.TrackException(ex); } using (var context = new PopcornContextFactory().CreateDbContext(new string[0])) { var skipParameter = new SqlParameter("@skip", (currentPage - 1) * nbMoviesPerPage); var takeParameter = new SqlParameter("@take", nbMoviesPerPage); var query = @" SELECT DISTINCT Movie.Title, Movie.Year, Movie.Rating, Movie.PosterImage, Movie.ImdbCode, Movie.GenreNames, Torrent.Peers, Torrent.Seeds, COUNT(*) OVER () as TotalCount FROM MovieSet AS Movie INNER JOIN TorrentMovieSet AS Torrent ON Torrent.MovieId = Movie.Id INNER JOIN Similar ON Similar.MovieId = Movie.Id AND Torrent.Quality = '720p' WHERE Similar.TmdbId IN ({@imdbIds}) ORDER BY Movie.Rating DESC"; query += @" OFFSET @skip ROWS FETCH NEXT @take ROWS ONLY"; using (var cmd = new SqlCommand(query, new SqlConnection(context.Database.GetDbConnection().ConnectionString))) { cmd.AddArrayParameters(imdbIds, "@imdbIds"); cmd.Parameters.Add(skipParameter); cmd.Parameters.Add(takeParameter); await cmd.Connection.OpenAsync(); var reader = await cmd.ExecuteReaderAsync(new CancellationToken()); var count = 0; var movies = new List <MovieLightJson>(); while (await reader.ReadAsync()) { var movie = new MovieLightJson { Title = reader[0].GetType() != typeof(DBNull) ? (string)reader[0] : string.Empty, Year = reader[1].GetType() != typeof(DBNull) ? (int)reader[1] : 0, Rating = reader[2].GetType() != typeof(DBNull) ? (double)reader[2] : 0d, PosterImage = reader[3].GetType() != typeof(DBNull) ? (string)reader[3] : string.Empty, ImdbCode = reader[4].GetType() != typeof(DBNull) ? (string)reader[4] : string.Empty, Genres = reader[5].GetType() != typeof(DBNull) ? (string)reader[5] : string.Empty }; movies.Add(movie); count = reader[8].GetType() != typeof(DBNull) ? (int)reader[8] : 0; } var response = new MovieLightResponse { TotalMovies = count, Movies = movies }; await _cachingService.SetCache(hash, JsonConvert.SerializeObject(response), TimeSpan.FromDays(1)); return (Json(response)); } } }
/// <summary> /// Get similar movies /// </summary> /// <param name="page">Page to return</param> /// <param name="limit">The maximum number of movies to return</param> /// <param name="imdbIds">The imdbIds of the movies, split by comma</param> /// <param name="ct">Cancellation token</param> /// <returns>Similar movies</returns> public async Task <(IEnumerable <MovieLightJson> movies, int nbMovies)> GetSimilarAsync(int page, int limit, IEnumerable <string> imdbIds, CancellationToken ct) { var watch = Stopwatch.StartNew(); var wrapper = new MovieLightResponse(); if (limit < 1 || limit > 50) { limit = Utils.Constants.MaxMoviesPerPage; } if (page < 1) { page = 1; } var restClient = new RestClient(Utils.Constants.PopcornApi); var request = new RestRequest("/{segment}/{subsegment}", Method.POST); request.AddUrlSegment("segment", "movies"); request.AddUrlSegment("subsegment", "similar"); request.AddQueryParameter("limit", limit.ToString()); request.AddQueryParameter("page", page.ToString()); request.AddJsonBody(imdbIds); try { var response = await restClient.ExecuteTaskAsync <MovieLightResponse>(request, ct); if (response.ErrorException != null) { throw response.ErrorException; } wrapper = response.Data; } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "GetSimilarAsync cancelled."); } catch (Exception exception) { Logger.Error( $"GetSimilarAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"GetSimilarAsync ({page}, {limit}, {imdbIds}) in {elapsedMs} milliseconds."); } var result = wrapper?.Movies ?? new List <MovieLightJson>(); Task.Run(async() => { await ProcessTranslations(result).ConfigureAwait(false); }).ConfigureAwait(false); var nbResult = wrapper?.TotalMovies ?? 0; return(result, nbResult); }
/// <summary> /// Get similar movies /// </summary> /// <param name="page">Page</param> /// <param name="limit">Limit</param> /// <param name="ratingFilter">Rating</param> /// <param name="sortBy">SortBy</param> /// <param name="imdbIds">The imdbIds of the movies, split by comma</param> /// <param name="ct">Cancellation token</param> /// <param name="genre">Genre</param> /// <returns>Similar movies</returns> public async Task <(IEnumerable <MovieLightJson> movies, int nbMovies)> GetSimilar(int page, int limit, double ratingFilter, string sortBy, IList <string> imdbIds, CancellationToken ct, GenreJson genre = null) { var timeoutPolicy = Policy.TimeoutAsync(Constants.DefaultRequestTimeoutInSecond, TimeoutStrategy.Optimistic); try { return(await timeoutPolicy.ExecuteAsync(async cancellation => { var watch = Stopwatch.StartNew(); var wrapper = new MovieLightResponse(); if (limit < 1 || limit > 50) { limit = Constants.MaxMoviesPerPage; } if (page < 1) { page = 1; } var request = new RestRequest("/{segment}/{subsegment}", Method.POST); request.AddUrlSegment("segment", "movies"); request.AddUrlSegment("subsegment", "similar"); request.AddQueryParameter("limit", limit.ToString()); request.AddQueryParameter("page", page.ToString()); request.AddQueryParameter("genre", genre != null ? genre.EnglishName : string.Empty); request.AddQueryParameter("minimum_rating", Convert.ToInt32(ratingFilter).ToString()); request.AddQueryParameter("sort_by", sortBy); request.AddQueryParameter("query_term", string.Empty); request.AddJsonBody(imdbIds); try { var response = await _restClient.ExecuteTaskAsync(request, cancellation); if (response.ErrorException != null) { throw response.ErrorException; } wrapper = JsonConvert.DeserializeObject <MovieLightResponse>(response.Content); foreach (var movie in wrapper.Movies) { movie.TranslationLanguage = (await _tmdbService.GetClient).DefaultLanguage; } } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "GetMoviesByIds cancelled."); } catch (Exception exception) { Logger.Error( $"GetMoviesByIds: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Trace( $"GetMoviesByIds ({string.Join(",", imdbIds)}) in {elapsedMs} milliseconds."); } var result = wrapper?.Movies ?? new List <MovieLightJson>(); await ProcessTranslations(result); var nbResult = wrapper?.TotalMovies ?? 0; return (result, nbResult); }, ct)); } catch (Exception ex) { Logger.Error(ex); return(new List <MovieLightJson>(), 0); } }