|
1 | 1 | import Bun from "bun"; |
2 | 2 | import { heapStats } from "bun:jsc"; |
3 | 3 | import { |
| 4 | + ActionRowBuilder, |
4 | 5 | ApplicationCommandOptionType, |
5 | 6 | ApplicationCommandType, |
6 | 7 | AutocompleteInteraction, |
| 8 | + ButtonBuilder, |
| 9 | + ButtonStyle, |
7 | 10 | ChannelType, |
8 | 11 | ChatInputCommandInteraction, |
| 12 | + ComponentType, |
| 13 | + EmbedBuilder, |
9 | 14 | GuildMember, |
10 | 15 | MessageFlags, |
11 | 16 | type ApplicationCommandOptionData, |
@@ -942,32 +947,107 @@ const commands: Record<string, Command> = { |
942 | 947 | return; |
943 | 948 | } |
944 | 949 |
|
945 | | - const youtubeChannels = trackedChannels.data.youtubeSubscriptions |
946 | | - .map( |
947 | | - (channel) => |
948 | | - `YouTube: [${channel.youtubeChannel.youtubeChannelName}](<https://www.youtube.com/channel/${channel.youtubeChannel.youtubeChannelId}>) | <#${channel.subscription.notificationChannelId}>`, |
949 | | - ) |
950 | | - .join("\n"); |
951 | | - const twitchChannels = trackedChannels.data.twitchSubscriptions |
952 | | - .map( |
953 | | - (channel) => |
954 | | - `Twitch: [${channel.twitchChannel.twitchChannelName}](<https://www.twitch.tv/${channel.twitchChannel.twitchChannelName}>) | <#${channel.subscription.notificationChannelId}>`, |
955 | | - ) |
956 | | - .join("\n"); |
957 | | - const response = [ |
958 | | - "Here are the channels being tracked in this guild:", |
959 | | - youtubeChannels |
960 | | - ? `**YouTube Channels:**\n${youtubeChannels}` |
961 | | - : "", |
962 | | - twitchChannels ? `**Twitch Channels:**\n${twitchChannels}` : "", |
963 | | - ] |
964 | | - .filter(Boolean) |
965 | | - .join("\n\n"); |
| 950 | + const youtubeChannels = |
| 951 | + trackedChannels.data.youtubeSubscriptions ?? []; |
| 952 | + const twitchChannels = |
| 953 | + trackedChannels.data.twitchSubscriptions ?? []; |
| 954 | + |
| 955 | + const entries = [ |
| 956 | + ...youtubeChannels.map((c) => ({ |
| 957 | + type: "YouTube" as const, |
| 958 | + name: c.youtubeChannel.youtubeChannelName, |
| 959 | + id: c.youtubeChannel.youtubeChannelId, |
| 960 | + notifyId: c.subscription.notificationChannelId, |
| 961 | + })), |
| 962 | + ...twitchChannels.map((c) => ({ |
| 963 | + type: "Twitch" as const, |
| 964 | + name: c.twitchChannel.twitchChannelName, |
| 965 | + id: c.twitchChannel.twitchChannelName, |
| 966 | + notifyId: c.subscription.notificationChannelId, |
| 967 | + })), |
| 968 | + ].sort((a, b) => a.name.localeCompare(b.name)); |
| 969 | + |
| 970 | + const pageSize = 10; |
| 971 | + const totalPages = Math.ceil(entries.length / pageSize); |
| 972 | + let currentPage = 0; |
| 973 | + |
| 974 | + const getPageEmbed = (page: number) => { |
| 975 | + const start = page * pageSize; |
| 976 | + const end = start + pageSize; |
| 977 | + const pageEntries = entries.slice(start, end); |
| 978 | + |
| 979 | + const description = |
| 980 | + pageEntries |
| 981 | + .map((entry) => { |
| 982 | + const link = |
| 983 | + entry.type === "YouTube" |
| 984 | + ? `https://www.youtube.com/channel/${entry.id}` |
| 985 | + : `https://www.twitch.tv/${entry.id}`; |
| 986 | + |
| 987 | + return `**[${entry.name}](${link})** • ${entry.type} • <#${entry.notifyId}>`; |
| 988 | + }) |
| 989 | + .join("\n") || "No entries."; |
| 990 | + |
| 991 | + return new EmbedBuilder() |
| 992 | + .setTitle("Tracked Channels") |
| 993 | + .setDescription(description) |
| 994 | + .setFooter({ |
| 995 | + text: `Page ${page + 1} of ${totalPages}`, |
| 996 | + }) |
| 997 | + .setColor(0x5865f2); |
| 998 | + }; |
| 999 | + |
| 1000 | + const getButtons = (page: number) => { |
| 1001 | + return new ActionRowBuilder<ButtonBuilder>().addComponents( |
| 1002 | + new ButtonBuilder() |
| 1003 | + .setCustomId("prev") |
| 1004 | + .setLabel("Previous") |
| 1005 | + .setStyle(ButtonStyle.Secondary) |
| 1006 | + .setDisabled(page === 0), |
| 1007 | + new ButtonBuilder() |
| 1008 | + .setCustomId("next") |
| 1009 | + .setLabel("Next") |
| 1010 | + .setStyle(ButtonStyle.Primary) |
| 1011 | + .setDisabled(page >= totalPages - 1), |
| 1012 | + ); |
| 1013 | + }; |
966 | 1014 |
|
967 | 1015 | await interaction.reply({ |
968 | | - content: response, |
| 1016 | + embeds: [getPageEmbed(currentPage)], |
| 1017 | + components: [getButtons(currentPage)], |
969 | 1018 | flags: MessageFlags.Ephemeral, |
970 | 1019 | }); |
| 1020 | + |
| 1021 | + const message = await interaction.fetchReply(); |
| 1022 | + |
| 1023 | + const collector = message.createMessageComponentCollector({ |
| 1024 | + componentType: ComponentType.Button, |
| 1025 | + time: 60_000, |
| 1026 | + filter: (i) => i.user.id === interaction.user.id, |
| 1027 | + }); |
| 1028 | + |
| 1029 | + collector.on("collect", async (i) => { |
| 1030 | + if (i.customId === "next" && currentPage < totalPages - 1) { |
| 1031 | + currentPage++; |
| 1032 | + } else if (i.customId === "prev" && currentPage > 0) { |
| 1033 | + currentPage--; |
| 1034 | + } |
| 1035 | + |
| 1036 | + await i.update({ |
| 1037 | + embeds: [getPageEmbed(currentPage)], |
| 1038 | + components: [getButtons(currentPage)], |
| 1039 | + }); |
| 1040 | + }); |
| 1041 | + |
| 1042 | + collector.on("end", async () => { |
| 1043 | + try { |
| 1044 | + await interaction.editReply({ |
| 1045 | + components: [], |
| 1046 | + }); |
| 1047 | + } catch { |
| 1048 | + console.error("Failed to edit reply"); |
| 1049 | + } |
| 1050 | + }); |
971 | 1051 | }, |
972 | 1052 | }, |
973 | 1053 | }; |
|
0 commit comments