import { listSongs, readSong } from "@/lib/browse"; import { allContext, clipCitation, momentCitation, momentsContext, songContext } from "@/lib/context"; export const dynamic = "force-dynamic"; // The paste. Markdown, as text/plain, so `curl` gives you something you can // read and the UI can drop it straight on the clipboard. // // /api/browse/context?song=metal-slug one song // /api/browse/context every song // /api/browse/context?song=x&rel=y&t=42.3 one moment, resolved // /api/browse/context?song=x&rel=y every mark on that file // /api/browse/context?song=x&clip= one clip in the arrangement // // The moment form is the one that could not exist before: a timestamp on a // rendered file, turned back into the clip playing there and a link to that // moment in the archive. const text = (body: string) => new Response(body, { headers: { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store" }, }); export async function GET(request: Request) { const url = new URL(request.url); const id = url.searchParams.get("song"); const rel = url.searchParams.get("rel"); const t = url.searchParams.get("t"); if (!id) { const songs = await listSongs(); return text(await allContext(songs.map((s) => s.id))); } const song = await readSong(id); if (!song) return new Response("no such song", { status: 404 }); const clip = url.searchParams.get("clip"); if (clip) { if (!/^[A-Za-z0-9_-]+@[0-9.]+$/.test(clip)) return new Response("bad clip", { status: 400 }); return text(await clipCitation(id, clip)); } if (rel) { const known = [ ...song.cuts.flatMap((c) => [c.shipped, ...c.variants]), ...song.unattributed, ].some((r) => r && r.rel === rel); if (!known) return new Response("not a file in this song", { status: 404 }); // With a `t`, one moment. Without, every mark on that file -- which is what // the "copy N marks" button wants, and what citing only the first was // quietly doing wrong. if (t === null) return text(await momentsContext(id, rel)); const seconds = Number(t); if (!Number.isFinite(seconds) || seconds < 0) return new Response("bad t", { status: 400 }); return text(await momentCitation(id, rel, seconds, url.searchParams.get("note") ?? undefined)); } return text(await songContext(id)); }