Switch the internal downloader (again).

This commit is contained in:
Roger Far 2024-01-05 11:07:38 -07:00
parent 6ad51b036e
commit 8114baa7b8
3 changed files with 98 additions and 27 deletions

View file

@ -99,6 +99,10 @@ public class DbSettingsDownloadClient
[Description("Maximum amount of parallel threads that are used to download a single file to your host. If set to 0 no parallel downloading will be done.")] [Description("Maximum amount of parallel threads that are used to download a single file to your host. If set to 0 no parallel downloading will be done.")]
public Int32 ParallelCount { get; set; } = 0; public Int32 ParallelCount { get; set; } = 0;
[DisplayName("Chunk Count")]
[Description("Split the downloaded file in this amount of chunks. If left to 0, automatically deteremine the chunk size based on the file size.")]
public Int32 ChunkCount { get; set; } = 0;
[DisplayName("Connection Timeout (only used for the Internal Downloader)")] [DisplayName("Connection Timeout (only used for the Internal Downloader)")]
[Description("Timeout in milliseconds before the downloader times out.")] [Description("Timeout in milliseconds before the downloader times out.")]
public Int32 Timeout { get; set; } = 5000; public Int32 Timeout { get; set; } = 5000;

View file

@ -11,13 +11,13 @@
<FrameworkReference Include="Microsoft.AspNetCore.App" /> <FrameworkReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="AllDebrid.NET" Version="1.0.12" /> <PackageReference Include="AllDebrid.NET" Version="1.0.12" />
<PackageReference Include="Aria2.NET" Version="1.0.5" /> <PackageReference Include="Aria2.NET" Version="1.0.5" />
<PackageReference Include="Downloader.NET" Version="1.0.9" /> <PackageReference Include="Downloader" Version="3.0.6" />
<PackageReference Include="MonoTorrent" Version="2.0.7" /> <PackageReference Include="MonoTorrent" Version="2.0.7" />
<PackageReference Include="Premiumize.NET" Version="1.0.4" /> <PackageReference Include="Premiumize.NET" Version="1.0.4" />
<PackageReference Include="RD.NET" Version="2.1.4" /> <PackageReference Include="RD.NET" Version="2.1.4" />
<PackageReference Include="Serilog" Version="3.1.1" /> <PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SharpCompress" Version="0.34.2" /> <PackageReference Include="SharpCompress" Version="0.35.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,4 +1,5 @@
using DownloaderNET; using System.Net;
using Downloader;
using Serilog; using Serilog;
namespace RdtClient.Service.Services.Downloaders; namespace RdtClient.Service.Services.Downloaders;
@ -8,16 +9,14 @@ public class InternalDownloader : IDownloader
public event EventHandler<DownloadCompleteEventArgs>? DownloadComplete; public event EventHandler<DownloadCompleteEventArgs>? DownloadComplete;
public event EventHandler<DownloadProgressEventArgs>? DownloadProgress; public event EventHandler<DownloadProgressEventArgs>? DownloadProgress;
private readonly Downloader _downloadService; private readonly DownloadService _downloadService;
private readonly DownloaderNET.Settings _downloadConfiguration; private readonly DownloadConfiguration _downloadConfiguration;
private readonly String _filePath; private readonly String _filePath;
private readonly String _uri; private readonly String _uri;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly CancellationTokenSource _cancellationToken = new();
private Boolean _finished; private Boolean _finished;
public InternalDownloader(String uri, String filePath) public InternalDownloader(String uri, String filePath)
@ -27,15 +26,39 @@ public class InternalDownloader : IDownloader
_uri = uri; _uri = uri;
_filePath = filePath; _filePath = filePath;
_downloadConfiguration = new DownloaderNET.Settings(); var settingProxyServer = Settings.Get.DownloadClient.ProxyServer;
// For all options, see https://github.com/bezzad/Downloader
_downloadConfiguration = new DownloadConfiguration
{
BufferBlockSize = 1024 * 8,
MaxTryAgainOnFailover = 5,
RangeDownload = false,
ClearPackageOnCompletionWithFailure = false,
MinimumSizeOfChunking = 1024,
ReserveStorageSpaceBeforeStartingDownload = false,
CheckDiskSizeBeforeDownload = true,
RequestConfiguration =
{
Accept = "*/*",
UserAgent = $"rdt-client",
ProtocolVersion = HttpVersion.Version11,
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
KeepAlive = true,
UseDefaultCredentials = false
}
};
SetSettings(); SetSettings();
_downloadService = new Downloader(_uri, _filePath, _downloadConfiguration); if (!String.IsNullOrWhiteSpace(settingProxyServer))
{
_downloadConfiguration.RequestConfiguration.Proxy = new WebProxy(new Uri(settingProxyServer), false);
}
//_downloadService.OnLog += message => Debug.WriteLine(message.Message); _downloadService = new DownloadService(_downloadConfiguration);
_downloadService.OnProgress += (chunks, _) => _downloadService.DownloadProgressChanged += (_, args) =>
{ {
if (DownloadProgress == null) if (DownloadProgress == null)
{ {
@ -45,41 +68,68 @@ public class InternalDownloader : IDownloader
DownloadProgress.Invoke(this, DownloadProgress.Invoke(this,
new DownloadProgressEventArgs new DownloadProgressEventArgs
{ {
Speed = (Int64)chunks.Where(m => m.IsActive).Sum(m => m.Speed), Speed = (Int64)args.BytesPerSecondSpeed,
BytesDone = chunks.Sum(m => m.DownloadBytes), BytesDone = args.ReceivedBytesSize,
BytesTotal = chunks.Sum(m => m.LengthBytes) BytesTotal = args.TotalBytesToReceive
}); });
}; };
_downloadService.OnComplete += (_, error) => _downloadService.DownloadFileCompleted += (_, args) =>
{ {
String? error = null;
if (args.Cancelled)
{
error = $"The download was cancelled";
}
else if (args.Error != null)
{
error = args.Error.Message;
}
DownloadComplete?.Invoke(this, DownloadComplete?.Invoke(this,
new DownloadCompleteEventArgs new DownloadCompleteEventArgs
{ {
Error = error?.Message Error = error
}); });
_finished = true; _finished = true;
return Task.CompletedTask;
}; };
} }
public Task<String?> Download() public async Task<String?> Download()
{ {
_logger.Debug($"Starting download of {_uri}, writing to path: {_filePath}"); _logger.Debug($"Starting download of {_uri}, writing to path: {_filePath}");
Task.Run(async () => await _downloadService.Download(_cancellationToken.Token)); if (Settings.Get.DownloadClient.ChunkCount == 0)
Task.Run(StartTimer); {
var contentSize = await GetContentSize();
return Task.FromResult<String?>(null); var chunkSize = contentSize switch
{
<= 1024 * 1024 * 10 => 1024 * 1024 * 10,
<= 1024 * 1024 * 100 => 1024 * 1024 * 25,
_ => 1024 * 1024 * 50
};
_downloadConfiguration.ChunkCount = (Int32) Math.Ceiling(contentSize / (Double) chunkSize);
}
_ = Task.Run(async () =>
{
await _downloadService.DownloadFileTaskAsync(_uri, _filePath);
});
_ = Task.Run(StartTimer);
return null;
} }
public Task Cancel() public Task Cancel()
{ {
_logger.Debug($"Cancelling download {_uri}"); _logger.Debug($"Cancelling download {_uri}");
_cancellationToken.Cancel(false); _downloadService.CancelAsync();
return Task.CompletedTask; return Task.CompletedTask;
} }
@ -119,10 +169,10 @@ public class InternalDownloader : IDownloader
settingDownloadTimeout = 1000; settingDownloadTimeout = 1000;
} }
_downloadConfiguration.Parallel = settingDownloadParallelCount;
_downloadConfiguration.MaximumBytesPerSecond = settingDownloadMaxSpeed; _downloadConfiguration.MaximumBytesPerSecond = settingDownloadMaxSpeed;
_downloadConfiguration.ParallelDownload = settingDownloadParallelCount > 1;
_downloadConfiguration.ParallelCount = settingDownloadParallelCount;
_downloadConfiguration.Timeout = settingDownloadTimeout; _downloadConfiguration.Timeout = settingDownloadTimeout;
_downloadConfiguration.RetryCount = 5;
} }
private async Task StartTimer() private async Task StartTimer()
@ -139,4 +189,21 @@ public class InternalDownloader : IDownloader
SetSettings(); SetSettings();
} }
} }
private async Task<Int64> GetContentSize()
{
var httpClient = new HttpClient();
var responseHeaders = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, _uri));
if (!responseHeaders.IsSuccessStatusCode)
{
var content = await responseHeaders.Content.ReadAsStringAsync();
var ex = new Exception($"Unable to retrieve content size before downloading, received response: {responseHeaders.StatusCode} {content}");
throw ex;
}
var result = responseHeaders.Content.Headers.ContentLength ?? -1;
return result;
}
} }