40 lines
1.1 KiB
TypeScript
40 lines
1.1 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import { Download } from "lucide-react";
|
||
|
|
import { Button } from "@/components/ui/button";
|
||
|
|
|
||
|
|
function formatDuration(sec?: number | null): string {
|
||
|
|
if (!sec) return "";
|
||
|
|
const m = Math.floor(sec / 60);
|
||
|
|
const s = sec % 60;
|
||
|
|
return `${m}:${String(s).padStart(2, "0")}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function AudioPlayer({
|
||
|
|
storageKey,
|
||
|
|
durationSec,
|
||
|
|
}: {
|
||
|
|
storageKey: string;
|
||
|
|
durationSec?: number | null;
|
||
|
|
}) {
|
||
|
|
const src = `/api/assets/${storageKey}`;
|
||
|
|
return (
|
||
|
|
<div className="space-y-3">
|
||
|
|
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
|
||
|
|
<audio controls src={src} className="w-full" preload="metadata" />
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
{durationSec ? (
|
||
|
|
<span className="text-xs text-muted-foreground">Length {formatDuration(durationSec)}</span>
|
||
|
|
) : (
|
||
|
|
<span />
|
||
|
|
)}
|
||
|
|
<Button asChild variant="outline" size="sm">
|
||
|
|
<a href={`${src}?download=1`} download>
|
||
|
|
<Download className="h-4 w-4" /> Download MP3
|
||
|
|
</a>
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|