feat: add video upload feature with support for validation and processing

- Introduced "video" as a new content type across backend and frontend.
- Updated validation schemas and MIME-type handling for video files.
- Implemented file size limits for videos (10 MB max) in configuration.
- Enhanced upload flow with auto-detection of file types (image, GIF, video).
- Expanded media processing to handle video files and convert them to WebM format.
This commit is contained in:
Mathis HERRIOT
2026-01-28 14:07:00 +01:00
parent f4cd20a010
commit f1a571196d
8 changed files with 54 additions and 25 deletions

View File

@@ -42,7 +42,7 @@ import type { Category } from "@/types/content";
const uploadSchema = z.object({
title: z.string().min(3, "Le titre doit faire au moins 3 caractères"),
type: z.enum(["meme", "gif"]),
type: z.enum(["meme", "gif", "video"]),
categoryId: z.string().optional(),
tags: z.string().optional(),
});
@@ -112,6 +112,16 @@ export default function UploadPage() {
return;
}
setFile(selectedFile);
// Auto-détection du type
if (selectedFile.type === "image/gif") {
form.setValue("type", "gif");
} else if (selectedFile.type.startsWith("video/")) {
form.setValue("type", "video");
} else {
form.setValue("type", "meme");
}
const reader = new FileReader();
reader.onloadend = () => {
setPreview(reader.result as string);
@@ -182,7 +192,7 @@ export default function UploadPage() {
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<div className="space-y-4">
<FormLabel>Fichier (Image ou GIF)</FormLabel>
<FormLabel>Fichier (Image, GIF ou Vidéo)</FormLabel>
{!preview ? (
<button
type="button"
@@ -194,25 +204,29 @@ export default function UploadPage() {
</div>
<p className="font-medium">Cliquez pour choisir un fichier</p>
<p className="text-xs text-muted-foreground mt-1">
PNG, JPG ou GIF jusqu'à 10Mo
PNG, JPG, GIF, MP4 ou MOV jusqu'à 10Mo
</p>
<input
id="file-upload"
type="file"
className="hidden"
accept="image/*,.gif"
accept="image/*,video/mp4,video/webm,video/quicktime,.gif"
onChange={handleFileChange}
/>
</button>
) : (
<div className="relative rounded-lg overflow-hidden border bg-zinc-100 dark:bg-zinc-800">
<div className="relative h-[400px] w-full">
<NextImage
src={preview}
alt="Preview"
fill
className="object-contain"
/>
<div className="relative h-[400px] w-full flex items-center justify-center">
{file?.type.startsWith("video/") ? (
<video src={preview} controls className="max-h-full max-w-full" />
) : (
<NextImage
src={preview}
alt="Preview"
fill
className="object-contain"
/>
)}
</div>
<Button
type="button"
@@ -260,6 +274,7 @@ export default function UploadPage() {
<SelectContent>
<SelectItem value="meme">Image fixe</SelectItem>
<SelectItem value="gif">GIF Animé</SelectItem>
<SelectItem value="video">Vidéo</SelectItem>
</SelectContent>
</Select>
<FormMessage />

View File

@@ -7,7 +7,7 @@ export interface Content {
description?: string;
url: string;
thumbnailUrl?: string;
type: "meme" | "gif";
type: "meme" | "gif" | "video";
mimeType: string;
size: number;
width?: number;