From 3a5acd425c1707376f20efb81dfe792d5d70a2e5 Mon Sep 17 00:00:00 2001 From: R0m1k3 Date: Thu, 19 Mar 2026 14:51:16 +0100 Subject: [PATCH] feat: Implement new Reel creation functionality with dedicated mobile and desktop UIs, server-side API routes, and a new FFmpeg processing service. --- client/src/pages/mobile/new-reel.tsx | 13 +++++++++++++ client/src/pages/new-reel.tsx | 13 +++++++++++++ ffmpeg-service/main.py | 7 +++++-- server/routes/reels.ts | 6 ++++++ server/services/ffmpeg.ts | 5 +++++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/client/src/pages/mobile/new-reel.tsx b/client/src/pages/mobile/new-reel.tsx index 04073e8..cc2ea1b 100644 --- a/client/src/pages/mobile/new-reel.tsx +++ b/client/src/pages/mobile/new-reel.tsx @@ -63,6 +63,7 @@ export default function MobileNewReel() { // État audio preview const [isPlaying, setIsPlaying] = useState(null); const [stabilize, setStabilize] = useState(true); // Activé par défaut pour les Reels + const [enableEndingEffect, setEnableEndingEffect] = useState(true); const { data: pages = [] } = useQuery({ @@ -204,6 +205,7 @@ export default function MobileNewReel() { drawText: true, ttsEnabled, ttsVoice, + enableEndingEffect, }); }; @@ -395,6 +397,17 @@ export default function MobileNewReel() { className="text-lg" rows={3} /> +
+ + +
+
{ @@ -336,6 +337,7 @@ export default function NewReel() { ttsVoice, drawText, stabilize: stabilize, + enableEndingEffect, }); }; @@ -710,6 +712,17 @@ export default function NewReel() {
+
+ + +
+
str: @@ -861,7 +862,7 @@ async def process_reel(request: ReelRequest, x_api_key: str = Header(None)): v_chain += text_filter if has_watermark: - if request.store_name: + if request.store_name and request.enable_ending_effect: # Ouro Party Mode + Persistent bottom right # We need two scaled versions of the logo @@ -890,7 +891,9 @@ async def process_reel(request: ReelRequest, x_api_key: str = Header(None)): v_chain += "[v_pre_wm];[v_pre_wm][wm]overlay=W-w-20:H-h-20" # Add Video Fade Out - v_chain += f",fade=t=out:st={fade_start}:d={fade_duration}" + if request.enable_ending_effect: + v_chain += f",fade=t=out:st={fade_start}:d={fade_duration}" + # End of video chain v_chain += "[vout]" diff --git a/server/routes/reels.ts b/server/routes/reels.ts index 51c6421..085d574 100644 --- a/server/routes/reels.ts +++ b/server/routes/reels.ts @@ -302,6 +302,7 @@ reelsRouter.post('/reels/preview', async (req: Request, res: Response) => { musicVolume = 0.25, drawText = true, stabilize = false, + enableEndingEffect = true, } = req.body; // Récupérer le média vidéo @@ -360,6 +361,7 @@ reelsRouter.post('/reels/preview', async (req: Request, res: Response) => { drawText, stabilize, watermarkUrl, + enableEndingEffect, }); if (!result.success) { @@ -471,6 +473,7 @@ async function processReelBackground( musicVolume?: number; drawText?: boolean; stabilize?: boolean; + enableEndingEffect?: boolean; }, storeName?: string ) { @@ -489,6 +492,7 @@ async function processReelBackground( musicVolume, drawText, stabilize, + enableEndingEffect, } = data; console.log(`🔄 [Background] Starting processing for Post ${postId}`); @@ -570,6 +574,7 @@ async function processReelBackground( stabilize, watermarkUrl, storeName, + enableEndingEffect, }); console.log(`⏱️ [Background] FFmpeg took ${(Date.now() - startTime) / 1000}s`); @@ -728,6 +733,7 @@ reelsRouter.post('/reels', async (req: Request, res: Response) => { musicVolume = 0.25, drawText = true, stabilize = false, + enableEndingEffect = true, } = req.body; // Validation immédiate diff --git a/server/services/ffmpeg.ts b/server/services/ffmpeg.ts index 9dfe5f1..f59b907 100644 --- a/server/services/ffmpeg.ts +++ b/server/services/ffmpeg.ts @@ -20,6 +20,7 @@ interface FFmpegReelRequest { stabilize?: boolean; // Stabilisation vidéo via vidstab (default: false) watermark_url?: string; // URL du logo store_name?: string; // Nom du magasin pour l'outro + enable_ending_effect?: boolean; // Activer l'effet de fin (logo+fondu) } interface FFmpegReelResponse { @@ -77,6 +78,7 @@ export class FFmpegService { stabilize?: boolean; watermarkUrl?: string; storeName?: string; + enableEndingEffect?: boolean; } = {} ): Promise<{ success: boolean; videoBase64?: string; duration?: number; error?: string }> { const config = this.ensureConfigured(); @@ -95,6 +97,7 @@ export class FFmpegService { stabilize: options.stabilize ?? false, watermark_url: options.watermarkUrl, store_name: options.storeName, + enable_ending_effect: options.enableEndingEffect ?? true, }; // Remove undefined values @@ -176,6 +179,7 @@ export class FFmpegService { stabilize?: boolean; watermarkUrl?: string; storeName?: string; + enableEndingEffect?: boolean; } = {} ): Promise<{ success: boolean; videoBase64?: string; duration?: number; error?: string }> { const config = this.ensureConfigured(); @@ -194,6 +198,7 @@ export class FFmpegService { stabilize: options.stabilize ?? false, watermark_url: options.watermarkUrl, store_name: options.storeName, + enable_ending_effect: options.enableEndingEffect ?? true, }; // Remove undefined values