import { notFound } from "next/navigation"; import type { Metadata } from "next"; import { query, getTempoMapsForSong } from "@/lib/db/client"; import type { SongRow } from "@/lib/db/client"; import TempoMapEditor from "@/components/TempoMapEditor"; import ClickTrackPlayer from "@/components/ClickTrackPlayer"; import type { CTPDocument } from "@/lib/ctp/schema"; interface PageProps { params: { id: string }; } async function getSong(mbid: string): Promise { const { rows } = await query( "SELECT * FROM songs WHERE mbid = $1", [mbid] ); return rows[0] ?? null; } export async function generateMetadata({ params }: PageProps): Promise { const song = await getSong(params.id); if (!song) return { title: "Track not found" }; return { title: `${song.title} — ${song.artist}` }; } export default async function TrackPage({ params }: PageProps) { const song = await getSong(params.id); if (!song) notFound(); const tempoMaps = await getTempoMapsForSong(params.id); const bestMap = tempoMaps.find((m) => m.verified) ?? tempoMaps[0] ?? null; return (
{/* Song header */}

Click Track

{song.title}

{song.artist}

{song.duration_seconds && (

{Math.floor(song.duration_seconds / 60)}m{" "} {Math.round(song.duration_seconds % 60)}s

)}
{/* Player / Download */} {bestMap ? ( ) : (

No tempo map yet

Be the first to contribute a tempo map for this song via the community registry.

)} {/* Tempo map editor / viewer */} {bestMap && (

Tempo Map

)} {/* All maps */} {tempoMaps.length > 1 && (

All community maps ({tempoMaps.length})

    {tempoMaps.map((m) => (
  • By{" "} {(m.ctp_data as { metadata?: { contributed_by?: string } }).metadata?.contributed_by ?? "unknown"}
    {m.verified && ( verified )} {m.upvotes} upvotes
  • ))}
)}
); }