|
|
|
@ -38,50 +38,49 @@ internal partial class ExportAssetDownloader
|
|
|
|
|
var fileName = GetFileNameFromUrl(url);
|
|
|
|
|
var filePath = Path.Combine(_workingDirPath, fileName);
|
|
|
|
|
|
|
|
|
|
using (await Locker.LockAsync(filePath, cancellationToken))
|
|
|
|
|
{
|
|
|
|
|
if (_pathCache.TryGetValue(url, out var cachedFilePath))
|
|
|
|
|
return cachedFilePath;
|
|
|
|
|
using var _ = await Locker.LockAsync(filePath, cancellationToken);
|
|
|
|
|
|
|
|
|
|
if (_pathCache.TryGetValue(url, out var cachedFilePath))
|
|
|
|
|
return cachedFilePath;
|
|
|
|
|
|
|
|
|
|
// Reuse existing files if we're allowed to
|
|
|
|
|
if (_reuse && File.Exists(filePath))
|
|
|
|
|
return _pathCache[url] = filePath;
|
|
|
|
|
// Reuse existing files if we're allowed to
|
|
|
|
|
if (_reuse && File.Exists(filePath))
|
|
|
|
|
return _pathCache[url] = filePath;
|
|
|
|
|
|
|
|
|
|
Directory.CreateDirectory(_workingDirPath);
|
|
|
|
|
Directory.CreateDirectory(_workingDirPath);
|
|
|
|
|
|
|
|
|
|
await Http.ResiliencePolicy.ExecuteAsync(async () =>
|
|
|
|
|
{
|
|
|
|
|
// Download the file
|
|
|
|
|
using var response = await Http.Client.GetAsync(url, cancellationToken);
|
|
|
|
|
await using (var output = File.Create(filePath))
|
|
|
|
|
await response.Content.CopyToAsync(output, cancellationToken);
|
|
|
|
|
|
|
|
|
|
await Http.ResiliencePolicy.ExecuteAsync(async () =>
|
|
|
|
|
// Try to set the file date according to the last-modified header
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// Download the file
|
|
|
|
|
using var response = await Http.Client.GetAsync(url, cancellationToken);
|
|
|
|
|
await using (var output = File.Create(filePath))
|
|
|
|
|
await response.Content.CopyToAsync(output, cancellationToken);
|
|
|
|
|
var lastModified = response.Content.Headers.TryGetValue("Last-Modified")?.Pipe(s =>
|
|
|
|
|
DateTimeOffset.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.None, out var instant)
|
|
|
|
|
? instant
|
|
|
|
|
: (DateTimeOffset?)null
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Try to set the file date according to the last-modified header
|
|
|
|
|
try
|
|
|
|
|
if (lastModified is not null)
|
|
|
|
|
{
|
|
|
|
|
var lastModified = response.Content.Headers.TryGetValue("Last-Modified")?.Pipe(s =>
|
|
|
|
|
DateTimeOffset.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.None, out var instant)
|
|
|
|
|
? instant
|
|
|
|
|
: (DateTimeOffset?)null
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (lastModified is not null)
|
|
|
|
|
{
|
|
|
|
|
File.SetCreationTimeUtc(filePath, lastModified.Value.UtcDateTime);
|
|
|
|
|
File.SetLastWriteTimeUtc(filePath, lastModified.Value.UtcDateTime);
|
|
|
|
|
File.SetLastAccessTimeUtc(filePath, lastModified.Value.UtcDateTime);
|
|
|
|
|
}
|
|
|
|
|
File.SetCreationTimeUtc(filePath, lastModified.Value.UtcDateTime);
|
|
|
|
|
File.SetLastWriteTimeUtc(filePath, lastModified.Value.UtcDateTime);
|
|
|
|
|
File.SetLastAccessTimeUtc(filePath, lastModified.Value.UtcDateTime);
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// This can apparently fail for some reason.
|
|
|
|
|
// Updating the file date is not a critical task, so we'll just ignore exceptions thrown here.
|
|
|
|
|
// https://github.com/Tyrrrz/DiscordChatExporter/issues/585
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// This can apparently fail for some reason.
|
|
|
|
|
// Updating the file date is not a critical task, so we'll just ignore exceptions thrown here.
|
|
|
|
|
// https://github.com/Tyrrrz/DiscordChatExporter/issues/585
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return _pathCache[url] = filePath;
|
|
|
|
|
}
|
|
|
|
|
return _pathCache[url] = filePath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|