feat: add dynamic social media follower/member counts to profile links

This commit is contained in:
2026-06-20 20:41:37 +07:00 Unverified
parent c7e431d99e
commit 45945c0b07
5 changed files with 115 additions and 1 deletions
+21
View File
@@ -0,0 +1,21 @@
export async function getDiscordMemberCount(): Promise<number | null> {
const token = process.env.DISCORD_BOT_TOKEN;
const guildId = process.env.DISCORD_GUILD_ID;
if (!token || !guildId) return null;
try {
const res = await fetch(
`https://discord.com/api/v10/guilds/${encodeURIComponent(guildId)}?with_counts=true`,
{
headers: { Authorization: `Bot ${token}` },
next: { revalidate: 300 },
}
);
if (!res.ok) return null;
const data = await res.json();
return data.approximate_member_count ?? null;
} catch {
return null;
}
}
+48
View File
@@ -0,0 +1,48 @@
import { getYoutubeSubscriberCount } from "./youtube";
import { getRobloxFollowerCount } from "./roblox";
import { getDiscordMemberCount } from "./discord";
export interface FollowerCounts {
youtube: number | null;
roblox: number | null;
discord: number | null;
}
export interface FollowerInfo {
count: number;
label: string;
}
export async function getFollowerCounts(): Promise<FollowerCounts> {
const [youtube, roblox, discord] = await Promise.all([
getYoutubeSubscriberCount(),
getRobloxFollowerCount(),
getDiscordMemberCount(),
]);
return { youtube, roblox, discord };
}
const followerLabels: Record<keyof FollowerCounts, string> = {
youtube: "ผู้ติดตาม",
roblox: "ผู้ติดตาม",
discord: "สมาชิก",
};
export function getCountForLink(name: string, counts: FollowerCounts): FollowerInfo | null {
const key = name.toLowerCase();
for (const [platform, label] of Object.entries(followerLabels)) {
const count = counts[platform as keyof FollowerCounts];
if (key.includes(platform) && count !== null) {
return { count, label };
}
}
return null;
}
export function formatCount(n: number): string {
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
return n.toString();
}
+17
View File
@@ -0,0 +1,17 @@
export async function getRobloxFollowerCount(): Promise<number | null> {
const userId = process.env.ROBLOX_USER_ID;
if (!userId) return null;
try {
const res = await fetch(
`https://friends.roblox.com/v1/users/${encodeURIComponent(userId)}/followers/count`,
{ next: { revalidate: 300 } }
);
if (!res.ok) return null;
const data = await res.json();
return data.count ?? null;
} catch {
return null;
}
}
+19
View File
@@ -0,0 +1,19 @@
export async function getYoutubeSubscriberCount(): Promise<number | null> {
const apiKey = process.env.YOUTUBE_API_KEY;
const channelId = process.env.YOUTUBE_CHANNEL_ID;
if (!apiKey || !channelId) return null;
try {
const res = await fetch(
`https://www.googleapis.com/youtube/v3/channels?part=statistics&id=${encodeURIComponent(channelId)}&key=${encodeURIComponent(apiKey)}`,
{ next: { revalidate: 300 } }
);
if (!res.ok) return null;
const data = await res.json();
const count = data.items?.[0]?.statistics?.subscriberCount;
return count ? Number(count) : null;
} catch {
return null;
}
}