From 1caebf3d8a8ba9deb7fb77fcc17b02c46652f9f1 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Thu, 16 Nov 2023 21:49:11 -0800 Subject: feat: add supplementary audio upload option --- src/app/page.tsx | 240 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 190 insertions(+), 50 deletions(-) (limited to 'src/app') diff --git a/src/app/page.tsx b/src/app/page.tsx index 4be028c..457610d 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,4 +1,4 @@ -"use client" +"use client"; import React, { useEffect, useRef, useState } from "react"; import styled from "styled-components"; import KaraokePlayer from "./components/KaraokePlayer"; @@ -35,6 +35,7 @@ const FileInput = styled.input` padding: 10px 15px; border-radius: 5px; border: 1px solid #ddd; + justify-content: center; cursor: pointer; display: none; font-family: Arial; @@ -57,29 +58,46 @@ const FileInputLabel = styled.label` } `; +const ControlBarButton = styled.button` + padding: 10px 15px; + border-radius: 5px; + border: 1px solid #ddd; + align-items: center; + cursor: pointer; + &:hover, + &:focus { + background-color: #eaeaea; + outline: none; + } +`; + const StyledLink = styled.a` - font-size: 20px; - font-family: Arial; - text-decoration: none; - text-color: black; - &:hover { - text-decoration: underline; - } - `; + font-size: 20px; + font-family: Arial; + text-decoration: none; + text-color: black; + &:hover { + text-decoration: underline; + } +`; function KaraokePage() { const [currentMillisecond, setCurrentMillisecond] = useState(0); - const [lrcContent, setLrcContent] = useState(""); - const [videoUrl, setVideoUrl] = useState(""); - const [isPlaying, setIsPlaying] = useState(false); - const [showVolume, setShowVolume] = useState(false); - const [scrubValue, setScrubValue] = useState(0); - const [showFileInputs, setShowFileInputs] = useState(true); + const [lrcContent, setLrcContent] = useState(""); + const [videoUrl, setVideoUrl] = useState(""); + const [supplementAudioUrl, setSupplementAudioUrl] = 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 [captionsText, setCaptionsText] = useState(""); - const [offset, setOffset] = useState("0"); - const [dragOver, setDragOver] = useState(false); - const [statusText, setStatusText] = useState("No video selected"); + const supplementAudioRef = useRef(null); + const [captionsText, setCaptionsText] = useState(""); + const [offset, setOffset] = useState("0"); + const [dragOver, setDragOver] = useState(false); + const [statusText, setStatusText] = useState("No video selected"); + const [balance, setBalance] = useState(0); + const [supplementAudioOffset, setSupplementAudioOffset] = useState("0"); // Functions for handling file input changes const handleLrcFileChange = (event: React.ChangeEvent) => { @@ -118,7 +136,26 @@ function KaraokePage() { }; reader.readAsText(file); toast.success("SRV file loaded successfully", { autoClose: 2000 }); - } + } + }; + + const handleSupplementAudioFileChange = ( + event: React.ChangeEvent + ) => { + const file = event.target.files?.[0]; + const video = videoRef.current; + if (file) { + const url = URL.createObjectURL(file); + setSupplementAudioUrl(url); + setCurrentMillisecond(0); + setScrubValue(0); + setIsPlaying(false); + if (video) + video.pause(); + toast.success("Supplemental Audio file loaded successfully", { + autoClose: 2000, + }); + } }; // Side effects for keyboard shortcuts @@ -161,6 +198,26 @@ function KaraokePage() { }; }); + useEffect(() => { + const video = videoRef.current; + const audio = supplementAudioRef.current; + if (!video || !audio) return; + + if (balance < 0) { + video.volume = (1 + balance); + } else { + video.volume = 1; + audio.volume = (1 - balance); + } + }, [balance]); + + useEffect(() => { + const video = videoRef.current; + const audio = supplementAudioRef.current; + if (!video || !audio) return; + if (supplementAudioOffset === "" || supplementAudioOffset == null) return; + audio.currentTime = video.currentTime + parseInt(supplementAudioOffset)/1000; + },[supplementAudioOffset]); // General video control functionality @@ -174,13 +231,16 @@ function KaraokePage() { if (video.paused) { video.play(); + if (supplementAudioUrl) supplementAudioRef.current?.play(); setIsPlaying(true); } else { video.pause(); + if (supplementAudioUrl) supplementAudioRef.current?.pause(); setIsPlaying(false); } }; + // Status text styling depending on whats loaded. Not all visible useEffect(() => { if (videoUrl && lrcContent) { setStatusText("Ready to play!"); @@ -193,19 +253,47 @@ function KaraokePage() { } }, [videoUrl, lrcContent]); + // Video Control Bar functionality const handleScrub = (event: React.ChangeEvent) => { const time = (parseFloat(event.target.value) / 100) * videoRef.current!.duration; videoRef.current!.currentTime = time; + if (supplementAudioOffset === "" || supplementAudioOffset == null){ + supplementAudioRef.current!.currentTime = time; + } + else { + supplementAudioRef.current!.currentTime = time + parseInt(supplementAudioOffset)/1000; + } setScrubValue(parseFloat(event.target.value)); }; const handleVolumeChange = (event: React.ChangeEvent) => { + const volume = Number(event.target.value) / 100; const video = videoRef.current; - if (!video) return; - video.volume = Number(event.target.value) / 100; + const audio = supplementAudioRef.current; + if (!video || !audio) return; + + if (balance < 0) { + video.volume = volume * (1 + balance); + audio.volume = volume; + } else { + video.volume = volume; + audio.volume = volume * (1 - balance); + } + }; + + const handleVideoEnded = () => { + setIsPlaying(false); + supplementAudioRef.current?.pause(); }; + const syncSupplementAudioWithVideo = () => { + const video = videoRef.current; + const audio = supplementAudioRef.current; + if (!video || !audio) return; + if (supplementAudioOffset === "" || supplementAudioOffset == null) return; + audio.currentTime = video.currentTime + parseInt(supplementAudioOffset)/1000; + } // Handling drag and drop files const handleDragOver = (event: React.DragEvent) => { @@ -227,7 +315,7 @@ function KaraokePage() { event.preventDefault(); setDragOver(false); const file = event.dataTransfer.files?.[0]; - if(file.name.endsWith(".lrc")) { + if (file.name.endsWith(".lrc")) { const reader = new FileReader(); reader.onload = (e) => { setLrcContent(e.target?.result as string); @@ -235,44 +323,44 @@ function KaraokePage() { }; reader.readAsText(file); toast.success("LRC file loaded successfully", { autoClose: 2000 }); - } - else if(file.name.endsWith(".srv3")) { + } else if (file.name.endsWith(".srv3")) { const reader = new FileReader(); reader.onload = (e) => { setCaptionsText(e.target?.result as string); }; reader.readAsText(file); toast.success("SRV file loaded successfully", { autoClose: 2000 }); - } - else if(file.type.startsWith("video") || file.type.startsWith("audio") ) { + } else if (file.type.startsWith("video") || file.type.startsWith("audio")) { const url = URL.createObjectURL(file); setVideoUrl(url); setCurrentMillisecond(0); setScrubValue(0); setIsPlaying(false); - toast.success("Video/Audio file loaded successfully", { autoClose: 2000 }); - } - else{ + toast.success("Video/Audio file loaded successfully", { + autoClose: 2000, + }); + } else { toast.error("Unsupported file type", { autoClose: 2000 }); } - } - - + }; return ( - {/*LRC viewer*/ } + {/*LRC viewer*/}
- {/* Ternary operation for if videoUrl has been set */}
setShowFileInputs(true)} onMouseLeave={() => setShowFileInputs(false)} onDragOver={handleDragOver} @@ -286,17 +374,23 @@ function KaraokePage() { ref={videoRef} src={videoUrl} style={{ position: "absolute", width: "100%", height: "100%" }} + onEnded={handleVideoEnded} /> -
handlePlayPause()} +
-- cgit v1.2.3