连续20秒速度为0时,重试

This commit is contained in:
nilaoda 2022-09-25 10:41:41 +08:00
parent b032b46bd3
commit 9211e185fd
5 changed files with 70 additions and 29 deletions

View File

@ -32,7 +32,7 @@ namespace N_m3u8DL_RE.Common.Util
public static readonly HttpClient AppHttpClient = new(HttpClientHandler) public static readonly HttpClient AppHttpClient = new(HttpClientHandler)
{ {
Timeout = TimeSpan.FromMinutes(2) Timeout = TimeSpan.FromSeconds(100)
}; };
private static async Task<HttpResponseMessage> DoGetAsync(string url, Dictionary<string, string>? headers = null) private static async Task<HttpResponseMessage> DoGetAsync(string url, Dictionary<string, string>? headers = null)

View File

@ -13,10 +13,11 @@ namespace N_m3u8DL_RE.Column
{ {
internal sealed class DownloadSpeedColumn : ProgressColumn internal sealed class DownloadSpeedColumn : ProgressColumn
{ {
private long _stopSpeed = 0;
private ConcurrentDictionary<int, string> DateTimeStringDic = new(); private ConcurrentDictionary<int, string> DateTimeStringDic = new();
private ConcurrentDictionary<int, string> SpeedDic = new(); private ConcurrentDictionary<int, string> SpeedDic = new();
protected override bool NoWrap => true; protected override bool NoWrap => true;
public ConcurrentDictionary<int, SpeedContainer> SpeedContainerDic { get; set; } private ConcurrentDictionary<int, SpeedContainer> SpeedContainerDic { get; set; }
public DownloadSpeedColumn(ConcurrentDictionary<int, SpeedContainer> SpeedContainerDic) public DownloadSpeedColumn(ConcurrentDictionary<int, SpeedContainer> SpeedContainerDic)
{ {
@ -41,6 +42,9 @@ namespace N_m3u8DL_RE.Column
if (DateTimeStringDic.TryGetValue(taskId, out var oldTime) && oldTime != now) if (DateTimeStringDic.TryGetValue(taskId, out var oldTime) && oldTime != now)
{ {
SpeedDic[taskId] = FormatFileSize(speedContainer.Downloaded); SpeedDic[taskId] = FormatFileSize(speedContainer.Downloaded);
//速度为0计数增加
if (speedContainer.Downloaded <= _stopSpeed) { speedContainer.AddLowSpeedCount(); SpeedDic[taskId] += $"({speedContainer.LowSpeedCount})"; }
else speedContainer.ResetLowSpeedCount();
speedContainer.Reset(); speedContainer.Reset();
} }
DateTimeStringDic[taskId] = now; DateTimeStringDic[taskId] = now;

View File

@ -406,7 +406,7 @@ namespace N_m3u8DL_RE.CommandLine
Environment.Exit(0); Environment.Exit(0);
} }
var rootCommand = new RootCommand("N_m3u8DL-RE (Beta version) 20220922") var rootCommand = new RootCommand("N_m3u8DL-RE (Beta version) 20220925")
{ {
Input, TmpDir, SaveDir, SaveName, BaseUrl, ThreadCount, DownloadRetryCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount, Input, TmpDir, SaveDir, SaveName, BaseUrl, ThreadCount, DownloadRetryCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount,
BinaryMerge, DelAfterDone, WriteMetaJson, AppendUrlParams, ConcurrentDownload, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix, BinaryMerge, DelAfterDone, WriteMetaJson, AppendUrlParams, ConcurrentDownload, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix,

View File

@ -14,12 +14,25 @@ namespace N_m3u8DL_RE.Entity
public bool SingleSegment { get; set; } = false; public bool SingleSegment { get; set; } = false;
public long? ResponseLength { get; set; } public long? ResponseLength { get; set; }
public long RDownloaded { get; set; } = 0L; public long RDownloaded { get; set; } = 0L;
private int _zeroSpeedCount = 0;
public int LowSpeedCount { get => _zeroSpeedCount; }
public bool ShouldStop { get => LowSpeedCount >= 20; }
/////////////////////////////////////////////////// ///////////////////////////////////////////////////
private long _downloaded = 0; private long _downloaded = 0;
public long Downloaded { get => _downloaded; } public long Downloaded { get => _downloaded; }
public int AddLowSpeedCount()
{
return Interlocked.Add(ref _zeroSpeedCount, 1);
}
public int ResetLowSpeedCount()
{
return Interlocked.Exchange(ref _zeroSpeedCount, 0);
}
public long Add(long size) public long Add(long size)
{ {
if (SingleSegment) RDownloaded += size; if (SingleSegment) RDownloaded += size;
@ -34,6 +47,7 @@ namespace N_m3u8DL_RE.Entity
public void ResetVars() public void ResetVars()
{ {
Reset(); Reset();
ResetLowSpeedCount();
SingleSegment = false; SingleSegment = false;
ResponseLength = null; ResponseLength = null;
RDownloaded = 0L; RDownloaded = 0L;

View File

@ -31,37 +31,60 @@ namespace N_m3u8DL_RE.Util
} }
} }
Logger.Debug(request.Headers.ToString()); Logger.Debug(request.Headers.ToString());
using var response = await AppHttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); CancellationTokenSource cancellationTokenSource = new(); //取消下载
if (response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.Moved) using var watcher = Task.Factory.StartNew(async () =>
{ {
HttpResponseHeaders respHeaders = response.Headers; while (true)
Logger.Debug(respHeaders.ToString());
if (respHeaders != null && respHeaders.Location != null)
{ {
var redirectedUrl = respHeaders.Location.AbsoluteUri; if (speedContainer == null) break;
return await DownloadToFileAsync(redirectedUrl, path, speedContainer, headers, fromPosition, toPosition); if (speedContainer.ShouldStop)
{
cancellationTokenSource.Cancel();
speedContainer.ResetLowSpeedCount();
Logger.WarnMarkUp("Cancel...");
break;
}
await Task.Delay(500);
} }
} });
response.EnsureSuccessStatusCode(); try
var contentLength = response.Content.Headers.ContentLength;
if (speedContainer.SingleSegment) speedContainer.ResponseLength = contentLength;
using var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
using var responseStream = await response.Content.ReadAsStreamAsync();
var buffer = new byte[16 * 1024];
var size = 0;
while ((size = await responseStream.ReadAsync(buffer)) > 0)
{ {
speedContainer.Add(size); using var response = await AppHttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationTokenSource.Token);
await stream.WriteAsync(buffer, 0, size); if (response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.Moved)
} {
HttpResponseHeaders respHeaders = response.Headers;
Logger.Debug(respHeaders.ToString());
if (respHeaders != null && respHeaders.Location != null)
{
var redirectedUrl = respHeaders.Location.AbsoluteUri;
return await DownloadToFileAsync(redirectedUrl, path, speedContainer, headers, fromPosition, toPosition);
}
}
response.EnsureSuccessStatusCode();
var contentLength = response.Content.Headers.ContentLength;
if (speedContainer.SingleSegment) speedContainer.ResponseLength = contentLength;
return new DownloadResult() using var stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
using var responseStream = await response.Content.ReadAsStreamAsync(cancellationTokenSource.Token);
var buffer = new byte[16 * 1024];
var size = 0;
while ((size = await responseStream.ReadAsync(buffer, cancellationTokenSource.Token)) > 0)
{
speedContainer.Add(size);
await stream.WriteAsync(buffer, 0, size);
}
return new DownloadResult()
{
ActualContentLength = stream.Length,
RespContentLength = contentLength,
ActualFilePath = path
};
}
catch (OperationCanceledException oce) when (oce.CancellationToken == cancellationTokenSource.Token)
{ {
ActualContentLength = stream.Length, throw new Exception("Download speed too slow!");
RespContentLength = contentLength, }
ActualFilePath = path
};
} }
} }
} }