using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; using TMDbLib.Objects.Authentication; using TMDbLib.Objects.Changes; using TMDbLib.Objects.General; using TMDbLib.Objects.Reviews; using TMDbLib.Objects.Search; using TMDbLib.Objects.TvShows; using TMDbLib.Rest; using TMDbLib.Utilities; using Credits = TMDbLib.Objects.TvShows.Credits; namespace TMDbLib.Client { public partial class TMDbClient { private async Task GetTvShowMethodInternal(int id, TvShowMethods tvShowMethod, string dateFormat = null, string language = null, string includeImageLanguage = null, int page = 0, CancellationToken cancellationToken = default) where T : new() { RestRequest req = _client.Create("tv/{id}/{method}"); req.AddUrlSegment("id", id.ToString(CultureInfo.InvariantCulture)); req.AddUrlSegment("method", tvShowMethod.GetDescription()); // TODO: Dateformat? //if (dateFormat != null) // req.DateFormat = dateFormat; if (page > 0) req.AddParameter("page", page.ToString()); language ??= DefaultLanguage; if (!string.IsNullOrWhiteSpace(language)) req.AddParameter("language", language); includeImageLanguage ??= DefaultImageLanguage; if (!string.IsNullOrWhiteSpace(includeImageLanguage)) req.AddParameter("include_image_language", includeImageLanguage); T resp = await req.GetOfT(cancellationToken).ConfigureAwait(false); return resp; } private async Task> GetTvShowListInternal(int page, string language, string tvShowListType, CancellationToken cancellationToken = default) { RestRequest req = _client.Create("tv/" + tvShowListType); language ??= DefaultLanguage; if (!string.IsNullOrWhiteSpace(language)) req.AddParameter("language", language); if (page >= 1) req.AddParameter("page", page.ToString()); SearchContainer response = await req.GetOfT>(cancellationToken).ConfigureAwait(false); return response; } public async Task GetLatestTvShowAsync(CancellationToken cancellationToken = default) { RestRequest req = _client.Create("tv/latest"); TvShow resp = await req.GetOfT(cancellationToken).ConfigureAwait(false); return resp; } /// /// Retrieves all information for a specific tv show in relation to the current user account /// /// The id of the tv show 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 GetTvShowAccountStateAsync(int tvShowId, CancellationToken cancellationToken = default) { RequireSessionId(SessionType.UserSession); RestRequest req = _client.Create("tv/{tvShowId}/{method}"); req.AddUrlSegment("tvShowId", tvShowId.ToString(CultureInfo.InvariantCulture)); req.AddUrlSegment("method", TvShowMethods.AccountStates.GetDescription()); AddSessionId(req, SessionType.UserSession); using RestResponse response = await req.Get(cancellationToken).ConfigureAwait(false); return await response.GetDataObject().ConfigureAwait(false); } public async Task> GetTvShowAlternativeTitlesAsync(int id, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal>(id, TvShowMethods.AlternativeTitles, cancellationToken: cancellationToken).ConfigureAwait(false); } /// /// Retrieve a tv Show by id. /// /// TMDb id of the tv show to retrieve. /// Enum flags indicating any additional data that should be fetched in the same request. /// If specified the api will attempt to return a localized result. ex: en,it,es. /// If specified the api will attempt to return localized image results eg. en,it,es. /// A cancellation token /// The requested Tv Show public async Task GetTvShowAsync(int id, TvShowMethods extraMethods = TvShowMethods.Undefined, string language = null, string includeImageLanguage = null, CancellationToken cancellationToken = default) { if (extraMethods.HasFlag(TvShowMethods.AccountStates)) RequireSessionId(SessionType.UserSession); RestRequest req = _client.Create("tv/{id}"); req.AddUrlSegment("id", id.ToString(CultureInfo.InvariantCulture)); if (extraMethods.HasFlag(TvShowMethods.AccountStates)) AddSessionId(req, SessionType.UserSession); language ??= DefaultLanguage; if (!string.IsNullOrWhiteSpace(language)) req.AddParameter("language", language); if (!string.IsNullOrWhiteSpace(includeImageLanguage)) req.AddParameter("include_image_language", includeImageLanguage); string appends = string.Join(",", Enum.GetValues(typeof(TvShowMethods)) .OfType() .Except(new[] { TvShowMethods.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; TvShow item = await response.GetDataObject().ConfigureAwait(false); // No data to patch up so return if (item == null) return null; // Patch up data, so that the end user won't notice that we share objects between request-types. if (item.Translations != null) item.Translations.Id = id; if (item.AccountStates != null) item.AccountStates.Id = id; if (item.Recommendations != null) item.Recommendations.Id = id; if (item.ExternalIds != null) item.ExternalIds.Id = id; return item; } public async Task GetTvShowChangesAsync(int id, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal(id, TvShowMethods.Changes, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetTvShowContentRatingsAsync(int id, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal>(id, TvShowMethods.ContentRatings, cancellationToken: cancellationToken).ConfigureAwait(false); } /// /// Returns a credits object for the tv show associated with the provided TMDb id. /// /// The TMDb id of the target tv show. /// If specified the api will attempt to return a localized result. ex: en,it,es /// A cancellation token public async Task GetTvShowCreditsAsync(int id, string language = null, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal(id, TvShowMethods.Credits, "yyyy-MM-dd", language, cancellationToken: cancellationToken).ConfigureAwait(false); } /// /// Returns a credits object for the aggragation of tv show associated with the provided TMDb id. /// /// The TMDb id of the target tv show. /// If specified the api will attempt to return a localized result. ex: en,it,es /// A cancellation token /// public async Task GetAggregateCredits(int id, string language = null, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal(id, TvShowMethods.CreditsAggregate, language: language, page: 0, cancellationToken: cancellationToken).ConfigureAwait(false); } /// /// Returns an object that contains all known exteral id's for the tv show related to the specified TMDB id. /// /// The TMDb id of the target tv show. /// A cancellation token public async Task GetTvShowExternalIdsAsync(int id, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal(id, TvShowMethods.ExternalIds, cancellationToken: cancellationToken).ConfigureAwait(false); } /// /// Retrieves all images all related to the specified tv show. /// /// The TMDb id of the target tv show. /// /// If specified the api will attempt to return a localized result. ex: en,it,es. /// For images this means that the image might contain language specifc text /// /// If you want to include a fallback language (especially useful for backdrops) you can use the include_image_language parameter. This should be a comma separated value like so: include_image_language=en,null. /// A cancellation token public async Task GetTvShowImagesAsync(int id, string language = null, string includeImageLanguage = null, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal(id, TvShowMethods.Images, language: language, includeImageLanguage: includeImageLanguage, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetTvShowReviewsAsync(int id, string language = null, int page = 0, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal>(id, TvShowMethods.Reviews, language: language, page: page, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetTvShowKeywordsAsync(int id, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal>(id, TvShowMethods.Keywords, cancellationToken: cancellationToken).ConfigureAwait(false); } /// /// Fetches a dynamic list of TV Shows /// /// Type of list to fetch /// Page /// Only relevant for list type AiringToday /// A cancellation token /// public async Task> GetTvShowListAsync(TvShowListType list, int page = 0, string timezone = null, CancellationToken cancellationToken = default) { return await GetTvShowListAsync(list, DefaultLanguage, page, timezone, cancellationToken).ConfigureAwait(false); } /// /// Fetches a dynamic list of TV Shows /// /// Type of list to fetch /// Language /// Page /// Only relevant for list type AiringToday /// A cancellation token /// public async Task> GetTvShowListAsync(TvShowListType list, string language, int page = 0, string timezone = null, CancellationToken cancellationToken = default) { RestRequest req = _client.Create("tv/{method}"); req.AddUrlSegment("method", list.GetDescription()); if (page > 0) req.AddParameter("page", page.ToString()); if (!string.IsNullOrEmpty(timezone)) req.AddParameter("timezone", timezone); language ??= DefaultLanguage; if (!string.IsNullOrWhiteSpace(language)) req.AddParameter("language", language); SearchContainer resp = await req.GetOfT>(cancellationToken).ConfigureAwait(false); return resp; } /// /// Get the list of popular TV shows. This list refreshes every day. /// /// /// Returns the basic information about a tv show. /// For additional data use the main GetTvShowAsync method using the tv show id as parameter. /// public async Task> GetTvShowPopularAsync(int page = -1, string language = null, CancellationToken cancellationToken = default) { return await GetTvShowListInternal(page, language, "popular", cancellationToken).ConfigureAwait(false); } public async Task> GetTvShowSimilarAsync(int id, int page = 0, CancellationToken cancellationToken = default) { return await GetTvShowSimilarAsync(id, DefaultLanguage, page, cancellationToken).ConfigureAwait(false); } public async Task> GetTvShowSimilarAsync(int id, string language, int page = 0, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal>(id, TvShowMethods.Similar, language: language, page: page, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetTvShowRecommendationsAsync(int id, int page = 0, CancellationToken cancellationToken = default) { return await GetTvShowRecommendationsAsync(id, DefaultLanguage, page, cancellationToken).ConfigureAwait(false); } public async Task> GetTvShowRecommendationsAsync(int id, string language, int page = 0, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal>(id, TvShowMethods.Recommendations, language: language, page: page, cancellationToken: cancellationToken).ConfigureAwait(false); } /// /// Get the list of top rated TV shows. By default, this list will only include TV shows that have 2 or more votes. This list refreshes every day. /// /// /// Returns the basic information about a tv show. /// For additional data use the main GetTvShowAsync method using the tv show id as parameter /// public async Task> GetTvShowTopRatedAsync(int page = -1, string language = null, CancellationToken cancellationToken = default) { return await GetTvShowListInternal(page, language, "top_rated", cancellationToken).ConfigureAwait(false); } public async Task GetTvShowTranslationsAsync(int id, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal(id, TvShowMethods.Translations, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task> GetTvShowVideosAsync(int id, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal>(id, TvShowMethods.Videos, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task>> GetTvShowWatchProvidersAsync(int id, CancellationToken cancellationToken = default) { return await GetTvShowMethodInternal>>(id, TvShowMethods.WatchProviders, cancellationToken: cancellationToken).ConfigureAwait(false); } public async Task TvShowRemoveRatingAsync(int tvShowId, CancellationToken cancellationToken = default) { RequireSessionId(SessionType.GuestSession); RestRequest req = _client.Create("tv/{tvShowId}/rating"); req.AddUrlSegment("tvShowId", tvShowId.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: Original code had a check for item=null return item.StatusCode == 13; } /// /// Change the rating of a specified tv show. /// /// The id of the tv show to rate /// The rating you wish to assign to the specified tv show. 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 tv show'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 TvShowSetRatingAsync(int tvShowId, double rating, CancellationToken cancellationToken = default) { RequireSessionId(SessionType.GuestSession); RestRequest req = _client.Create("tv/{tvShowId}/rating"); req.AddUrlSegment("tvShowId", tvShowId.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: Original code had a check for item=null return item.StatusCode == 1 || item.StatusCode == 12; } } }