private async Task HandleSeason(Season season) { if (season.Series == null || !season.Series.TryGetProviderId(MetadataProvider.Tvdb.ToString(), out var tvdbIdTxt)) { return; } var tvdbId = Convert.ToInt32(tvdbIdTxt, CultureInfo.InvariantCulture); var query = new EpisodeQuery { AiredSeason = season.IndexNumber }; var allEpisodes = await GetAllEpisodes(tvdbId, season.GetPreferredMetadataLanguage(), query).ConfigureAwait(false); var existingEpisodes = season.Children.OfType <Episode>().ToList(); for (var i = 0; i < allEpisodes.Count; i++) { var episode = allEpisodes[i]; if (EpisodeExists(episode, existingEpisodes)) { continue; } AddVirtualEpisode(episode, season); } }
private async Task <bool> GetEpisodes() { try { var query = new EpisodeQuery { UserId = AuthenticationService.Current.LoggedInUserId, SeasonId = SelectedSeason.Id, SeriesId = SelectedSeason.SeriesId, Fields = new[] { ItemFields.ParentId, ItemFields.Overview, ItemFields.MediaSources, }, IsMissing = App.SpecificSettings.ShowMissingEpisodes, IsVirtualUnaired = App.SpecificSettings.ShowUnairedEpisodes }; Log.Info("Getting episodes for Season [{0}] ({1}) of TV Show [{2}] ({3})", SelectedSeason.Name, SelectedSeason.Id, SelectedTvSeries.Name, SelectedTvSeries.Id); var episodes = await ApiClient.GetEpisodesAsync(query); Episodes = episodes.Items.ToList(); return(true); } catch (HttpException ex) { Utils.HandleHttpException("GetEpisodes()", ex, NavigationService, Log); App.ShowMessage(AppResources.ErrorEpisodes); return(false); } }
// ReSharper disable once InconsistentNaming public async void GetEpisodesAsync_With_Query_Makes_The_Right_Request() { var jsonClient = CreateJsonClient(); var client = this.CreateClient(jsonClient); const int Id = 42; const int Page = 2; const string Route = "/series/42/episodes/query?page=2&airedSeason=1&imdbId=tt0118480"; var query = new EpisodeQuery { ImdbId = "tt0118480", AiredSeason = 1 }; var expectedData = new TvDbResponse <BasicEpisode[]>(); jsonClient.GetJsonAsync <TvDbResponse <BasicEpisode[]> >(Route, CancellationToken.None).Returns(expectedData); var responseData = await client.GetEpisodesAsync(Id, Page, query, CancellationToken.None); await jsonClient.Received().GetJsonAsync <TvDbResponse <BasicEpisode[]> >(Route, CancellationToken.None); Assert.Equal(expectedData, responseData); }
public async Task GetEpisodeDetails() { if (NavigationService.IsNetworkAvailable) { var index = SelectedEpisode.IndexNumber; if (SelectedEpisode != null && Episodes.IsNullOrEmpty()) { SetProgressBar(AppResources.SysTrayGettingEpisodeDetails); try { if (string.IsNullOrEmpty(SelectedEpisode.SeriesId)) { var episode = await ApiClient.GetItemAsync(SelectedEpisode.Id, AuthenticationService.Current.LoggedInUserId); if (episode == null) { await _messageBox.ShowAsync(AppResources.ErrorEpisodeDetails); NavigationService.GoBack(); return; } SelectedEpisode = episode; } var query = new EpisodeQuery { UserId = AuthenticationService.Current.LoggedInUserId, SeasonId = SelectedEpisode.SeasonId, SeriesId = SelectedEpisode.SeriesId, Fields = new[] { ItemFields.ParentId, ItemFields.Overview, ItemFields.MediaSources, } }; //Log.Info("Getting episodes for Season [{0}] ({1}) of TV Show [{2}] ({3})", SelectedSeason.Name, SelectedSeason.Id, SelectedTvSeries.Name, SelectedTvSeries.Id); var episodes = await ApiClient.GetEpisodesAsync(query); Episodes = episodes.Items.OrderBy(x => x.IndexNumber).ToList(); } catch (HttpException ex) { Utils.HandleHttpException("GetEpisodeDetails()", ex, NavigationService, Log); } SetProgressBar(); } if (SelectedEpisode != null) { SelectedEpisode = Episodes.FirstOrDefault(x => x.IndexNumber == index); CanResume = SelectedEpisode != null && SelectedEpisode.CanResume; } } }
// TODO use async events private void OnLibraryManagerItemRemoved(object sender, ItemChangeEventArgs itemChangeEventArgs) { // No action needed if the item is virtual if (itemChangeEventArgs.Item.IsVirtualItem || !IsEnabledForLibrary(itemChangeEventArgs.Item)) { return; } // Create a new virtual season if the real one was deleted. // Similarly, create a new virtual episode if the real one was deleted. if (itemChangeEventArgs.Item is Season season) { var newSeason = AddVirtualSeason(season.IndexNumber !.Value, season.Series); HandleSeason(newSeason).GetAwaiter().GetResult(); } else if (itemChangeEventArgs.Item is Episode episode) { var tvdbId = Convert.ToInt32(episode.Series?.GetProviderId(MetadataProvider.Tvdb)); if (tvdbId == 0) { return; } var query = new EpisodeQuery { AiredSeason = episode.ParentIndexNumber, AiredEpisode = episode.IndexNumber }; var episodeRecords = GetAllEpisodes(tvdbId, episode.GetPreferredMetadataLanguage(), query).GetAwaiter().GetResult(); AddVirtualEpisode(episodeRecords.FirstOrDefault(), episode.Season); } }
private void MapSeriesToResult(MetadataResult <Series> result, TvDbSharper.Dto.Series tvdbSeries, string metadataLanguage) { Series series = result.Item; series.SetProviderId(MetadataProviders.Tvdb, tvdbSeries.Id.ToString()); series.Name = tvdbSeries.SeriesName; series.Overview = (tvdbSeries.Overview ?? string.Empty).Trim(); result.ResultLanguage = metadataLanguage; series.AirDays = TVUtils.GetAirDays(tvdbSeries.AirsDayOfWeek); series.AirTime = tvdbSeries.AirsTime; series.CommunityRating = (float?)tvdbSeries.SiteRating; series.SetProviderId(MetadataProviders.Imdb, tvdbSeries.ImdbId); series.SetProviderId(MetadataProviders.Zap2It, tvdbSeries.Zap2itId); if (Enum.TryParse(tvdbSeries.Status, true, out SeriesStatus seriesStatus)) { series.Status = seriesStatus; } if (DateTime.TryParse(tvdbSeries.FirstAired, out var date)) { // dates from tvdb are UTC but without offset or Z series.PremiereDate = date; series.ProductionYear = date.Year; } series.RunTimeTicks = TimeSpan.FromMinutes(Convert.ToDouble(tvdbSeries.Runtime)).Ticks; foreach (var genre in tvdbSeries.Genre) { series.AddGenre(genre); } series.AddStudio(tvdbSeries.Network); if (result.Item.Status.HasValue && result.Item.Status.Value == SeriesStatus.Ended) { try { var episodeSummary = _tvDbClientManager .GetSeriesEpisodeSummaryAsync(tvdbSeries.Id, metadataLanguage, CancellationToken.None).Result.Data; var maxSeasonNumber = episodeSummary.AiredSeasons.Select(s => Convert.ToInt32(s)).Max(); var episodeQuery = new EpisodeQuery { AiredSeason = maxSeasonNumber }; var episodesPage = _tvDbClientManager.GetEpisodesPageAsync(tvdbSeries.Id, episodeQuery, metadataLanguage, CancellationToken.None).Result.Data; result.Item.EndDate = episodesPage.Select(e => { DateTime.TryParse(e.FirstAired, out var firstAired); return(firstAired); }).Max(); } catch (TvDbServerException e) { _logger.LogError(e, "Failed to find series end date for series {TvdbId}", tvdbSeries.Id); } } }
public Task <TvDbResponse <EpisodeRecord[]> > GetEpisodesPageAsync( int tvdbId, EpisodeQuery episodeQuery, string language, CancellationToken cancellationToken) { return(GetEpisodesPageAsync(tvdbId, 1, episodeQuery, language, cancellationToken)); }
public async Task <string> GetEpisodeTvdbId(int seriesTvdbId, EpisodeQuery episodeQuery, string language, CancellationToken cancellationToken) { var episodePage = await GetEpisodesPageAsync(Convert.ToInt32(seriesTvdbId), episodeQuery, language, cancellationToken) .ConfigureAwait(false); return(episodePage.Data.FirstOrDefault()?.Id.ToString()); }
/// <summary> /// Gets a page of episodes. /// </summary> /// <param name="tvdbId">Tvdb series id.</param> /// <param name="page">Episode page.</param> /// <param name="episodeQuery">Episode query.</param> /// <param name="language">Metadata language.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>The page of episodes.</returns> public Task <TvDbResponse <EpisodeRecord[]> > GetEpisodesPageAsync( int tvdbId, int page, EpisodeQuery episodeQuery, string language, CancellationToken cancellationToken) { var cacheKey = GenerateKey(language, tvdbId, episodeQuery); return(TryGetValue(cacheKey, language, tvDbClient => tvDbClient.Series.GetEpisodesAsync(tvdbId, page, episodeQuery, cancellationToken))); }
public async Task <TvDbResponse <BasicEpisode[]> > GetEpisodesAsync( int seriesId, int page, EpisodeQuery query, CancellationToken cancellationToken) { string url = $"/series/{seriesId}/episodes/query?page={Math.Max(page, 1)}&{this.UrlHelpers.Querify(query)}"; var request = new ApiRequest("GET", url); var response = await this.ApiClient.SendRequestAsync(request, cancellationToken).ConfigureAwait(false); return(this.Parser.Parse <TvDbResponse <BasicEpisode[]> >(response, ErrorMessages.Series.GetAsync)); }
// ReSharper disable once InconsistentNaming public Task GetEpisodesAsync_With_Query_Makes_The_Right_Request(int seriesId, int page, int actualPage, int aired, int dvd) { var query = new EpisodeQuery { AiredEpisode = aired, DvdEpisode = dvd }; return(CreateClient() .WithErrorMap(ErrorMessages.Series.GetAsync) .SetResultObject(new TvDbResponse <EpisodeRecord[]>()) .WhenCallingAMethod((impl, token) => impl.GetEpisodesAsync(seriesId, page, query, token)) .ShouldRequest("GET", $"/series/{seriesId}/episodes/query?page={actualPage}&airedEpisode={aired}&dvdEpisode={dvd}") .RunAsync()); }
// ReSharper disable once InconsistentNaming public async void GetEpisodesAsync_With_CancellationToken_With_Query_Throws_With_The_Correct_Message(int statusCode) { var jsonClient = CreateJsonClient(); var client = this.CreateClient(jsonClient); var query = new EpisodeQuery { ImdbId = "tt0118480", AiredSeason = 1 }; jsonClient.GetJsonAsync <TvDbResponse <BasicEpisode[]> >(null, CancellationToken.None) .ThrowsForAnyArgs(info => new TvDbServerException(null, (HttpStatusCode)statusCode, null)); var ex = await Assert.ThrowsAsync <TvDbServerException>(async() => await client.GetEpisodesAsync(42, 2, query)); Assert.Equal(this.ErrorMessages.Series.GetAsync[statusCode], ex.Message); }
// TODO use async events private void OnLibraryManagerItemRemoved(object?sender, ItemChangeEventArgs itemChangeEventArgs) { // No action needed if the item is virtual if (itemChangeEventArgs.Item.IsVirtualItem || !IsEnabledForLibrary(itemChangeEventArgs.Item)) { return; } // Create a new virtual season if the real one was deleted. // Similarly, create a new virtual episode if the real one was deleted. if (itemChangeEventArgs.Item is Season season) { var newSeason = AddVirtualSeason(season.IndexNumber !.Value, season.Series); HandleSeason(newSeason).GetAwaiter().GetResult(); } else if (itemChangeEventArgs.Item is Episode episode) { if (episode.Series == null || !episode.Series.TryGetProviderId(MetadataProvider.Tvdb.ToString(), out var tvdbIdTxt)) { return; } var tvdbId = Convert.ToInt32(tvdbIdTxt, CultureInfo.InvariantCulture); var query = new EpisodeQuery { AiredSeason = episode.ParentIndexNumber, AiredEpisode = episode.IndexNumber }; var episodeRecords = GetAllEpisodes(tvdbId, episode.GetPreferredMetadataLanguage(), query).GetAwaiter().GetResult(); EpisodeRecord?episodeRecord = null; if (episodeRecords.Count > 0) { episodeRecord = episodeRecords[0]; } AddVirtualEpisode(episodeRecord, episode.Season); } }
public Task <string> GetEpisodeTvdbId( EpisodeInfo searchInfo, string language, CancellationToken cancellationToken) { searchInfo.SeriesProviderIds.TryGetValue( nameof(MetadataProvider.Tvdb), out var seriesTvdbId); var episodeQuery = new EpisodeQuery(); // Prefer SxE over premiere date as it is more robust if (searchInfo.IndexNumber.HasValue && searchInfo.ParentIndexNumber.HasValue) { switch (searchInfo.SeriesDisplayOrder) { case "dvd": episodeQuery.DvdEpisode = searchInfo.IndexNumber.Value; episodeQuery.DvdSeason = searchInfo.ParentIndexNumber.Value; break; case "absolute": episodeQuery.AbsoluteNumber = searchInfo.IndexNumber.Value; break; default: // aired order episodeQuery.AiredEpisode = searchInfo.IndexNumber.Value; episodeQuery.AiredSeason = searchInfo.ParentIndexNumber.Value; break; } } else if (searchInfo.PremiereDate.HasValue) { // tvdb expects yyyy-mm-dd format episodeQuery.FirstAired = searchInfo.PremiereDate.Value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture); } return(GetEpisodeTvdbId(Convert.ToInt32(seriesTvdbId, CultureInfo.InvariantCulture), episodeQuery, language, cancellationToken)); }
public Task <string> GetEpisodeTvdbId(EpisodeInfo searchInfo, string language, CancellationToken cancellationToken) { searchInfo.SeriesProviderIds.TryGetValue(MetadataProviders.Tvdb.ToString(), out var seriesTvdbId); var episodeQuery = new EpisodeQuery(); // Prefer SxE over premiere date as it is more robust if (searchInfo.IndexNumber.HasValue && searchInfo.ParentIndexNumber.HasValue) { episodeQuery.AiredEpisode = searchInfo.IndexNumber.Value; episodeQuery.AiredSeason = searchInfo.ParentIndexNumber.Value; } else if (searchInfo.PremiereDate.HasValue) { // tvdb expects yyyy-mm-dd format episodeQuery.FirstAired = searchInfo.PremiereDate.Value.ToString("yyyy-MM-dd"); } return(GetEpisodeTvdbId(Convert.ToInt32(seriesTvdbId), episodeQuery, language, cancellationToken)); }
public Task <TvDbResponse <BasicEpisode[]> > GetEpisodesAsync( int seriesId, int page, EpisodeQuery query, CancellationToken cancellationToken) { try { string requestUri = $"/series/{seriesId}/episodes/query?page={Math.Max(page, 1)}&{this.UrlHelpers.Querify(query)}"; return(this.GetAsync <BasicEpisode[]>(requestUri, cancellationToken)); } catch (TvDbServerException ex) { string message = this.GetMessage(ex.StatusCode, this.ErrorMessages.Series.GetAsync); if (message == null) { throw; } throw new TvDbServerException(message, ex.StatusCode, ex); } }
private async void GetEpisodes() { if (TvShows != null) { //Load Episode Data from TvShows and write back to TvShows; var client = new TvDbClient(); await client.Authentication.AuthenticateAsync(Data.ApiKey, Data.UserName, Data.UserKey); client.AcceptedLanguage = Data.prefLang; var tasks = new List <Task <TvDbResponse <TvDbSharper.Dto.EpisodeRecord[]> > >(); var response = new TvDbResponse <EpisodeRecord[]>(); tvShow show = TvShows.Find(i => i.tvdbID == actualTvDbID); if (show.Count > 1) { foreach (showEpisode ep in TvShows.Where(i => i.tvdbID == actualTvDbID)) { response = await client.Series.GetEpisodesAsync(ep.tvdbID, 1); for (int i = 2; i <= response.Links.Last; i++) { tasks.Add(client.Series.GetEpisodesAsync(ep.tvdbID, i)); } } } else { EpisodeQuery q = new EpisodeQuery(); q.AiredSeason = TvShows[0][0].seasonNr; q.AiredEpisode = TvShows[0][0].episodeNr; response = await client.Series.GetEpisodesAsync(show.tvdbID, 1, q); } var results = await Task.WhenAll(tasks); //var eps = response.Data.Concat(results.SelectMany(x => x.Data)); foreach (EpisodeRecord er in response.Data.Concat(results.SelectMany(x => x.Data))) { foreach (showEpisode ep in TvShows.Where(i => i.tvdbID == actualTvDbID)) { if (er.AiredSeason == ep.seasonNr && er.AiredEpisodeNumber == ep.episodeNr) { //DateTime dt = DateTime.Parse(ep.FirstAired); if (er.EpisodeName == null) //Backup if no German { client.AcceptedLanguage = "en"; TvDbResponse <EpisodeRecord> er1 = await client.Episodes.GetAsync(er.Id); ep.episodeName = er1.Data.EpisodeName; ep.description = er1.Data.Overview; } else { ep.episodeName = er.EpisodeName; ep.description = er.Overview; } ep.tvDbEpisodeId = er.Id; if (helper.isDateTime(er.FirstAired)) { ep.episodeAirDate = DateTime.Parse(er.FirstAired); } if (ep.episodeName != null && ep.episodeNumbering != null) { ep.newFilename = GetCorrectedFileName(ep.episodeName, ep.episodeNumbering); } } } } //Episode not found in Episode List } }
public Task <TvDbResponse <BasicEpisode[]> > GetEpisodesAsync(int seriesId, int page, EpisodeQuery query) { return(this.GetEpisodesAsync(seriesId, page, query, CancellationToken.None)); }
private async Task <IReadOnlyList <EpisodeRecord> > GetAllEpisodes(int tvdbId, string acceptedLanguage, EpisodeQuery episodeQuery = null) { if (string.IsNullOrEmpty(_tvDbClient.Authentication.Token) || DateTime.Now.AddHours(-24) >= _tokenCreatedAt) { await _tvDbClient.Authentication.AuthenticateAsync(_tvdbApiKey).ConfigureAwait(false); _tokenCreatedAt = DateTime.Now; } _tvDbClient.AcceptedLanguage = acceptedLanguage; // Fetch all episodes for the series var allEpisodes = new List <EpisodeRecord>(); var page = 1; while (true) { episodeQuery ??= new EpisodeQuery(); var episodes = await _tvDbClient.Series.GetEpisodesAsync(tvdbId, page, episodeQuery).ConfigureAwait(false); allEpisodes.AddRange(episodes.Data); if (!episodes.Links.Next.HasValue) { break; } page = episodes.Links.Next.Value; } return(allEpisodes); }