Add YouTube transcripts tab to Mission Control
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
/**
|
||||
* POST /api/discord
|
||||
*
|
||||
* Receives a formatted message and forwards it to a Discord webhook.
|
||||
* The DISCORD_WEBHOOK_URL environment variable must be set for messages to be sent.
|
||||
*
|
||||
* Body:
|
||||
* {
|
||||
* channel: "morning" | "eod" | "amun",
|
||||
* source: "horus" | "amun",
|
||||
* date: "YYYY-MM-DD",
|
||||
* formatted_text: "Markdown-style message string"
|
||||
* }
|
||||
*
|
||||
* Example curl:
|
||||
* curl -X POST http://localhost:3000/api/discord \
|
||||
* -H "Content-Type: application/json" \
|
||||
* -d '{
|
||||
* "channel": "morning",
|
||||
* "source": "horus",
|
||||
* "date": "2026-02-27",
|
||||
* "formatted_text": "☀ **Morning Brief — 27 Feb 2026**\n📍 Benalmádena, 22°C Sunny\n📈 BTC: $68,000 (+2.5%)\n⚡ Priorities: 5 set"
|
||||
* }'
|
||||
*
|
||||
* Note: Add Authorization: Bearer <token> header when auth is implemented.
|
||||
*/
|
||||
|
||||
interface DiscordPayload {
|
||||
channel: "morning" | "eod" | "amun";
|
||||
source: "horus" | "amun";
|
||||
date: string;
|
||||
formatted_text: string;
|
||||
}
|
||||
|
||||
const channelEmoji: Record<string, string> = {
|
||||
morning: "☀",
|
||||
eod: "🌙",
|
||||
amun: "⚙️",
|
||||
};
|
||||
|
||||
const sourceEmoji: Record<string, string> = {
|
||||
horus: "🦅",
|
||||
amun: "⚙️",
|
||||
};
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body: DiscordPayload = await request.json();
|
||||
|
||||
// Validate required fields
|
||||
if (!body.channel || !body.source || !body.date || !body.formatted_text) {
|
||||
return NextResponse.json(
|
||||
{ error: "Missing required fields: channel, source, date, formatted_text" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!["morning", "eod", "amun"].includes(body.channel)) {
|
||||
return NextResponse.json(
|
||||
{ error: "channel must be one of: morning, eod, amun" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
if (!["horus", "amun"].includes(body.source)) {
|
||||
return NextResponse.json(
|
||||
{ error: "source must be one of: horus, amun" },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
const webhookUrl = process.env.DISCORD_WEBHOOK_URL;
|
||||
|
||||
if (!webhookUrl) {
|
||||
// Webhook not configured — log and return success (non-blocking)
|
||||
console.log(
|
||||
`[Discord] Webhook not configured. Would have sent to #${body.channel}:`,
|
||||
body.formatted_text.slice(0, 100)
|
||||
);
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
sent: false,
|
||||
reason: "DISCORD_WEBHOOK_URL not configured",
|
||||
});
|
||||
}
|
||||
|
||||
// Build Discord embed
|
||||
const embed = {
|
||||
title: `${channelEmoji[body.channel]} ${body.channel.charAt(0).toUpperCase() + body.channel.slice(1)} Brief — ${body.date}`,
|
||||
description: body.formatted_text,
|
||||
color:
|
||||
body.channel === "morning"
|
||||
? 0xf59e0b // amber
|
||||
: body.channel === "eod"
|
||||
? 0x3b82f6 // blue
|
||||
: 0x8b5cf6, // purple
|
||||
footer: {
|
||||
text: `${sourceEmoji[body.source]} Sent by ${body.source.charAt(0).toUpperCase() + body.source.slice(1)}`,
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
const discordRes = await fetch(webhookUrl, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
username: "Horus & Amun",
|
||||
avatar_url: "https://cdn.discordapp.com/embed/avatars/0.png",
|
||||
embeds: [embed],
|
||||
}),
|
||||
});
|
||||
|
||||
if (!discordRes.ok) {
|
||||
const errText = await discordRes.text();
|
||||
console.error("[Discord] Webhook failed:", discordRes.status, errText);
|
||||
return NextResponse.json(
|
||||
{ error: "Discord webhook failed", status: discordRes.status },
|
||||
{ status: 502 }
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json({ ok: true, sent: true });
|
||||
} catch (error) {
|
||||
console.error("POST /api/discord error:", error);
|
||||
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user