Preliminary support for threads (#1032)

pull/1037/head
William Unsworth 2 years ago committed by GitHub
parent 9048557b17
commit 25caf04445
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -20,6 +20,12 @@ public class GetChannelsCommand : DiscordCommandBase
)] )]
public required Snowflake GuildId { get; init; } public required Snowflake GuildId { get; init; }
[CommandOption(
"include-threads",
Description = "Display threads alongside channels."
)]
public bool IncludeTHreads { get; init; }
public override async ValueTask ExecuteAsync(IConsole console) public override async ValueTask ExecuteAsync(IConsole console)
{ {
var cancellationToken = console.RegisterCancellationHandler(); var cancellationToken = console.RegisterCancellationHandler();
@ -44,6 +50,32 @@ public class GetChannelsCommand : DiscordCommandBase
// Channel category / name // Channel category / name
using (console.WithForegroundColor(ConsoleColor.White)) using (console.WithForegroundColor(ConsoleColor.White))
await console.Output.WriteLineAsync($"{channel.Category.Name} / {channel.Name}"); await console.Output.WriteLineAsync($"{channel.Category.Name} / {channel.Name}");
if (IncludeThreads)
{
var threads = (await Discord.GetGuildChannelThreadsAsync(channel.Id.ToString(), cancellationToken))
.OrderBy(c => c.Name)
.ToArray();
foreach (var thread in threads)
{
// Indent
await console.Output.WriteAsync('\t');
// Thread ID
await console.Output.WriteAsync(
thread.Id.ToString().PadRight(18, ' ')
);
// Separator
using (console.WithForegroundColor(ConsoleColor.DarkGray))
await console.Output.WriteAsync(" | ");
// Thread / thread name
using (console.WithForegroundColor(ConsoleColor.White))
await console.Output.WriteLineAsync($"Thread / {thread.Name}");
}
}
} }
} }
} }

@ -0,0 +1,50 @@
using System.Linq;
using System.Text.Json;
using DiscordChatExporter.Core.Discord.Data.Common;
using DiscordChatExporter.Core.Utils.Extensions;
using JsonExtensions.Reading;
namespace DiscordChatExporter.Core.Discord.Data;
// https://discord.com/developers/docs/resources/channel#channel-object-example-thread-channel
public partial record ThreadChannel(
Snowflake Id,
ChannelKind Kind,
Snowflake GuildId,
string Name,
Snowflake? LastMessageId) : IHasId
{
}
public partial record ThreadChannel
{
public static ThreadChannel Parse(JsonElement json)
{
var id = json.GetProperty("id").GetNonWhiteSpaceString().Pipe(Snowflake.Parse);
var kind = (ChannelKind)json.GetProperty("type").GetInt32();
var guildId =
json.GetPropertyOrNull("guild_id")?.GetNonWhiteSpaceStringOrNull()?.Pipe(Snowflake.Parse) ?? default;
var name =
// Guild channel
json.GetPropertyOrNull("name")?.GetNonWhiteSpaceStringOrNull() ??
// Fallback
id.ToString();
var lastMessageId = json
.GetPropertyOrNull("last_message_id")?
.GetNonWhiteSpaceStringOrNull()?
.Pipe(Snowflake.Parse);
return new ThreadChannel(
id,
kind,
guildId,
name,
lastMessageId
);
}
}

@ -200,6 +200,35 @@ public class DiscordClient
return Guild.Parse(response); return Guild.Parse(response);
} }
public async IAsyncEnumerable<ThreadChannel> GetGuildChannelThreadsAsync(
string channelId,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
int currentOffset = 0;
while (true)
{
var url = new UrlBuilder()
.SetPath($"channels/{channelId}/threads/search")
.SetQueryParameter("offset", currentOffset.ToString())
.Build();
var response = await TryGetJsonResponseAsync(url, cancellationToken);
if (response is null)
break;
foreach (var threadJson in response.Value.GetProperty("threads").EnumerateArray())
yield return ThreadChannel.Parse(threadJson);
if (!response.Value.GetProperty("has_more").GetBoolean())
{
break;
}
currentOffset += response.Value.GetProperty("threads").GetArrayLength();
}
}
public async IAsyncEnumerable<Channel> GetGuildChannelsAsync( public async IAsyncEnumerable<Channel> GetGuildChannelsAsync(
Snowflake guildId, Snowflake guildId,
[EnumeratorCancellation] CancellationToken cancellationToken = default) [EnumeratorCancellation] CancellationToken cancellationToken = default)

Loading…
Cancel
Save