mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-11 17:26:45 +02:00
Une case sur les écrans de création (bureau, mobile) et de programmation d'un Reel double la publication d'une story vidéo sur les pages Facebook sélectionnées. TikTok n'ayant pas de stories, l'option ne le concerne pas. - Publication immédiate : la story part juste après le Reel, à partir de la vidéo rendue envoyée en binaire (nouvelle publishVideoStoryFromBuffer). Un échec de la story est noté dans l'historique sans faire échouer le Reel. - Publication programmée : une entrée « story » est planifiée à côté du Reel ; le planificateur la publie comme les autres stories. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPMYHUDaZyrG3xRCM5iGVr
64 lines
2.5 KiB
TypeScript
64 lines
2.5 KiB
TypeScript
/**
|
|
* Paramètres des rendus de Reels, validés à l'entrée des routes et stockés tels
|
|
* quels dans `reel_jobs.params` : un job repris après redémarrage retrouve ainsi
|
|
* exactement ce que l'utilisateur avait demandé.
|
|
*/
|
|
|
|
import { z } from "zod";
|
|
import { CAPTION_STYLES, DEFAULT_CAPTION_STYLE } from "./captions";
|
|
import { srtCuesSchema } from "./srt";
|
|
import { TTS_ENGINES, TTS_STYLES } from "./voices";
|
|
|
|
const optionalText = z
|
|
.string()
|
|
.trim()
|
|
.optional()
|
|
.transform((value) => (value ? value : undefined));
|
|
|
|
/** Reel construit à partir d'une vidéo de la médiathèque. */
|
|
export const videoReelParamsSchema = z.object({
|
|
videoMediaId: z.string({ required_error: "Vidéo requise" }).min(1, "Vidéo requise"),
|
|
pageIds: z
|
|
.array(z.string().min(1), { required_error: "Au moins une page requise" })
|
|
.min(1, "Au moins une page requise"),
|
|
musicTrackId: optionalText,
|
|
musicUrl: optionalText,
|
|
overlayText: optionalText,
|
|
// Sous-titres SRT : remplacent le texte libre, la voix lit chacun à son instant
|
|
srtCues: srtCuesSchema.optional(),
|
|
description: optionalText,
|
|
ttsEnabled: z.boolean().default(false),
|
|
ttsVoice: optionalText,
|
|
ttsEngine: z.enum(TTS_ENGINES).optional(),
|
|
ttsStyle: z.enum(TTS_STYLES).optional(),
|
|
scheduledFor: optionalText,
|
|
// Publie aussi la vidéo en story sur les pages Facebook (sans effet sur TikTok)
|
|
alsoStory: z.boolean().default(false),
|
|
// Ancien réglage, ignoré : le minutage vient désormais de la voix elle-même
|
|
wordDuration: z.number().optional(),
|
|
fontSize: z.number().int().min(16).max(200).default(64),
|
|
musicVolume: z.number().min(0).max(2).default(0.25),
|
|
drawText: z.boolean().default(true),
|
|
captionStyle: z.enum(CAPTION_STYLES).default(DEFAULT_CAPTION_STYLE),
|
|
stabilize: z.boolean().default(false),
|
|
// Petit logo pendant la vidéo ; le grand logo de fin dépend de enableEndingEffect
|
|
showLogo: z.boolean().default(true),
|
|
enableEndingEffect: z.boolean().default(true),
|
|
// Déterminé par le serveur à partir de la première page, jamais par le client
|
|
storeName: z.string().optional(),
|
|
});
|
|
|
|
export type VideoReelParams = z.infer<typeof videoReelParamsSchema>;
|
|
|
|
/** Aperçu de la voix. */
|
|
export const ttsPreviewSchema = z.object({
|
|
text: z.string({ required_error: "Texte requis" }).trim().min(1, "Texte requis").max(2000),
|
|
ttsVoice: optionalText,
|
|
ttsEngine: z.enum(TTS_ENGINES).optional(),
|
|
ttsStyle: z.enum(TTS_STYLES).optional(),
|
|
});
|
|
|
|
export type ReelJobKind = "video";
|
|
|
|
export type ReelJobStatus = "pending" | "processing" | "completed" | "failed";
|