feat: add dynamic social media follower/member counts to profile links
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user