增加速度计算

This commit is contained in:
nilaoda 2022-08-19 20:03:45 +08:00
parent 68e8e1d739
commit ee62328d2b
6 changed files with 97 additions and 12 deletions

View File

@ -0,0 +1,54 @@
using N_m3u8DL_RE.Entity;
using Spectre.Console;
using Spectre.Console.Rendering;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace N_m3u8DL_RE.Column
{
internal sealed class DownloadSpeedColumn : ProgressColumn
{
private TimeSpan CalcTimeSpan = TimeSpan.FromSeconds(0);
private string Speed = "0Bps";
protected override bool NoWrap => true;
public SpeedContainer SpeedContainer { get; set; }
public DownloadSpeedColumn(SpeedContainer SpeedContainer)
{
this.SpeedContainer = SpeedContainer;
}
public Style MyStyle { get; set; } = new Style(foreground: Color.Green);
public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
{
CalcTimeSpan = CalcTimeSpan.Add(deltaTime);
//一秒汇报一次即可
if (CalcTimeSpan.TotalSeconds > 1)
{
Speed = FormatFileSize(SpeedContainer.Downloaded / CalcTimeSpan.TotalSeconds);
SpeedContainer.Reset();
CalcTimeSpan = TimeSpan.FromSeconds(0);
}
var percentage = (int)task.Percentage;
var flag = percentage == 100 || percentage == 0;
var style = flag ? Style.Plain : MyStyle;
return flag ? new Text("-", style).Centered() : new Text(Speed, style).Centered();
}
private static string FormatFileSize(double fileSize)
{
return fileSize switch
{
< 0 => throw new ArgumentOutOfRangeException(nameof(fileSize)),
>= 1024 * 1024 * 1024 => string.Format("{0:########0.00}GBps", (double)fileSize / (1024 * 1024 * 1024)),
>= 1024 * 1024 => string.Format("{0:####0.00}MBps", (double)fileSize / (1024 * 1024)),
>= 1024 => string.Format("{0:####0.00}KBps", (double)fileSize / 1024),
_ => string.Format("{0}Bps", fileSize)
};
}
}
}

View File

@ -1,4 +1,5 @@
using Mp4SubtitleParser; using Mp4SubtitleParser;
using N_m3u8DL_RE.Column;
using N_m3u8DL_RE.Common.Entity; using N_m3u8DL_RE.Common.Entity;
using N_m3u8DL_RE.Common.Enum; using N_m3u8DL_RE.Common.Enum;
using N_m3u8DL_RE.Common.Log; using N_m3u8DL_RE.Common.Log;
@ -84,7 +85,7 @@ namespace N_m3u8DL_RE.DownloadManager
} }
} }
private async Task<bool> DownloadStreamAsync(StreamSpec streamSpec, ProgressTask task) private async Task<bool> DownloadStreamAsync(StreamSpec streamSpec, ProgressTask task, SpeedContainer speedContainer)
{ {
bool useAACFilter = false; //ffmpeg合并flag bool useAACFilter = false; //ffmpeg合并flag
ConcurrentDictionary<MediaSegment, DownloadResult?> FileDic = new(); ConcurrentDictionary<MediaSegment, DownloadResult?> FileDic = new();
@ -143,7 +144,7 @@ namespace N_m3u8DL_RE.DownloadManager
} }
var path = Path.Combine(tmpDir, "_init.mp4.tmp"); var path = Path.Combine(tmpDir, "_init.mp4.tmp");
var result = await Downloader.DownloadSegmentAsync(streamSpec.Playlist.MediaInit, path, headers); var result = await Downloader.DownloadSegmentAsync(streamSpec.Playlist.MediaInit, path, speedContainer, headers);
FileDic[streamSpec.Playlist.MediaInit] = result; FileDic[streamSpec.Playlist.MediaInit] = result;
if (result == null) if (result == null)
{ {
@ -193,7 +194,7 @@ namespace N_m3u8DL_RE.DownloadManager
var index = seg.Index; var index = seg.Index;
var path = Path.Combine(tmpDir, index.ToString(pad) + $".{streamSpec.Extension ?? "clip"}.tmp"); var path = Path.Combine(tmpDir, index.ToString(pad) + $".{streamSpec.Extension ?? "clip"}.tmp");
var result = await Downloader.DownloadSegmentAsync(seg, path, headers); var result = await Downloader.DownloadSegmentAsync(seg, path, speedContainer, headers);
FileDic[seg] = result; FileDic[seg] = result;
task.Increment(1); task.Increment(1);
//实时解密 //实时解密
@ -232,7 +233,7 @@ namespace N_m3u8DL_RE.DownloadManager
{ {
var index = seg.Index; var index = seg.Index;
var path = Path.Combine(tmpDir, index.ToString(pad) + $".{streamSpec.Extension ?? "clip"}.tmp"); var path = Path.Combine(tmpDir, index.ToString(pad) + $".{streamSpec.Extension ?? "clip"}.tmp");
var result = await Downloader.DownloadSegmentAsync(seg, path, headers); var result = await Downloader.DownloadSegmentAsync(seg, path, speedContainer, headers);
FileDic[seg] = result; FileDic[seg] = result;
task.Increment(1); task.Increment(1);
//实时解密 //实时解密
@ -512,6 +513,7 @@ namespace N_m3u8DL_RE.DownloadManager
public async Task<bool> StartDownloadAsync(IEnumerable<StreamSpec> streamSpecs) public async Task<bool> StartDownloadAsync(IEnumerable<StreamSpec> streamSpecs)
{ {
SpeedContainer speedContainer = new SpeedContainer(); //速度计算
ConcurrentDictionary<StreamSpec, bool?> Results = new(); ConcurrentDictionary<StreamSpec, bool?> Results = new();
var progress = AnsiConsole.Progress().AutoClear(true); var progress = AnsiConsole.Progress().AutoClear(true);
@ -522,6 +524,7 @@ namespace N_m3u8DL_RE.DownloadManager
new TaskDescriptionColumn() { Alignment = Justify.Left }, new TaskDescriptionColumn() { Alignment = Justify.Left },
new ProgressBarColumn(), new ProgressBarColumn(),
new PercentageColumn(), new PercentageColumn(),
new DownloadSpeedColumn(speedContainer), //速度计算
new RemainingTimeColumn(), new RemainingTimeColumn(),
new SpinnerColumn(), new SpinnerColumn(),
}); });
@ -538,7 +541,7 @@ namespace N_m3u8DL_RE.DownloadManager
foreach (var kp in dic) foreach (var kp in dic)
{ {
var task = kp.Value; var task = kp.Value;
var result = await DownloadStreamAsync(kp.Key, task); var result = await DownloadStreamAsync(kp.Key, task, speedContainer);
Results[kp.Key] = result; Results[kp.Key] = result;
} }
}); });

View File

@ -10,6 +10,6 @@ namespace N_m3u8DL_RE.Downloader
{ {
internal interface IDownloader internal interface IDownloader
{ {
Task<DownloadResult?> DownloadSegmentAsync(MediaSegment segment, string savePath, Dictionary<string, string>? headers = null); Task<DownloadResult?> DownloadSegmentAsync(MediaSegment segment, string savePath, SpeedContainer speedContainer, Dictionary<string, string>? headers = null);
} }
} }

View File

@ -27,10 +27,10 @@ namespace N_m3u8DL_RE.Downloader
DownloaderConfig = config; DownloaderConfig = config;
} }
public async Task<DownloadResult?> DownloadSegmentAsync(MediaSegment segment, string savePath, Dictionary<string, string>? headers = null) public async Task<DownloadResult?> DownloadSegmentAsync(MediaSegment segment, string savePath, SpeedContainer speedContainer, Dictionary<string, string>? headers = null)
{ {
var url = segment.Url; var url = segment.Url;
var dResult = await DownClipAsync(url, savePath, segment.StartRange, segment.StopRange, headers, DownloaderConfig.DownloadRetryCount); var dResult = await DownClipAsync(url, savePath, speedContainer, segment.StartRange, segment.StopRange, headers, DownloaderConfig.DownloadRetryCount);
if (dResult != null && dResult.Success && segment.EncryptInfo != null) if (dResult != null && dResult.Success && segment.EncryptInfo != null)
{ {
if (segment.EncryptInfo.Method == EncryptMethod.AES_128) if (segment.EncryptInfo.Method == EncryptMethod.AES_128)
@ -53,7 +53,7 @@ namespace N_m3u8DL_RE.Downloader
return dResult; return dResult;
} }
private async Task<DownloadResult?> DownClipAsync(string url, string path, long? fromPosition, long? toPosition, Dictionary<string, string>? headers = null, int retryCount = 3) private async Task<DownloadResult?> DownClipAsync(string url, string path, SpeedContainer speedContainer, long? fromPosition, long? toPosition, Dictionary<string, string>? headers = null, int retryCount = 3)
{ {
retry: retry:
try try
@ -64,7 +64,7 @@ namespace N_m3u8DL_RE.Downloader
{ {
return new DownloadResult() { ActualContentLength = 0, ActualFilePath = des }; return new DownloadResult() { ActualContentLength = 0, ActualFilePath = des };
} }
var result = await DownloadUtil.DownloadToFileAsync(url, path, headers, fromPosition, toPosition); var result = await DownloadUtil.DownloadToFileAsync(url, path, speedContainer, headers, fromPosition, toPosition);
//下载完成后改名 //下载完成后改名
if (result.Success || !DownloaderConfig.CheckContentLength) if (result.Success || !DownloaderConfig.CheckContentLength)
{ {

View File

@ -0,0 +1,27 @@
using NiL.JS.Statements;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace N_m3u8DL_RE.Entity
{
internal class SpeedContainer
{
private long _downloaded = 0;
public long Downloaded { get => _downloaded; }
public long Add(long size)
{
return Interlocked.Add(ref _downloaded, size);
}
public void Reset()
{
Interlocked.Exchange(ref _downloaded, 0);
}
}
}

View File

@ -24,7 +24,7 @@ namespace N_m3u8DL_RE.Util
Timeout = TimeSpan.FromMinutes(2) Timeout = TimeSpan.FromMinutes(2)
}; };
public static async Task<DownloadResult> DownloadToFileAsync(string url, string path, Dictionary<string, string>? headers = null, long? fromPosition = null, long? toPosition = null) public static async Task<DownloadResult> DownloadToFileAsync(string url, string path, SpeedContainer speedContainer, Dictionary<string, string>? headers = null, long? fromPosition = null, long? toPosition = null)
{ {
Logger.Debug(ResString.fetch + url); Logger.Debug(ResString.fetch + url);
using var request = new HttpRequestMessage(HttpMethod.Get, new Uri(url)); using var request = new HttpRequestMessage(HttpMethod.Get, new Uri(url));
@ -46,7 +46,7 @@ namespace N_m3u8DL_RE.Util
if (respHeaders != null && respHeaders.Location != null) if (respHeaders != null && respHeaders.Location != null)
{ {
var redirectedUrl = respHeaders.Location.AbsoluteUri; var redirectedUrl = respHeaders.Location.AbsoluteUri;
return await DownloadToFileAsync(redirectedUrl, path, headers); return await DownloadToFileAsync(redirectedUrl, path, speedContainer, headers, fromPosition, toPosition);
} }
} }
response.EnsureSuccessStatusCode(); response.EnsureSuccessStatusCode();
@ -57,6 +57,7 @@ namespace N_m3u8DL_RE.Util
var size = 0; var size = 0;
while ((size = await responseStream.ReadAsync(buffer)) > 0) while ((size = await responseStream.ReadAsync(buffer)) > 0)
{ {
speedContainer.Add(size);
await stream.WriteAsync(buffer, 0, size); await stream.WriteAsync(buffer, 0, size);
} }