ADD range slider that follows player

This commit is contained in:
2025-05-22 23:30:49 +02:00
parent 9348dd928e
commit 318fbe84f6

View File

@@ -1,35 +1,60 @@
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import RangeSlider from 'react-range-slider-input'; import RangeSlider from 'react-range-slider-input';
import 'react-range-slider-input/dist/style.css'; import 'react-range-slider-input/dist/style.css';
export type VideoMetadata = {
startPoint: number,
endPoint: number,
fps: number,
width: number,
height: number,
fileSize: number
}
const fetchMetadata = async (id: string): Promise<VideoMetadata> => {
const res = await fetch(`/api/v1/metadata/original/${id}`);
if (!res.ok) throw new Error("Failed to fetch");
return res.json();
};
export default function video() { export default function video() {
const { id } = useParams(); const { id } = useParams();
const videoRef = useRef<HTMLVideoElement | null>(null); const videoRef = useRef<HTMLVideoElement | null>(null);
const videoUrl = "api/v1/download/input/" + id; const videoUrl = "api/v1/download/input/" + id;
const [videoDuration, setVideoDuration] = useState(0);
const [metadata, setMetadata] = useState<VideoMetadata | null>(null);
let previousInput = [0, 0];
const handleInput = (val: [number, number]) => {
if (!videoRef.current) {
return;
}
if (previousInput[0] != val[0]) {
videoRef.current.currentTime = val[0];
} else if (previousInput[1] != val[1]) {
videoRef.current.currentTime = val[1];
}
previousInput = val;
};
useEffect(() => { useEffect(() => {
const videoEl = videoRef.current; fetch(`api/v1/metadata/original/${id}`)
.then((res) => {
if (!videoEl) return; if (!res.ok) throw new Error("Failed to fetch metadata");
return res.json();
const handleLoadedMetadata = () => { })
setVideoDuration(videoEl.duration); .then(setMetadata)
}; .catch((err) => console.log(err.message));
}, []);
videoEl.addEventListener("loadedmetadata", handleLoadedMetadata);
return () => {
videoEl.removeEventListener("loadedmetadata", handleLoadedMetadata);
};
}, [videoUrl]);
return ( return (
<div className={"flex flex-col gap-2 max-w-3xl m-auto"}> <div className={"flex flex-col gap-2 max-w-3xl m-auto"}>
<video controls <video
ref={videoRef} ref={videoRef}
preload="metadata"
width="600" width="600"
className={"w-full max-w-3xl rounded-lg shadow-lg border border-gray-300 bg-black m-auto"}> className={"w-full max-w-3xl rounded-lg shadow-lg border border-gray-300 bg-black m-auto"}>
<source src={videoUrl} type="video/mp4" /> <source src={videoUrl} type="video/mp4" />
@@ -38,9 +63,14 @@ export default function video() {
Your browser does not support the video tag. Your browser does not support the video tag.
</video> </video>
<RangeSlider className={"w-600px"}
min={0} {metadata &&
max={videoDuration}/> <RangeSlider className={"w-600px"}
min={0}
max={metadata.endPoint}
step={0.1}
onInput={handleInput}/>
}
</div> </div>
); );
} }