import { NextResponse } from "next/server"; import { getTiktokProfile } from "@/lib/followers/tiktok"; export async function POST(req: Request) { try { if (process.env.TIKTOK_WEBHOOK_SECRET) { const { searchParams } = new URL(req.url); if (searchParams.get("secret") !== process.env.TIKTOK_WEBHOOK_SECRET) { console.error("[TikTok Webhook] Unauthorized request: invalid or missing secret query parameter."); return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); } } // Read the body as text first in case it's not JSON or for signature verification if needed const rawBody = await req.text(); let body: any = {}; if (rawBody) { try { body = JSON.parse(rawBody); } catch (e) { console.error("[TikTok Webhook] Failed to parse JSON:", rawBody); } } console.log("[TikTok Webhook] Received payload:", JSON.stringify(body, null, 2)); const event = body.event || body.type || body.Event; const data = body.data || body.Data || body; let message = ""; let embed: any = null; // Fetch the user's official TikTok profile to use for author name & avatar let officialAuthorName = "TikTok"; let officialAvatarUrl: string | undefined = undefined; try { const profile = await getTiktokProfile(); if (profile.displayName) officialAuthorName = profile.displayName; if (profile.avatarUrl) officialAvatarUrl = profile.avatarUrl; } catch (e) { console.error("[TikTok Webhook] Failed to fetch profile:", e); } // Check if it's a video upload or live event if (typeof event === "string") { const eventLower = event.toLowerCase(); if (eventLower.includes("video") && (eventLower.includes("upload") || eventLower.includes("publish"))) { const link = data.share_url || data.url || data.video_url || data.link || ""; let title = data.title || data.video_title || data.desc || "คลิปใหม่จาก TikTok"; let thumbnailUrl = data.cover_url || data.thumbnail_url || ""; // Default to official profile info let authorName = officialAuthorName; let authorAvatar = officialAvatarUrl || ""; if (link && link.includes("tiktok.com")) { try { // Using tikwm API for video thumbnail and title const oembedRes = await fetch(`https://www.tikwm.com/api/?url=${encodeURIComponent(link)}`); if (oembedRes.ok) { const oembedData = await oembedRes.json(); if (oembedData.data) { if (oembedData.data.title) title = oembedData.data.title; if (oembedData.data.cover) thumbnailUrl = oembedData.data.cover; // If the official API failed for some reason, fallback to tikwm author info if (officialAuthorName === "TikTok" && oembedData.data.author?.nickname) authorName = oembedData.data.author.nickname; if (!officialAvatarUrl && oembedData.data.author?.avatar) authorAvatar = oembedData.data.author.avatar; } } } catch (e) { console.error("[TikTok Webhook] Failed to fetch video info:", e); } } message = `ลงคลิปใหม่แล้วววสสสสส ${link}`; embed = { title: title, url: link || undefined, color: 0xff0050, author: { name: authorName, url: link || "https://www.tiktok.com/", icon_url: authorAvatar || undefined }, image: thumbnailUrl ? { url: thumbnailUrl } : undefined }; } else if (eventLower.includes("live")) { const link = data.share_url || data.url || data.room_url || data.link || ""; const title = data.title || data.live_title || data.desc || ""; message = `${link}`; embed = { title: title, url: link || undefined, color: 0xff0050, author: { name: officialAuthorName, url: "https://www.tiktok.com/", icon_url: officialAvatarUrl || undefined }, thumbnail: officialAvatarUrl ? { url: officialAvatarUrl } : undefined }; } } else { // Fallback: search payload keys for indicators const payloadStr = JSON.stringify(body).toLowerCase(); if (payloadStr.includes("video") && (payloadStr.includes("upload") || payloadStr.includes("publish"))) { message = `คลิปใหม่!`; } else if (payloadStr.includes("live")) { message = `Live!`; } } if (message) { await sendDiscordNotification(message, embed); } return NextResponse.json({ success: true }, { status: 200 }); } catch (error) { console.error("[TikTok Webhook] Error processing request:", error); return NextResponse.json({ error: "Internal Server Error" }, { status: 500 }); } } async function sendDiscordNotification(content: string, embed?: any) { const token = process.env.DISCORD_BOT_TOKEN; const channelId = process.env.DISCORD_CHANNEL_ID; if (!token) { console.error("[TikTok Webhook] Missing DISCORD_BOT_TOKEN"); return; } if (!channelId) { console.error("[TikTok Webhook] Missing DISCORD_CHANNEL_ID environment variable. Please add it to your .env file."); return; } try { const res = await fetch(`https://discord.com/api/v10/channels/${channelId}/messages`, { method: "POST", headers: { "Authorization": `Bot ${token}`, "Content-Type": "application/json" }, body: JSON.stringify({ content, embeds: embed ? [embed] : undefined }) }); if (!res.ok) { console.error("[TikTok Webhook] Failed to send Discord message:", await res.text()); } else { console.log("[TikTok Webhook] Successfully sent Discord message"); } } catch (error) { console.error("[TikTok Webhook] Error sending Discord message:", error); } }