/// <summary> /// Set the show /// </summary> /// <param name="show">Show</param> public async Task SetShowAsync(ShowJson show) { var watch = Stopwatch.StartNew(); try { var showToUpdate = User.ShowHistory.FirstOrDefault(a => a.ImdbId == show.ImdbId); if (showToUpdate == null) { User.ShowHistory.Add(new ShowHistoryJson { ImdbId = show.ImdbId, Favorite = show.IsFavorite, }); } else { showToUpdate.Favorite = show.IsFavorite; } await UpdateHistoryAsync(); } catch (Exception exception) { Logger.Error( $"SetShowAsync: {exception.Message}"); } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"SetShowAsync ({show.ImdbId}) in {elapsedMs} milliseconds."); } }
/// <summary> /// Get show by its Imdb code /// </summary> /// <param name="imdbId">Show's Imdb code</param> /// <returns>The show</returns> public async Task <ShowJson> GetShowAsync(string imdbId, CancellationToken ct) { var timeoutPolicy = Policy.TimeoutAsync(Utils.Constants.DefaultRequestTimeoutInSecond, TimeoutStrategy.Pessimistic); try { return(await timeoutPolicy.ExecuteAsync(async cancellation => { var watch = Stopwatch.StartNew(); var restClient = new RestClient(Utils.Constants.PopcornApi); var request = new RestRequest("/{segment}/{show}", Method.GET); request.AddUrlSegment("segment", "shows"); request.AddUrlSegment("show", imdbId); var show = new ShowJson(); try { var response = await restClient.ExecuteTaskAsync(request, cancellation) .ConfigureAwait(false); if (response.ErrorException != null) { throw response.ErrorException; } show = JsonSerializer.Deserialize <ShowJson>(response.RawBytes); } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "GetShowAsync cancelled."); } catch (Exception exception) { Logger.Error( $"GetShowAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"GetShowAsync ({imdbId}) in {elapsedMs} milliseconds."); } return show; }, ct).ConfigureAwait(false)); } catch (Exception ex) { Logger.Error(ex); throw; } }
/// <summary> /// Constructor /// </summary> /// <param name="showService">The show service</param> /// <param name="subtitlesService">The subtitles service</param> /// <param name="showTrailerService">The show trailer service</param> /// <param name="cacheService">The cache service</param> public ShowDetailsViewModel(IShowService showService, ISubtitlesService subtitlesService, IShowTrailerService showTrailerService, ICacheService cacheService) { _showTrailerService = showTrailerService; _showService = showService; Show = new ShowJson(); RegisterCommands(); RegisterMessages(); CancellationLoadingTrailerToken = new CancellationTokenSource(); var downloadService = new DownloadShowService <EpisodeShowJson>(cacheService); DownloadShow = new DownloadShowViewModel(downloadService, subtitlesService, cacheService); }
/// <summary> /// Load the requested show /// </summary> /// <param name="show">The show to load</param> private async Task LoadShow(ShowJson show) { var watch = Stopwatch.StartNew(); Messenger.Default.Send(new LoadShowMessage()); Show = show; watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug($"LoadShow ({show.ImdbId}) in {elapsedMs} milliseconds."); }
/// <summary> /// Load movie's trailer asynchronously /// </summary> /// <param name="show">The show</param> /// <param name="ct">Cancellation token</param> public async Task LoadTrailerAsync(ShowJson show, CancellationToken ct) { try { var trailer = await ShowService.GetShowTrailerAsync(show, ct); if (!ct.IsCancellationRequested && string.IsNullOrEmpty(trailer)) { Logger.Error( $"Failed loading show's trailer: {show.Title}"); Messenger.Default.Send( new ManageExceptionMessage( new PopcornException( LocalizationProviderHelper.GetLocalizedValue <string>("TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); return; } if (!ct.IsCancellationRequested) { Logger.Debug( $"Show's trailer loaded: {show.Title}"); Messenger.Default.Send(new PlayTrailerMessage(trailer, show.Title, () => { Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); }, () => { Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); }, Utils.MediaType.Show)); } } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "LoadTrailerAsync cancelled."); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); } catch (Exception exception) { Logger.Error( $"LoadTrailerAsync: {exception.Message}"); Messenger.Default.Send( new ManageExceptionMessage( new PopcornException( LocalizationProviderHelper.GetLocalizedValue <string>( "TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); } }
/// <summary> /// Get show by its Imdb code /// </summary> /// <param name="imdbCode">Show's Imdb code</param> /// <returns>The show</returns> public async Task <ShowJson> GetShowAsync(string imdbCode) { var watch = Stopwatch.StartNew(); var restClient = new RestClient(Utils.Constants.PopcornApi); var request = new RestRequest("/{segment}/{show}", Method.GET); request.AddUrlSegment("segment", "shows"); request.AddUrlSegment("show", imdbCode); var show = new ShowJson(); try { var response = await restClient.ExecuteGetTaskAsync <ShowJson>(request); if (response.ErrorException != null) { throw response.ErrorException; } show = response.Data; } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "GetShowAsync cancelled."); } catch (Exception exception) { Logger.Error( $"GetShowAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"GetShowAsync ({imdbCode}) in {elapsedMs} milliseconds."); } return(show); }
/// <summary> /// Get the link to the youtube trailer of a show /// </summary> /// <param name="show">The show</param> /// <param name="ct">Used to cancel loading trailer</param> /// <returns>Video trailer</returns> public async Task <string> GetShowTrailerAsync(ShowJson show, CancellationToken ct) { var timeoutPolicy = Policy.TimeoutAsync(Utils.Constants.DefaultRequestTimeoutInSecond, TimeoutStrategy.Pessimistic); try { return(await timeoutPolicy.ExecuteAsync(async cancellation => { var watch = Stopwatch.StartNew(); var uri = string.Empty; try { var tmdbVideos = await(await _tmdbService.GetClient).GetTvShowVideosAsync(show.TmdbId); if (tmdbVideos != null && tmdbVideos.Results.Any()) { var trailer = tmdbVideos.Results.FirstOrDefault(); using (var service = Client.For(YouTube.Default)) { var videos = (await service .GetAllVideosAsync("https://youtube.com/watch?v=" + trailer.Key)) .ToList(); if (videos.Any()) { var settings = SimpleIoc.Default.GetInstance <ApplicationSettingsViewModel>(); var maxRes = settings.DefaultHdQuality ? 1080 : 720; uri = await videos .Where(a => !a.Is3D && a.Resolution <= maxRes && a.Format == VideoFormat.Mp4 && a.AudioBitrate > 0) .Aggregate((i1, i2) => i1.Resolution > i2.Resolution ? i1 : i2) .GetUriAsync(); } } } else { throw new PopcornException("No trailer found."); } } catch (Exception exception) when(exception is TaskCanceledException || exception is OperationCanceledException) { Logger.Debug( "GetShowTrailerAsync cancelled."); } catch (Exception exception) { Logger.Error( $"GetShowTrailerAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Trace( $"GetShowTrailerAsync ({show.ImdbId}) in {elapsedMs} milliseconds."); } return uri; }, ct)); } catch (Exception ex) { Logger.Error(ex); throw; } }
/// <summary> /// Get show by its Imdb code /// </summary> /// <param name="imdbId">Show's Imdb code</param> /// <param name="ct">Cancellation token</param> /// <returns>The show</returns> public async Task <ShowJson> GetShowAsync(string imdbId, CancellationToken ct) { var timeoutPolicy = Policy.TimeoutAsync(Constants.DefaultRequestTimeoutInSecond, TimeoutStrategy.Optimistic); try { return(await timeoutPolicy.ExecuteAsync(async cancellation => { var optionsBuilder = new DbContextOptionsBuilder <PopcornContext>(); optionsBuilder.UseSqlServer( (ConfigurationManager.GetSection("settings") as NameValueCollection)["SQLConnectionString"], builder => { builder.CommandTimeout(Convert.ToInt32(TimeSpan.FromSeconds(60).TotalSeconds)); builder.EnableRetryOnFailure(); }); await using var context = new PopcornContext(optionsBuilder.Options); var watch = Stopwatch.StartNew(); var showJson = new ShowJson(); try { var show = await context.ShowSet.Include(a => a.Rating) .Include(a => a.Episodes) .ThenInclude(episode => episode.Torrents) .ThenInclude(torrent => torrent.Torrent0) .Include(a => a.Episodes) .ThenInclude(episode => episode.Torrents) .ThenInclude(torrent => torrent.Torrent1080p) .Include(a => a.Episodes) .ThenInclude(episode => episode.Torrents) .ThenInclude(torrent => torrent.Torrent480p) .Include(a => a.Episodes) .Include(a => a.Episodes) .ThenInclude(episode => episode.Torrents) .ThenInclude(torrent => torrent.Torrent720p) .Include(a => a.Genres) .Include(a => a.Images) .Include(a => a.Similars).AsQueryable() .FirstOrDefaultAsync(a => a.ImdbId == imdbId, cancellation); showJson = ConvertShowToJson(show); var shows = await(await _tmdbService.GetClient).SearchTvShowAsync(show.Title, cancellationToken: cancellation); if (shows.Results.Any()) { foreach (var tvShow in shows.Results) { try { var result = await(await _tmdbService.GetClient).GetTvShowExternalIdsAsync(tvShow.Id, cancellation); if (result.ImdbId == show.ImdbId) { showJson.TmdbId = result.Id; } } catch (Exception ex) { Logger.Error(ex); } } } } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "GetShowAsync cancelled."); } catch (Exception exception) { Logger.Error( $"GetShowAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Trace( $"GetShowAsync ({imdbId}) in {elapsedMs} milliseconds."); } return showJson; }, ct)); } catch (Exception ex) { Logger.Error(ex); throw; } }
/// <summary> /// Get the link to the youtube trailer of a show /// </summary> /// <param name="show">The show</param> /// <param name="ct">Used to cancel loading trailer</param> /// <returns>Video trailer</returns> public async Task <string> GetShowTrailerAsync(ShowJson show, CancellationToken ct) { var watch = Stopwatch.StartNew(); var uri = string.Empty; try { var shows = await TmdbClient.SearchTvShowAsync(show.Title).ConfigureAwait(false); if (shows.Results.Any()) { Video trailer = null; foreach (var tvShow in shows.Results) { try { var result = await TmdbClient.GetTvShowExternalIdsAsync(tvShow.Id).ConfigureAwait(false); if (result.ImdbId == show.ImdbId) { var videos = await TmdbClient.GetTvShowVideosAsync(result.Id).ConfigureAwait(false); if (videos != null && videos.Results.Any()) { trailer = videos.Results.FirstOrDefault(); } } } catch (Exception ex) { Logger.Error(ex); } } if (trailer != null) { using (var service = Client.For(YouTube.Default)) { var videos = (await service.GetAllVideosAsync("https://youtube.com/watch?v=" + trailer.Key) .ConfigureAwait(false)) .ToList(); if (videos.Any()) { var settings = SimpleIoc.Default.GetInstance <ApplicationSettingsViewModel>(); var maxRes = settings.DefaultHdQuality ? 1080 : 720; uri = await videos .Where(a => !a.Is3D && a.Resolution <= maxRes && a.Format == VideoFormat.Mp4 && a.AudioBitrate > 0) .Aggregate((i1, i2) => i1.Resolution > i2.Resolution ? i1 : i2).GetUriAsync(); } } } else { throw new PopcornException("No trailer found."); } } } catch (Exception exception) when(exception is TaskCanceledException || exception is OperationCanceledException) { Logger.Debug( "GetShowTrailerAsync cancelled."); } catch (Exception exception) { Logger.Error( $"GetShowTrailerAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"GetShowTrailerAsync ({show.ImdbId}) in {elapsedMs} milliseconds."); } return(uri); }
/// <summary> /// Load movie's trailer asynchronously /// </summary> /// <param name="show">The show</param> /// <param name="ct">Cancellation token</param> public async Task LoadTrailerAsync(ShowJson show, CancellationToken ct) { var timeoutPolicy = Policy.TimeoutAsync(5, TimeoutStrategy.Pessimistic); try { await timeoutPolicy.ExecuteAsync(async cancellation => { try { var trailer = await ShowService.GetShowTrailerAsync(show, cancellation); if (!ct.IsCancellationRequested && string.IsNullOrEmpty(trailer)) { Logger.Error( $"Failed loading show's trailer: {show.Title}"); Messenger.Default.Send( new ManageExceptionMessage( new TrailerNotAvailableException( LocalizationProviderHelper.GetLocalizedValue <string>("TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); return; } if (!ct.IsCancellationRequested) { Logger.Debug( $"Show's trailer loaded: {show.Title}"); Messenger.Default.Send(new PlayTrailerMessage(trailer, show.Title, () => { Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); }, () => { Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); }, Utils.MediaType.Show)); } } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "LoadTrailerAsync cancelled."); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); } catch (Exception exception) { Logger.Error( $"LoadTrailerAsync: {exception.Message}"); Messenger.Default.Send( new ManageExceptionMessage( new TrailerNotAvailableException( LocalizationProviderHelper.GetLocalizedValue <string>( "TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); } }, ct).ConfigureAwait(false); } catch (Exception ex) { Logger.Error(ex); } }
/// <summary> /// Load movie's trailer asynchronously /// </summary> /// <param name="show">The show</param> /// <param name="ct">Cancellation token</param> public async Task LoadTrailerAsync(ShowJson show, CancellationToken ct) { var timeoutPolicy = Policy.TimeoutAsync(Utils.Constants.DefaultRequestTimeoutInSecond, TimeoutStrategy.Pessimistic); try { await timeoutPolicy.ExecuteAsync(async cancellation => { try { var trailer = await ShowService.GetShowTrailerAsync(show, cancellation); if (!ct.IsCancellationRequested && string.IsNullOrEmpty(trailer)) { Logger.Error( $"Failed loading show's trailer: {show.Title}"); Messenger.Default.Send( new ManageExceptionMessage( new TrailerNotAvailableException( LocalizationProviderHelper.GetLocalizedValue <string>("TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); return; } if (!ct.IsCancellationRequested) { Uri uriResult; bool result = Uri.TryCreate(trailer, UriKind.Absolute, out uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); if (result) { var client = new HttpClient(); try { using (var response = await client.GetAsync(uriResult, HttpCompletionOption.ResponseHeadersRead, ct)) { if (response == null || response.StatusCode != HttpStatusCode.OK) { Logger.Error( $"Failed loading show's trailer: {show.Title}"); Messenger.Default.Send( new ManageExceptionMessage( new TrailerNotAvailableException( LocalizationProviderHelper.GetLocalizedValue <string>("TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); return; } } } catch (WebException) { Logger.Error( $"Failed loading show's trailer: {show.Title}"); Messenger.Default.Send( new ManageExceptionMessage( new TrailerNotAvailableException( LocalizationProviderHelper.GetLocalizedValue <string>("TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); return; } } else { Logger.Error( $"Failed loading show's trailer: {show.Title}"); Messenger.Default.Send( new ManageExceptionMessage( new TrailerNotAvailableException( LocalizationProviderHelper.GetLocalizedValue <string>("TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); return; } Logger.Info( $"Show's trailer loaded: {show.Title}"); Messenger.Default.Send(new PlayTrailerMessage(trailer, show.Title, () => { Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); }, () => { Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); }, Utils.MediaType.Show)); } } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "LoadTrailerAsync cancelled."); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); } catch (Exception exception) { Logger.Error( $"LoadTrailerAsync: {exception.Message}"); Messenger.Default.Send( new ManageExceptionMessage( new TrailerNotAvailableException( LocalizationProviderHelper.GetLocalizedValue <string>( "TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage(Utils.MediaType.Show)); } }, ct); } catch (Exception ex) { Logger.Error(ex); } }
/// <summary> /// Get show by its Imdb code /// </summary> /// <param name="imdbId">Show's Imdb code</param> /// <param name="ct">Cancellation token</param> /// <returns>The show</returns> public async Task <ShowJson> GetShowAsync(string imdbId, CancellationToken ct) { var timeoutPolicy = Policy.TimeoutAsync(Constants.DefaultRequestTimeoutInSecond, TimeoutStrategy.Optimistic); try { return(await timeoutPolicy.ExecuteAsync(async cancellation => { var watch = Stopwatch.StartNew(); var request = new RestRequest("/{segment}/{show}", Method.GET); request.AddUrlSegment("segment", "shows"); request.AddUrlSegment("show", imdbId); var show = new ShowJson(); try { var response = await _restClient.ExecuteTaskAsync(request, cancellation); if (response.ErrorException != null) { throw response.ErrorException; } show = JsonConvert.DeserializeObject <ShowJson>(response.Content); var shows = await(await _tmdbService.GetClient).SearchTvShowAsync(show.Title, cancellationToken: cancellation); if (shows.Results.Any()) { foreach (var tvShow in shows.Results) { try { var result = await(await _tmdbService.GetClient).GetTvShowExternalIdsAsync(tvShow.Id, cancellationToken: cancellation); if (result.ImdbId == show.ImdbId) { show.TmdbId = result.Id; } } catch (Exception ex) { Logger.Error(ex); } } } } catch (Exception exception) when(exception is TaskCanceledException) { Logger.Debug( "GetShowAsync cancelled."); } catch (Exception exception) { Logger.Error( $"GetShowAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Trace( $"GetShowAsync ({imdbId}) in {elapsedMs} milliseconds."); } return show; }, ct)); } catch (Exception ex) { Logger.Error(ex); throw; } }