aboutsummaryrefslogtreecommitdiffstats
path: root/src/app/page.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/page.tsx')
-rw-r--r--src/app/page.tsx1088
1 files changed, 583 insertions, 505 deletions
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 3b23eca..3e8dfb6 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -10,559 +10,637 @@ import { Button } from "react-bootstrap";
// Srtyled components
const Root = styled.div`
- position: absolute;
- width: 100%;
- height: 100%;
- top: 0;
- left: 0;
- display: flex;
- flex-direction: column;
- align-items: center;
- background-color: #f5f5f5;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ background-color: #f5f5f5;
`;
const FileInputContainer = styled.div`
- margin-bottom: 20px;
- display: flex;
- justify-content: center;
- gap: 20px;
- padding: 10px;
- border-radius: 5px;
- background-color: #ffffff;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ margin-bottom: 20px;
+ display: flex;
+ justify-content: center;
+ gap: 20px;
+ padding: 10px;
+ border-radius: 5px;
+ background-color: #ffffff;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
`;
const FileInput = styled.input`
- padding: 10px 15px;
- border-radius: 5px;
- border: 1px solid #ddd;
- justify-content: center;
- cursor: pointer;
- display: none;
- font-family: Arial;
- &:hover,
- &:focus {
- background-color: #eaeaea;
- outline: none;
- }
+ padding: 10px 15px;
+ border-radius: 5px;
+ border: 1px solid #ddd;
+ justify-content: center;
+ cursor: pointer;
+ display: none;
+ font-family: Arial;
+ &:hover,
+ &:focus {
+ background-color: #eaeaea;
+ outline: none;
+ }
`;
const FileInputLabel = styled.label`
- padding: 10px 15px;
- border-radius: 5px;
- border: 1px solid #ddd;
- cursor: pointer;
- &:hover,
- &:focus {
- background-color: #eaeaea;
- outline: none;
- }
+ padding: 10px 15px;
+ border-radius: 5px;
+ border: 1px solid #ddd;
+ cursor: pointer;
+ &:hover,
+ &:focus {
+ background-color: #eaeaea;
+ outline: none;
+ }
`;
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;
- }
+ 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<string>("");
- const [videoUrl, setVideoUrl] = useState<string>("");
- const [supplementAudioUrl, setSupplementAudioUrl] = useState<string>("");
- const [isPlaying, setIsPlaying] = useState<boolean>(false);
- const [showVolume, setShowVolume] = useState<boolean>(false);
- const [scrubValue, setScrubValue] = useState<number>(0);
- const [showFileInputs, setShowFileInputs] = useState<boolean>(true);
- const videoRef = useRef<HTMLVideoElement>(null);
- const supplementAudioRef = useRef<HTMLAudioElement>(null);
- const [captionsText, setCaptionsText] = useState<string>("");
- const [offset, setOffset] = useState<number>(0);
- const [dragOver, setDragOver] = useState<boolean>(false);
- const [statusText, setStatusText] = useState<string>("No video selected");
- const [balance, setBalance] = useState<number>(0);
- const [supplementAudioOffset, setSupplementAudioOffset] = useState<number>(0);
+ const [currentMillisecond, setCurrentMillisecond] = useState(0);
+ const [lrcContent, setLrcContent] = useState<string>("");
+ const [videoUrl, setVideoUrl] = useState<string>("");
+ const [supplementAudioUrl, setSupplementAudioUrl] = useState<string>("");
+ const [isPlaying, setIsPlaying] = useState<boolean>(false);
+ const [showVolume, setShowVolume] = useState<boolean>(false);
+ const [scrubValue, setScrubValue] = useState<number>(0);
+ const [showFileInputs, setShowFileInputs] = useState<boolean>(true);
+ const videoRef = useRef<HTMLVideoElement>(null);
+ const supplementAudioRef = useRef<HTMLAudioElement>(null);
+ const [captionsText, setCaptionsText] = useState<string>("");
+ const [offset, setOffset] = useState<number>(0);
+ const [dragOver, setDragOver] = useState<boolean>(false);
+ const [statusText, setStatusText] = useState<string>("No video selected");
+ const [balance, setBalance] = useState<number>(0);
+ const [animate, setAnimate] = useState<boolean>(true);
+ const [supplementAudioOffset, setSupplementAudioOffset] =
+ useState<number>(0);
- // Functions for handling file input changes
- const handleLrcFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- const file = event.target.files?.[0];
- if (file) {
- const reader = new FileReader();
- reader.onload = (e) => {
- setLrcContent(e.target?.result as string);
- if (videoUrl) setShowFileInputs(false);
- };
- reader.readAsText(file);
- toast.success("LRC file loaded successfully", { autoClose: 2000 });
- }
- };
-
- const handleVideoFileChange = (
- event: React.ChangeEvent<HTMLInputElement>
- ) => {
- const file = event.target.files?.[0];
- if (file) {
- const url = URL.createObjectURL(file);
- setVideoUrl(url);
- setCurrentMillisecond(0);
- setScrubValue(0);
- setIsPlaying(false);
- toast.success("Video file loaded successfully", { autoClose: 2000 });
- }
- };
-
- const handleSrvFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- 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 });
- }
- };
-
- const handleSupplementAudioFileChange = (
- event: React.ChangeEvent<HTMLInputElement>
- ) => {
- 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,
- });
- }
- };
+ // Functions for handling file input changes
+ const handleLrcFileChange = (
+ event: React.ChangeEvent<HTMLInputElement>,
+ ) => {
+ const file = event.target.files?.[0];
+ if (file) {
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ setLrcContent(e.target?.result as string);
+ if (videoUrl) setShowFileInputs(false);
+ };
+ reader.readAsText(file);
+ toast.success("LRC file loaded successfully", { autoClose: 2000 });
+ }
+ };
- const handleOnClickDemoButton = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
- event.preventDefault();
- setOffset(-1550);
- fetch("https://utfs.io/f/e2e18ea7-9841-437b-9ca3-5723355bd41a-rlck46.lrc")
- .then(function (response) {
- response.text().then(function (responseString) {
- setLrcContent(responseString)
- });
- })
- setVideoUrl("https://utfs.io/f/84f5dfa6-821d-407f-a16d-a685b09c11d9-7xx2h4.webm")
- toast.success("Loading Demo: Mr.Raindrop - Amplified")
- toast.success("Applied offset of -1550ms")
+ const handleVideoFileChange = (
+ event: React.ChangeEvent<HTMLInputElement>,
+ ) => {
+ const file = event.target.files?.[0];
+ if (file) {
+ const url = URL.createObjectURL(file);
+ setVideoUrl(url);
+ setCurrentMillisecond(0);
+ setScrubValue(0);
+ setIsPlaying(false);
+ toast.success("Video file loaded successfully", {
+ autoClose: 2000,
+ });
+ }
+ };
- }
+ const handleSrvFileChange = (
+ event: React.ChangeEvent<HTMLInputElement>,
+ ) => {
+ 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 });
+ }
+ };
- // Side effects for keyboard shortcuts
- useEffect(() => {
- const handleKeyDown = (e: KeyboardEvent) => {
- if (e.code === "Space") {
- handlePlayPause();
- }
- if (e.code === "ArrowRight") {
- if (document.activeElement?.tagName === "INPUT") return;
- const video = videoRef.current;
- if (!video) return;
- video.currentTime += 5;
- }
- if (e.code === "ArrowLeft") {
- if (document.activeElement?.tagName === "INPUT") return;
+ const handleSupplementAudioFileChange = (
+ event: React.ChangeEvent<HTMLInputElement>,
+ ) => {
+ const file = event.target.files?.[0];
const video = videoRef.current;
- if (!video) return;
- video.currentTime -= 5;
- }
- };
- document.addEventListener("keydown", handleKeyDown);
- return () => {
- document.removeEventListener("keydown", handleKeyDown);
+ 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 the video itself
- useEffect(() => {
- const video = videoRef.current;
- if (!video) return;
- const syncLrcWithVideo = () => {
- setCurrentMillisecond(video.currentTime * 1000 + offset); // updates lrc position
- setScrubValue((video.currentTime / video.duration) * 100); // update playhead position
+ const handleOnClickDemoButton = (
+ event: React.MouseEvent<HTMLAnchorElement, MouseEvent>,
+ ) => {
+ event.preventDefault();
+ setOffset(-1550);
+ fetch(
+ "https://utfs.io/f/e2e18ea7-9841-437b-9ca3-5723355bd41a-rlck46.lrc",
+ ).then(function (response) {
+ response.text().then(function (responseString) {
+ setLrcContent(responseString);
+ });
+ });
+ setVideoUrl(
+ "https://utfs.io/f/84f5dfa6-821d-407f-a16d-a685b09c11d9-7xx2h4.webm",
+ );
+ toast.success("Loading Demo: Mr.Raindrop - Amplified");
+ toast.success("Applied offset of -1550ms");
};
- video.addEventListener("timeupdate", syncLrcWithVideo);
- return () => {
- video.removeEventListener("timeupdate", syncLrcWithVideo);
- };
- });
+ // Side effects for keyboard shortcuts
+ useEffect(() => {
+ const handleKeyDown = (e: KeyboardEvent) => {
+ if (e.code === "Space") {
+ handlePlayPause();
+ }
+ if (e.code === "ArrowRight") {
+ if (document.activeElement?.tagName === "INPUT") return;
+ const video = videoRef.current;
+ if (!video) return;
+ video.currentTime += 5;
+ }
+ if (e.code === "ArrowLeft") {
+ if (document.activeElement?.tagName === "INPUT") return;
+ const video = videoRef.current;
+ if (!video) return;
+ video.currentTime -= 5;
+ }
+ };
+ document.addEventListener("keydown", handleKeyDown);
+ return () => {
+ document.removeEventListener("keydown", handleKeyDown);
+ };
+ });
- useEffect(() => {
- const video = videoRef.current;
- const audio = supplementAudioRef.current;
- if (!video || !audio) return;
+ // Side effects for the video itself
+ useEffect(() => {
+ const video = videoRef.current;
+ if (!video) return;
+ const syncLrcWithVideo = () => {
+ setCurrentMillisecond(video.currentTime * 1000 + offset); // updates lrc position
+ setScrubValue((video.currentTime / video.duration) * 100); // update playhead position
+ };
+ video.addEventListener("timeupdate", syncLrcWithVideo);
- if (balance < 0) {
- video.volume = (1 + balance);
- } else {
- video.volume = 1;
- audio.volume = (1 - balance);
- }
- }, [balance]);
+ return () => {
+ video.removeEventListener("timeupdate", syncLrcWithVideo);
+ };
+ });
- useEffect(() => {
- const video = videoRef.current;
- const audio = supplementAudioRef.current;
- if (!video || !audio) return;
- if (supplementAudioOffset === null || supplementAudioOffset == null) return;
- audio.currentTime = video.currentTime + supplementAudioOffset / 1000;
- }, [supplementAudioOffset]);
+ useEffect(() => {
+ const video = videoRef.current;
+ const audio = supplementAudioRef.current;
+ if (!video || !audio) return;
- // General video control functionality
+ if (balance < 0) {
+ video.volume = 1 + balance;
+ } else {
+ video.volume = 1;
+ audio.volume = 1 - balance;
+ }
+ }, [balance]);
- const handleVolumeToggle = () => {
- setShowVolume(!showVolume);
- };
+ useEffect(() => {
+ const video = videoRef.current;
+ const audio = supplementAudioRef.current;
+ if (!video || !audio) return;
+ if (supplementAudioOffset === null || supplementAudioOffset == null)
+ return;
+ audio.currentTime = video.currentTime + supplementAudioOffset / 1000;
+ }, [supplementAudioOffset]);
- const handlePlayPause = () => {
- const video = videoRef.current;
- if (!video) return;
+ // General video control functionality
- if (video.paused) {
- video.play();
- if (supplementAudioUrl) supplementAudioRef.current?.play();
- setIsPlaying(true);
- } else {
- video.pause();
- if (supplementAudioUrl) supplementAudioRef.current?.pause();
- setIsPlaying(false);
- }
- };
+ const handleVolumeToggle = () => {
+ setShowVolume(!showVolume);
+ };
- // Status text styling depending on whats loaded. Not all visible
- useEffect(() => {
- if (videoUrl && lrcContent) {
- setStatusText("Ready to play!");
- } else if (videoUrl) {
- setStatusText("No lyrics file selected");
- } else if (lrcContent) {
- setStatusText("No video file selected");
- } else {
- setStatusText("No video or lyrics file selected");
- }
- }, [videoUrl, lrcContent]);
+ const handlePlayPause = () => {
+ const video = videoRef.current;
+ if (!video) return;
- // Video Control Bar functionality
- const handleScrub = (event: React.ChangeEvent<HTMLInputElement>) => {
- const time =
- (parseFloat(event.target.value) / 100) * videoRef.current!.duration;
- videoRef.current!.currentTime = time;
- if (supplementAudioOffset === null || supplementAudioOffset == null) {
- supplementAudioRef.current!.currentTime = time;
- }
- else {
- supplementAudioRef.current!.currentTime = time + supplementAudioOffset / 1000;
- }
- setScrubValue(parseFloat(event.target.value));
- };
+ 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!");
+ } else if (videoUrl) {
+ setStatusText("No lyrics file selected");
+ } else if (lrcContent) {
+ setStatusText("No video file selected");
+ } else {
+ setStatusText("No video or lyrics file selected");
+ }
+ }, [videoUrl, lrcContent]);
- const handleVideoEnded = () => {
- setIsPlaying(false);
- supplementAudioRef.current?.pause();
- };
+ // Video Control Bar functionality
+ const handleScrub = (event: React.ChangeEvent<HTMLInputElement>) => {
+ const time =
+ (parseFloat(event.target.value) / 100) * videoRef.current!.duration;
+ videoRef.current!.currentTime = time;
+ if (supplementAudioOffset === null || supplementAudioOffset == null) {
+ supplementAudioRef.current!.currentTime = time;
+ } else {
+ supplementAudioRef.current!.currentTime =
+ time + supplementAudioOffset / 1000;
+ }
+ setScrubValue(parseFloat(event.target.value));
+ };
- const syncSupplementAudioWithVideo = () => {
- const video = videoRef.current;
- const audio = supplementAudioRef.current;
- if (!video || !audio) return;
- if (supplementAudioOffset === null || supplementAudioOffset == null) return;
- audio.currentTime = video.currentTime + supplementAudioOffset / 1000;
- }
+ const handleVideoEnded = () => {
+ setIsPlaying(false);
+ supplementAudioRef.current?.pause();
+ };
- // Handling drag and drop files
- const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
- setDragOver(true);
- event.preventDefault();
- };
+ const syncSupplementAudioWithVideo = () => {
+ const video = videoRef.current;
+ const audio = supplementAudioRef.current;
+ if (!video || !audio) return;
+ if (supplementAudioOffset === null || supplementAudioOffset == null)
+ return;
+ audio.currentTime = video.currentTime + supplementAudioOffset / 1000;
+ };
- const handleDragEnter = (event: React.DragEvent<HTMLDivElement>) => {
- setDragOver(true);
- event.preventDefault();
- };
+ // Handling drag and drop files
+ const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
+ setDragOver(true);
+ event.preventDefault();
+ };
- const handleDragLeave = (event: React.DragEvent<HTMLDivElement>) => {
- setDragOver(false);
- event.preventDefault();
- };
+ const handleDragEnter = (event: React.DragEvent<HTMLDivElement>) => {
+ setDragOver(true);
+ event.preventDefault();
+ };
- const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
- event.preventDefault();
- setDragOver(false);
- const file = event.dataTransfer.files?.[0];
- if (file.name.endsWith(".lrc")) {
- const reader = new FileReader();
- reader.onload = (e) => {
- setLrcContent(e.target?.result as string);
- if (videoUrl) setShowFileInputs(false);
- };
- reader.readAsText(file);
- toast.success("LRC file loaded successfully", { autoClose: 2000 });
- } 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")) {
- const url = URL.createObjectURL(file);
- setVideoUrl(url);
- setCurrentMillisecond(0);
- setScrubValue(0);
- setIsPlaying(false);
- toast.success("Video/Audio file loaded successfully", {
- autoClose: 2000,
- });
- } else {
- toast.error("Unsupported file type", { autoClose: 2000 });
- }
- };
+ const handleDragLeave = (event: React.DragEvent<HTMLDivElement>) => {
+ setDragOver(false);
+ event.preventDefault();
+ };
- return (
- <Root>
- <ToastContainer />
- {/*LRC viewer*/}
- <div style={{ display: "flex", width: "100%", height: "100vh" }}>
- <LRCPlayer
- lrc={lrcContent}
- currentMillisecond={currentMillisecond}
- />
+ const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
+ event.preventDefault();
+ setDragOver(false);
+ const file = event.dataTransfer.files?.[0];
+ if (file.name.endsWith(".lrc")) {
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ setLrcContent(e.target?.result as string);
+ if (videoUrl) setShowFileInputs(false);
+ };
+ reader.readAsText(file);
+ toast.success("LRC file loaded successfully", { autoClose: 2000 });
+ } 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")
+ ) {
+ const url = URL.createObjectURL(file);
+ setVideoUrl(url);
+ setCurrentMillisecond(0);
+ setScrubValue(0);
+ setIsPlaying(false);
+ toast.success("Video/Audio file loaded successfully", {
+ autoClose: 2000,
+ });
+ } else {
+ toast.error("Unsupported file type", { autoClose: 2000 });
+ }
+ };
- {/* Ternary operation for if videoUrl has been set */}
- <div
- style={{
- flex: 1,
- position: "relative",
- backgroundColor: dragOver ? "lightblue" : "white",
- }}
- onMouseEnter={() => setShowFileInputs(true)}
- onMouseLeave={() => setShowFileInputs(false)}
- onDragOver={handleDragOver}
- onDragEnter={handleDragEnter}
- onDragLeave={handleDragLeave}
- onDrop={handleDrop}
- >
- {videoUrl ? (
- <>
- <video
- ref={videoRef}
- src={videoUrl}
- style={{ position: "absolute", width: "100%", height: "100%" }}
- onEnded={handleVideoEnded}
- />
- <audio
- ref={supplementAudioRef}
- src={supplementAudioUrl}
- style={{ display: "none" }}
- />
- <div
- style={{ width: "90%", height: "90%", margin: "auto" }}
- onClick={() => handlePlayPause()}
- >
- <CaptionsRenderer
- srv3={captionsText}
- currentTime={currentMillisecond / 1000}
+ return (
+ <Root>
+ <ToastContainer />
+ {/*LRC viewer*/}
+ <div style={{ display: "flex", width: "100%", height: "100vh" }}>
+ <LRCPlayer
+ lrc={lrcContent}
+ currentMillisecond={currentMillisecond}
+ animate={animate}
/>
- </div>
- {/*Video control bar*/}
- <div
- style={{
- position: "absolute",
- bottom: 0,
- left: 0,
- width: "100%",
- display: "flex",
- alignItems: "center",
- backgroundColor: "rgba(0, 0, 0, 0.5)",
- height: "50px",
- }}
- >
- <button
- onClick={handlePlayPause}
- style={{
- width: "50px",
- height: "50px",
- padding: "10px",
- border: "none",
- borderRadius: "5px",
- backgroundColor: "white",
- color: "black",
- }}
+
+ {/* Ternary operation for if videoUrl has been set */}
+ <div
+ style={{
+ flex: 1,
+ position: "relative",
+ backgroundColor: dragOver ? "lightblue" : "white",
+ }}
+ onMouseEnter={() => setShowFileInputs(true)}
+ onMouseLeave={() => setShowFileInputs(false)}
+ onDragOver={handleDragOver}
+ onDragEnter={handleDragEnter}
+ onDragLeave={handleDragLeave}
+ onDrop={handleDrop}
>
- {isPlaying ? <FaPause /> : <FaPlay />}
- </button>
- <input
- type="range"
- min="0"
- max="100"
- value={scrubValue}
- style={{ flex: 1, height: "50px", width: "100%" }}
- onInput={handleScrub}
- />
- </div>
- </>
- ) : (
- <div
- style={{
- width: "100%",
- height: "100%",
- display: "flex",
- justifyContent: "center",
- alignItems: "center",
- flexDirection: "column",
- }}
- >
- <h1
- style={{
- fontFamily: "Arial",
- fontWeight: "bold",
- fontSize: "32px",
- }}
- >
- {statusText}
- </h1>
- {/* Show a placeholder while no video selected */}
- <p
- style={{
- fontSize: "30px",
- textAlign: "center",
- fontFamily: "Arial",
- }}
- >
- Please select the video and lrc (lyrics) file <br />
- (Drag and Drop them here, or use the menus below!)
- <br />
- <StyledLink href="/about"> About </StyledLink>
- <StyledLink href="" onClick={handleOnClickDemoButton}> Demo </StyledLink>
- </p>
- </div>
- )}
+ {videoUrl ? (
+ <>
+ <video
+ ref={videoRef}
+ src={videoUrl}
+ style={{
+ position: "absolute",
+ width: "100%",
+ height: "100%",
+ }}
+ onEnded={handleVideoEnded}
+ />
+ <audio
+ ref={supplementAudioRef}
+ src={supplementAudioUrl}
+ style={{ display: "none" }}
+ />
+ <div
+ style={{
+ width: "90%",
+ height: "90%",
+ margin: "auto",
+ }}
+ onClick={() => handlePlayPause()}
+ >
+ <CaptionsRenderer
+ srv3={captionsText}
+ currentTime={currentMillisecond / 1000}
+ />
+ </div>
+ {/*Video control bar*/}
+ <div
+ style={{
+ position: "absolute",
+ bottom: 0,
+ left: 0,
+ width: "100%",
+ display: "flex",
+ alignItems: "center",
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
+ height: "50px",
+ }}
+ >
+ <button
+ onClick={handlePlayPause}
+ style={{
+ width: "50px",
+ height: "50px",
+ padding: "10px",
+ border: "none",
+ borderRadius: "5px",
+ backgroundColor: "white",
+ color: "black",
+ }}
+ >
+ {isPlaying ? <FaPause /> : <FaPlay />}
+ </button>
+ <input
+ type="range"
+ min="0"
+ max="100"
+ value={scrubValue}
+ style={{
+ flex: 1,
+ height: "50px",
+ width: "100%",
+ }}
+ onInput={handleScrub}
+ />
+ </div>
+ </>
+ ) : (
+ <div
+ style={{
+ width: "100%",
+ height: "100%",
+ display: "flex",
+ justifyContent: "center",
+ alignItems: "center",
+ flexDirection: "column",
+ }}
+ >
+ <h1
+ style={{
+ fontFamily: "Arial",
+ fontWeight: "bold",
+ fontSize: "32px",
+ }}
+ >
+ {statusText}
+ </h1>
+ {/* Show a placeholder while no video selected */}
+ <p
+ style={{
+ fontSize: "30px",
+ textAlign: "center",
+ fontFamily: "Arial",
+ }}
+ >
+ Please select the video and lrc (lyrics) file{" "}
+ <br />
+ (Drag and Drop them here, or use the menus
+ below!) <br />
+ <br />
+ Chrome is recommended!
+ <br />
+ <StyledLink href="/about"> About </StyledLink>
+ <StyledLink
+ href=""
+ onClick={handleOnClickDemoButton}
+ >
+ {" "}
+ Demo{" "}
+ </StyledLink>
+ </p>
+ </div>
+ )}
- {/* File inputs, shown on hover over video div region*/}
- {showFileInputs && (
- <FileInputContainer
- style={{ position: "absolute", bottom: "30px", left: 0 }}
- >
- <FileInputLabel htmlFor="lrcUpload" style={{ cursor: "pointer" }}>
- LRC
- </FileInputLabel>
- <FileInput
- id="lrcUpload"
- type="file"
- accept=".lrc"
- onChange={handleLrcFileChange}
- />
- <FileInputLabel
- htmlFor="videoUpload"
- style={{ cursor: "pointer" }}
- >
- Media
- </FileInputLabel>
- <FileInput
- id="videoUpload"
- type="file"
- accept="video/*,audio/*"
- onChange={handleVideoFileChange}
- />
- <FileInputLabel htmlFor="srvUpload" style={{ cursor: "pointer" }}>
- SRV
- </FileInputLabel>
- <FileInput
- id="srvUpload"
- type="file"
- accept=".srv3"
- onChange={handleSrvFileChange}
- />
- <FileInputLabel
- htmlFor="supplementAudioUpload"
- style={{ cursor: "pointer" }}
- >
- Audio #2
- </FileInputLabel>
- <FileInput
- id="supplementAudioUpload"
- type="file"
- accept="audio/*"
- onChange={handleSupplementAudioFileChange}
- />
- <ControlBarButton onClick={syncSupplementAudioWithVideo}>Sync Audio</ControlBarButton>
- <div
- style={{
- display: "flex",
- flexDirection: "column",
- fontFamily: "Arial",
- }}
- >
- <label>Audio/Video Balance</label>
- <input
- type="range"
- min="-1"
- max="1"
- step="0.01"
- value={balance}
- onChange={(e) => setBalance(Number(e.target.value))}
- />
- <label>Offset (±ms) </label>
- <input
- type="number"
- style={{ fontSize: "14px" }}
- id="numberInput"
- value={offset}
- onChange={(e) => setOffset(Number(e.target.value))}
- step="25"
- />
- </div>
- <div
- style={{
- display: "flex",
- flexDirection: "column",
- fontFamily: "Arial",
- }}
- >
- <label>Audio 2 Offset (±ms) </label>
- <input
- type="number"
- style={{ fontSize: "14px" }}
- id="numberInput"
- value={supplementAudioOffset}
- onChange={(e) => setSupplementAudioOffset(Number(e.target.value))}
- step="25"
- />
- </div>
- </FileInputContainer>
- )}
- </div>
- </div>
- </Root>
- );
+ {/* File inputs, shown on hover over video div region*/}
+ {showFileInputs && (
+ <FileInputContainer
+ style={{
+ position: "absolute",
+ bottom: "30px",
+ left: 0,
+ }}
+ >
+ <FileInputLabel
+ htmlFor="lrcUpload"
+ style={{ cursor: "pointer" }}
+ >
+ LRC
+ </FileInputLabel>
+ <FileInput
+ id="lrcUpload"
+ type="file"
+ accept=".lrc"
+ onChange={handleLrcFileChange}
+ />
+ <FileInputLabel
+ htmlFor="videoUpload"
+ style={{ cursor: "pointer" }}
+ >
+ Media
+ </FileInputLabel>
+ <FileInput
+ id="videoUpload"
+ type="file"
+ accept="video/*,audio/*"
+ onChange={handleVideoFileChange}
+ />
+ <FileInputLabel
+ htmlFor="srvUpload"
+ style={{ cursor: "pointer" }}
+ >
+ SRV
+ </FileInputLabel>
+ <FileInput
+ id="srvUpload"
+ type="file"
+ accept=".srv3"
+ onChange={handleSrvFileChange}
+ />
+ <FileInputLabel
+ htmlFor="supplementAudioUpload"
+ style={{ cursor: "pointer" }}
+ >
+ Audio #2
+ </FileInputLabel>
+ <FileInput
+ id="supplementAudioUpload"
+ type="file"
+ accept="audio/*"
+ onChange={handleSupplementAudioFileChange}
+ />
+ <ControlBarButton
+ onClick={syncSupplementAudioWithVideo}
+ >
+ Sync Audio
+ </ControlBarButton>
+ <div
+ style={{
+ display: "flex",
+ flexDirection: "column",
+ fontFamily: "Arial",
+ }}
+ >
+ <label>Audio/Video Balance</label>
+ <input
+ type="range"
+ min="-1"
+ max="1"
+ step="0.01"
+ value={balance}
+ onChange={(e) =>
+ setBalance(Number(e.target.value))
+ }
+ />
+ <label>Offset (±ms) </label>
+ <input
+ type="number"
+ style={{ fontSize: "14px" }}
+ id="numberInput"
+ value={offset}
+ onChange={(e) =>
+ setOffset(Number(e.target.value))
+ }
+ step="25"
+ />
+ </div>
+ <div
+ style={{
+ display: "flex",
+ flexDirection: "column",
+ fontFamily: "Arial",
+ }}
+ >
+ <label>Audio 2 Offset (±ms) </label>
+ <input
+ type="number"
+ style={{ fontSize: "14px" }}
+ id="numberInput"
+ value={supplementAudioOffset}
+ onChange={(e) =>
+ setSupplementAudioOffset(
+ Number(e.target.value),
+ )
+ }
+ step="25"
+ />
+ </div>
+ <label
+ style={{
+ fontSize: "14px",
+ fontFamily: "Arial",
+ userSelect: "none",
+ }}
+ >
+ <input
+ type="checkbox"
+ checked={animate}
+ onChange={(e) =>
+ setAnimate(e.target.checked)
+ }
+ onSelect={(e) => e.preventDefault()}
+ style={{ marginRight: "8px" }}
+ />
+ Line Animation
+ </label>
+ </FileInputContainer>
+ )}
+ </div>
+ </div>
+ </Root>
+ );
}
export default KaraokePage;
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage