Skip to content

Commit dfade03

Browse files
Merge pull request #1 from Lymia/master
Improve filenames for downloaded assets. Fixes Tyrrrz#1231
2 parents f31e73b + 7be46d6 commit dfade03

File tree

1 file changed

+84
-19
lines changed

1 file changed

+84
-19
lines changed

DiscordChatExporter.Core/Exporting/ExportAssetDownloader.cs

Lines changed: 84 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Globalization;
44
using System.IO;
5+
using System.Linq;
56
using System.Security.Cryptography;
67
using System.Text;
78
using System.Text.RegularExpressions;
@@ -66,34 +67,46 @@ await Http.ResiliencePipeline.ExecuteAsync(
6667

6768
internal partial class ExportAssetDownloader
6869
{
69-
private static string GetUrlHash(string url)
70+
private const String CHARSET = "0123456789bcdfghjklmnpqrstvwxyz_";
71+
72+
private static String Base32(byte[] data)
7073
{
71-
// Remove signature parameters from Discord CDN URLs to normalize them
72-
static string NormalizeUrl(string url)
73-
{
74-
var uri = new Uri(url);
75-
if (!string.Equals(uri.Host, "cdn.discordapp.com", StringComparison.OrdinalIgnoreCase))
76-
return url;
74+
var newString = new StringBuilder();
75+
uint accum = 0;
76+
uint bits = 0;
7777

78-
var query = HttpUtility.ParseQueryString(uri.Query);
79-
query.Remove("ex");
80-
query.Remove("is");
81-
query.Remove("hm");
78+
foreach (byte b in data)
79+
{
80+
accum <<= 8;
81+
accum |= b;
82+
bits += 8;
8283

83-
return uri.GetLeftPart(UriPartial.Path) + query;
84+
while (bits > 5)
85+
{
86+
char ch = CHARSET[(int)(accum & 0x1F)];
87+
accum >>= 5;
88+
bits -= 5;
89+
newString.Append(ch);
90+
}
91+
}
92+
if (bits != 0)
93+
{
94+
char ch = CHARSET[(int)(accum & 0x1F)];
95+
newString.Append(ch);
8496
}
8597

86-
return SHA256
87-
.HashData(Encoding.UTF8.GetBytes(NormalizeUrl(url)))
88-
.ToHex()
89-
// 5 chars ought to be enough for anybody
90-
.Truncate(5);
98+
return newString.ToString();
9199
}
92100

93-
private static string GetFileNameFromUrl(string url)
101+
private static string GetUrlHash(string url)
94102
{
95-
var urlHash = GetUrlHash(url);
103+
var hash = SHA256.HashData(Encoding.UTF8.GetBytes(url));
104+
// 12 characters of base32 contains about as much entropy as a Discord snowflake
105+
return Base32(hash).Truncate(12);
106+
}
96107

108+
private static string AddHashToUrl(string url, string urlHash)
109+
{
97110
// Try to extract the file name from URL
98111
var fileName = Regex.Match(url, @".+/([^?]*)").Groups[1].Value;
99112

@@ -117,4 +130,56 @@ private static string GetFileNameFromUrl(string url)
117130
fileNameWithoutExtension.Truncate(42) + '-' + urlHash + fileExtension
118131
);
119132
}
133+
134+
private static string GetFileNameFromUrl(string url)
135+
{
136+
var uri = new Uri(url);
137+
138+
if (string.Equals(uri.Host, "cdn.discordapp.com"))
139+
{
140+
string[] split = uri.AbsolutePath.Split("/");
141+
142+
// Attachments
143+
if (uri.AbsolutePath.StartsWith("/attachments/") && split.Length == 5)
144+
{
145+
// use the attachment snowflake for attachments
146+
if (ulong.TryParse(split[3], out var snowflake))
147+
return AddHashToUrl(url, snowflake.ToString());
148+
}
149+
150+
// Emojis
151+
if (
152+
uri.AbsolutePath.StartsWith("/emojis/")
153+
&& split.Length == 3
154+
&& split[2].Contains(".")
155+
)
156+
{
157+
var nameSplit = split[2].Split(".", 2);
158+
if (ulong.TryParse(nameSplit[0], out var snowflake))
159+
return $"emoji-discord-{snowflake}.{nameSplit[1]}";
160+
}
161+
162+
// Avatars
163+
if (uri.AbsolutePath.StartsWith("/avatars/") && split.Length == 4)
164+
{
165+
return $"avatar-{split[2]}-{GetUrlHash(url)}.{split[3].Split(".").Last()}";
166+
}
167+
}
168+
169+
if (string.Equals(uri.Host, "cdn.jsdelivr.net"))
170+
{
171+
string[] split = uri.AbsolutePath.Split("/");
172+
173+
// twemoji
174+
if (
175+
uri.AbsolutePath.StartsWith("/gh/twitter/twemoji@latest/assets/svg/")
176+
&& split.Length == 7
177+
)
178+
{
179+
return $"emoji-twemoji-{split[6]}";
180+
}
181+
}
182+
183+
return AddHashToUrl(url, GetUrlHash(url));
184+
}
120185
}

0 commit comments

Comments
 (0)