From 782159c7a965203f4f134dabe13634e59b579cc7 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Wed, 15 Nov 2023 01:41:32 -0800 Subject: feat: add support for srv3 --- src/app/App.tsx | 288 ++++++++++++++++++++++++++++++----- src/app/components/VideoControls.tsx | 153 +++++++++++++++++++ 2 files changed, 404 insertions(+), 37 deletions(-) create mode 100644 src/app/components/VideoControls.tsx (limited to 'src') diff --git a/src/app/App.tsx b/src/app/App.tsx index 871e387..e813cae 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -1,8 +1,10 @@ -import React, { useEffect, useRef, useState } from 'react'; -import styled from 'styled-components'; -import KaraokePlayer from './components/KaraokePlayer'; -import { toast, ToastContainer } from 'react-toastify'; -import 'react-toastify/dist/ReactToastify.css'; +import React, { useEffect, useRef, useState } from "react"; +import styled from "styled-components"; +import KaraokePlayer from "./components/KaraokePlayer"; +import { toast, ToastContainer } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; +import { FaPlay, FaPause, FaVolumeUp, FaVolumeMute } from "react-icons/fa"; +import { CaptionsRenderer } from "react-srv3"; const Root = styled.div` position: absolute; @@ -24,7 +26,7 @@ const FileInputContainer = styled.div` padding: 10px; border-radius: 5px; background-color: #ffffff; - box-shadow: 0 2px 4px rgba(0,0,0,0.1); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); `; const FileInput = styled.input` @@ -33,7 +35,8 @@ const FileInput = styled.input` border: 1px solid #ddd; cursor: pointer; display: none; - &:hover, &:focus { + &:hover, + &:focus { background-color: #eaeaea; outline: none; } @@ -44,21 +47,25 @@ const FileInputLabel = styled.label` border-radius: 5px; border: 1px solid #ddd; cursor: pointer; - &:hover, &:focus { + &:hover, + &:focus { background-color: #eaeaea; outline: none; } `; - function App() { - const [currentMillisecond, setCurrentMillisecond] = useState(0); - const [lrcContent, setLrcContent] = useState(''); - const [videoUrl, setVideoUrl] = useState(''); + const [lrcContent, setLrcContent] = useState(""); + const [videoUrl, setVideoUrl] = useState(""); + const [srv3Url, setSrv3Url] = useState(""); + const [isPlaying, setIsPlaying] = useState(false); + const [showVolume, setShowVolume] = useState(false); + const [scrubValue, setScrubValue] = useState(0); const [showFileInputs, setShowFileInputs] = useState(true); const videoRef = useRef(null); - const [offset, setOffset] = useState('0'); + const [captionsText, setCaptionsText] = useState(""); + const [offset, setOffset] = useState("0"); const handleLrcFileChange = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { @@ -71,60 +78,267 @@ function App() { toast.success("LRC file loaded successfully", { autoClose: 2000 }); } }; - - const handleVideoFileChange = (event: React.ChangeEvent) => { + + const handleVideoFileChange = ( + event: React.ChangeEvent + ) => { const file = event.target.files?.[0]; if (file) { const url = URL.createObjectURL(file); setVideoUrl(url); - setShowFileInputs(true); toast.success("Video file loaded successfully", { autoClose: 2000 }); } }; + const handleSrvFileChange = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onload = (e) => { + setCaptionsText(e.target?.result as string); + }; + reader.readAsText(file); + toast.success("SRV file loaded successfully", { autoClose: 2000 }); + } + }; + + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.code === "Space") { + handlePlayPause(); + } + if (e.code === "ArrowRight") { + const video = videoRef.current; + if (!video) return; + video.currentTime += 5; + } + if (e.code === "ArrowLeft") { + const video = videoRef.current; + if (!video) return; + video.currentTime -= 5; + } + }; + document.addEventListener("keydown", handleKeyDown); + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }); + useEffect(() => { const video = videoRef.current; if (!video) return; - + ; const syncLrcWithVideo = () => { console.log(offset); - setCurrentMillisecond((video.currentTime * 1000) + parseInt(offset)); + setCurrentMillisecond(video.currentTime * 1000 + parseInt(offset)); + setScrubValue((video.currentTime / video.duration) * 100); }; - video.addEventListener('timeupdate', syncLrcWithVideo); + video.addEventListener("timeupdate", syncLrcWithVideo); return () => { - video.removeEventListener('timeupdate', syncLrcWithVideo); + video.removeEventListener("timeupdate", syncLrcWithVideo); }; }); + const handleVolumeToggle = () => { + setShowVolume(!showVolume); + }; + + const handlePlayPause = () => { + const video = videoRef.current; + if (!video) return; + + if (video.paused) { + video.play(); + setIsPlaying(true); + } else { + video.pause(); + setIsPlaying(false); + } + }; + + const handleScrub = (event: React.ChangeEvent) => { + const time = + (parseFloat(event.target.value) / 100) * videoRef.current!.duration; + videoRef.current!.currentTime = time; + setScrubValue(parseFloat(event.target.value)); + }; + + const handleVolumeChange = (event: React.ChangeEvent) => { + const video = videoRef.current; + if (!video) return; + + video.volume = Number(event.target.value) / 100; + }; + return ( -
+
-
setShowFileInputs(true)} onMouseLeave={() => setShowFileInputs(false)}> - {videoUrl ?