Skip to content

Commit

Permalink
Prefer message timestamp over the last-modified header for asset fi…
Browse files Browse the repository at this point in the history
…le dates (#1321)
  • Loading branch information
ritiek authored Dec 12, 2024
1 parent bf417db commit a9acf17
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 32 deletions.
35 changes: 7 additions & 28 deletions DiscordChatExporter.Core/Exporting/ExportAssetDownloader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ internal partial class ExportAssetDownloader(string workingDirPath, bool reuse)

public async ValueTask<string> DownloadAsync(
string url,
CancellationToken cancellationToken = default
CancellationToken cancellationToken = default,
DateTimeOffset? timestamp = null
)
{
var fileName = GetFileNameFromUrl(url);
Expand All @@ -48,34 +49,12 @@ await Http.ResiliencePipeline.ExecuteAsync(
await using (var output = File.Create(filePath))
await response.Content.CopyToAsync(output, innerCancellationToken);

// Try to set the file date according to the last-modified header
try
// Try to set the file date according to the message timestamp
if (timestamp 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);
}
}
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
File.SetCreationTimeUtc(filePath, timestamp.Value.UtcDateTime);
File.SetLastWriteTimeUtc(filePath, timestamp.Value.UtcDateTime);
File.SetLastAccessTimeUtc(filePath, timestamp.Value.UtcDateTime);
}
},
cancellationToken
Expand Down
5 changes: 3 additions & 2 deletions DiscordChatExporter.Core/Exporting/ExportContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,16 @@ public IReadOnlyList<Role> GetUserRoles(Snowflake id) =>

public async ValueTask<string> ResolveAssetUrlAsync(
string url,
CancellationToken cancellationToken = default
CancellationToken cancellationToken = default,
DateTimeOffset? timestamp = null
)
{
if (!Request.ShouldDownloadAssets)
return url;

try
{
var filePath = await _assetDownloader.DownloadAsync(url, cancellationToken);
var filePath = await _assetDownloader.DownloadAsync(url, cancellationToken, timestamp);
var relativeFilePath = Path.GetRelativePath(Request.OutputDirPath, filePath);

// Prefer the relative path so that the export package can be copied around without breaking references.
Expand Down
4 changes: 2 additions & 2 deletions DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ await FormatMarkdownAsync(message.Content, cancellationToken)
_writer.WriteString("id", attachment.Id.ToString());
_writer.WriteString(
"url",
await Context.ResolveAssetUrlAsync(attachment.Url, cancellationToken)
await Context.ResolveAssetUrlAsync(attachment.Url, cancellationToken, message.Timestamp)
);
_writer.WriteString("fileName", attachment.FileName);
_writer.WriteNumber("fileSizeBytes", attachment.FileSize.TotalBytes);
Expand Down Expand Up @@ -466,7 +466,7 @@ await Context.ResolveAssetUrlAsync(attachment.Url, cancellationToken)
_writer.WriteString("format", sticker.Format.ToString());
_writer.WriteString(
"sourceUrl",
await Context.ResolveAssetUrlAsync(sticker.SourceUrl, cancellationToken)
await Context.ResolveAssetUrlAsync(sticker.SourceUrl, cancellationToken, message.Timestamp)
);

_writer.WriteEndObject();
Expand Down

0 comments on commit a9acf17

Please sign in to comment.