From 71b680fb9d29057b97748c54d1ad20229fe3394c Mon Sep 17 00:00:00 2001
From: Pinapelz <yukais@pinapelz.com>
Date: Wed, 15 Nov 2023 00:28:35 -0800
Subject: feat: add custom upload for lrc and video/audio

---
 src/app/App.tsx | 151 +++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 101 insertions(+), 50 deletions(-)

(limited to 'src/app/App.tsx')

diff --git a/src/app/App.tsx b/src/app/App.tsx
index ebe2d33..871e387 100644
--- a/src/app/App.tsx
+++ b/src/app/App.tsx
@@ -1,7 +1,8 @@
-import { CSSProperties, useCallback, useRef, useEffect, useState } from "react";
-import styled, { css } from "styled-components";
-import { Lrc, LrcLine } from "react-lrc";
-import { LRC } from "./data";
+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';
 
 const Root = styled.div`
   position: absolute;
@@ -9,79 +10,129 @@ const Root = styled.div`
   height: 100%;
   top: 0;
   left: 0;
-
   display: flex;
   flex-direction: column;
+  align-items: center;
+  background-color: #f5f5f5;
 `;
-const lrcStyle: CSSProperties = {
-  flex: 1,
-  minHeight: 0,
-  overflow: 'hidden !important'
-};
-const Line = styled.div<{ $active: boolean; $next: boolean }>`
-  min-height: 10px;
-  padding: 14px 30px;
 
-  font-size: 40px;
-  font-family : "Roboto", sans-serif;
-  font-weight: 500;
-  text-align: center;
-  color: rgb(72,72,72);
+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);
+`;
 
-  background: linear-gradient(to right, rgba(0,0,0,0) 50%, rgb(200, 190, 190) 50%);
-  background-size: 200% 100%;
-  background-position: right bottom;
+const FileInput = styled.input`
+  padding: 10px 15px;
+  border-radius: 5px;
+  border: 1px solid #ddd;
+  cursor: pointer;
+  display: none;
+  &:hover, &:focus {
+    background-color: #eaeaea;
+    outline: none;
+  }
+`;
 
-  ${({ $active }) => $active && css`
-    color: black;
-    font-weight: 700;
-    background-position: left bottom;
-    color: rgb(50, 50, 50);
-  `}
+const FileInputLabel = styled.label`
+  padding: 10px 15px;
+  border-radius: 5px;
+  border: 1px solid #ddd;
+  cursor: pointer;
+  &:hover, &:focus {
+    background-color: #eaeaea;
+    outline: none;
+  }
 `;
 
+
 function App() {
+  
   const [currentMillisecond, setCurrentMillisecond] = useState(0);
-
+  const [lrcContent, setLrcContent] = useState('');
+  const [videoUrl, setVideoUrl] = useState('');
+  const [showFileInputs, setShowFileInputs] = useState(true);
   const videoRef = useRef<HTMLVideoElement>(null);
+  const [offset, setOffset] = useState('0');
+  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);
+      setShowFileInputs(true);
+      toast.success("Video file loaded successfully", { autoClose: 2000 });
+    }
+  };
 
   useEffect(() => {
     const video = videoRef.current;
     if (!video) return;
 
     const syncLrcWithVideo = () => {
-      const offset = 400;
-      setCurrentMillisecond((video.currentTime * 1000)+offset);
+      console.log(offset);
+      setCurrentMillisecond((video.currentTime * 1000) + parseInt(offset));
     };
-
     video.addEventListener('timeupdate', syncLrcWithVideo);
 
     return () => {
       video.removeEventListener('timeupdate', syncLrcWithVideo);
     };
-  }, [setCurrentMillisecond]);
-
-  const lineRenderer = useCallback(
-    ({ active, line: { content } }: { active: boolean; line: LrcLine }) => {
-      const next = active && content === '';
-      return <Line $active={active} $next={next}>{content}</Line>
-    },
-    []
-  );
+  });
 
   return (
     <Root>
+      <ToastContainer />
       <div style={{ display: 'flex', width: '100%', height: '100vh' }}>
-        <Lrc
-            lrc={LRC}
-            lineRenderer={lineRenderer}
-            currentMillisecond={currentMillisecond}
-            style={lrcStyle}
-            recoverAutoScrollInterval={0}
-          />
-        <div style={{ flex: 1 }}>
-        <video ref={videoRef} src="https://cdn.pinapelz.com/VTuber%20Covers%20Archive/pj9yqqTYa-E.webm" controls style={{ width: '100%', height: '100%' }} />
-         
+        <KaraokePlayer
+          lrc={lrcContent}
+          currentMillisecond={currentMillisecond}
+        />
+        <div style={{ flex: 1, position: 'relative' }} onMouseEnter={() => setShowFileInputs(true)} onMouseLeave={() => setShowFileInputs(false)}>
+          {videoUrl ? <video ref={videoRef} src={videoUrl} controls style={{ width: '100%', height: '100%' }} /> :<div style={{ width: '100%', height: '100%', backgroundColor: '#ddd', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
+            <p style={{fontSize: '30px', textAlign: 'center', fontFamily:'Arial', fontWeight:'bold'}}>
+              Please select the video and lrc (lyrics) file <br/>
+              Hover over me for a menu</p>
+          </div>
+          }
+          {showFileInputs && (
+            <FileInputContainer style={{ position: 'absolute', bottom: '20px', 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' }}>Video</FileInputLabel>
+              <FileInput id="videoUpload" type="file" accept="video/*" onChange={handleVideoFileChange} />
+              <FileInputLabel htmlFor="srvUpload" style={{ cursor: 'pointer' }}>SRV</FileInputLabel>
+              <FileInput disabled type="file" accept=".srv" />
+              <div style={{ display: 'flex', flexDirection: 'column', fontFamily: 'Arial' }}>
+                <label>Offset (±ms) </label>
+                <input
+                  type="number"
+                  style={{ fontSize: '20px' }}
+                  id="numberInput"
+                  value={offset}
+                  onChange={(e) => setOffset(e.target.value)}
+                  step="100"
+                />
+              </div>
+            </FileInputContainer>
+          )}
         </div>
       </div>
     </Root>
-- 
cgit v1.2.3

