mirror of
https://github.com/Tyrrrz/DiscordChatExporter.git
synced 2026-02-14 15:53:30 -07:00
Preliminary support for threads (#1032)
This commit is contained in:
parent
9048557b17
commit
25caf04445
|
|
@ -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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
50
DiscordChatExporter.Core/Discord/Data/ThreadChannel.cs
Normal file
50
DiscordChatExporter.Core/Discord/Data/ThreadChannel.cs
Normal file
|
|
@ -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…
Reference in a new issue