From 89a2dabf2d74f0dc98ef5fd8140b0c51032ad375 Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Thu, 12 Mar 2026 15:15:57 +0000 Subject: [PATCH 01/11] feat: add x-super-properties header The x-super-properties header is an important header that contains info about the client with a launch signature. if this header is not provided, discord may flag requests and cause accounts to be banned/restricted --- .../Discord/DiscordClient.cs | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index c3846136..bd13cb17 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -33,17 +33,41 @@ public class DiscordClient( ) { return await Http.ResponseResiliencePipeline.ExecuteAsync( - async innerCancellationToken => + async innerCancellationToken => { using var request = new HttpRequestMessage(HttpMethod.Get, new Uri(_baseUri, url)); - // Don't validate because the token can have special characters - // https://github.com/Tyrrrz/DiscordChatExporter/issues/828 + // Authorization header request.Headers.TryAddWithoutValidation( "Authorization", tokenKind == TokenKind.Bot ? $"Bot {token}" : token ); + // add browser headers like x-super-properties and user-agent + // this is really important as discord flags requests that dont have valid xsp header + if (tokenKind != TokenKind.Bot) + { + try + { + var headersJson = await Http.Client.GetStringAsync( + "https://gist.githubusercontent.com/MinerPL/731977099ca84bef7ad0a66978010045/raw/stable.headers.json", + innerCancellationToken + ); + + var userHeaders = JsonSerializer.Deserialize>(headersJson); + if (userHeaders is not null) + { + foreach (var kv in userHeaders) + request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); + } + } + catch + { + + } + } + + var response = await Http.Client.SendAsync( request, HttpCompletionOption.ResponseHeadersRead, From e0e0eccf925e8ca6e39a629c675ef388a60588a3 Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Thu, 12 Mar 2026 15:16:58 +0000 Subject: [PATCH 02/11] revert back accidentally removed comment --- DiscordChatExporter.Core/Discord/DiscordClient.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index bd13cb17..b036f2c5 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -37,7 +37,8 @@ public class DiscordClient( { using var request = new HttpRequestMessage(HttpMethod.Get, new Uri(_baseUri, url)); - // Authorization header + // Don't validate because the token can have special characters + // https://github.com/Tyrrrz/DiscordChatExporter/issues/828 request.Headers.TryAddWithoutValidation( "Authorization", tokenKind == TokenKind.Bot ? $"Bot {token}" : token From 98a096035c017c7fa6572e2fd4076ae7b28e5b14 Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:17:08 +0000 Subject: [PATCH 03/11] make some props values random --- .../Discord/DiscordClient.cs | 57 ++++++++++++++++--- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index b036f2c5..1896acd5 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -18,6 +18,31 @@ using JsonExtensions.Reading; namespace DiscordChatExporter.Core.Discord; +// https://docs.discord.food/reference#launch-signature +static string GenerateLaunchSignature() +{ + const string maskBinary = + "00000000100000000001000000010000000010000001000000001000000000000010000010000001000000000100000000000001000000000000100000000000"; + + var mask = Convert.ToUInt128(maskBinary, 2); + + var uuid = Guid.NewGuid().ToByteArray(); + var value = new UInt128(BitConverter.ToUInt64(uuid, 8), BitConverter.ToUInt64(uuid, 0)); + + value &= ~mask; + + Span bytes = stackalloc byte[16]; + BitConverter.TryWriteBytes(bytes[..8], (ulong)value.Lower); + BitConverter.TryWriteBytes(bytes[8..], (ulong)value.Upper); + + return new Guid(bytes).ToString(); +} + +static string GenerateUuid() +{ + return Guid.NewGuid().ToString(); +} + public class DiscordClient( string token, RateLimitPreference rateLimitPreference = RateLimitPreference.RespectAll @@ -33,7 +58,7 @@ public class DiscordClient( ) { return await Http.ResponseResiliencePipeline.ExecuteAsync( - async innerCancellationToken => + async innerCancellationToken => { using var request = new HttpRequestMessage(HttpMethod.Get, new Uri(_baseUri, url)); @@ -55,20 +80,34 @@ public class DiscordClient( innerCancellationToken ); - var userHeaders = JsonSerializer.Deserialize>(headersJson); - if (userHeaders is not null) + var userHeaders = JsonSerializer.Deserialize>( + headersJson + ); + + if (userHeaders.TryGetValue("x-super-properties", out var xsp)) { + var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(xsp)); + + var props = JsonSerializer.Deserialize>( + decoded + ); + + props["client_heartbeat_session_id"] = GenerateUuid(); + props["client_launch_id"] = GenerateUuid(); + props["client_launch_signature"] = GenerateLaunchSignature(); + + var newJson = JsonSerializer.Serialize(props); + var newBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(newJson)); + + userHeaders["x-super-properties"] = newBase64; + foreach (var kv in userHeaders) request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); } } - catch - { - - } + catch { } } - var response = await Http.Client.SendAsync( request, HttpCompletionOption.ResponseHeadersRead, From 18558909e2462224afa8d3793242fd0799a34120 Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Thu, 12 Mar 2026 16:51:01 +0000 Subject: [PATCH 04/11] use better api for xsp* --- .../Discord/DiscordClient.cs | 86 ++++++++++++++----- 1 file changed, 66 insertions(+), 20 deletions(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index 1896acd5..54e4323d 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -70,40 +70,86 @@ public class DiscordClient( ); // add browser headers like x-super-properties and user-agent - // this is really important as discord flags requests that dont have valid xsp header + // discord flags requests that don't look like a real browser if (tokenKind != TokenKind.Bot) { try { - var headersJson = await Http.Client.GetStringAsync( - "https://gist.githubusercontent.com/MinerPL/731977099ca84bef7ad0a66978010045/raw/stable.headers.json", + var apiJson = await Http.Client.GetStringAsync( + "https://cordapi.dolfi.es/api/v2/properties/web", innerCancellationToken ); - var userHeaders = JsonSerializer.Deserialize>( - headersJson - ); + using var doc = JsonDocument.Parse(apiJson); - if (userHeaders.TryGetValue("x-super-properties", out var xsp)) + var client = doc.RootElement.GetProperty("client"); + var browser = doc.RootElement.GetProperty("browser"); + var os = browser.GetProperty("os"); + + string userAgent = browser.GetProperty("user_agent").GetString()!; + string browserVersion = browser.GetProperty("version").GetString()!; + string browserType = browser.GetProperty("type").GetString()!; + string osType = os.GetProperty("type").GetString()!; + string osVersion = os.GetProperty("version").GetString()!; + + int buildNumber = client.GetProperty("build_number").GetInt32(); + string releaseChannel = client.GetProperty("release_channel").GetString()!; + + string chromeMajor = browserVersion.Split('.')[0]; + + var xsp = new Dictionary { - var decoded = Encoding.UTF8.GetString(Convert.FromBase64String(xsp)); + ["os"] = osType, + ["browser"] = browserType, + ["device"] = "", + ["system_locale"] = "en-US", - var props = JsonSerializer.Deserialize>( - decoded - ); + ["browser_user_agent"] = userAgent, + ["browser_version"] = browserVersion, + ["os_version"] = osVersion, - props["client_heartbeat_session_id"] = GenerateUuid(); - props["client_launch_id"] = GenerateUuid(); - props["client_launch_signature"] = GenerateLaunchSignature(); + ["referrer"] = "", + ["referring_domain"] = "", + ["referrer_current"] = "https://www.google.com/", + ["referring_domain_current"] = "www.google.com", + ["search_engine_current"] = "google", + ["mp_keyword_current"] = "discord", - var newJson = JsonSerializer.Serialize(props); - var newBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(newJson)); + ["release_channel"] = releaseChannel, + ["client_build_number"] = buildNumber, + ["client_event_source"] = null, + ["has_client_mods"] = false, - userHeaders["x-super-properties"] = newBase64; + ["client_launch_id"] = GenerateUuid(), + ["launch_signature"] = GenerateLaunchSignature(), + ["client_heartbeat_session_id"] = GenerateUuid(), + }; - foreach (var kv in userHeaders) - request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); - } + var xspJson = JsonSerializer.Serialize(xsp); + var xspBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(xspJson)); + + var headers = new Dictionary + { + ["sec-ch-ua-platform"] = $"\"{osType}\"", + ["referer"] = "https://discord.com/app", + ["x-debug-options"] = "bugReporterEnabled", + ["accept-language"] = "en-US,en;q=0.9", + + ["sec-ch-ua"] = + $"\"Chromium\";v=\"{chromeMajor}\", \"Not;A=Brand\";v=\"99\"", + + ["sec-ch-ua-mobile"] = "?0", + + ["x-discord-timezone"] = "Europe/Warsaw", + ["x-context-properties"] = "eyJsb2NhdGlvbiI6Ii9hcHAifQ==", + ["x-discord-locale"] = "en-US", + + ["user-agent"] = userAgent, + ["x-super-properties"] = xspBase64, + }; + + foreach (var kv in headers) + request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); } catch { } } From 06117adf4711a4b8c8df594105fa538b9e567e05 Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Thu, 12 Mar 2026 17:06:40 +0000 Subject: [PATCH 05/11] use correct http method to get xsp --- .../Discord/DiscordClient.cs | 123 +++++++----------- 1 file changed, 47 insertions(+), 76 deletions(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index 54e4323d..287117c4 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -69,90 +69,61 @@ public class DiscordClient( tokenKind == TokenKind.Bot ? $"Bot {token}" : token ); - // add browser headers like x-super-properties and user-agent - // discord flags requests that don't look like a real browser - if (tokenKind != TokenKind.Bot) + // add browser headers like x-super-properties and user-agent + // discord flags requests that don't look like a real browser + if (tokenKind != TokenKind.Bot) + { + try { - try + using var apiReq = new HttpRequestMessage( + HttpMethod.Post, + "https://cordapi.dolfi.es/api/v2/properties/web" + ); + + using var apiRes = await Http.Client.SendAsync(apiReq, innerCancellationToken); + apiRes.EnsureSuccessStatusCode(); + + var apiJson = await apiRes.Content.ReadAsStringAsync(innerCancellationToken); + + using var doc = JsonDocument.Parse(apiJson); + + var root = doc.RootElement; + + string xspBase64 = root.GetProperty("encoded").GetString()!; + + var properties = root.GetProperty("properties"); + + string userAgent = proprties.GetProperty("user_agent").GetString()!; + string browserVersion = proprties.GetProperty("browser_version").GetString()!; + string osType = properties.GetProperty("os").GetString()!; + + string chromeMajor = browserVersion.Split('.')[0]; + + var headers = new Dictionary { - var apiJson = await Http.Client.GetStringAsync( - "https://cordapi.dolfi.es/api/v2/properties/web", - innerCancellationToken - ); + ["sec-ch-ua-platform"] = $"\"{osType}\"", + ["referer"] = "https://discord.com/app", + ["x-debug-options"] = "bugReporterEnabled", + ["accept-language"] = "en-US,en;q=0.9", - using var doc = JsonDocument.Parse(apiJson); + ["sec-ch-ua"] = + $"\"Chromium\";v=\"{chromeMajor}\", \"Not;A=Brand\";v=\"99\"", - var client = doc.RootElement.GetProperty("client"); - var browser = doc.RootElement.GetProperty("browser"); - var os = browser.GetProperty("os"); + ["sec-ch-ua-mobile"] = "?0", - string userAgent = browser.GetProperty("user_agent").GetString()!; - string browserVersion = browser.GetProperty("version").GetString()!; - string browserType = browser.GetProperty("type").GetString()!; - string osType = os.GetProperty("type").GetString()!; - string osVersion = os.GetProperty("version").GetString()!; + ["x-discord-timezone"] = "Europe/Warsaw", + ["x-context-properties"] = "eyJsb2NhdGlvbiI6Ii9hcHAifQ==", + ["x-discord-locale"] = "en-US", - int buildNumber = client.GetProperty("build_number").GetInt32(); - string releaseChannel = client.GetProperty("release_channel").GetString()!; + ["user-agent"] = userAgent, + ["x-super-properties"] = xspBase64, + }; - string chromeMajor = browserVersion.Split('.')[0]; - - var xsp = new Dictionary - { - ["os"] = osType, - ["browser"] = browserType, - ["device"] = "", - ["system_locale"] = "en-US", - - ["browser_user_agent"] = userAgent, - ["browser_version"] = browserVersion, - ["os_version"] = osVersion, - - ["referrer"] = "", - ["referring_domain"] = "", - ["referrer_current"] = "https://www.google.com/", - ["referring_domain_current"] = "www.google.com", - ["search_engine_current"] = "google", - ["mp_keyword_current"] = "discord", - - ["release_channel"] = releaseChannel, - ["client_build_number"] = buildNumber, - ["client_event_source"] = null, - ["has_client_mods"] = false, - - ["client_launch_id"] = GenerateUuid(), - ["launch_signature"] = GenerateLaunchSignature(), - ["client_heartbeat_session_id"] = GenerateUuid(), - }; - - var xspJson = JsonSerializer.Serialize(xsp); - var xspBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(xspJson)); - - var headers = new Dictionary - { - ["sec-ch-ua-platform"] = $"\"{osType}\"", - ["referer"] = "https://discord.com/app", - ["x-debug-options"] = "bugReporterEnabled", - ["accept-language"] = "en-US,en;q=0.9", - - ["sec-ch-ua"] = - $"\"Chromium\";v=\"{chromeMajor}\", \"Not;A=Brand\";v=\"99\"", - - ["sec-ch-ua-mobile"] = "?0", - - ["x-discord-timezone"] = "Europe/Warsaw", - ["x-context-properties"] = "eyJsb2NhdGlvbiI6Ii9hcHAifQ==", - ["x-discord-locale"] = "en-US", - - ["user-agent"] = userAgent, - ["x-super-properties"] = xspBase64, - }; - - foreach (var kv in headers) - request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); - } - catch { } + foreach (var kv in headers) + request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); } + catch { } + } var response = await Http.Client.SendAsync( request, From eccc481b4479a0ca16511b5c00befbb5ece666b3 Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Fri, 13 Mar 2026 11:15:31 +0000 Subject: [PATCH 06/11] Cache headers Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../Discord/DiscordClient.cs | 84 ++++++++++--------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index 287117c4..70708977 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -75,51 +75,59 @@ public class DiscordClient( { try { - using var apiReq = new HttpRequestMessage( - HttpMethod.Post, - "https://cordapi.dolfi.es/api/v2/properties/web" - ); + // Cache headers from the external API so we don't make this request on every call. + static Dictionary? cachedHeaders; - using var apiRes = await Http.Client.SendAsync(apiReq, innerCancellationToken); - apiRes.EnsureSuccessStatusCode(); - - var apiJson = await apiRes.Content.ReadAsStringAsync(innerCancellationToken); - - using var doc = JsonDocument.Parse(apiJson); - - var root = doc.RootElement; - - string xspBase64 = root.GetProperty("encoded").GetString()!; - - var properties = root.GetProperty("properties"); - - string userAgent = proprties.GetProperty("user_agent").GetString()!; - string browserVersion = proprties.GetProperty("browser_version").GetString()!; - string osType = properties.GetProperty("os").GetString()!; - - string chromeMajor = browserVersion.Split('.')[0]; - - var headers = new Dictionary + if (cachedHeaders is null) { - ["sec-ch-ua-platform"] = $"\"{osType}\"", - ["referer"] = "https://discord.com/app", - ["x-debug-options"] = "bugReporterEnabled", - ["accept-language"] = "en-US,en;q=0.9", + using var apiReq = new HttpRequestMessage( + HttpMethod.Post, + "https://cordapi.dolfi.es/api/v2/properties/web" + ); - ["sec-ch-ua"] = - $"\"Chromium\";v=\"{chromeMajor}\", \"Not;A=Brand\";v=\"99\"", + using var apiRes = await Http.Client.SendAsync(apiReq, innerCancellationToken); + apiRes.EnsureSuccessStatusCode(); - ["sec-ch-ua-mobile"] = "?0", + var apiJson = await apiRes.Content.ReadAsStringAsync(innerCancellationToken); - ["x-discord-timezone"] = "Europe/Warsaw", - ["x-context-properties"] = "eyJsb2NhdGlvbiI6Ii9hcHAifQ==", - ["x-discord-locale"] = "en-US", + using var doc = JsonDocument.Parse(apiJson); - ["user-agent"] = userAgent, - ["x-super-properties"] = xspBase64, - }; + var root = doc.RootElement; - foreach (var kv in headers) + string xspBase64 = root.GetProperty("encoded").GetString()!; + + var properties = root.GetProperty("properties"); + + string userAgent = properties.GetProperty("user_agent").GetString()!; + string browserVersion = properties.GetProperty("browser_version").GetString()!; + string osType = properties.GetProperty("os").GetString()!; + + string chromeMajor = browserVersion.Split('.')[0]; + + var headers = new Dictionary + { + ["sec-ch-ua-platform"] = $"\"{osType}\"", + ["referer"] = "https://discord.com/app", + ["x-debug-options"] = "bugReporterEnabled", + ["accept-language"] = "en-US,en;q=0.9", + + ["sec-ch-ua"] = + $"\"Chromium\";v=\"{chromeMajor}\", \"Not;A=Brand\";v=\"99\"", + + ["sec-ch-ua-mobile"] = "?0", + + ["x-discord-timezone"] = "Europe/Warsaw", + ["x-context-properties"] = "eyJsb2NhdGlvbiI6Ii9hcHAifQ==", + ["x-discord-locale"] = "en-US", + + ["user-agent"] = userAgent, + ["x-super-properties"] = xspBase64, + }; + + cachedHeaders = headers; + } + + foreach (var kv in cachedHeaders) request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); } catch { } From 03d96c7ff342762e75f170b422f9f601dfda1440 Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Sat, 14 Mar 2026 19:40:21 +0000 Subject: [PATCH 07/11] fix code errors --- .../Discord/DiscordClient.cs | 30 ++----------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index 70708977..39715940 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -18,30 +18,6 @@ using JsonExtensions.Reading; namespace DiscordChatExporter.Core.Discord; -// https://docs.discord.food/reference#launch-signature -static string GenerateLaunchSignature() -{ - const string maskBinary = - "00000000100000000001000000010000000010000001000000001000000000000010000010000001000000000100000000000001000000000000100000000000"; - - var mask = Convert.ToUInt128(maskBinary, 2); - - var uuid = Guid.NewGuid().ToByteArray(); - var value = new UInt128(BitConverter.ToUInt64(uuid, 8), BitConverter.ToUInt64(uuid, 0)); - - value &= ~mask; - - Span bytes = stackalloc byte[16]; - BitConverter.TryWriteBytes(bytes[..8], (ulong)value.Lower); - BitConverter.TryWriteBytes(bytes[8..], (ulong)value.Upper); - - return new Guid(bytes).ToString(); -} - -static string GenerateUuid() -{ - return Guid.NewGuid().ToString(); -} public class DiscordClient( string token, @@ -50,6 +26,7 @@ public class DiscordClient( { private readonly Uri _baseUri = new("https://discord.com/api/v10/", UriKind.Absolute); private TokenKind? _resolvedTokenKind; + private static Dictionary? _cachedBrowserHeaders; private async ValueTask GetResponseAsync( string url, @@ -76,9 +53,8 @@ public class DiscordClient( try { // Cache headers from the external API so we don't make this request on every call. - static Dictionary? cachedHeaders; - if (cachedHeaders is null) + if (_cachedBrowserHeaders is null) { using var apiReq = new HttpRequestMessage( HttpMethod.Post, @@ -124,7 +100,7 @@ public class DiscordClient( ["x-super-properties"] = xspBase64, }; - cachedHeaders = headers; + _cachedBrowserHeaders = headers; } foreach (var kv in cachedHeaders) From 4ca9490839f98006ec20ad3e995e9fcfcf5898f8 Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Sat, 14 Mar 2026 21:15:15 +0000 Subject: [PATCH 08/11] fix errors (again) --- DiscordChatExporter.Core/Discord/DiscordClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index 39715940..c855ef36 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -103,8 +103,8 @@ public class DiscordClient( _cachedBrowserHeaders = headers; } - foreach (var kv in cachedHeaders) - request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); + foreach (var kv in _cachedBrowserHeaders) + if (!request.Headers.Contains(kv.Key)) request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); } catch { } } From 5b6508d7805be5158f62b3391900555604d9be39 Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Sun, 15 Mar 2026 18:48:52 +0000 Subject: [PATCH 09/11] fix ua --- DiscordChatExporter.Core/Discord/DiscordClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index c855ef36..0f032029 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -74,7 +74,7 @@ public class DiscordClient( var properties = root.GetProperty("properties"); - string userAgent = properties.GetProperty("user_agent").GetString()!; + string userAgent = properties.GetProperty("browser_user_agent").GetString()!; string browserVersion = properties.GetProperty("browser_version").GetString()!; string osType = properties.GetProperty("os").GetString()!; From 825b1470e112b69f895ba2ed1321d0ab919d055d Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Sun, 15 Mar 2026 20:15:58 +0000 Subject: [PATCH 10/11] use task.run to add headers instead --- DiscordChatExporter.Core/Discord/DiscordClient.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index 0f032029..9e0edcff 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -50,7 +50,7 @@ public class DiscordClient( // discord flags requests that don't look like a real browser if (tokenKind != TokenKind.Bot) { - try + await Task.Run(async () => { // Cache headers from the external API so we don't make this request on every call. @@ -105,8 +105,7 @@ public class DiscordClient( foreach (var kv in _cachedBrowserHeaders) if (!request.Headers.Contains(kv.Key)) request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); - } - catch { } + }) } var response = await Http.Client.SendAsync( From ff9303d2b927d3c966c7e2e4ef34874e6db950b1 Mon Sep 17 00:00:00 2001 From: Wave Dev <66224387+wavedevgit@users.noreply.github.com> Date: Mon, 16 Mar 2026 15:35:33 +0000 Subject: [PATCH 11/11] remove task.run --- DiscordChatExporter.Core/Discord/DiscordClient.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index 9e0edcff..f492bd1c 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -50,7 +50,7 @@ public class DiscordClient( // discord flags requests that don't look like a real browser if (tokenKind != TokenKind.Bot) { - await Task.Run(async () => + try { // Cache headers from the external API so we don't make this request on every call. @@ -105,7 +105,8 @@ public class DiscordClient( foreach (var kv in _cachedBrowserHeaders) if (!request.Headers.Contains(kv.Key)) request.Headers.TryAddWithoutValidation(kv.Key, kv.Value); - }) + } + catch {} } var response = await Http.Client.SendAsync(