mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2026-09-14 06:41:08 +02:00
Compare commits
4 Commits
5a57c4202d
...
b11a57a825
| Author | SHA1 | Date | |
|---|---|---|---|
| b11a57a825 | |||
| f502e577c2 | |||
| 8bc9fe7c72 | |||
| 97485c280b |
@@ -38,23 +38,28 @@ internal partial class ExportAssetDownloader(string workingDirPath, bool reuse)
|
||||
return _previousPathsByUrl[url] = filePath;
|
||||
|
||||
// Check for a file cached by the legacy naming scheme (5-char hash) and rename it
|
||||
// to the new naming scheme to preserve backwards compatibility with existing exports
|
||||
// to the new naming scheme to preserve backwards compatibility with existing exports.
|
||||
// This will catch both the 5-char lowercase hash and the 5-char uppercase hash variants.
|
||||
if (reuse)
|
||||
{
|
||||
var legacyFilePath = Path.Combine(workingDirPath, GetLegacyFileNameFromUrl(url));
|
||||
if (File.Exists(legacyFilePath))
|
||||
var legacyFileNames = GetLegacyFileNamesFromUrl(url);
|
||||
foreach (var legacyFileName in legacyFileNames)
|
||||
{
|
||||
// Overwrite in case the destination file was created concurrently between our
|
||||
// earlier existence check and this move operation
|
||||
try
|
||||
var legacyFilePath = Path.Combine(workingDirPath, legacyFileName);
|
||||
if (File.Exists(legacyFilePath))
|
||||
{
|
||||
File.Move(legacyFilePath, filePath, overwrite: true);
|
||||
return _previousPathsByUrl[url] = filePath;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// The legacy file was moved or deleted concurrently or something else happened.
|
||||
// Upgrading old files is not crucial, so we can just move on.
|
||||
// Overwrite in case the destination file was created concurrently between our
|
||||
// earlier existence check and this move operation
|
||||
try
|
||||
{
|
||||
File.Move(legacyFilePath, filePath, true);
|
||||
return _previousPathsByUrl[url] = filePath;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// The legacy file was moved or deleted concurrently or something else happened.
|
||||
// Upgrading old files is not crucial, so we can just move on.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,10 +92,16 @@ internal partial class ExportAssetDownloader
|
||||
{
|
||||
private static string NormalizeUrl(string url)
|
||||
{
|
||||
// Remove signature parameters from Discord CDN URLs to normalize them
|
||||
// Remove signature parameters from Discord CDN/media URLs to normalize them
|
||||
var uri = new Uri(url);
|
||||
if (!string.Equals(uri.Host, "cdn.discordapp.com", StringComparison.OrdinalIgnoreCase))
|
||||
|
||||
if (
|
||||
!string.Equals(uri.Host, "cdn.discordapp.com", StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(uri.Host, "media.discordapp.net", StringComparison.OrdinalIgnoreCase)
|
||||
)
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
||||
var query = HttpUtility.ParseQueryString(uri.Query);
|
||||
query.Remove("ex");
|
||||
@@ -137,13 +148,16 @@ internal partial class ExportAssetDownloader
|
||||
);
|
||||
|
||||
// Legacy naming used a 5-char hash, kept for backwards compatibility with existing exports
|
||||
private static string GetLegacyFileNameFromUrl(string url) =>
|
||||
GetFileNameFromUrl(
|
||||
url,
|
||||
SHA256
|
||||
.HashData(Encoding.UTF8.GetBytes(NormalizeUrl(url)))
|
||||
.Pipe(Convert.ToHexStringLower)
|
||||
// 5 chars = 20 bits, reaches 1% collision probability at ~145 files
|
||||
.Truncate(5)
|
||||
);
|
||||
private static IReadOnlyList<string> GetLegacyFileNamesFromUrl(string url)
|
||||
{
|
||||
var hashData = SHA256.HashData(Encoding.UTF8.GetBytes(NormalizeUrl(url)));
|
||||
|
||||
return
|
||||
[
|
||||
// Lowercase variant (introduced in 2.46.1)
|
||||
GetFileNameFromUrl(url, Convert.ToHexStringLower(hashData).Truncate(5)),
|
||||
// Uppercase variant (original)
|
||||
GetFileNameFromUrl(url, Convert.ToHexString(hashData).Truncate(5)),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,10 +206,15 @@ public partial class ExportRequest
|
||||
{
|
||||
var actualOutputPath = FormatPath(outputPath, guild, channel, after, before);
|
||||
|
||||
// Output is a directory
|
||||
// Determine whether the output path refers to a directory or a file.
|
||||
// The extension-based heuristic is evaluated on the original, unsubstituted path,
|
||||
// because the value of a template token (e.g. a guild or channel name) may contain
|
||||
// a period that would otherwise be mistaken for a file extension, incorrectly causing
|
||||
// a directory path to be treated as a file.
|
||||
// https://github.com/Tyrrrz/DiscordChatExporter/issues/1502
|
||||
if (
|
||||
Directory.Exists(actualOutputPath)
|
||||
|| string.IsNullOrWhiteSpace(Path.GetExtension(actualOutputPath))
|
||||
|| string.IsNullOrWhiteSpace(Path.GetExtension(outputPath))
|
||||
)
|
||||
{
|
||||
var fileName = GetDefaultOutputFileName(guild, channel, format, after, before);
|
||||
|
||||
Reference in New Issue
Block a user