Backend MP4 conversion (#23)
* ADD conversion queue * ADD RemuxService for MP4 conversion * REMOVE unused conversion queue * REORGANISE Job-related classes * ADD Job stages * REVERT to old commit, using Spring Async instead * ADD asynchronous processing for video tasks * PATCH and streamline progress tracking * ADD asynchronous video processing and job restructuring * REFACTOR job service method * ADD job remux functionality * ADD remuxing endpoint * PATCH complete flag not updating in API response * ADD progress type in frontend * ADD reset functionality for job status * PATCH missing progress bar for subsequent exports * REDESIGN settings box * ADD tracking video file conversion in frontend * PATCH extension bug * REMOVE autowired decorator
This commit is contained in:
@@ -1,25 +1,75 @@
|
||||
import {useState} from "react";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
import { uploadFile } from "../utils/endpoints"
|
||||
import {uploadFile, convertFile, getProgress} from "../utils/endpoints"
|
||||
import BlueButton from "../components/buttons/BlueButton.tsx";
|
||||
import Box from "../components/Box.tsx";
|
||||
|
||||
const clipUpload = () => {
|
||||
const ClipUpload = () => {
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [error, setError] = useState<null | string>(null);
|
||||
const [progress, setProgress] = useState<number>(0);
|
||||
|
||||
const isVideoFileSupported = (file: File): boolean => {
|
||||
const video = document.createElement("video");
|
||||
|
||||
if (file.type && video.canPlayType(file.type) !== "") {
|
||||
return true;
|
||||
}
|
||||
|
||||
const extension = file.name.split(".").pop()?.toLowerCase();
|
||||
const extensionToMime: Record<string, string> = {
|
||||
mp4: "video/mp4",
|
||||
webm: "video/webm",
|
||||
ogg: "video/ogg",
|
||||
mov: "video/quicktime",
|
||||
};
|
||||
|
||||
if (extension && extensionToMime[extension]) {
|
||||
return video.canPlayType(extensionToMime[extension]) !== "";
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const press = (() => {
|
||||
if (!file) {
|
||||
setError("Please choose a file");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uploadFile(file)
|
||||
.then(uuid => navigate(`/create/${uuid}`))
|
||||
.then(uuid => {
|
||||
|
||||
if (isVideoFileSupported(file)) {
|
||||
navigate(`/create/${uuid}`)
|
||||
} else {
|
||||
convertFile(uuid);
|
||||
const interval = setInterval(async() => await pollProgress(uuid, interval), 500);
|
||||
}
|
||||
|
||||
})
|
||||
.catch((e: Error) => setError(`Failed to upload file: ${e.message}`));
|
||||
|
||||
});
|
||||
|
||||
const pollProgress = async (id: string, intervalId: number) => {
|
||||
getProgress(id)
|
||||
.then((progress) => {
|
||||
setProgress(progress.conversion.progress);
|
||||
|
||||
if (progress.conversion.complete) {
|
||||
clearInterval(intervalId);
|
||||
navigate(`/create/${id}`)
|
||||
}
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
setError(`Failed to fetch progress: ${err.message}`);
|
||||
clearInterval(intervalId);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Box className={"flex flex-col justify-between gap-3 p-5"}>
|
||||
<input
|
||||
@@ -37,8 +87,12 @@ const clipUpload = () => {
|
||||
</BlueButton>
|
||||
|
||||
<label className={"text-center text-red-500"}>{error}</label>
|
||||
<progress
|
||||
value={progress}
|
||||
className={"bg-gray-300 rounded-lg h-1"}>
|
||||
</progress>
|
||||
</Box>
|
||||
)
|
||||
};
|
||||
|
||||
export default clipUpload;
|
||||
export default ClipUpload;
|
||||
|
||||
Reference in New Issue
Block a user