76 lines
2.0 KiB
TypeScript
76 lines
2.0 KiB
TypeScript
import "server-only";
|
|
import { getDiscordServerConfig } from "@/lib/config/server";
|
|
|
|
export type DiscordVoiceChannel = {
|
|
id: string;
|
|
name: string;
|
|
type: 2 | 13;
|
|
position: number;
|
|
};
|
|
|
|
type DiscordChannelPayload = {
|
|
id?: unknown;
|
|
name?: unknown;
|
|
type?: unknown;
|
|
position?: unknown;
|
|
};
|
|
|
|
const CHANNEL_CACHE_TTL_MS = 5 * 60_000;
|
|
const channelCache: {
|
|
data: DiscordVoiceChannel[] | null;
|
|
expiresAt: number;
|
|
} = {
|
|
data: null,
|
|
expiresAt: 0,
|
|
};
|
|
|
|
export function parseCurrentVoiceChannels(payload: unknown): DiscordVoiceChannel[] {
|
|
if (!Array.isArray(payload)) {
|
|
throw new Error("Discord returned an invalid channel list.");
|
|
}
|
|
|
|
return payload
|
|
.filter((channel): channel is DiscordChannelPayload => {
|
|
if (!channel || typeof channel !== "object") return false;
|
|
const type = (channel as DiscordChannelPayload).type;
|
|
return type === 2 || type === 13;
|
|
})
|
|
.filter((channel) => (
|
|
typeof channel.id === "string"
|
|
&& typeof channel.name === "string"
|
|
))
|
|
.map((channel) => ({
|
|
id: channel.id as string,
|
|
name: channel.name as string,
|
|
type: channel.type as 2 | 13,
|
|
position: typeof channel.position === "number" ? channel.position : 0,
|
|
}))
|
|
.sort((a, b) => a.position - b.position || a.name.localeCompare(b.name, "th"));
|
|
}
|
|
|
|
export async function getCurrentDiscordVoiceChannels() {
|
|
if (channelCache.data && Date.now() < channelCache.expiresAt) {
|
|
return channelCache.data;
|
|
}
|
|
|
|
const { token, guildId } = getDiscordServerConfig();
|
|
|
|
const response = await fetch(
|
|
`https://discord.com/api/v10/guilds/${guildId}/channels`,
|
|
{
|
|
headers: { Authorization: `Bot ${token}` },
|
|
cache: "no-store",
|
|
signal: AbortSignal.timeout(5_000),
|
|
},
|
|
);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Discord channel request failed with status ${response.status}.`);
|
|
}
|
|
|
|
const channels = parseCurrentVoiceChannels(await response.json());
|
|
channelCache.data = channels;
|
|
channelCache.expiresAt = Date.now() + CHANNEL_CACHE_TTL_MS;
|
|
return channels;
|
|
}
|