fix: vignettes vidéo persistantes et remise à zéro des erreurs de types

Deux corrections demandées ensemble.

1. Vignettes vidéo

Le planificateur supprime la vidéo locale une fois publiée, alors que la
ligne `media` survit pour l'historique. L'interface tentait donc de lire
un fichier disparu pour en extraire une image : d'où les avertissements
« Video thumbnail generation failed » et les tuiles vides.

Une vignette JPEG est désormais extraite à la création du reel, dans les
deux flux de génération, et stockée à part : elle reste disponible quand
la vidéo ne l'est plus. La purge quotidienne la nettoie en même temps que
la ligne qu'elle illustre. L'extraction est tolérante à l'échec — une
vignette manquante dégrade l'affichage mais ne fait jamais échouer une
publication — et le composant retombe sur son icône de remplacement pour
les médias créés avant ce changement. La fonction d'extraction, jusque-là
privée à la route Remotion, devient un service partagé.

2. Erreurs de compilation préexistantes (27 → 0)

- remotion-video.tsx (bureau et mobile) : les composants Select étaient
  utilisés sans être importés, ce qui faisait planter le sélecteur de voix
  à l'exécution.
- external.ts : fileSize et aiGenerated étaient transmis dans un type que
  le schéma ne déclare pas, et ne fonctionnaient que par conversion
  implicite de PostgreSQL.
- reels.ts : l'interface MusicTrack, référencée mais jamais déclarée dans
  ce module.
- remotion.ts : chromiumOptions.args retiré. Remotion ne lit jamais cette
  clé, les drapeaux Chrome qu'elle contenait n'atteignaient donc pas le
  navigateur.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018uUPZ1GNpEkYB1dpXHYPek
This commit is contained in:
Claude committed 2026-08-12 08:00:48 +00:00
1 parent c69fe4e462
commit ac8b494f24
16 files changed
+173 -25

No files matched your search

+19
View File
@@ -8,6 +8,7 @@ import { storage } from '../storage';
import { ffmpegService } from '../services/ffmpeg';
import { facebookService } from '../services/facebook';
import { tiktokService } from '../services/tiktok';
import { createVideoThumbnail } from '../services/thumbnail';
import { minioService as cloudinaryService, buildMinioUrl, resolveInternalUrl } from '../services/minio';
import { openRouterService, describeGenerationError } from '../services/openrouter';
import { db } from '../db';
@@ -15,6 +16,19 @@ import { cloudinaryConfig } from '@shared/schema';
import { eq } from 'drizzle-orm';
import { ttsSyncService } from '../services/ttsSync';
/** Piste musicale telle qu'attendue par le client. */
interface MusicTrack {
id: string;
title: string;
artist: string;
albumName: string;
duration: number;
previewUrl: string;
downloadUrl: string;
imageUrl: string;
license: string;
}
export const reelsRouter = Router();
// ============================================
@@ -616,6 +630,10 @@ async function processReelBackground(
console.log('✅ [Background] Uploaded:', cloudinaryResult.originalUrl);
// 5. Créer l'enregistrement Media pour la vidéo traitée
// La vignette est extraite maintenant : la vidéo sera supprimée du disque
// après publication, mais l'historique doit rester illustré.
const thumbnailUrl = await createVideoThumbnail(videoBuffer);
const processedMedia = await storage.createMedia({
userId: userId,
type: 'video',
@@ -624,6 +642,7 @@ async function processReelBackground(
facebookFeedUrl: cloudinaryResult.facebookFeedUrl || null,
instagramFeedUrl: cloudinaryResult.instagramFeedUrl || null,
instagramStoryUrl: cloudinaryResult.instagramStoryUrl || null,
thumbnailUrl,
fileName: `reel-processed-${Date.now()}.mp4`,
fileSize: videoBuffer.length,
});