增加速度计算
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 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;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue