mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-23 15:08:13 +02:00
feat: Add music search and favorite API routes, and introduce FFmpeg service for Reels.
This commit is contained in:
1 parent
cb42558e52
commit
4fcc8cf53c
4 files changed
+44
-5
No files matched your search
+16
-2
@@ -153,6 +153,7 @@ class ReelRequest(BaseModel):
|
|||||||
music_id: Optional[str] = None
|
music_id: Optional[str] = None
|
||||||
music_url: Optional[str] = None
|
music_url: Optional[str] = None
|
||||||
watermark_url: Optional[str] = None
|
watermark_url: Optional[str] = None
|
||||||
|
store_name: Optional[str] = None
|
||||||
word_duration: float = 0.6
|
word_duration: float = 0.6
|
||||||
font_size: int = 64
|
font_size: int = 64
|
||||||
music_volume: float = 0.25
|
music_volume: float = 0.25
|
||||||
@@ -819,8 +820,21 @@ async def process_reel(request: ReelRequest, x_api_key: str = Header(None)):
|
|||||||
v_chain += text_filter
|
v_chain += text_filter
|
||||||
|
|
||||||
if has_watermark:
|
if has_watermark:
|
||||||
fc_parts.append(f"[{watermark_idx}:v]scale=200:-1[wm]")
|
if request.store_name:
|
||||||
v_chain += "[v_pre_wm];[v_pre_wm][wm]overlay=W-w-20:H-h-20"
|
# Ouro Party Mode
|
||||||
|
# 1. Scaling the logo large for the center
|
||||||
|
fc_parts.append(f"[{watermark_idx}:v]scale=-1:300[wm]")
|
||||||
|
# 2. Placing it in the center, and fading it IN during the last 2 seconds
|
||||||
|
v_chain += f"[v_pre_wm];[v_pre_wm][wm]overlay=(W-w)/2:(H-h)/2-100:enable='between(t,{fade_start},{video_duration})'"
|
||||||
|
# 3. Drawing the Store Name below the logo, with a fade in as well
|
||||||
|
escaped_store_name = request.store_name.replace("'", "\\'").replace(
|
||||||
|
":", "\\:"
|
||||||
|
)
|
||||||
|
v_chain += f",drawtext=text='{escaped_store_name}':x=(w-text_w)/2:y=(h-text_h)/2+150:fontsize=70:fontcolor=white:shadowcolor=black:shadowx=3:shadowy=3:enable='between(t,{fade_start},{video_duration})'"
|
||||||
|
else:
|
||||||
|
# Normal watermark (bottom right)
|
||||||
|
fc_parts.append(f"[{watermark_idx}:v]scale=200:-1[wm]")
|
||||||
|
v_chain += "[v_pre_wm];[v_pre_wm][wm]overlay=W-w-20:H-h-20"
|
||||||
|
|
||||||
# Add Video Fade Out
|
# Add Video Fade Out
|
||||||
v_chain += f",fade=t=out:st={fade_start}:d={fade_duration}"
|
v_chain += f",fade=t=out:st={fade_start}:d={fade_duration}"
|
||||||
|
|||||||
+15
-2
@@ -470,7 +470,8 @@ async function processReelBackground(
|
|||||||
musicVolume?: number;
|
musicVolume?: number;
|
||||||
drawText?: boolean;
|
drawText?: boolean;
|
||||||
stabilize?: boolean;
|
stabilize?: boolean;
|
||||||
}
|
},
|
||||||
|
storeName?: string
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
videoMediaId,
|
videoMediaId,
|
||||||
@@ -567,6 +568,7 @@ async function processReelBackground(
|
|||||||
drawText,
|
drawText,
|
||||||
stabilize,
|
stabilize,
|
||||||
watermarkUrl,
|
watermarkUrl,
|
||||||
|
storeName,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`⏱️ [Background] FFmpeg took ${(Date.now() - startTime) / 1000}s`);
|
console.log(`⏱️ [Background] FFmpeg took ${(Date.now() - startTime) / 1000}s`);
|
||||||
@@ -746,6 +748,17 @@ reelsRouter.post('/reels', async (req: Request, res: Response) => {
|
|||||||
? "File d'attente pleine. Votre vidéo sera traitée dès que possible."
|
? "File d'attente pleine. Votre vidéo sera traitée dès que possible."
|
||||||
: "Traitement démarré en arrière-plan.";
|
: "Traitement démarré en arrière-plan.";
|
||||||
|
|
||||||
|
// Récupérer le nom de la première page pour l'utiliser comme storeName
|
||||||
|
let storeName: string | undefined = undefined;
|
||||||
|
try {
|
||||||
|
const page = await storage.getSocialPage(pageIds[0]);
|
||||||
|
if (page) {
|
||||||
|
storeName = page.pageName;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Erreur récupération nom de page', e);
|
||||||
|
}
|
||||||
|
|
||||||
// Créer immédiatement le Post en base
|
// Créer immédiatement le Post en base
|
||||||
// ON STOCKE LES PARAMS DU JOB DANS productInfo POUR POUVOIR LE REPRENDRE PLUS TARD
|
// ON STOCKE LES PARAMS DU JOB DANS productInfo POUR POUVOIR LE REPRENDRE PLUS TARD
|
||||||
// C'est un hack car on n'a pas de table params_job, mais ça marche car productInfo est jsonb
|
// C'est un hack car on n'a pas de table params_job, mais ça marche car productInfo est jsonb
|
||||||
@@ -764,7 +777,7 @@ reelsRouter.post('/reels', async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
if (!isQueueBusy) {
|
if (!isQueueBusy) {
|
||||||
// Démarrer le traitement en arrière-plan (Fire & Forget)
|
// Démarrer le traitement en arrière-plan (Fire & Forget)
|
||||||
processReelBackground(user.id, post.id, req.body).catch(err => {
|
processReelBackground(user.id, post.id, req.body, storeName).catch(err => {
|
||||||
console.error('🔥 Unhandled background error:', err);
|
console.error('🔥 Unhandled background error:', err);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ interface FFmpegReelRequest {
|
|||||||
draw_text?: boolean; // Dessiner le texte sur la vidéo (default: true)
|
draw_text?: boolean; // Dessiner le texte sur la vidéo (default: true)
|
||||||
stabilize?: boolean; // Stabilisation vidéo via vidstab (default: false)
|
stabilize?: boolean; // Stabilisation vidéo via vidstab (default: false)
|
||||||
watermark_url?: string; // URL du logo
|
watermark_url?: string; // URL du logo
|
||||||
|
store_name?: string; // Nom du magasin pour l'outro
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FFmpegReelResponse {
|
interface FFmpegReelResponse {
|
||||||
@@ -75,6 +76,7 @@ export class FFmpegService {
|
|||||||
drawText?: boolean;
|
drawText?: boolean;
|
||||||
stabilize?: boolean;
|
stabilize?: boolean;
|
||||||
watermarkUrl?: string;
|
watermarkUrl?: string;
|
||||||
|
storeName?: string;
|
||||||
} = {}
|
} = {}
|
||||||
): Promise<{ success: boolean; videoBase64?: string; duration?: number; error?: string }> {
|
): Promise<{ success: boolean; videoBase64?: string; duration?: number; error?: string }> {
|
||||||
const config = this.ensureConfigured();
|
const config = this.ensureConfigured();
|
||||||
@@ -92,6 +94,7 @@ export class FFmpegService {
|
|||||||
draw_text: options.drawText ?? true,
|
draw_text: options.drawText ?? true,
|
||||||
stabilize: options.stabilize ?? false,
|
stabilize: options.stabilize ?? false,
|
||||||
watermark_url: options.watermarkUrl,
|
watermark_url: options.watermarkUrl,
|
||||||
|
store_name: options.storeName,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove undefined values
|
// Remove undefined values
|
||||||
@@ -172,6 +175,7 @@ export class FFmpegService {
|
|||||||
drawText?: boolean;
|
drawText?: boolean;
|
||||||
stabilize?: boolean;
|
stabilize?: boolean;
|
||||||
watermarkUrl?: string;
|
watermarkUrl?: string;
|
||||||
|
storeName?: string;
|
||||||
} = {}
|
} = {}
|
||||||
): Promise<{ success: boolean; videoBase64?: string; duration?: number; error?: string }> {
|
): Promise<{ success: boolean; videoBase64?: string; duration?: number; error?: string }> {
|
||||||
const config = this.ensureConfigured();
|
const config = this.ensureConfigured();
|
||||||
@@ -189,6 +193,7 @@ export class FFmpegService {
|
|||||||
draw_text: options.drawText ?? true,
|
draw_text: options.drawText ?? true,
|
||||||
stabilize: options.stabilize ?? false,
|
stabilize: options.stabilize ?? false,
|
||||||
watermark_url: options.watermarkUrl,
|
watermark_url: options.watermarkUrl,
|
||||||
|
store_name: options.storeName,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Remove undefined values
|
// Remove undefined values
|
||||||
|
|||||||
@@ -6,10 +6,17 @@ Ajout d'une fonctionnalité complète de création de Reels Facebook permettant
|
|||||||
|
|
||||||
## Current Focus
|
## Current Focus
|
||||||
|
|
||||||
**Phase: EXECUTION** - Implémentation de la gestion interne des musiques (MP3) et incrustation du logo existant sur les Reels.
|
**Phase: EXECUTION** - Implémenter l'effet Outro (Logo central + nom du magasin) à la fin des Réels via le Party Mode.
|
||||||
|
|
||||||
## Master Plan
|
## Master Plan
|
||||||
|
|
||||||
|
### Party Mode & Outro (Nouvelle fonctionnalité)
|
||||||
|
|
||||||
|
- [x] Créer l'Implementation Plan basé sur la réflexion du Party Mode
|
||||||
|
- [/] `server/routes/reels.ts` : Passer `storeName` à FFmpeg (le nom de la page).
|
||||||
|
- [/] `ffmpeg-service/main.py` : Ajouter le scale du logo et `drawtext` du `storeName` centrés.
|
||||||
|
- [/] Appliquer ces filtres avec un fondu d'entrée correspondant à la durée du fondu de sortie global.
|
||||||
|
|
||||||
### Phase 0: Clarifications ✅
|
### Phase 0: Clarifications ✅
|
||||||
|
|
||||||
- [x] Confirmer source de musique → FreeSound API (ex-Jamendo)
|
- [x] Confirmer source de musique → FreeSound API (ex-Jamendo)
|
||||||
|
|||||||
Reference in new issue
Block a user