using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; using TMDbLib.Objects.Authentication; using TMDbLib.Objects.General; using TMDbLib.Objects.Movies; using TMDbLib.Objects.Reviews; using TMDbLib.Objects.Search; using TMDbLib.Rest; using TMDbLib.Utilities; using Credits = TMDbLib.Objects.Movies.Credits; namespace TMDbLib.Client { public partial class TMDbClient { private async Task GetMovieMethodInternal(int movieId, MovieMethods movieMethod, string dateFormat = null, string country = null, string language = null, string includeImageLanguage = null, int page = 0, DateTime? startDate = null, DateTime? endDate = null, CancellationToken cancellationToken = default) where T : new() { RestRequest req = _client.Create("movie/{movieId}/{method}"); req.AddUrlSegment("movieId", movieId.ToString(CultureInfo.InvariantCulture)); req.AddUrlSegment("method", movieMethod.GetDescription()); if (country != null) req.AddParameter("country", country); language ??= DefaultLanguage; if (!string.IsNullOrWhiteSpace(language)) req.AddParameter("language", language); if (!string.IsNullOrWhiteSpace(includeImageLanguage)) req.AddParameter("include_image_language", includeImageLanguage); if (page >= 1) req.AddParameter("page", page.ToString()); if (startDate.HasValue) req.AddParameter("start_date", startDate.Value.ToString("yyyy-MM-dd")); if (endDate != null) req.AddParameter("end_date", endDate.Value.ToString("yyyy-MM-dd")); T response = await req.GetOfT(cancellationToken).ConfigureAwait(false); return response; } /// /// Retrieves all information for a specific movie in relation to the current user account /// /// The id of the movie to get the account states for /// A cancellation token /// Requires a valid user session /// Thrown when the current client object doens't have a user session assigned. public async Task GetMovieAccountStateAsync(int movieId, CancellationToken cancellationToken = default) { RequireSessionId(SessionType.UserSession); RestRequest req = _client.Create("movie/{movieId}/{method}"); req.AddUrlSegment("movieId", movieId.ToString(CultureInfo.InvariantCulture)); req.AddUrlSegment("method", MovieMethods.AccountStates.GetDescription()); AddSessionId(req, SessionType.UserSession); using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); return await response.GetDataObject().ConfigureAwait(false); } public async Task GetMovieAlternativeTitlesAsync(int movieId, CancellationToken cancellationToken = default) { return await GetMovieAlternativeTitlesAsync(movieId, DefaultCountry, cancellationToken).ConfigureAwait(false); } public async Task GetMovieAlternativeTitlesAsync(int movieId, string country, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal(movieId, MovieMethods.AlternativeTitles, country: country, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task GetMovieAsync(int movieId, MovieMethods extraMethods = MovieMethods.Undefined, CancellationToken cancellationToken = default) { return await GetMovieAsync(movieId, DefaultLanguage, null, extraMethods, cancellationToken).ConfigureAwait(false); } public async Task GetMovieAsync(string imdbId, MovieMethods extraMethods = MovieMethods.Undefined, CancellationToken cancellationToken = default) { return await GetMovieAsync(imdbId, DefaultLanguage, null, extraMethods, cancellationToken).ConfigureAwait(false); } public async Task GetMovieAsync(int movieId, string language, string includeImageLanguage = null, MovieMethods extraMethods = MovieMethods.Undefined, CancellationToken cancellationToken = default) { return await GetMovieAsync(movieId.ToString(CultureInfo.InvariantCulture), language, includeImageLanguage, extraMethods, cancellationToken).ConfigureAwait(false); } /// /// Retrieves a movie by its IMDb Id /// /// The IMDb id of the movie OR the TMDb id as string /// Language to localize the results in. /// If specified the api will attempt to return localized image results eg. en,it,es. /// A list of additional methods to execute for this req as enum flags /// A cancellation token /// The reqed movie or null if it could not be found /// Requires a valid user session when specifying the extra method 'AccountStates' flag /// Thrown when the current client object doens't have a user session assigned, see remarks. public async Task GetMovieAsync(string imdbId, string language, string includeImageLanguage = null, MovieMethods extraMethods = MovieMethods.Undefined, CancellationToken cancellationToken = default) { if (extraMethods.HasFlag(MovieMethods.AccountStates)) RequireSessionId(SessionType.UserSession); RestRequest req = _client.Create("movie/{movieId}"); req.AddUrlSegment("movieId", imdbId); if (extraMethods.HasFlag(MovieMethods.AccountStates)) AddSessionId(req, SessionType.UserSession); if (language != null) req.AddParameter("language", language); includeImageLanguage ??= DefaultImageLanguage; if (includeImageLanguage != null) req.AddParameter("include_image_language", includeImageLanguage); string appends = string.Join(",", Enum.GetValues(typeof(MovieMethods)) .OfType() .Except(new[] { MovieMethods.Undefined }) .Where(s => extraMethods.HasFlag(s)) .Select(s => s.GetDescription())); if (appends != string.Empty) req.AddParameter("append_to_response", appends); using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); if (!response.IsValid) return null; Movie item = await response.GetDataObject().ConfigureAwait(false); // Patch up data, so that the end user won't notice that we share objects between req-types. if (item.Videos != null) item.Videos.Id = item.Id; if (item.AlternativeTitles != null) item.AlternativeTitles.Id = item.Id; if (item.Credits != null) item.Credits.Id = item.Id; if (item.Releases != null) item.Releases.Id = item.Id; if (item.Keywords != null) item.Keywords.Id = item.Id; if (item.Translations != null) item.Translations.Id = item.Id; if (item.AccountStates != null) item.AccountStates.Id = item.Id; if (item.ExternalIds != null) item.ExternalIds.Id = item.Id; // Overview is the only field that is HTML encoded from the source. item.Overview = WebUtility.HtmlDecode(item.Overview); return item; } public async Task GetMovieCreditsAsync(int movieId, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal(movieId, MovieMethods.Credits, cancellationToken: cancellationToken).ConfigureAwait(false); } /// /// Returns an object that contains all known exteral id's for the movie related to the specified TMDB id. /// /// The TMDb id of the target movie. /// A cancellation token public async Task GetMovieExternalIdsAsync(int id, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal(id, MovieMethods.ExternalIds, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task GetMovieImagesAsync(int movieId, CancellationToken cancellationToken = default) { return await GetMovieImagesAsync(movieId, DefaultLanguage, null, cancellationToken).ConfigureAwait(false); } public async Task GetMovieImagesAsync(int movieId, string language, string includeImageLanguage = null, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal(movieId, MovieMethods.Images, language: language, includeImageLanguage: includeImageLanguage, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task GetMovieKeywordsAsync(int movieId, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal(movieId, MovieMethods.Keywords, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task GetMovieLatestAsync(CancellationToken cancellationToken = default) { RestRequest req = _client.Create("movie/latest"); using RestResponse resp = await req.Get(cancellationToken).ConfigureAwait(false); Movie item = await resp.GetDataObject().ConfigureAwait(false); // Overview is the only field that is HTML encoded from the source. if (item != null) item.Overview = WebUtility.HtmlDecode(item.Overview); return item; } public async Task> GetMovieListsAsync(int movieId, int page = 0, CancellationToken cancellationToken = default) { return await GetMovieListsAsync(movieId, DefaultLanguage, page, cancellationToken).ConfigureAwait(false); } public async Task> GetMovieListsAsync(int movieId, string language, int page = 0, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal>(movieId, MovieMethods.Lists, page: page, language: language, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetMovieRecommendationsAsync(int id, int page = 0, CancellationToken cancellationToken = default) { return await GetMovieRecommendationsAsync(id, DefaultLanguage, page, cancellationToken).ConfigureAwait(false); } public async Task> GetMovieRecommendationsAsync(int id, string language, int page = 0, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal>(id, MovieMethods.Recommendations, language: language, page: page, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetMovieNowPlayingListAsync(string language = null, int page = 0, string region = null, CancellationToken cancellationToken = default) { RestRequest req = _client.Create("movie/now_playing"); if (page >= 1) req.AddParameter("page", page.ToString()); if (language != null) req.AddParameter("language", language); if (region != null) req.AddParameter("region", region); SearchContainerWithDates resp = await req.GetOfT>(cancellationToken).ConfigureAwait(false); return resp; } public async Task> GetMoviePopularListAsync(string language = null, int page = 0, string region = null, CancellationToken cancellationToken = default) { RestRequest req = _client.Create("movie/popular"); if (page >= 1) req.AddParameter("page", page.ToString()); if (language != null) req.AddParameter("language", language); if (region != null) req.AddParameter("region", region); SearchContainer resp = await req.GetOfT>(cancellationToken).ConfigureAwait(false); return resp; } public async Task> GetMovieReleaseDatesAsync(int movieId, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal>(movieId, MovieMethods.ReleaseDates, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task GetMovieReleasesAsync(int movieId, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal(movieId, MovieMethods.Releases, dateFormat: "yyyy-MM-dd", cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetMovieReviewsAsync(int movieId, int page = 0, CancellationToken cancellationToken = default) { return await GetMovieReviewsAsync(movieId, DefaultLanguage, page, cancellationToken).ConfigureAwait(false); } public async Task> GetMovieReviewsAsync(int movieId, string language, int page = 0, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal>(movieId, MovieMethods.Reviews, page: page, language: language, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetMovieSimilarAsync(int movieId, int page = 0, CancellationToken cancellationToken = default) { return await GetMovieSimilarAsync(movieId, DefaultLanguage, page, cancellationToken).ConfigureAwait(false); } public async Task> GetMovieSimilarAsync(int movieId, string language, int page = 0, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal>(movieId, MovieMethods.Similar, page: page, language: language, dateFormat: "yyyy-MM-dd", cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetMovieTopRatedListAsync(string language = null, int page = 0, string region = null, CancellationToken cancellationToken = default) { RestRequest req = _client.Create("movie/top_rated"); if (page >= 1) req.AddParameter("page", page.ToString()); if (language != null) req.AddParameter("language", language); if (region != null) req.AddParameter("region", region); SearchContainer resp = await req.GetOfT>(cancellationToken).ConfigureAwait(false); return resp; } public async Task GetMovieTranslationsAsync(int movieId, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal(movieId, MovieMethods.Translations, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetMovieUpcomingListAsync(string language = null, int page = 0, string region = null, CancellationToken cancellationToken = default) { RestRequest req = _client.Create("movie/upcoming"); if (page >= 1) req.AddParameter("page", page.ToString()); if (language != null) req.AddParameter("language", language); if (region != null) req.AddParameter("region", region); SearchContainerWithDates resp = await req.GetOfT>(cancellationToken).ConfigureAwait(false); return resp; } public async Task> GetMovieVideosAsync(int movieId, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal>(movieId, MovieMethods.Videos, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task>> GetMovieWatchProvidersAsync(int movieId, CancellationToken cancellationToken = default) { return await GetMovieMethodInternal>>(movieId, MovieMethods.WatchProviders, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task MovieRemoveRatingAsync(int movieId, CancellationToken cancellationToken = default) { RequireSessionId(SessionType.GuestSession); RestRequest req = _client.Create("movie/{movieId}/rating"); req.AddUrlSegment("movieId", movieId.ToString(CultureInfo.InvariantCulture)); AddSessionId(req); using RestResponse response = await req.Delete(cancellationToken).ConfigureAwait(false); // status code 13 = "The item/record was deleted successfully." PostReply item = await response.GetDataObject().ConfigureAwait(false); // TODO: Previous code checked for item=null return item != null && item.StatusCode == 13; } /// /// Change the rating of a specified movie. /// /// The id of the movie to rate /// The rating you wish to assign to the specified movie. Value needs to be between 0.5 and 10 and must use increments of 0.5. Ex. using 7.1 will not work and return false. /// A cancellation token /// True if the the movie's rating was successfully updated, false if not /// Requires a valid guest or user session /// Thrown when the current client object doens't have a guest or user session assigned. public async Task MovieSetRatingAsync(int movieId, double rating, CancellationToken cancellationToken = default) { RequireSessionId(SessionType.GuestSession); RestRequest req = _client.Create("movie/{movieId}/rating"); req.AddUrlSegment("movieId", movieId.ToString(CultureInfo.InvariantCulture)); AddSessionId(req); req.SetBody(new { value = rating }); using RestResponse response = await req.Post(cancellationToken).ConfigureAwait(false); // status code 1 = "Success" // status code 12 = "The item/record was updated successfully" - Used when an item was previously rated by the user PostReply item = await response.GetDataObject().ConfigureAwait(false); // TODO: Previous code checked for item=null return item.StatusCode == 1 || item.StatusCode == 12; } } }