'use client' import { useState } from "react"; import { AudioLines, Loader2, RefreshCw } from "lucide-react"; import { Button } from "~/components/ui/button"; import { trpc } from "~/app/_trpc/Client"; import { useUploadThing } from "~/lib/uploadthing"; import { transcodeToAac } from "~/lib/ffmpeg/transcode"; import { toast } from "sonner"; import type { RouterOutputs } from "~/server/routers/_app"; import type { IterableElement } from "type-fest"; export default function ConvertToStreamButton(props: { track: IterableElement; }) { const { track } = props; const utils = trpc.useUtils(); const [busy, setBusy] = useState(false); const [stage, setStage] = useState(""); const [progress, setProgress] = useState(0); const setStream = trpc.music.setStream.useMutation({ onSuccess: () => utils.music.list.invalidate(), }); const { startUpload } = useUploadThing("musicUploader"); async function handleConvert() { setBusy(true); setProgress(0); let currentStage = "Loading ffmpeg"; const goto = (s: string) => { currentStage = s; setStage(s); }; try { goto("Transcoding"); const file = await transcodeToAac({ sourceUrl: track.fileUrl, outputName: `${track.title || "track"}.m4a`, onProgress: setProgress, }); goto("Uploading"); const uploaded = await startUpload([file]); const res = uploaded?.[0]; if (!res) throw new Error("Upload returned no file"); goto("Saving"); await setStream.mutateAsync({ id: track.id, streamUrl: res.serverData.fileUrl, streamKey: res.serverData.fileKey, streamName: res.serverData.fileName, }); toast("Streaming version saved"); } catch (e) { console.error("[ConvertToStream] failed during", currentStage, e); const detail = e instanceof Error ? e.message : typeof e === "string" ? e : (() => { try { return JSON.stringify(e); } catch { return String(e); } })(); toast(`Conversion failed (${currentStage}): ${detail || "see console for details"}`); } finally { setBusy(false); setStage(""); setProgress(0); } } return (
{track.streamUrl && !busy && ( Streaming version ready )}
); }