增加速度计算
This commit is contained in:
parent
68e8e1d739
commit
ee62328d2b
|
@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Mp4SubtitleParser;
|
||||
using N_m3u8DL_RE.Column;
|
||||
using N_m3u8DL_RE.Common.Entity;
|
||||
using N_m3u8DL_RE.Common.Enum;
|
||||
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
|
||||
ConcurrentDictionary<MediaSegment, DownloadResult?> FileDic = new();
|
||||
|
@ -143,7 +144,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
}
|
||||
|
||||
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;
|
||||
if (result == null)
|
||||
{
|
||||
|
@ -193,7 +194,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
|
||||
var index = seg.Index;
|
||||
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;
|
||||
task.Increment(1);
|
||||
//实时解密
|
||||
|
@ -232,7 +233,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
{
|
||||
var index = seg.Index;
|
||||
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;
|
||||
task.Increment(1);
|
||||
//实时解密
|
||||
|
@ -512,6 +513,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
|
||||
public async Task<bool> StartDownloadAsync(IEnumerable<StreamSpec> streamSpecs)
|
||||
{
|
||||
SpeedContainer speedContainer = new SpeedContainer(); //速度计算
|
||||
ConcurrentDictionary<StreamSpec, bool?> Results = new();
|
||||
|
||||
var progress = AnsiConsole.Progress().AutoClear(true);
|
||||
|
@ -522,6 +524,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
new TaskDescriptionColumn() { Alignment = Justify.Left },
|
||||
new ProgressBarColumn(),
|
||||
new PercentageColumn(),
|
||||
new DownloadSpeedColumn(speedContainer), //速度计算
|
||||
new RemainingTimeColumn(),
|
||||
new SpinnerColumn(),
|
||||
});
|
||||
|
@ -538,7 +541,7 @@ namespace N_m3u8DL_RE.DownloadManager
|
|||
foreach (var kp in dic)
|
||||
{
|
||||
var task = kp.Value;
|
||||
var result = await DownloadStreamAsync(kp.Key, task);
|
||||
var result = await DownloadStreamAsync(kp.Key, task, speedContainer);
|
||||
Results[kp.Key] = result;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,6 +10,6 @@ namespace N_m3u8DL_RE.Downloader
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@ namespace N_m3u8DL_RE.Downloader
|
|||
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 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 (segment.EncryptInfo.Method == EncryptMethod.AES_128)
|
||||
|
@ -53,7 +53,7 @@ namespace N_m3u8DL_RE.Downloader
|
|||
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:
|
||||
try
|
||||
|
@ -64,7 +64,7 @@ namespace N_m3u8DL_RE.Downloader
|
|||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ namespace N_m3u8DL_RE.Util
|
|||
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);
|
||||
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)
|
||||
{
|
||||
var redirectedUrl = respHeaders.Location.AbsoluteUri;
|
||||
return await DownloadToFileAsync(redirectedUrl, path, headers);
|
||||
return await DownloadToFileAsync(redirectedUrl, path, speedContainer, headers, fromPosition, toPosition);
|
||||
}
|
||||
}
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
@ -57,6 +57,7 @@ namespace N_m3u8DL_RE.Util
|
|||
var size = 0;
|
||||
while ((size = await responseStream.ReadAsync(buffer)) > 0)
|
||||
{
|
||||
speedContainer.Add(size);
|
||||
await stream.WriteAsync(buffer, 0, size);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue