예제 #1
0
        /// <summary>
        /// 下载分片
        /// </summary>
        /// <param name="segment"></param>
        /// <param name="progressAction"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        protected virtual DownloadTask DownloadSegmentFileAsync(DownloadSegmentInfo segment, Action <long, float> progressAction, CancellationToken cancellationToken = default)
        {
            Stream localFile;

            if (string.IsNullOrEmpty(segment.TempFile))
            {
                localFile          = new FileStream(LocalFileFullPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
                localFile.Position = segment.Start + segment.TotalReadBytes;
            }
            else
            {
                localFile = new FileStream(segment.TempFile, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
            }
            segment.DstStream = localFile;
            var task = segment.DownloadAsync(progressAction, cancellationToken);

            return(task);
        }
        /// <summary>
        /// 加载M3U8分片内容
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        private Task <IList <DownloadSegmentInfo> > LoadM3U8FileSegmentsAsync(Stream stream)
        {
            int Count = 0;
            Uri uri   = new Uri(Url);
            IList <DownloadSegmentInfo> list = new List <DownloadSegmentInfo>();

            using (var reader = new StreamReader(stream))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    string newUrl = string.Empty;
                    if (line.StartsWith("http:"))
                    {
                        newUrl = line;
                    }
                    else if (!line.StartsWith("#EXT"))
                    {
                        var schema = uri.AbsoluteUri.Substring(0, uri.AbsoluteUri.LastIndexOf("/"));
                        newUrl = $"{schema}/{line}";
                    }
                    if (!string.IsNullOrEmpty(newUrl))
                    {
                        var downloadSegmentInfo = new DownloadSegmentInfo()
                        {
                            ID             = Count++,
                            Url            = newUrl,
                            TotalReadBytes = 0,
                            TempFile       = Path.GetTempFileName()
                        };
                        list.Add(downloadSegmentInfo);
                    }
                }
            }
            return(Task.FromResult(list));
        }
예제 #3
0
 public DownloadTask(DownloadSegmentInfo downloadSegmentInfo)
 {
     _downloadSegmentInfo = downloadSegmentInfo;
 }
예제 #4
0
        public static DownloadTask DownloadAsync(this DownloadSegmentInfo downloadInfo,
                                                 Action <long, float> progressAction, CancellationToken cancellationToken = default)
        {
            Pipe pipeline            = new Pipe();
            bool isCompleted         = false;
            var  downloadTask        = new DownloadTask(downloadInfo);
            Func <List <Task> > func = new Func <List <Task> >(() =>
            {
                var readTask = Task.Run(async() =>
                {
                    int bytesRead;
                    try
                    {
                        if (downloadInfo.Percentage >= 100)
                        {
                            return;
                        }
                        if (downloadInfo.Size != 0 && downloadInfo.TotalReadBytes == downloadInfo.Size)
                        {
                            return;
                        }
                        if (downloadInfo.SrcStream == null)
                        {
                            var httpClient = HttpClientFactory.Instance.GetHttpClient(downloadInfo.Url);
                            if (downloadInfo.Size != 0)
                            {
                                httpClient.DefaultRequestHeaders.Range = new RangeHeaderValue(downloadInfo.TotalReadBytes, downloadInfo.Size);
                            }
                            var response           = await httpClient.GetAsync(downloadInfo.Url);
                            downloadInfo.SrcStream = await response.Content.ReadAsStreamAsync();
                            var size = response.Content.Headers.ContentLength.GetValueOrDefault();
                            if (size > 0 && downloadInfo.Size == 0)
                            {
                                downloadInfo.Size = size;
                                if (downloadInfo.End == 0)
                                {
                                    downloadInfo.End = downloadInfo.Start + size;
                                }
                            }
                            if (downloadInfo.TotalReadBytes > 0)
                            {
                                ///设置文件流写入位置
                                downloadInfo.DstStream.Position = downloadInfo.Start + downloadInfo.TotalReadBytes;
                            }
                        }

                        while (true) // Where the downloading part is happening
                        {
                            bytesRead = await downloadInfo.SrcStream.ReadAsync(pipeline.Writer.GetMemory(), cancellationToken);
                            if (bytesRead <= 0)
                            {
                                break;
                            }
                            pipeline.Writer.Advance(bytesRead);
                            var flushResult = await pipeline.Writer.FlushAsync(cancellationToken);
                            if (flushResult.IsCanceled)
                            {
                                break;
                            }
                            if (flushResult.IsCompleted)
                            {
                                break;
                            }
                        }
                        pipeline.Writer.Complete();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    finally
                    {
                        isCompleted = true;
                    }
                }, cancellationToken);

                var writeTask = Task.Run(async() =>
                {
                    float percentage = 0;
                    long bytesRead   = 0;
                    try
                    {
                        while (true)
                        {
                            var readResult = await pipeline.Reader.ReadAsync(cancellationToken);
                            foreach (var segment in readResult.Buffer)
                            {
                                bytesRead += segment.Length;
                                await downloadInfo.DstStream.WriteAsync(segment, cancellationToken);
                            }
                            downloadInfo.TotalReadBytes += bytesRead;
                            if (bytesRead > 0)//有进度才会提示
                            {
                                percentage = downloadInfo.Percentage;
                                progressAction.Invoke(bytesRead, percentage); // To Get the current percentage.
                                bytesRead = 0;
                            }
                            pipeline.Reader.AdvanceTo(readResult.Buffer.End);
                            if (readResult.IsCompleted || readResult.IsCanceled)
                            {
                                break;
                            }
                            if (isCompleted)
                            {
                                break;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }
                    finally
                    {
                        isCompleted = true;
                        downloadTask.Close();
                    }
                    pipeline.Reader.Complete();
                }, cancellationToken);

                return(new List <Task>()
                {
                    readTask, writeTask
                });
            });

            downloadTask.Create(func);
            return(downloadTask);
        }