@lobehub/tts
Version:
A high-quality & reliable TTS React Hooks library
115 lines (113 loc) • 3.51 kB
JavaScript
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 };