mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2024-09-19 12:18:48 -04:00
Add check for message content intent
This commit is contained in:
parent
89f2084759
commit
a8895663fe
6 changed files with 96 additions and 19 deletions
28
DiscordChatExporter.Core/Discord/Data/Application.cs
Normal file
28
DiscordChatExporter.Core/Discord/Data/Application.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System.Text.Json;
|
||||
using DiscordChatExporter.Core.Utils.Extensions;
|
||||
using JsonExtensions.Reading;
|
||||
|
||||
namespace DiscordChatExporter.Core.Discord.Data;
|
||||
|
||||
// https://discord.com/developers/docs/resources/application#application-object
|
||||
public partial record Application(Snowflake Id, string Name, ApplicationFlags Flags)
|
||||
{
|
||||
public bool IsMessageContentIntentEnabled =>
|
||||
Flags.HasFlag(ApplicationFlags.GatewayMessageContent)
|
||||
|| Flags.HasFlag(ApplicationFlags.GatewayMessageContentLimited);
|
||||
}
|
||||
|
||||
public partial record Application
|
||||
{
|
||||
public static Application Parse(JsonElement json)
|
||||
{
|
||||
var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse);
|
||||
var name = json.GetProperty("name").GetNonWhiteSpaceString();
|
||||
|
||||
var flags =
|
||||
json.GetPropertyOrNull("flags")?.GetInt32OrNull()?.Pipe(x => (ApplicationFlags)x)
|
||||
?? ApplicationFlags.None;
|
||||
|
||||
return new Application(id, name, flags);
|
||||
}
|
||||
}
|
20
DiscordChatExporter.Core/Discord/Data/ApplicationFlags.cs
Normal file
20
DiscordChatExporter.Core/Discord/Data/ApplicationFlags.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
|
||||
namespace DiscordChatExporter.Core.Discord.Data;
|
||||
|
||||
// https://discord.com/developers/docs/resources/application#application-object-application-flags
|
||||
[Flags]
|
||||
public enum ApplicationFlags
|
||||
{
|
||||
None = 0,
|
||||
ApplicationAutoModerationRuleCreateBadge = 64,
|
||||
GatewayPresence = 4096,
|
||||
GatewayPresenceLimited = 8192,
|
||||
GatewayGuildMembers = 16384,
|
||||
GatewayGuildMembersLimited = 32768,
|
||||
VerificationPendingGuildLimit = 65536,
|
||||
Embedded = 131072,
|
||||
GatewayMessageContent = 262144,
|
||||
GatewayMessageContentLimited = 524288,
|
||||
ApplicationCommandBadge = 8388608
|
||||
}
|
|
@ -62,7 +62,7 @@ public partial record Channel
|
|||
public static Channel Parse(JsonElement json, Channel? parent = null, int? positionHint = null)
|
||||
{
|
||||
var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse);
|
||||
var kind = (ChannelKind)json.GetProperty("type").GetInt32();
|
||||
var kind = json.GetProperty("type").GetInt32().Pipe(t => (ChannelKind)t);
|
||||
|
||||
var guildId =
|
||||
json.GetPropertyOrNull("guild_id")
|
||||
|
|
|
@ -118,14 +118,15 @@ public partial record Message
|
|||
public static Message Parse(JsonElement json)
|
||||
{
|
||||
var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse);
|
||||
var kind = (MessageKind)json.GetProperty("type").GetInt32();
|
||||
var flags =
|
||||
(MessageFlags?)json.GetPropertyOrNull("flags")?.GetInt32OrNull() ?? MessageFlags.None;
|
||||
var author = json.GetProperty("author").Pipe(User.Parse);
|
||||
var kind = json.GetProperty("type").GetInt32().Pipe(t => (MessageKind)t);
|
||||
|
||||
var flags =
|
||||
json.GetPropertyOrNull("flags")?.GetInt32OrNull()?.Pipe(f => (MessageFlags)f)
|
||||
?? MessageFlags.None;
|
||||
|
||||
var author = json.GetProperty("author").Pipe(User.Parse);
|
||||
var timestamp = json.GetProperty("timestamp").GetDateTimeOffset();
|
||||
var editedTimestamp = json.GetPropertyOrNull("edited_timestamp")?.GetDateTimeOffsetOrNull();
|
||||
|
||||
var callEndedTimestamp = json.GetPropertyOrNull("call")
|
||||
?.GetPropertyOrNull("ended_timestamp")
|
||||
?.GetDateTimeOffsetOrNull();
|
||||
|
|
|
@ -13,7 +13,7 @@ public record Sticker(Snowflake Id, string Name, StickerFormat Format, string So
|
|||
{
|
||||
var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse);
|
||||
var name = json.GetProperty("name").GetNonNullString();
|
||||
var format = (StickerFormat)json.GetProperty("format_type").GetInt32();
|
||||
var format = json.GetProperty("format_type").GetInt32().Pipe(t => (StickerFormat)t);
|
||||
|
||||
var sourceUrl = ImageCdn.GetStickerUrl(
|
||||
id,
|
||||
|
|
|
@ -86,10 +86,13 @@ public class DiscordClient
|
|||
);
|
||||
}
|
||||
|
||||
private async ValueTask<TokenKind> GetTokenKindAsync(
|
||||
private async ValueTask<TokenKind> ResolveTokenKindAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (_resolvedTokenKind is not null)
|
||||
return _resolvedTokenKind.Value;
|
||||
|
||||
// Try authenticating as a user
|
||||
using var userResponse = await GetResponseAsync(
|
||||
"users/@me",
|
||||
|
@ -98,7 +101,7 @@ public class DiscordClient
|
|||
);
|
||||
|
||||
if (userResponse.StatusCode != HttpStatusCode.Unauthorized)
|
||||
return TokenKind.User;
|
||||
return (_resolvedTokenKind = TokenKind.User).Value;
|
||||
|
||||
// Try authenticating as a bot
|
||||
using var botResponse = await GetResponseAsync(
|
||||
|
@ -108,7 +111,7 @@ public class DiscordClient
|
|||
);
|
||||
|
||||
if (botResponse.StatusCode != HttpStatusCode.Unauthorized)
|
||||
return TokenKind.Bot;
|
||||
return (_resolvedTokenKind = TokenKind.Bot).Value;
|
||||
|
||||
throw new DiscordChatExporterException("Authentication token is invalid.", true);
|
||||
}
|
||||
|
@ -116,11 +119,12 @@ public class DiscordClient
|
|||
private async ValueTask<HttpResponseMessage> GetResponseAsync(
|
||||
string url,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var tokenKind = _resolvedTokenKind ??= await GetTokenKindAsync(cancellationToken);
|
||||
return await GetResponseAsync(url, tokenKind, cancellationToken);
|
||||
}
|
||||
) =>
|
||||
await GetResponseAsync(
|
||||
url,
|
||||
await ResolveTokenKindAsync(cancellationToken),
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
private async ValueTask<JsonElement> GetJsonResponseAsync(
|
||||
string url,
|
||||
|
@ -152,9 +156,9 @@ public class DiscordClient
|
|||
_
|
||||
=> throw new DiscordChatExporterException(
|
||||
$"""
|
||||
Request to '{url}' failed: {response.StatusCode.ToString().ToSpaceSeparatedWords().ToLowerInvariant()}.
|
||||
Response content: {await response.Content.ReadAsStringAsync(cancellationToken)}
|
||||
""",
|
||||
Request to '{url}' failed: {response.StatusCode.ToString().ToSpaceSeparatedWords().ToLowerInvariant()}.
|
||||
Response content: {await response.Content.ReadAsStringAsync(cancellationToken)}
|
||||
""",
|
||||
true
|
||||
)
|
||||
};
|
||||
|
@ -174,6 +178,14 @@ public class DiscordClient
|
|||
: null;
|
||||
}
|
||||
|
||||
public async ValueTask<Application> GetApplicationAsync(
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
var response = await GetJsonResponseAsync("applications/@me", cancellationToken);
|
||||
return Application.Parse(response);
|
||||
}
|
||||
|
||||
public async ValueTask<User?> TryGetUserAsync(
|
||||
Snowflake userId,
|
||||
CancellationToken cancellationToken = default
|
||||
|
@ -285,7 +297,7 @@ public class DiscordClient
|
|||
if (guildId == Guild.DirectMessages.Id)
|
||||
yield break;
|
||||
|
||||
var tokenKind = _resolvedTokenKind ??= await GetTokenKindAsync(cancellationToken);
|
||||
var tokenKind = await ResolveTokenKindAsync(cancellationToken);
|
||||
|
||||
var channels = (await GetGuildChannelsAsync(guildId, cancellationToken))
|
||||
// Categories cannot have threads
|
||||
|
@ -559,6 +571,22 @@ public class DiscordClient
|
|||
[EnumeratorCancellation] CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
// If authenticating as a bot, ensure that we have the correct permissions to
|
||||
// retrieve message content.
|
||||
// https://github.com/Tyrrrz/DiscordChatExporter/issues/1106#issuecomment-1741548959
|
||||
var tokenKind = await ResolveTokenKindAsync(cancellationToken);
|
||||
if (tokenKind == TokenKind.Bot)
|
||||
{
|
||||
var application = await GetApplicationAsync(cancellationToken);
|
||||
if (!application.IsMessageContentIntentEnabled)
|
||||
{
|
||||
throw new DiscordChatExporterException(
|
||||
"Bot account does not have the Message Content Intent enabled.",
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the last message in the specified range, so we can later calculate the
|
||||
// progress based on the difference between message timestamps.
|
||||
// This also snapshots the boundaries, which means that messages posted after
|
||||
|
|
Loading…
Reference in a new issue