UNPKG

@lobehub/tts

Version:

A high-quality & reliable TTS React Hooks library

115 lines (113 loc) 3.51 kB
import { useCallback, useEffect, useRef, useState } from "react"; import useSWR from "swr"; //#region src/react/hooks/useAudioPlayer.ts const useAudioPlayer = ({ src, type = "audio/mp3" } = {}) => { const audioRef = useRef(null); const [arrayBuffers, setArrayBuffers] = useState([]); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); const [isPlaying, setIsPlaying] = useState(false); const [isGlobalLoading, setIsGlobalLoading] = useState(true); const { isLoading } = useSWR(src || null, async () => { if (!src) return; setIsGlobalLoading(true); const arrayBuffer = await (await fetch(src)).arrayBuffer(); setArrayBuffers([arrayBuffer]); const newBlob = new Blob([arrayBuffer], { type }); if (!audioRef.current) audioRef.current = new Audio(); audioRef.current.pause(); audioRef.current.currentTime = 0; if (audioRef.current.src) URL.revokeObjectURL(audioRef.current.src); audioRef.current.src = URL.createObjectURL(newBlob); audioRef.current.load(); }); useEffect(() => { if (!audioRef.current) audioRef.current = new Audio(); const onLoadedMetadata = () => { if (!audioRef.current) return; setDuration(audioRef.current.duration); setIsGlobalLoading(false); }; const onTimeUpdate = () => { if (!audioRef.current) return; setCurrentTime(audioRef.current.currentTime); }; const onEnded = async () => { if (!audioRef.current) return; setIsPlaying(false); audioRef.current.currentTime = 0; setCurrentTime(0); }; audioRef.current.addEventListener("ended", onEnded); audioRef.current.addEventListener("loadedmetadata", onLoadedMetadata); audioRef.current.addEventListener("timeupdate", onTimeUpdate); return () => { if (!audioRef.current) return; audioRef.current.pause(); audioRef.current.load(); audioRef.current.removeEventListener("ended", onEnded); audioRef.current.removeEventListener("loadedmetadata", onLoadedMetadata); audioRef.current.removeEventListener("timeupdate", onTimeUpdate); setIsGlobalLoading(true); }; }, []); const handlePlay = useCallback(() => { try { if (!audioRef.current) return; setIsPlaying(true); audioRef.current?.play(); } catch { setTimeout(() => { handlePlay(); }, 200); } }, []); const handlePause = useCallback(() => { if (!audioRef.current) return; setIsPlaying(false); audioRef.current.pause(); }, []); const handleStop = useCallback(() => { if (!audioRef.current) return; setIsPlaying(false); audioRef.current.pause(); audioRef.current.currentTime = 0; }, []); const setTime = useCallback((value) => { if (!audioRef.current) return; setCurrentTime(value); audioRef.current.currentTime = value; }, []); const reset = useCallback(() => { if (!audioRef.current) return; audioRef.current.pause(); audioRef.current.currentTime = 0; if (audioRef.current.src) URL.revokeObjectURL(audioRef.current.src); audioRef.current.src = ""; setDuration(0); setCurrentTime(0); }, []); return { arrayBuffers, currentTime, download: useCallback(async () => { if (!audioRef.current) return; const a = document.createElement("a"); a.href = audioRef.current.src; a.download = "audio.mp3"; a.click(); }, []), duration, isLoading: isLoading || isGlobalLoading, isPlaying, pause: handlePause, play: handlePlay, ref: audioRef, reset, setTime, stop: handleStop, url: audioRef?.current?.src || "" }; }; //#endregion export { useAudioPlayer };