Files
vibepod/podcast-forge/hooks/useAudioPlayer.ts
T

95 lines
2.7 KiB
TypeScript

"use client";
import { useCallback, useEffect, useRef, useState } from "react";
interface AudioPlayerState {
isPlaying: boolean;
currentTime: number;
duration: number;
volume: number;
}
export function useAudioPlayer(audioUrl: string | null) {
const audioRef = useRef<HTMLAudioElement | null>(null);
const [state, setState] = useState<AudioPlayerState>({
isPlaying: false,
currentTime: 0,
duration: 0,
volume: 1,
});
// Create/replace the Audio element whenever the URL changes
useEffect(() => {
if (!audioUrl) {
if (audioRef.current) {
audioRef.current.pause();
audioRef.current = null;
}
setState({ isPlaying: false, currentTime: 0, duration: 0, volume: 1 });
return;
}
const audio = new Audio(audioUrl);
audioRef.current = audio;
const onTimeUpdate = () =>
setState((prev) => ({ ...prev, currentTime: audio.currentTime }));
const onDurationChange = () =>
setState((prev) => ({ ...prev, duration: audio.duration }));
const onEnded = () =>
setState((prev) => ({ ...prev, isPlaying: false, currentTime: 0 }));
const onPlay = () => setState((prev) => ({ ...prev, isPlaying: true }));
const onPause = () => setState((prev) => ({ ...prev, isPlaying: false }));
audio.addEventListener("timeupdate", onTimeUpdate);
audio.addEventListener("durationchange", onDurationChange);
audio.addEventListener("loadedmetadata", onDurationChange);
audio.addEventListener("ended", onEnded);
audio.addEventListener("play", onPlay);
audio.addEventListener("pause", onPause);
return () => {
audio.pause();
audio.removeEventListener("timeupdate", onTimeUpdate);
audio.removeEventListener("durationchange", onDurationChange);
audio.removeEventListener("loadedmetadata", onDurationChange);
audio.removeEventListener("ended", onEnded);
audio.removeEventListener("play", onPlay);
audio.removeEventListener("pause", onPause);
};
}, [audioUrl]);
const toggle = useCallback(() => {
const audio = audioRef.current;
if (!audio) return;
if (audio.paused) {
audio.play();
} else {
audio.pause();
}
}, []);
const seek = useCallback((time: number) => {
const audio = audioRef.current;
if (!audio) return;
audio.currentTime = Math.max(0, Math.min(time, audio.duration));
}, []);
const setVolume = useCallback((v: number) => {
const audio = audioRef.current;
if (!audio) return;
audio.volume = Math.max(0, Math.min(1, v));
setState((prev) => ({ ...prev, volume: v }));
}, []);
return {
isPlaying: state.isPlaying,
currentTime: state.currentTime,
duration: state.duration,
volume: state.volume,
toggle,
seek,
setVolume,
};
}