add thumbnail support on video upload modal

This commit is contained in:
MarconLP 2023-04-22 05:27:06 +02:00
parent 2b648bd8e6
commit 91dae86499
No known key found for this signature in database
GPG key ID: A08A9C8B623F5EA5

View file

@ -1,4 +1,4 @@
import { type ChangeEvent, Fragment, useState } from "react"; import React, { type ChangeEvent, Fragment, useRef, useState } from "react";
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
import { api } from "~/utils/api"; import { api } from "~/utils/api";
import axios from "axios"; import axios from "axios";
@ -13,6 +13,7 @@ export default function VideoUploadModal() {
const [file, setFile] = useState<File>(); const [file, setFile] = useState<File>();
const getSignedUrl = api.video.getUploadUrl.useMutation(); const getSignedUrl = api.video.getUploadUrl.useMutation();
const apiUtils = api.useContext(); const apiUtils = api.useContext();
const videoRef = useRef<null | HTMLVideoElement>(null);
const handleFileChange = (e: ChangeEvent<HTMLInputElement>): void => { const handleFileChange = (e: ChangeEvent<HTMLInputElement>): void => {
if (e.target.files) { if (e.target.files) {
@ -20,6 +21,16 @@ export default function VideoUploadModal() {
} }
}; };
const generateThumbnail = async (video: HTMLVideoElement) => {
const canvas = document.createElement("canvas");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas
.getContext("2d")
?.drawImage(video, 0, 0, canvas.width, canvas.height);
return await new Promise((resolve) => canvas.toBlob(resolve));
};
function closeModal() { function closeModal() {
setOpen(false); setOpen(false);
} }
@ -27,14 +38,26 @@ export default function VideoUploadModal() {
const handleSubmit = async (): Promise<void> => { const handleSubmit = async (): Promise<void> => {
if (!file) return; if (!file) return;
setSubmitting(true); setSubmitting(true);
const { signedUrl, id } = await getSignedUrl.mutateAsync({ const { signedVideoUrl, signedThumbnailUrl, id } =
key: file.name, await getSignedUrl.mutateAsync({
}); key: file.name,
});
await axios await axios
.put(signedUrl, file.slice(), { .put(signedVideoUrl, file.slice(), {
headers: { "Content-Type": file.type }, headers: { "Content-Type": file.type },
}) })
.then(async () => {
if (!videoRef.current) return;
return axios.put(
signedThumbnailUrl,
await generateThumbnail(videoRef.current),
{
headers: { "Content-Type": "image/png" },
}
);
})
.then(() => { .then(() => {
setOpen(false);
void router.push("share/" + id); void router.push("share/" + id);
}) })
.catch((err) => { .catch((err) => {
@ -66,6 +89,14 @@ export default function VideoUploadModal() {
<div className="flex flex-col items-center gap-2"> <div className="flex flex-col items-center gap-2">
<label className="flex h-32 w-full min-w-[300px] cursor-pointer appearance-none justify-center rounded-md border-2 border-dashed border-gray-300 px-4 transition hover:border-gray-400 focus:outline-none"> <label className="flex h-32 w-full min-w-[300px] cursor-pointer appearance-none justify-center rounded-md border-2 border-dashed border-gray-300 px-4 transition hover:border-gray-400 focus:outline-none">
<span className="mx-6 flex items-center space-x-2 text-[#292D34]"> <span className="mx-6 flex items-center space-x-2 text-[#292D34]">
{file ? (
<video
src={URL.createObjectURL(file)}
controls
ref={videoRef}
className="max-h-[0px] max-w-[15px]"
/>
) : null}
{file ? ( {file ? (
<span className="font-medium">{file.name}</span> <span className="font-medium">{file.name}</span>
) : ( ) : (