feat: Implement new Reel creation functionality with dedicated mobile and desktop UIs, server-side API routes, and a new FFmpeg processing service.

This commit is contained in:
Michael committed 2026-03-19 14:51:16 +01:00
1 parent ae0048a6e1
commit 3a5acd425c
5 files changed
+42 -2

No files matched your search

+13
View File
@@ -63,6 +63,7 @@ export default function MobileNewReel() {
// État audio preview
const [isPlaying, setIsPlaying] = useState<string | null>(null);
const [stabilize, setStabilize] = useState(true); // Activé par défaut pour les Reels
const [enableEndingEffect, setEnableEndingEffect] = useState(true);
const { data: pages = [] } = useQuery<SocialPage[]>({
@@ -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}
/>
<div className="flex items-center space-x-2 mt-4">
<Switch
id="enable-ending-effect"
checked={enableEndingEffect}
onCheckedChange={setEnableEndingEffect}
/>
<Label htmlFor="enable-ending-effect" className="font-medium cursor-pointer">
Activer l'effet de fin (logo + fondu)
</Label>
</div>
<div className="flex items-center space-x-2 mt-4">
<Switch
id="tts-mode"
+13
View File
@@ -68,6 +68,7 @@ export default function NewReel() {
const [ttsVoice, setTtsVoice] = useState("fr-FR-VivienneMultilingualNeural");
const [drawText, setDrawText] = useState(true);
const [stabilize, setStabilize] = useState(true); // default to true
const [enableEndingEffect, setEnableEndingEffect] = useState(true);
// Enable TTS by default on mobile
useEffect(() => {
@@ -336,6 +337,7 @@ export default function NewReel() {
ttsVoice,
drawText,
stabilize: stabilize,
enableEndingEffect,
});
};
@@ -710,6 +712,17 @@ export default function NewReel() {
</Label>
</div>
<div className="flex items-center space-x-2 mt-4">
<Switch
id="enable-ending-effect"
checked={enableEndingEffect}
onCheckedChange={setEnableEndingEffect}
/>
<Label htmlFor="enable-ending-effect" className="font-medium cursor-pointer">
Activer l'effet de fin (logo + fondu)
</Label>
</div>
<div className="flex items-center space-x-2 mt-4">
<Switch
id="tts-mode"
+5 -2
View File
@@ -161,6 +161,7 @@ class ReelRequest(BaseModel):
tts_voice: str = "fr-FR-VivienneMultilingualNeural"
draw_text: bool = True
stabilize: bool = False # Stabilisation vidéo via vidstab
enable_ending_effect: bool = True
def clean_text_for_display(text: str) -> 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]"
+6
View File
@@ -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
+5
View File
@@ -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