mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-11 17:26:45 +02:00
Service ffmpeg-api réécrit (ffmpeg-service/app/) : - Appels FFmpeg asynchrones : le service ne se fige plus pendant un rendu - Vidéo récupérée par téléchargement (GET /files/…) au lieu de base64 en JSON - Vraies erreurs HTTP ; échec explicite si la voix demandée est impossible - 30 voix Gemini + ton de lecture (dynamique, chaleureux, promo, calme), clé en en-tête, modèle configurable avec repli - Edge TTS 7 (minutage des mots restauré), secours en voix françaises - Voix traitée : filtre, compression, niveau constant ; musique bouclée et baissée automatiquement sous la voix ; mix final à -14 LUFS - Sous-titres calés mot à mot (Whisper pour Gemini et la voix d'origine, à la place de ffsubsync), style Montserrat, placés hors des boutons Reels - Vidéo : plus de retouche luminosité forcée, scaling lanczos, HDR iPhone converti, BT.709, AAC 48 kHz 192k ; la vidéo s'allonge si la voix dépasse - Grand logo de fin affiché après la voix ; FFmpeg 7.0.2 épinglé, polices et modèle Whisper intégrés à l'image ; tests pytest et ruff Application : - Sélecteur de voix partagé (4 pages) : moteur, 30 voix, ton, écoute - Reel images : minutage réel des mots, interrupteur voix respecté - sync-info ne génère plus de voix à chaque frappe (estimation locale) - Stabilisation désactivée par défaut, route /reels/preview inutilisée retirée - Log « [ReelQueue] Worker démarré » pour vérifier la version déployée Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018Ze4bs7tpF1KGWUk6ZZSZ4
45 lines
1.2 KiB
Python
45 lines
1.2 KiB
Python
"""Dossiers de travail des rendus et purge des fichiers oubliés."""
|
|
|
|
import re
|
|
import shutil
|
|
import time
|
|
import uuid
|
|
from pathlib import Path
|
|
|
|
from . import config
|
|
|
|
_SAFE_ID = re.compile(r"^[0-9a-f-]{36}$")
|
|
_SAFE_NAME = re.compile(r"^[\w.-]+$")
|
|
|
|
|
|
def new_job() -> tuple[str, Path]:
|
|
job_id = str(uuid.uuid4())
|
|
workdir = config.TEMP_DIR / job_id
|
|
workdir.mkdir(parents=True)
|
|
return job_id, workdir
|
|
|
|
|
|
def job_file(job_id: str, name: str) -> Path | None:
|
|
"""Fichier d'un job, ou None si l'identifiant ou le nom sont suspects."""
|
|
if not _SAFE_ID.match(job_id) or not _SAFE_NAME.match(name):
|
|
return None
|
|
path = config.TEMP_DIR / job_id / name
|
|
return path if path.is_file() else None
|
|
|
|
|
|
def remove_job(job_id: str) -> None:
|
|
if _SAFE_ID.match(job_id):
|
|
shutil.rmtree(config.TEMP_DIR / job_id, ignore_errors=True)
|
|
|
|
|
|
def purge_expired() -> int:
|
|
"""Supprime les dossiers plus vieux que FILE_TTL_SECONDS."""
|
|
config.TEMP_DIR.mkdir(parents=True, exist_ok=True)
|
|
limit = time.time() - config.FILE_TTL_SECONDS
|
|
removed = 0
|
|
for entry in config.TEMP_DIR.iterdir():
|
|
if entry.is_dir() and entry.stat().st_mtime < limit:
|
|
shutil.rmtree(entry, ignore_errors=True)
|
|
removed += 1
|
|
return removed
|