UNPKG

lrc-maker

Version:

歌词滚动姬|可能是你所能见到的最好用的歌词制作工具

129 lines 5.85 kB
import { convertTimeToTag } from "../lrc-parser.js"; import { audioRef, audioStatePubSub, currentTimePubSub } from "../utils/audiomodule.js"; import { loadAudioDialogRef } from "./loadaudio.js"; import { Forward5sSVG, LoadAudioSVG, PauseSVG, PlaySVG, Replay5sSVG } from "./svg.js"; const { useState, useEffect, useRef, useCallback, useMemo } = React; const Slider = ({ min, max, step, value, onInput, className }) => { const total = max - min || 1; const percent = (value - min) / total; return (React.createElement("div", { className: `slider ${className}-slider` }, React.createElement("progress", { value: percent }), React.createElement("input", { type: "range", className: className, "aria-label": className, min: min, max: max, step: step, value: value, onInput: onInput }))); }; const TimeLine = ({ duration, paused }) => { const self = useRef(Symbol(TimeLine.name)); const [currentTime, setCurrentTime] = useState(audioRef.currentTime); const [rate, setRate] = useState(audioRef.playbackRate); useEffect(() => { return audioStatePubSub.sub(self.current, (data) => { if (data.type === 2) { setRate(data.payload); } }); }, []); useEffect(() => { if (paused) { return currentTimePubSub.sub(self.current, (data) => { setCurrentTime(data); }); } else { const id = setInterval(() => { setCurrentTime(audioRef.currentTime); }, 500 / rate); return () => { clearInterval(id); }; } }, [paused, rate]); const rafId = useRef(0); const onInput = useCallback((ev) => { if (rafId.current) { cancelAnimationFrame(rafId.current); } const value = ev.target.value; rafId.current = requestAnimationFrame(() => { const time = Number.parseInt(value, 0); setCurrentTime(time); audioRef.currentTime = time; }); }, []); const durationTimeTag = useMemo(() => { return duration ? " / " + convertTimeToTag(duration, 0, false) : false; }, [duration]); return (React.createElement(React.Fragment, null, React.createElement("time", null, convertTimeToTag(currentTime, 0, false), durationTimeTag), React.createElement(Slider, { min: 0, max: duration, step: 1, value: currentTime, className: "timeline", onInput: onInput }))); }; const RateSlider = ({ lang }) => { const self = useRef(Symbol(RateSlider.name)); const [playbackRate, setPlaybackRate] = useState(audioRef.playbackRate); useEffect(() => { return audioStatePubSub.sub(self.current, (data) => { if (data.type === 2) { setPlaybackRate(data.payload); } }); }, []); const playbackRateSliderValue = useMemo(() => { return Math.log(playbackRate); }, [playbackRate]); const onPlaybackRateChange = useCallback((ev) => { const value = Math.exp(Number.parseFloat(ev.target.value)); setPlaybackRate(value); audioRef.playbackRate = value; }, []); const onPlaybackRateReset = useCallback(() => { audioRef.playbackRate = 1; }, []); return (React.createElement(React.Fragment, null, React.createElement("button", { className: "ripple glow", title: lang.audio.resetRate, onClick: onPlaybackRateReset }, "X ", playbackRate.toFixed(2)), React.createElement(Slider, { className: "playbackrate", min: -1, max: 1, step: "any", value: playbackRateSliderValue, onInput: onPlaybackRateChange }))); }; export const LrcAudio = ({ lang }) => { const self = useRef(Symbol(LrcAudio.name)); const [paused, setPaused] = useState(audioRef.paused); const [duration, setDuration] = useState(audioRef.duration); useEffect(() => { return audioStatePubSub.sub(self.current, (data) => { switch (data.type) { case 1: { setDuration(data.payload); setPaused(audioRef.paused); break; } case 0: { setPaused(data.payload); break; } } }); }, []); const onReplay5s = useCallback((ev) => { audioRef.step(ev, -5); }, []); const onForward5s = useCallback((ev) => { audioRef.step(ev, 5); }, []); const onPlayPauseToggle = useCallback(() => { audioRef.toggle(); }, []); const onLoadAudioButtonClick = useCallback(() => { loadAudioDialogRef.open(); }, []); return (React.createElement("section", { className: "lrc-audio" + (paused ? "" : " playing") }, React.createElement("button", { className: "ripple glow loadaudio-button", title: lang.audio.loadAudio, onClick: onLoadAudioButtonClick }, React.createElement(LoadAudioSVG, null)), React.createElement("button", { className: "ripple glow", title: lang.audio.replay5s, onClick: onReplay5s, disabled: !duration }, React.createElement(Replay5sSVG, null)), React.createElement("button", { className: "ripple glow", title: paused ? lang.audio.play : lang.audio.pause, disabled: !duration, onClick: onPlayPauseToggle }, paused ? React.createElement(PlaySVG, null) : React.createElement(PauseSVG, null)), React.createElement("button", { className: "ripple glow", title: lang.audio.forward5s, onClick: onForward5s, disabled: !duration }, React.createElement(Forward5sSVG, null)), React.createElement(TimeLine, { duration: duration, paused: paused }), React.createElement(RateSlider, { lang: lang }))); }; //# sourceMappingURL=audio.js.map