apatil 7627433107
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Add album cover image to track
2025-05-07 20:46:13 +01:00

75 lines
2.2 KiB
TypeScript

'use client';
import { Box, Typography, IconButton, Slider, useTheme, CardMedia } from '@mui/material';
import { PlayArrow, Pause, VolumeUp } from '@mui/icons-material';
import { useEffect, useRef, useState } from 'react';
export default function AudioPlayer({ src, title }: { src: string; title: string }) {
const audioRef = useRef<HTMLAudioElement | null>(null);
const [playing, setPlaying] = useState(false);
const [volume, setVolume] = useState(100);
const [coverUrl, setCoverUrl] = useState<string | null>(null);
const theme = useTheme();
const filename = src.split('/').pop();
useEffect(() => {
if (filename)
setCoverUrl(`/api/music/${encodeURIComponent(filename)}/cover`)
}, [filename])
const togglePlay = () => {
const audio = audioRef.current;
if (!audio) return;
if (playing) {
audio.pause();
} else {
audio.play();
}
setPlaying(!playing);
};
const handleVolumeChange = (event: Event, newValue: number | number[]) => {
const audio = audioRef.current;
if (!audio) return;
const vol = typeof newValue === 'number' ? newValue : newValue[0];
setVolume(vol);
audio.volume = vol / 100;
};
return (
<Box
sx={{
display: 'flex',
alignItems: 'center',
flexDirection: 'column',
bgcolor: theme.palette.background.paper,
p: 2,
borderRadius: 2,
boxShadow: 3,
width: '100%',
maxWidth: 400,
mx: 'auto',
}}
>
{
coverUrl && (
<CardMedia component={"img"} image={`${coverUrl}`} alt='Album cover' sx={{ width: '100%', height: 200, objectFit: 'cover', borderRadius: 2, mb: 2 }} />
)
}
<Typography variant="subtitle1" gutterBottom>{title}</Typography>
<Box display="flex" alignItems="center" gap={1}>
<IconButton onClick={togglePlay}>
{playing ? <Pause /> : <PlayArrow />}
</IconButton>
<VolumeUp />
<Slider
value={volume}
onChange={(e, val) => handleVolumeChange(e, val)}
aria-label="Volume"
sx={{ width: 100 }}
/>
</Box>
<audio ref={audioRef} src={src} onEnded={() => setPlaying(false)} />
</Box>
);
}