public void Equals_DifferentMovies_ReturnsFalse() { var fixture = new Fixture(); var id1 = fixture.Create<int>(); var dateUploadedUnix1 = fixture.Create<int>(); var id2 = fixture.Create<int>(); var dateUploadedUnix2 = fixture.Create<int>(); var movie1 = new MovieFull { Id = id1, DateUploadedUnix = dateUploadedUnix1 }; var movie2 = new MovieFull { Id = id2, DateUploadedUnix = dateUploadedUnix2 }; Assert.AreEqual( _comparer.Equals(movie1, movie2), false); Assert.AreEqual( _comparer.Equals(movie1, null), false); Assert.AreEqual( _comparer.Equals(movie2, null), false); }
/// <summary> /// Load a movie /// </summary> /// <param name="movie">Movie to load</param> public void LoadMovie(MovieFull movie) { Logger.Info( $"Loading movie: {movie.Title}."); Movie = movie; TabName = !string.IsNullOrEmpty(Movie.Title) ? Movie.Title : Properties.Resources.PlayingTitleTab; }
/// <summary> /// Get the movie's subtitles /// </summary> /// <param name="movie">The movie</param> public async Task LoadSubtitlesAsync(MovieFull movie) { Logger.Debug( $"Load subtitles for movie: {movie.Title}"); Movie = movie; await _movieService.LoadSubtitlesAsync(movie, _cancellationDownloadingSubtitlesToken.Token); }
public void Equals_SameMovie_ReturnsTrue() { var fixture = new Fixture(); var movie1 = new MovieFull(); var movie2 = new MovieFull(); var id = fixture.Create<int>(); var dateUploadedUnix = fixture.Create<int>(); movie1.Id = id; movie2.Id = id; movie1.DateUploadedUnix = dateUploadedUnix; movie2.DateUploadedUnix = dateUploadedUnix; Assert.AreEqual( _comparer.Equals(movie1, movie1), true); Assert.AreEqual( _comparer.Equals(movie1, movie2), true); }
public void GetHashCode_SameMovie_ReturnsSameHashCode() { var fixture = new Fixture(); var movie1 = new MovieFull(); var movie2 = new MovieFull(); var id = fixture.Create<int>(); var dateUploadedUnix = fixture.Create<int>(); movie1.Id = id; movie2.Id = id; movie1.DateUploadedUnix = dateUploadedUnix; movie2.DateUploadedUnix = dateUploadedUnix; Assert.AreEqual( _comparer.GetHashCode(movie1), _comparer.GetHashCode(movie1)); Assert.AreEqual( _comparer.GetHashCode(movie1), _comparer.GetHashCode(movie2)); }
/// <summary> /// Stop downloading subtitles and clear movie /// </summary> public void ClearSubtitles() { StopDownloadingSubtitles(); Movie = null; }
/// <summary> /// Load a movie /// </summary> /// <param name="movie">The movie to load</param> public void LoadMovie(MovieFull movie) { Movie = movie; Subtitles.ClearSubtitles(); }
/// <summary> /// Download a movie asynchronously /// </summary> /// <param name="movie">The movie to download</param> /// <param name="downloadProgress">Report download progress</param> /// <param name="downloadRate">Report download rate</param> /// <param name="ct">Cancellation token</param> private async Task DownloadMovieAsync(MovieFull movie, IProgress<double> downloadProgress, IProgress<double> downloadRate, CancellationTokenSource ct) { await Task.Run(async () => { using (var session = new session()) { Logger.Info( $"Start downloading movie : {movie.Title}"); IsDownloadingMovie = true; downloadProgress?.Report(0d); downloadRate?.Report(0d); session.listen_on(6881, 6889); var torrentUrl = movie.WatchInFullHdQuality ? movie.Torrents?.FirstOrDefault(torrent => torrent.Quality == "1080p")?.Url : movie.Torrents?.FirstOrDefault(torrent => torrent.Quality == "720p")?.Url; var result = await DownloadFileHelper.DownloadFileTaskAsync(torrentUrl, Constants.TorrentDownloads + movie.ImdbCode + ".torrent", ct: ct); var torrentPath = string.Empty; if (result.Item3 == null && !string.IsNullOrEmpty(result.Item2)) torrentPath = result.Item2; var addParams = new add_torrent_params { save_path = Constants.MovieDownloads, ti = new torrent_info(torrentPath) }; var handle = session.add_torrent(addParams); handle.set_upload_limit(_settingsViewModel.DownloadLimit*1024); handle.set_download_limit(_settingsViewModel.UploadLimit*1024); // We have to download sequentially, so that we're able to play the movie without waiting handle.set_sequential_download(true); var alreadyBuffered = false; while (IsDownloadingMovie) { var status = handle.status(); var progress = status.progress*100d; downloadProgress?.Report(progress); downloadRate?.Report(Math.Round(status.download_rate/1024d, 0)); handle.flush_cache(); if (handle.need_save_resume_data()) handle.save_resume_data(1); if (progress >= Constants.MinimumBufferingBeforeMoviePlaying && !alreadyBuffered) { // Get movie file foreach ( var filePath in Directory.GetFiles(status.save_path + handle.torrent_file().name(), "*" + Constants.VideoFileExtension) ) { alreadyBuffered = true; movie.FilePath = new Uri(filePath); Messenger.Default.Send(new PlayMovieMessage(movie)); } } try { await Task.Delay(1000, ct.Token); } catch (TaskCanceledException) { return; } } } }, ct.Token); }
/// <summary> /// Load a movie /// </summary> /// <param name="movie">The movie to load</param> public void LoadMovie(MovieFull movie) { Movie = movie; MovieSettings.LoadMovie(Movie); }
/// <summary> /// Initialize a new instance of DownloadMovieMessage class /// </summary> /// <param name="movie">The movie to download</param> public DownloadMovieMessage(MovieFull movie) { Movie = movie; }
/// <summary> /// Translate movie informations (title, description, ...) /// </summary> /// <param name="movieToTranslate">Movie to translate</param> /// <param name="ct">Used to cancel translation</param> /// <returns>Task</returns> public async Task TranslateMovieFullAsync(MovieFull movieToTranslate, CancellationToken ct) { var watch = Stopwatch.StartNew(); try { await Task.Run(async () => { var movie = await TmdbClient.GetMovieAsync(movieToTranslate.ImdbCode, MovieMethods.Credits); movieToTranslate.Title = movie?.Title; movieToTranslate.Genres = movie?.Genres?.Select(a => a.Name).ToList(); movieToTranslate.DescriptionFull = movie?.Overview; }, ct); } catch (Exception exception) when (exception is TaskCanceledException) { Logger.Debug( "TranslateMovieFull cancelled."); } catch (Exception exception) { Logger.Error( $"TranslateMovieFull: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"TranslateMovieFull ({movieToTranslate.ImdbCode}) in {elapsedMs} milliseconds."); } }
/// <summary> /// Download actors' image for a movie /// </summary> /// <param name="movie">The movie to process</param> /// <param name="ct">Used to cancel downloading actor image</param> public async Task DownloadCastImageAsync(MovieFull movie, CancellationTokenSource ct) { if (movie.Cast == null) return; var watch = Stopwatch.StartNew(); try { await movie.Cast.ForEachAsync( cast => DownloadFileHelper.DownloadFileTaskAsync(cast.SmallImage, Constants.CastMovieDirectory + cast.Name + Constants.ImageFileExtension, ct: ct), (cast, t) => { if (t.Item3 == null && !string.IsNullOrEmpty(t.Item2)) cast.SmallImagePath = t.Item2; }); } catch (Exception exception) when (exception is TaskCanceledException) { Logger.Debug( "DownloadCastImageAsync cancelled."); } catch (Exception exception) { Logger.Error( $"DownloadCastImageAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"DownloadCastImageAsync ({movie.ImdbCode}) in {elapsedMs} milliseconds."); } }
/// <summary> /// Download the movie's poster image /// </summary> /// <param name="movie">The movie to process</param> /// <param name="ct">Used to cancel downloading poster image</param> public async Task DownloadPosterImageAsync(MovieFull movie, CancellationTokenSource ct) { var watch = Stopwatch.StartNew(); var posterPath = new List<string> { movie.LargeCoverImage }; try { await posterPath.ForEachAsync( poster => DownloadFileHelper.DownloadFileTaskAsync(poster, Constants.PosterMovieDirectory + movie.ImdbCode + Constants.ImageFileExtension, ct: ct), (poster, t) => { if (t.Item3 == null && !string.IsNullOrEmpty(t.Item2)) movie.LargeCoverImage = t.Item2; }); } catch (Exception exception) when (exception is TaskCanceledException) { Logger.Debug( "DownloadPosterImageAsync cancelled."); } catch (Exception exception) { Logger.Error( $"DownloadPosterImageAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"DownloadPosterImageAsync ({movie.ImdbCode}) in {elapsedMs} milliseconds."); } }
/// <summary> /// Download the movie's background image /// </summary> /// <param name="movie">The movie to process</param> /// <param name="ct">Used to cancel downloading background image</param> public async Task DownloadBackgroundImageAsync(MovieFull movie, CancellationTokenSource ct) { var watch = Stopwatch.StartNew(); try { await Task.Run(async () => { TmdbClient.GetConfig(); var tmdbMovie = await TmdbClient.GetMovieAsync(movie.ImdbCode, MovieMethods.Images); var remotePath = new List<string> { TmdbClient.GetImageUrl(Constants.BackgroundImageSizeTmDb, tmdbMovie.BackdropPath).AbsoluteUri }; await remotePath.ForEachAsync( background => DownloadFileHelper.DownloadFileTaskAsync(background, Constants.BackgroundMovieDirectory + movie.ImdbCode + Constants.ImageFileExtension, ct: ct), (background, t) => { if (t.Item3 == null && !string.IsNullOrEmpty(t.Item2)) movie.BackgroundImagePath = t.Item2; }); }, ct.Token); } catch (Exception exception) when (exception is TaskCanceledException) { Logger.Debug( "DownloadBackgroundImageAsync cancelled."); } catch (Exception exception) { Logger.Error( $"DownloadBackgroundImageAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"DownloadBackgroundImageAsync ({movie.ImdbCode}) in {elapsedMs} milliseconds."); } }
/// <summary> /// Download a subtitle /// </summary> /// <param name="movie">The movie of which to retrieve its subtitles</param> /// <param name="progress">Report the progress of the download</param> /// <param name="ct">Cancellation token</param> public async Task DownloadSubtitleAsync(MovieFull movie, IProgress<long> progress, CancellationTokenSource ct) { if (movie.SelectedSubtitle == null) return; var watch = Stopwatch.StartNew(); var filePath = Constants.Subtitles + movie.ImdbCode + "\\" + movie.SelectedSubtitle.Language.EnglishName + ".zip"; try { var result = await DownloadFileHelper.DownloadFileTaskAsync( Constants.YifySubtitles + movie.SelectedSubtitle.Url, filePath, progress: progress, ct: ct); if (result.Item3 == null && !string.IsNullOrEmpty(result.Item2)) { using (var archive = ZipFile.OpenRead(result.Item2)) { foreach (var entry in archive.Entries) { if (entry.FullName.StartsWith("_") || !entry.FullName.EndsWith(".srt", StringComparison.OrdinalIgnoreCase)) continue; var subtitlePath = Path.Combine(Constants.Subtitles + movie.ImdbCode, entry.FullName); if (!File.Exists(subtitlePath)) entry.ExtractToFile(subtitlePath); movie.SelectedSubtitle.FilePath = subtitlePath; } } } } catch (Exception exception) when (exception is TaskCanceledException) { Logger.Debug( "DownloadSubtitleAsync cancelled."); } catch (Exception exception) { Logger.Error( $"DownloadSubtitleAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"DownloadSubtitleAsync ({movie.ImdbCode}) in {elapsedMs} milliseconds."); } }
/// <summary> /// Get the movie's subtitles according to a language /// </summary> /// <param name="movie">The movie of which to retrieve its subtitles</param> /// <param name="ct">Cancellation token</param> public async Task LoadSubtitlesAsync(MovieFull movie, CancellationToken ct) { var watch = Stopwatch.StartNew(); var restClient = new RestClient(Constants.YifySubtitlesApi); var request = new RestRequest("/{segment}", Method.GET); request.AddUrlSegment("segment", movie.ImdbCode); try { var response = await restClient.ExecuteGetTaskAsync<SubtitlesWrapper>(request, ct); if (response.ErrorException != null) throw response.ErrorException; var wrapper = response.Data; var subtitles = new ObservableCollection<Subtitle>(); Dictionary<string, List<Subtitle>> movieSubtitles; if (wrapper.Subtitles == null) { await Task.CompletedTask; return; } if (wrapper.Subtitles.TryGetValue(movie.ImdbCode, out movieSubtitles)) { foreach (var subtitle in movieSubtitles) { var sub = subtitle.Value.Aggregate((sub1, sub2) => sub1.Rating > sub2.Rating ? sub1 : sub2); subtitles.Add(new Subtitle { Id = sub.Id, Language = new CustomLanguage { Culture = string.Empty, EnglishName = subtitle.Key, LocalizedName = string.Empty }, Hi = sub.Hi, Rating = sub.Rating, Url = sub.Url }); } } subtitles.Sort(); movie.AvailableSubtitles = subtitles; } catch (Exception exception) when (exception is TaskCanceledException) { Logger.Debug( "LoadSubtitlesAsync cancelled."); } catch (Exception exception) { Logger.Error( $"LoadSubtitlesAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"LoadSubtitlesAsync ({movie.ImdbCode}) in {elapsedMs} milliseconds."); } }
/// <summary> /// Get the link to the youtube trailer of a movie /// </summary> /// <param name="movie">The movie</param> /// <param name="ct">Used to cancel loading trailer</param> /// <returns>Video trailer</returns> public async Task<ResultContainer<Video>> GetMovieTrailerAsync(MovieFull movie, CancellationToken ct) { var watch = Stopwatch.StartNew(); var trailers = new ResultContainer<Video>(); try { await Task.Run(async () => trailers = (await TmdbClient.GetMovieAsync(movie.ImdbCode, MovieMethods.Videos))?.Videos, ct); } catch (Exception exception) when (exception is TaskCanceledException) { Logger.Debug( "GetMovieTrailerAsync cancelled."); } catch (Exception exception) { Logger.Error( $"GetMovieTrailerAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"GetMovieTrailerAsync ({movie.ImdbCode}) in {elapsedMs} milliseconds."); } return trailers; }
/// <summary> /// Initialize a new instance of PlayMovieMessage class /// </summary> /// <param name="movie">The movie</param> public PlayMovieMessage(MovieFull movie) { Movie = movie; }
/// <summary> /// Load movie's trailer asynchronously /// </summary> /// <param name="movie">The movie</param> /// <param name="ct">Cancellation token</param> public async Task LoadTrailerAsync(MovieFull movie, CancellationToken ct) { try { var trailer = await _movieService.GetMovieTrailerAsync(movie, ct); var video = await GetVideoInfoForStreamingAsync( Constants.YoutubePath + trailer.Results.FirstOrDefault()?.Key, Constants.YoutubeStreamingQuality.High); if (video != null && video.RequiresDecryption) { Logger.Info( $"Decrypting Youtube trailer url: {video.Title}"); await Task.Run(() => DownloadUrlResolver.DecryptDownloadUrl(video), ct); } if (video == null) { Logger.Error( $"Failed loading movie's trailer: {movie.Title}"); Messenger.Default.Send( new ManageExceptionMessage( new Exception( LocalizationProviderHelper.GetLocalizedValue<string>("TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage()); return; } if (!ct.IsCancellationRequested) { Logger.Debug( $"Movie's trailer loaded: {movie.Title}"); TrailerPlayer = new TrailerPlayerViewModel(_applicationState, _movieService, _movieHistoryService); TrailerPlayer.LoadTrailer(new Models.Trailer.Trailer(new Uri(video.DownloadUrl))); } } catch (Exception exception) when (exception is TaskCanceledException) { Logger.Debug( "GetMovieTrailerAsync cancelled."); Messenger.Default.Send(new StopPlayingTrailerMessage()); } catch (Exception exception) when (exception is SocketException || exception is WebException) { Logger.Error( $"GetMovieTrailerAsync: {exception.Message}"); Messenger.Default.Send(new StopPlayingTrailerMessage()); Messenger.Default.Send(new ManageExceptionMessage(exception)); } catch (Exception exception) when (exception is VideoNotAvailableException || exception is YoutubeParseException) { Logger.Error( $"GetMovieTrailerAsync: {exception.Message}"); Messenger.Default.Send( new ManageExceptionMessage( new Exception( LocalizationProviderHelper.GetLocalizedValue<string>( "TrailerNotAvailable")))); Messenger.Default.Send(new StopPlayingTrailerMessage()); } catch (Exception exception) { Logger.Error( $"GetMovieTrailerAsync: {exception.Message}"); Messenger.Default.Send(new StopPlayingTrailerMessage()); } }
/// <summary> /// Get TMDb movie informations /// </summary> /// <param name="movieToLoad">Movie to load</param> /// <param name="ct">Used to cancel loading</param> /// <returns>Movie's full details</returns> public async Task<MovieFull> GetMovieFullDetailsAsync(MovieShort movieToLoad, CancellationToken ct) { var watch = Stopwatch.StartNew(); var movie = new MovieFull(); var restClient = new RestClient(Constants.YtsApiEndpoint); var request = new RestRequest("/{segment}", Method.GET); request.AddUrlSegment("segment", "movie_details.json"); request.AddParameter("movie_id", movieToLoad.Id); request.AddParameter("with_images", "true"); request.AddParameter("with_cast", "true"); try { var response = await restClient.ExecuteGetTaskAsync<WrapperMovieFull>(request, ct); if (response.ErrorException != null) throw response.ErrorException; await Task.Run(async () => { var tmdbInfos = await TmdbClient.GetMovieAsync(response.Data.Data.Movie.ImdbCode, MovieMethods.Credits); movie = new MovieFull { Id = response.Data.Data.Movie.Id, Cast = response.Data.Data.Movie.Cast, BackgroundImagePath = string.Empty, DateUploaded = response.Data.Data.Movie.DateUploaded, DateUploadedUnix = response.Data.Data.Movie.DateUploadedUnix, DescriptionFull = tmdbInfos.Overview, DescriptionIntro = response.Data.Data.Movie.DescriptionIntro, DownloadCount = response.Data.Data.Movie.DownloadCount, FullHdAvailable = response.Data.Data.Movie.Torrents.Any(torrent => torrent.Quality == "1080p"), Genres = tmdbInfos.Genres.Select(a => a.Name).ToList(), ImdbCode = response.Data.Data.Movie.ImdbCode, Language = response.Data.Data.Movie.Language, LikeCount = response.Data.Data.Movie.LikeCount, MpaRating = response.Data.Data.Movie.MpaRating, LargeCoverImage = response.Data.Data.Movie.LargeCoverImage, PosterImagePath = string.Empty, RatingValue = response.Data.Data.Movie.Rating, RtAudienceRating = response.Data.Data.Movie.RtAudienceRating, RtAudienceScore = response.Data.Data.Movie.RtAudienceScore, RtCriticsRating = response.Data.Data.Movie.RtCriticsRating, RtCrtiticsScore = response.Data.Data.Movie.RtCrtiticsScore, Runtime = response.Data.Data.Movie.Runtime, Title = tmdbInfos.Title, TitleLong = response.Data.Data.Movie.TitleLong, Torrents = response.Data.Data.Movie.Torrents, Url = response.Data.Data.Movie.Url, WatchInFullHdQuality = false, Year = response.Data.Data.Movie.Year, YtTrailerCode = response.Data.Data.Movie.YtTrailerCode }; }, ct); } catch (Exception exception) when (exception is TaskCanceledException) { Logger.Debug( "GetMovieFullDetailsAsync cancelled."); } catch (Exception exception) { Logger.Error( $"GetMovieFullDetailsAsync: {exception.Message}"); throw; } finally { watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Logger.Debug( $"GetMovieFullDetailsAsync ({movie.ImdbCode}) in {elapsedMs} milliseconds."); } return movie; }
public void GetHashCode_DifferentMovies_ReturnsDifferentHashCode() { var fixture = new Fixture(); var id1 = fixture.Create<int>(); var dateUploadedUnix1 = fixture.Create<int>(); var id2 = fixture.Create<int>(); var dateUploadedUnix2 = fixture.Create<int>(); var movie1 = new MovieFull { Id = id1, DateUploadedUnix = dateUploadedUnix1 }; var movie2 = new MovieFull { Id = id2, DateUploadedUnix = dateUploadedUnix2 }; Assert.AreNotEqual( _comparer.GetHashCode(movie1), _comparer.GetHashCode(movie2)); }
/// <summary> /// Load a movie /// </summary> /// <param name="movie"></param> public void LoadMovie(MovieFull movie) { Movie = movie; }