75 lines
2.2 KiB
TypeScript
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>
|
|
);
|
|
} |