/// <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)); }
public DownloadTask(DownloadSegmentInfo downloadSegmentInfo) { _downloadSegmentInfo = downloadSegmentInfo; }
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); }