diff --git a/www/components/MediaPlayer.tsx b/www/components/MediaPlayer.tsx index 8dcfa0b..27fe8bf 100644 --- a/www/components/MediaPlayer.tsx +++ b/www/components/MediaPlayer.tsx @@ -63,6 +63,7 @@ export default function MediaPlayer({ blob }: { blob: Blob }) { + {currentTime || "--:--"} @@ -138,6 +139,9 @@ const CanvasContainer = styled.div` padding: 1rem 0; box-sizing: border-box; + display: flex; + flex-direction: row; + overflow: auto; -ms-overflow-style: none; /* IE and Edge */ @@ -151,6 +155,12 @@ const Canvas = styled.canvas` height: 100%; `; +const Spacer = styled.div` + height: 100%; + width: 100%; + flex-shrink: 0; +`; + const Duration = styled.div` display: flex; color: ${colors.blue}; diff --git a/www/shared/drawAudio.ts b/www/shared/drawAudio.ts index 3fbedc1..2d2740f 100644 --- a/www/shared/drawAudio.ts +++ b/www/shared/drawAudio.ts @@ -37,7 +37,7 @@ const draw = (normalizedData: number[]) => { const dpr = window.devicePixelRatio || 1; const padding = 10; const width = 8; - canvas.width = width * normalizedData.length; + canvas.width = width * normalizedData.length * dpr; canvas.height = (canvas.offsetHeight + padding * 2) * dpr; const ctx = canvas.getContext("2d"); ctx.scale(dpr, dpr); diff --git a/www/shared/useMediaPlayer.ts b/www/shared/useMediaPlayer.ts index 7e37e48..a32a4ae 100644 --- a/www/shared/useMediaPlayer.ts +++ b/www/shared/useMediaPlayer.ts @@ -2,17 +2,31 @@ import { useContext, useEffect, useState } from "react"; import { BlocksContext } from "./useBlocks"; import drawAudio from "./drawAudio"; -import { toast } from "react-toastify"; export default function useMediaPlayer(blob: Blob) { const { nextTrack } = useContext(BlocksContext); const [audio, setAudio] = useState(undefined); - const [currentTimeS, setCurrentTimeS] = useState(0); const [durationS, setDurationS] = useState(0); const [currentTime, setCurrentTime] = useState("00:00"); const [duration, setDuration] = useState(""); const [isPlaying, setIsPlaying] = useState(false); const [trackEnded, setTrackEnded] = useState(false); + const [canvasContainer, setCanvasContainer] = useState(undefined); + const [canvas, setCanvas] = useState(undefined); + const [stateInterval, setStateInterval] = useState(undefined); + + useEffect(() => { + const container = document.querySelector("#canvas-container"); + const canvas = document.querySelector("canvas"); + setCanvasContainer(container); + setCanvas(canvas); + + container.addEventListener("scroll", scroll); + + return () => { + container.removeEventListener("scroll", scroll); + }; + }); useEffect(() => { if (!blob) return; @@ -32,7 +46,7 @@ export default function useMediaPlayer(blob: Blob) { .substring(14, 19); setDuration(_duration); setAudio(audio); - if (trackEnded) audio.play(); + if (trackEnded) playMusic(); setTrackEnded(false); }; @@ -53,45 +67,73 @@ export default function useMediaPlayer(blob: Blob) { }); return () => { - if (!trackEnded) audio.pause(); + if (!trackEnded) pauseMusic(audio); timeout && clearTimeout(timeout); }; }, [blob]); - useEffect(() => { + function setReadableTime(seconds: number) { + const _currentTime = new Date(seconds * 1000) + .toISOString() + .substring(14, 19); + setCurrentTime(_currentTime); + } + + function playMusic() { if (!audio) return; + if (trackEnded) clearInterval(stateInterval); + + audio.play(); + const interval = setInterval(() => { const currentTimeS = audio.currentTime; - setCurrentTimeS(currentTimeS); - const _currentTime = new Date(currentTimeS * 1000) - .toISOString() - .substring(14, 19); - setCurrentTime(_currentTime); - }, 500); + scrollCanvasContainer(currentTimeS, durationS); + setReadableTime(currentTimeS); + }, 100); + + setStateInterval(interval); + } - return () => clearInterval(interval); - }, [audio]); + function pauseMusic(audio: HTMLAudioElement) { + audio.pause(); + clearInterval(stateInterval); + } function togglePlay() { if (!audio) return; setIsPlaying((prev) => { - prev ? audio.pause() : audio.play(); + prev ? pauseMusic(audio) : playMusic(); return !prev; }); } - useEffect(() => { + function scrollCanvasContainer( + currentTimeSeconds: number, + durationSeconds: number + ) { if (!audio) return; - const width = document.querySelector("#canvas-container").scrollWidth; - const widthPerSecond = width / durationS; - const scrollTo = widthPerSecond * currentTimeS; + const width = document.querySelector("canvas").scrollWidth; + const widthPerSecond = width / durationSeconds; + const scrollTo = widthPerSecond * currentTimeSeconds; document.querySelector("#canvas-container").scrollTo({ top: 0, left: scrollTo, behavior: "smooth", }); - }, [currentTimeS, durationS]); + } + + function scroll() { + if (!audio || !canvas || isPlaying) return; + + const newCurrentTimeS = Number( + ((durationS / canvas.scrollWidth) * canvasContainer.scrollLeft).toFixed(1) + ); + + setReadableTime(newCurrentTimeS); + + audio.currentTime = newCurrentTimeS; + } return { currentTime,