Ejemplo n.º 1
0
        /// <summary>
        /// Download media
        /// </summary>
        /// <param name="media">Media file <see cref="IMediaFile"/></param>
        /// <param name="type">Media type <see cref="MediaType"/></param>
        /// <param name="uploadLimit">Upload limit</param>
        /// <param name="downloadLimit">Download limit</param>
        /// <param name="downloadProgress">Download progress</param>
        /// <param name="bandwidthRate">Download rate</param>
        /// <param name="nbSeeds">Number of seeders</param>
        /// <param name="nbPeers">Number of peers</param>
        /// <param name="handle"><see cref="torrent_handle"/></param>
        /// <param name="session"><see cref="session"/></param>
        /// <param name="buffered">Action to execute when media has been buffered</param>
        /// <param name="cancelled">Action to execute when media download has been cancelled</param>
        /// <param name="cts"><see cref="CancellationTokenSource"/></param>
        /// <returns><see cref="Task"/></returns>
        private async Task HandleDownload(T media, MediaType type, int uploadLimit, int downloadLimit,
                                          IProgress <double> downloadProgress, IProgress <BandwidthRate> bandwidthRate, IProgress <int> nbSeeds, IProgress <int> nbPeers,
                                          torrent_handle handle,
                                          session session, Action buffered, Action cancelled, CancellationTokenSource cts)
        {
            handle.set_upload_limit(uploadLimit * 1024);
            handle.set_download_limit(downloadLimit * 1024);
            var alreadyBuffered    = false;
            var bandwidth          = new Progress <BandwidthRate>();
            var prog               = new Progress <double>();
            var playingProgress    = new Progress <double>();
            var playingProgression = 0d;

            playingProgress.ProgressChanged += (sender, d) =>
            {
                playingProgression = d;
            };

            IProgress <PieceAvailability> pieceAvailability = new Progress <PieceAvailability>();
            Stopwatch sw = new Stopwatch();

            sw.Start();

            while (!cts.IsCancellationRequested)
            {
                using (var status = handle.status())
                {
                    var filePath = string.Empty;
                    var progress = status.progress * 100d;
                    if (status.has_metadata)
                    {
                        var downRate = Math.Round(status.download_rate / 1024d, 0);
                        var upRate   = Math.Round(status.upload_rate / 1024d, 0);

                        nbSeeds.Report(status.num_seeds);
                        nbPeers.Report(status.num_peers);
                        downloadProgress.Report(progress);
                        var numFiles  = handle.torrent_file().num_files();
                        var fileIndex = -1;
                        for (var i = 0; i < numFiles; i++)
                        {
                            var path = handle.torrent_file().file_at(i);
                            if (path.EndsWith(".mp4") || path.EndsWith(".mkv") ||
                                path.EndsWith(".mov") || path.EndsWith(".avi"))
                            {
                                fileIndex = i;
                                filePath  = $@"{Directory.GetParent(status.save_path)}\{path}";
                            }
                        }

                        var fileProgress = handle.file_progress(1)[fileIndex];
                        var eta          = sw.GetEta(fileProgress, handle.torrent_file().total_size());
                        bandwidthRate.Report(new BandwidthRate
                        {
                            DownloadRate = downRate,
                            UploadRate   = upRate,
                            ETA          = eta
                        });

                        ((IProgress <double>)prog).Report(progress);
                        ((IProgress <BandwidthRate>)bandwidth).Report(new BandwidthRate
                        {
                            DownloadRate = downRate,
                            UploadRate   = upRate,
                            ETA          = eta
                        });

                        var numPieces = handle.torrent_file().num_pieces() - 1;
                        var cursor    = Math.Floor((numPieces - 3 * numPieces / 100d) * playingProgression);
                        var pieces    = handle.piece_priorities()
                                        .Select((piece, index) => new { Piece = piece, Index = index })
                                        .ToList();

                        var lastPieceAvailableIndex = 0;
                        foreach (var piece in pieces.Where(a => a.Index >= cursor))
                        {
                            if (!handle.have_piece(piece.Index))
                            {
                                handle.set_piece_deadline(piece.Index, 50);
                                foreach (var otherPiece in pieces.Where(a => a.Index != piece.Index))
                                {
                                    handle.reset_piece_deadline(otherPiece.Index);
                                }

                                break;
                            }
                            else
                            {
                                lastPieceAvailableIndex = piece.Index;
                                handle.reset_piece_deadline(piece.Index);
                            }
                        }

                        pieceAvailability.Report(new PieceAvailability(numPieces, pieces.FirstOrDefault(a => a.Index >= cursor - 3 * numPieces / 100d).Index, lastPieceAvailableIndex));
                    }

                    handle.flush_cache();
                    if (handle.need_save_resume_data())
                    {
                        handle.save_resume_data(1);
                    }

                    double minimumBuffering;
                    switch (type)
                    {
                    case MediaType.Show:
                        minimumBuffering = Constants.MinimumShowBuffering;
                        break;

                    default:
                        minimumBuffering = Constants.MinimumMovieBuffering;
                        break;
                    }

                    if (progress >= minimumBuffering && !alreadyBuffered)
                    {
                        buffered.Invoke();
                        if (!string.IsNullOrEmpty(filePath))
                        {
                            alreadyBuffered = true;
                            media.FilePath  = filePath;
                            BroadcastMediaBuffered(media, prog, bandwidth, playingProgress, (Progress <PieceAvailability>)pieceAvailability);
                        }

                        if (!alreadyBuffered)
                        {
                            session.remove_torrent(handle, 0);
                            if (type == MediaType.Unkown)
                            {
                                Messenger.Default.Send(
                                    new UnhandledExceptionMessage(
                                        new PopcornException(
                                            LocalizationProviderHelper.GetLocalizedValue <string>(
                                                "NoMediaInDroppedTorrent"))));
                            }
                            else
                            {
                                Messenger.Default.Send(
                                    new UnhandledExceptionMessage(
                                        new PopcornException(
                                            LocalizationProviderHelper.GetLocalizedValue <string>("NoMediaInTorrent"))));
                            }

                            break;
                        }
                    }

                    try
                    {
                        await Task.Delay(1000, cts.Token);
                    }
                    catch (TaskCanceledException)
                    {
                        cancelled.Invoke();
                        sw.Stop();
                        try
                        {
                            session.remove_torrent(handle, 1);
                        }
                        catch (Exception) { }
                        break;
                    }
                }
            }
        }