|
|
|
@ -7,6 +7,7 @@ using System.Text;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using AsyncKeyedLock;
|
|
|
|
|
using DiscordChatExporter.Core.Utils;
|
|
|
|
|
using DiscordChatExporter.Core.Utils.Extensions;
|
|
|
|
|
|
|
|
|
@ -14,6 +15,11 @@ namespace DiscordChatExporter.Core.Exporting;
|
|
|
|
|
|
|
|
|
|
internal partial class ExportAssetDownloader
|
|
|
|
|
{
|
|
|
|
|
private static readonly AsyncKeyedLocker<string> _locker = new(o =>
|
|
|
|
|
{
|
|
|
|
|
o.PoolSize = 20;
|
|
|
|
|
o.PoolInitialFill = 1;
|
|
|
|
|
});
|
|
|
|
|
private readonly string _workingDirPath;
|
|
|
|
|
private readonly bool _reuse;
|
|
|
|
|
|
|
|
|
@ -28,12 +34,14 @@ internal partial class ExportAssetDownloader
|
|
|
|
|
|
|
|
|
|
public async ValueTask<string> DownloadAsync(string url, CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
if (_pathCache.TryGetValue(url, out var cachedFilePath))
|
|
|
|
|
return cachedFilePath;
|
|
|
|
|
|
|
|
|
|
var fileName = GetFileNameFromUrl(url);
|
|
|
|
|
var filePath = Path.Combine(_workingDirPath, fileName);
|
|
|
|
|
|
|
|
|
|
using (await _locker.LockAsync(filePath, cancellationToken).ConfigureAwait(false))
|
|
|
|
|
{
|
|
|
|
|
if (_pathCache.TryGetValue(url, out var cachedFilePath))
|
|
|
|
|
return cachedFilePath;
|
|
|
|
|
|
|
|
|
|
// Reuse existing files if we're allowed to
|
|
|
|
|
if (!_reuse || !File.Exists(filePath))
|
|
|
|
|
{
|
|
|
|
@ -52,7 +60,7 @@ internal partial class ExportAssetDownloader
|
|
|
|
|
var lastModified = response.Content.Headers.TryGetValue("Last-Modified")?.Pipe(s =>
|
|
|
|
|
DateTimeOffset.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.None, out var instant)
|
|
|
|
|
? instant
|
|
|
|
|
: (DateTimeOffset?) null
|
|
|
|
|
: (DateTimeOffset?)null
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (lastModified is not null)
|
|
|
|
@ -74,6 +82,7 @@ internal partial class ExportAssetDownloader
|
|
|
|
|
|
|
|
|
|
return _pathCache[url] = filePath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal partial class ExportAssetDownloader
|
|
|
|
|