export const DISCORD_ID = "1014549805608992901"; const LANYARD_API = `https://api.lanyard.rest/v1/users/${DISCORD_ID}`; export const LANYARD_WS = "wss://api.lanyard.rest/socket"; export type DiscordStatus = "online" | "idle" | "dnd" | "offline"; export interface LanyardEmoji { name: string; id?: string; animated?: boolean; } export interface LanyardActivityAssets { large_image?: string; large_text?: string; small_image?: string; small_text?: string; } export interface LanyardActivity { id: string; name: string; type: number; state?: string | null; details?: string | null; emoji?: LanyardEmoji | null; timestamps?: { start?: number; end?: number } | null; application_id?: string | null; assets?: LanyardActivityAssets | null; } export function activityImageUrl(activity: LanyardActivity, small: boolean): string | null { const key = small ? activity.assets?.small_image : activity.assets?.large_image; if (!key) { return null; } if (key.startsWith("mp:")) { return `https://media.discordapp.net/external/${key.slice(3)}`; } if (key.startsWith("spotify:")) { return `https://i.scdn.co/image/${key.slice("spotify:".length)}`; } if (activity.application_id) { return `https://cdn.discordapp.com/app-assets/${activity.application_id}/${key}.png`; } return null; } export interface LanyardSpotify { track_id: string; timestamps: { start: number; end: number; }; song: string; artist: string; album: string; album_art_url: string | null; } export function formatSpotifyList(value: string | null | undefined): string { if (!value) { return ""; } return value .replace(/;/g, ",") .replace(/,[ \t]+,/g, ",") .replace(/\s{2,}/g, " ") .trim(); } export function spotifyTrackUrl(trackId: string): string { return `https://open.spotify.com/track/${trackId}`; } export function discordAppIconUrl( applicationId: string, iconHash: string | null, size = 128, ): string | null { if (!iconHash) { return null; } const extension = iconHash.startsWith("a_") ? "gif" : "png"; return `https://cdn.discordapp.com/app-icons/${applicationId}/${iconHash}.${extension}?size=${size}`; } export function discordGameUrl(gameId: string): string { return `https://discord.com/games/${gameId}`; } export interface DiscordAppInfo { id: string; name: string; icon: string | null; iconUrl: string | null; coverImage: string | null; coverUrl: string | null; gameId: string; gameUrl: string; } interface DiscordRpcResponse { id: string; name: string; icon?: string | null; cover_image?: string | null; linked_games?: Array<{ id: string }> | null; } export async function getDiscordAppInfo(applicationId: string): Promise { if (!/^\d+$/.test(applicationId)) { return null; } try { const response = await fetch( `https://discord.com/api/v10/applications/${applicationId}/rpc`, { headers: { "User-Agent": "fristy.net (personal site)" }, next: { revalidate: 86_400 }, }, ); if (!response.ok) { return null; } const json = (await response.json()) as DiscordRpcResponse; const gameId = json.linked_games?.[0]?.id ?? json.id ?? applicationId; return { id: json.id ?? applicationId, name: json.name ?? "", icon: json.icon ?? null, iconUrl: discordAppIconUrl(applicationId, json.icon ?? null), coverImage: json.cover_image ?? null, coverUrl: json.cover_image ? `https://cdn.discordapp.com/app-icons/${applicationId}/${json.cover_image}.png?size=512` : null, gameId, gameUrl: discordGameUrl(gameId), }; } catch { return null; } } export interface LanyardData { discord_user: { id: string; username: string; global_name: string | null; display_name: string | null; discriminator: string; avatar: string | null; bot: boolean; }; activities: LanyardActivity[]; discord_status: DiscordStatus; active_on_discord_desktop: boolean; active_on_discord_mobile: boolean; active_on_discord_web: boolean; listening_to_spotify: boolean; spotify: LanyardSpotify | null; } interface LanyardResponse { success: boolean; data: LanyardData; } export async function getLanyard(): Promise { try { const response = await fetch(LANYARD_API, { next: { revalidate: 10 } }); if (!response.ok) { return null; } const json = (await response.json()) as LanyardResponse; return json.success ? json.data : null; } catch { return null; } } export function lanyardUrl(): string { return LANYARD_API; } export function discordAvatarUrl(userId: string, avatarHash: string | null, size = 128): string { if (!avatarHash) { return `https://cdn.discordapp.com/embed/avatars/0.png?size=${size}`; } const extension = avatarHash.startsWith("a_") ? "gif" : "png"; return `https://cdn.discordapp.com/avatars/${userId}/${avatarHash}.${extension}?size=${size}`; } export function discordProfileUrl(userId: string): string { return `https://discord.com/users/${userId}`; }