diff --git a/DiscordChatExporter.Core/Discord/DiscordClient.cs b/DiscordChatExporter.Core/Discord/DiscordClient.cs index 9a44cc2..1d7a504 100644 --- a/DiscordChatExporter.Core/Discord/DiscordClient.cs +++ b/DiscordChatExporter.Core/Discord/DiscordClient.cs @@ -189,17 +189,17 @@ public class DiscordClient var response = await GetJsonResponseAsync(url, cancellationToken); - var isEmpty = true; + var count = 0; foreach (var guildJson in response.EnumerateArray()) { var guild = Guild.Parse(guildJson); yield return guild; currentAfter = guild.Id; - isEmpty = false; + count++; } - if (isEmpty) + if (count <= 0) yield break; } } @@ -491,38 +491,36 @@ public class DiscordClient Emoji emoji, [EnumeratorCancellation] CancellationToken cancellationToken = default) { - - var reactionName = Uri.EscapeDataString( - emoji.Id is not null - // Custom emoji - ? emoji.Name + ':' + emoji.Id - // Standard emoji - : emoji.Name - ); + var reactionName = emoji.Id is not null + // Custom emoji + ? emoji.Name + ':' + emoji.Id + // Standard emoji + : emoji.Name; var currentAfter = Snowflake.Zero; - while (true) { var url = new UrlBuilder() - .SetPath($"channels/{channelId}/messages/{messageId}/reactions/{reactionName}") + .SetPath($"channels/{channelId}/messages/{messageId}/reactions/{Uri.EscapeDataString(reactionName)}") .SetQueryParameter("limit", "100") .SetQueryParameter("after", currentAfter.ToString()) .Build(); var response = await GetJsonResponseAsync(url, cancellationToken); - var users = response.EnumerateArray().Select(User.Parse).ToArray(); - if (!users.Any()) - yield break; - foreach (var user in users) + var count = 0; + foreach (var userJson in response.EnumerateArray()) { + var user = User.Parse(userJson); yield return user; + currentAfter = user.Id; + count++; } + // Each batch can contain up to 100 users. // If we got fewer, then it's definitely the last batch. - if (users.Length < 100) + if (count < 100) yield break; } } diff --git a/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs b/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs index 03f7061..6d32cf6 100644 --- a/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs +++ b/DiscordChatExporter.Core/Exporting/JsonMessageWriter.cs @@ -361,16 +361,16 @@ internal class JsonMessageWriter : MessageWriter _writer.WriteNumber("count", reaction.Count); _writer.WriteStartArray("users"); - var users = await Context.Discord.GetMessageReactionsAsync(Context.Request.Channel.Id, message.Id, reaction.Emoji, cancellationToken); - foreach (var user in users) { - - // write limited user information without color and roles, - // because if we would write the full user information, - // we would have to fetch the guild member information for each user - // which would be a lot of requests - - _writer.WriteStartObject(); - + await foreach (var user in Context.Discord.GetMessageReactionsAsync( + Context.Request.Channel.Id, + message.Id, + reaction.Emoji, + cancellationToken)) + { + _writer.WriteStartObject(); + + // Write limited user information without color and roles, + // so we can avoid fetching guild member information for each user. _writer.WriteString("id", user.Id.ToString()); _writer.WriteString("name", user.Name); _writer.WriteString("discriminator", user.DiscriminatorFormatted); @@ -386,7 +386,6 @@ internal class JsonMessageWriter : MessageWriter ); _writer.WriteEndObject(); - await _writer.FlushAsync(cancellationToken); } _writer.WriteEndArray(); diff --git a/DiscordChatExporter.Core/Utils/Extensions/BinaryExtensions.cs b/DiscordChatExporter.Core/Utils/Extensions/BinaryExtensions.cs index bb3ac68..0dbd88e 100644 --- a/DiscordChatExporter.Core/Utils/Extensions/BinaryExtensions.cs +++ b/DiscordChatExporter.Core/Utils/Extensions/BinaryExtensions.cs @@ -1,4 +1,5 @@ -using System.Text; +using System.Globalization; +using System.Text; namespace DiscordChatExporter.Core.Utils.Extensions; @@ -11,7 +12,7 @@ public static class BinaryExtensions foreach (var b in data) { buffer.Append( - b.ToString(isUpperCase ? "X2" : "x2") + b.ToString(isUpperCase ? "X2" : "x2", CultureInfo.InvariantCulture) ); }