aboutsummaryrefslogtreecommitdiffstats
path: root/src/app/App.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/app/App.tsx')
-rw-r--r--src/app/App.tsx151
1 files changed, 101 insertions, 50 deletions
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>
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage