优化视频播放器UI

This commit is contained in:
2025-10-07 20:40:28 +08:00
parent b4d62ef111
commit cac2da001a
7 changed files with 83 additions and 114 deletions

View File

@@ -1,4 +1,4 @@
2025.10.07 新增文本朗读器
2025.10.07 新增文本朗读器优化了视频播放器UI
2025.10.06 更新了主页面UI移除IPA生成与文本朗读功能新增全语言翻译器
2025.10.05 新增IPA生成与文本朗读功能
2025.09.25 优化了主界面UI

View File

@@ -0,0 +1,53 @@
import Button from "@/components/Button";
import { useRef, useState } from "react";
export default function UploadArea(
{
setVideoUrl,
setSrtUrl
}: {
setVideoUrl: (url: string | null) => void;
setSrtUrl: (url: string | null) => void;
}
) {
const inputRef = useRef<HTMLInputElement>(null);
const [videoFile, setVideoFile] = useState<File | null>(null);
const [SrtFile, setSrtFile] = useState<File | null>(null);
const uploadVideo = () => {
const input = inputRef.current;
if (input) {
input.setAttribute('accept', 'video/*');
input.click();
input.onchange = () => {
const file = input.files?.[0];
if (file) {
setVideoFile(file);
setVideoUrl(URL.createObjectURL(file));
}
};
}
}
const uploadSRT = () => {
const input = inputRef.current;
if (input) {
input.setAttribute('accept', '.srt');
input.click();
input.onchange = () => {
const file = input.files?.[0];
if (file) {
setSrtFile(file);
setSrtUrl(URL.createObjectURL(file));
}
};
}
}
return (
<div className="w-full flex flex-col gap-2 m-2">
<Button label="上传视频" onClick={uploadVideo} />
<Button label="上传字幕" onClick={uploadSRT} />
<input type="file" className="hidden" ref={inputRef} />
</div >
)
}

View File

@@ -4,7 +4,7 @@ export default function SubtitleDisplay({ subtitle }: { subtitle: string }) {
const words = subtitle.match(/\b[\w']+(?:-[\w']+)*\b/g) || [];
let i = 0;
return (
<div className="subtitle overflow-y-auto h-16 mt-2 break-words bg-black/50 font-sans text-white text-center text-2xl">
<div className="w-full subtitle overflow-auto h-16 mt-2 break-words bg-black/50 font-sans text-white text-center text-2xl">
{
words.map((v) => (
<span

View File

@@ -1,7 +1,7 @@
import { useState, useRef, forwardRef, useEffect, KeyboardEvent, useCallback } from "react";
import Button from "../../../../components/Button";
import { getIndex, getNearistIndex, parseSrt } from "../../subtitle";
import SubtitleDisplay from "./SubtitleDisplay";
import Button from "@/components/Button";
import { getIndex, parseSrt, getNearistIndex } from "../subtitle";
type VideoPanelProps = {
videoUrl: string | null;
@@ -154,15 +154,15 @@ const VideoPanel = forwardRef<HTMLVideoElement, VideoPanelProps>((
}
return (
<div className="flex flex-col w-9/12" onKeyDown={handleKeyDownEvent}>
<video className="w-12/12" ref={videoRef} onTimeUpdate={timeUpdate}></video>
<div className="w-full flex flex-col" onKeyDown={handleKeyDownEvent}>
<video className="bg-gray-200" ref={videoRef} onTimeUpdate={timeUpdate}></video>
<SubtitleDisplay subtitle={subtitle}></SubtitleDisplay>
<div className="buttons flex mt-2 gap-2 flex-wrap">
<Button label={isPlaying ? 'PAUSE' : 'PLAY'} onClick={togglePlayPause}></Button>
<Button label="NEXT" onClick={next}></Button>
<Button label="PREVIOUS" onClick={previous}></Button>
<Button label="RESTART" onClick={restart}></Button>
<Button label={`AUTOPAUSE(${autoPause ? 'Y' : 'N'})`} onClick={handleAutoPauseToggle}></Button>
<Button label={isPlaying ? '暂停' : '播放'} onClick={togglePlayPause}></Button>
<Button label="上句" onClick={previous}></Button>
<Button label="下句" onClick={next}></Button>
<Button label="句首" onClick={restart}></Button>
<Button label={`自动播放(${autoPause ? '' : ''})`} onClick={handleAutoPauseToggle}></Button>
</div>
<input className="seekbar" type="range" min={0} max={srtLength} onChange={handleSeek} step={1} value={progress}></input>
<span>{spanText}</span>

View File

@@ -1,25 +0,0 @@
'use client'
import { useRef, useState } from "react";
import UploadArea from "./UploadArea";
import VideoPanel from "./VideoPlayer/VideoPanel";
export default function AppCard() {
const videoRef = useRef<HTMLVideoElement>(null);
const [videoUrl, setVideoUrl] = useState<string | null>(null);
const [srtUrl, setSrtUrl] = useState<string | null>(null);
return (
<div className="min-w-[410px] max-w-[1000px] w-10/12 flex items-center flex-col bg-gray-200 rounded shadow-2xl py-12">
<p className="text-4xl font-extrabold">SRT Video Player</p>
<VideoPanel
videoUrl={videoUrl}
srtUrl={srtUrl}
ref={videoRef} />
<UploadArea
setVideoUrl={setVideoUrl}
setSrtUrl={setSrtUrl} />
</div>
);
}

View File

@@ -1,75 +0,0 @@
import { useRef, useState } from "react";
import Button from "../../../components/Button";
export default function UploadArea(
{
setVideoUrl,
setSrtUrl
}: {
setVideoUrl: (url: string | null) => void;
setSrtUrl: (url: string | null) => void;
}
) {
const inputRef = useRef<HTMLInputElement>(null);
const [videoFile, setVideoFile] = useState<File | null>(null);
const [SrtFile, setSrtFile] = useState<File | null>(null);
const uploadVideo = () => {
const input = inputRef.current;
if (input) {
input.setAttribute('accept', 'video/*');
input.click();
input.onchange = () => {
const file = input.files?.[0];
if (file) {
setVideoFile(file);
setVideoUrl(URL.createObjectURL(file));
}
};
}
}
const uploadSRT = () => {
const input = inputRef.current;
if (input) {
input.setAttribute('accept', '.srt');
input.click();
input.onchange = () => {
const file = input.files?.[0];
if (file) {
setSrtFile(file);
setSrtUrl(URL.createObjectURL(file));
}
};
}
}
return (
<div className="flex flex-col">
<table className="border border-black border-collapse">
<thead>
<tr className="divide-x divide-black">
<th className="border border-black px-2 py-1">File Name</th>
<th className="border border-black px-2 py-1">Type</th>
<th className="border border-black px-2 py-1">Size</th>
<th className="border border-black px-2 py-1">Actions</th>
</tr>
</thead>
<tbody className="divide-y divide-black">
<tr className="divide-x divide-black">
<td className="px-2 py-1">{videoFile?.name}</td>
<td className="px-2 py-1">Video</td>
<td className="px-2 py-1">{videoFile ? (videoFile.size / 1024 / 1024).toFixed(2) + 'MB' : null}</td>
<td className="px-2 py-1"><Button label="Upload" onClick={uploadVideo} /></td>
</tr>
<tr className="divide-x divide-black">
<td className="px-2 py-1">{SrtFile?.name}</td>
<td className="px-2 py-1">SRT</td>
<td className="px-2 py-1">{SrtFile ? (SrtFile.size / 1024 / 1024).toFixed(2) + 'MB' : null}</td>
<td className="px-2 py-1"><Button label="Upload" onClick={uploadSRT} /></td>
</tr>
</tbody>
</table>
<input type="file" className="hidden" ref={inputRef} />
</div>
)
}

View File

@@ -1,9 +1,25 @@
import AppCard from "./components/AppCard";
'use client';
import { useRef, useState } from "react";
import UploadArea from "./UploadArea";
import VideoPanel from "./VideoPlayer/VideoPanel";
export default function Home() {
const videoRef = useRef<HTMLVideoElement>(null);
const [videoUrl, setVideoUrl] = useState<string | null>(null);
const [srtUrl, setSrtUrl] = useState<string | null>(null);
return (
<div className="flex w-screen h-screen items-center justify-center">
<AppCard />
<div className="flex w-screen pt-8 items-center justify-center">
<div className="w-[80vw] md:w-[45vw] flex items-center flex-col">
<VideoPanel
videoUrl={videoUrl}
srtUrl={srtUrl}
ref={videoRef} />
<UploadArea
setVideoUrl={setVideoUrl}
setSrtUrl={setSrtUrl} />
</div>
</div>
);
}