From 12c9b21d67378c2b36173e6d4b635b0fcb27534b Mon Sep 17 00:00:00 2001 From: thororen <78185467+thororen1234@users.noreply.github.com> Date: Sat, 26 Sep 2026 21:13:15 -0400 Subject: [PATCH] BetterAudioPlayer: Dont Use Observer --- .../betterAudioPlayer/index.tsx | 165 ++++++------------ 1 file changed, 49 insertions(+), 116 deletions(-) diff --git a/src/equicordplugins/betterAudioPlayer/index.tsx b/src/equicordplugins/betterAudioPlayer/index.tsx index 94c3d9770..5784f4bf8 100644 --- a/src/equicordplugins/betterAudioPlayer/index.tsx +++ b/src/equicordplugins/betterAudioPlayer/index.tsx @@ -13,12 +13,11 @@ import definePlugin, { OptionType } from "@utils/types"; import { ColorUtils, React, showToast, Toasts } from "@webpack/common"; const cl = classNameFactory("vc-better-audio-player-"); -const CORS_PROXY = "https://cors.keiran0.workers.dev?url="; -const MAX_FILE_SIZE = 12e6; interface PlayerInstance { - mediaRef: React.RefObject; - props: { src: string; type: string; }; + mediaRef: React.RefObject; + props: { type: string; }; + state: { playing: boolean; }; } function validateColor(value: string, key: string, fallback: string) { @@ -99,134 +98,62 @@ function drawSpectrograph(ctx: CanvasRenderingContext2D, w: number, h: number, f } } -async function fetchAudioBlob(src: string): Promise { - const url = new URL(src); - url.searchParams.set("t", Date.now().toString()); - - const response = await fetch(CORS_PROXY + encodeURIComponent(url.href)); - const contentLength = response.headers.get("content-length"); - if (contentLength && Number(contentLength) > MAX_FILE_SIZE) return null; - - const blob = await response.blob(); - return URL.createObjectURL(blob); -} - -function Visualizer({ playerRef, src }: { playerRef: React.RefObject; src: string; }) { +function Visualizer({ mediaRef, playing }: { mediaRef: PlayerInstance["mediaRef"]; playing: boolean; }) { const canvasRef = React.useRef(null); - const audioCtxRef = React.useRef(null); - const analyserRef = React.useRef(null); - const animFrameRef = React.useRef(0); - const setupDoneRef = React.useRef(false); - const blobUrlRef = React.useRef(null); + const graphRef = React.useRef<{ ctx: AudioContext; analyser: AnalyserNode; } | null>(null); React.useEffect(() => { - const audio = playerRef.current; - const canvas = canvasRef.current; - if (!audio || !canvas) return () => { }; + const audio = mediaRef.current; + const canvasCtx = canvasRef.current?.getContext("2d"); + if (!playing || !audio || !canvasCtx) return; - let cancelled = false; - - const init = async () => { - const blobUrl = await fetchAudioBlob(src).catch(() => null); - if (cancelled || !blobUrl) return; - - blobUrlRef.current = blobUrl; - - const wasPlaying = !audio.paused; - const { currentTime } = audio; - audio.src = blobUrl; - audio.currentTime = currentTime; - - const audioCtx = new AudioContext(); - const analyser = audioCtx.createAnalyser(); + if (!graphRef.current) { + const ctx = new AudioContext(); + const analyser = ctx.createAnalyser(); analyser.fftSize = 2048; - const source = audioCtx.createMediaElementSource(audio); - source.connect(analyser); - analyser.connect(audioCtx.destination); - audioCtxRef.current = audioCtx; - analyserRef.current = analyser; - setupDoneRef.current = true; + ctx.createMediaElementSource(audio).connect(analyser); + analyser.connect(ctx.destination); + graphRef.current = { ctx, analyser }; + } - if (wasPlaying) { - audio.play().catch(() => { }); - } - }; + const { ctx, analyser } = graphRef.current; + ctx.resume(); - const canvasCtx = canvas.getContext("2d"); - let dataArray: Uint8Array | null = null; - let frequencyData: Uint8Array | null = null; + const dataArray = new Uint8Array(analyser.frequencyBinCount); + const frequencyData = new Uint8Array(analyser.frequencyBinCount); + let frame = 0; const draw = () => { - const analyser = analyserRef.current; - if (!canvasCtx || !analyser) return; - - if (!dataArray || !frequencyData) { - const bufferLength = analyser.frequencyBinCount; - dataArray = new Uint8Array(bufferLength); - frequencyData = new Uint8Array(bufferLength); - } - - if (!audio.paused) animFrameRef.current = requestAnimationFrame(draw); + frame = requestAnimationFrame(draw); analyser.getByteTimeDomainData(dataArray); analyser.getByteFrequencyData(frequencyData); - const { width, height } = canvas.getBoundingClientRect(); + const { canvas } = canvasCtx; + const width = canvas.clientWidth; + const height = canvas.clientHeight; + const dpr = window.devicePixelRatio; + const pixelWidth = Math.round(width * dpr); + const pixelHeight = Math.round(height * dpr); + if (canvas.width !== pixelWidth || canvas.height !== pixelHeight) { + canvas.width = pixelWidth; + canvas.height = pixelHeight; + canvasCtx.setTransform(dpr, 0, 0, dpr, 0, 0); + } + canvasCtx.clearRect(0, 0, width, height); if (settings.store.oscilloscope) drawOscilloscope(canvasCtx, width, height, dataArray, dataArray.length); if (settings.store.spectrograph) drawSpectrograph(canvasCtx, width, height, frequencyData, frequencyData.length); }; - - const onPlay = () => { - if (!setupDoneRef.current) return; - if (audioCtxRef.current?.state === "suspended") { - audioCtxRef.current.resume(); - } - draw(); - }; - - const onPause = () => { - audioCtxRef.current?.suspend(); - cancelAnimationFrame(animFrameRef.current); - }; - - audio.addEventListener("play", onPlay); - audio.addEventListener("pause", onPause); - init(); + draw(); return () => { - cancelled = true; - audio.removeEventListener("play", onPlay); - audio.removeEventListener("pause", onPause); - cancelAnimationFrame(animFrameRef.current); - audioCtxRef.current?.close(); - audioCtxRef.current = null; - analyserRef.current = null; - setupDoneRef.current = false; - if (blobUrlRef.current) { - URL.revokeObjectURL(blobUrlRef.current); - blobUrlRef.current = null; - } + cancelAnimationFrame(frame); + ctx.suspend(); }; - }, [playerRef]); + }, [playing]); - React.useEffect(() => { - const canvas = canvasRef.current; - if (!canvas) return () => { }; - - const resize = () => { - const rect = canvas.getBoundingClientRect(); - canvas.width = rect.width * window.devicePixelRatio; - canvas.height = rect.height * window.devicePixelRatio; - const ctx = canvas.getContext("2d"); - ctx?.scale(window.devicePixelRatio, window.devicePixelRatio); - }; - - resize(); - const observer = new ResizeObserver(resize); - observer.observe(canvas); - return () => observer.disconnect(); - }, []); + React.useEffect(() => () => void graphRef.current?.ctx.close(), []); return ( ; + return ; }, });