mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-11 17:26:45 +02:00
- Nouveau Reel (bureau et mobile) : bouton « Importer un fichier SRT ». Tant qu'un SRT est chargé, le texte libre et l'assistant IA sont désactivés ; le choix de la voix (moteur, voix, ton) reste disponible. - Service Python : chaque sous-titre est lu séparément, ses silences retirés, puis posé à son instant de début. Une lecture trop longue est accélérée (atempo, sans changer la hauteur) pour tenir dans la durée du sous-titre, avec un avertissement au-delà de ×1,35. Après un repli sur Edge, tous les sous-titres gardent la même voix. - Sans voix, les mots de chaque sous-titre s'affichent sur son intervalle. - Aperçu : sous-titres calés sur le minutage du fichier. - Tests : lecture SRT (TS), fenêtres, accélération et mixage (Python). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WVqEw4Xycgf8BtwmSftE2M
55 lines
1.9 KiB
TypeScript
55 lines
1.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
import { parseSrt, srtEnd, srtText, srtWords } from "./srt";
|
||
import { videoReelParamsSchema } from "./reel";
|
||
|
||
const SAMPLE = `1
|
||
00:00:01,000 --> 00:00:03,500
|
||
Bonjour à tous !
|
||
|
||
2
|
||
00:00:04,000 --> 00:00:06,250
|
||
<i>Découvrez</i> nos
|
||
nouveautés en magasin
|
||
|
||
3
|
||
00:00:07,000 --> 00:00:07,000
|
||
Durée nulle, ignoré
|
||
`;
|
||
|
||
describe("parseSrt", () => {
|
||
it("lit les sous-titres, retire les balises et réunit les lignes", () => {
|
||
const cues = parseSrt(SAMPLE.replace(/\n/g, "\r\n"));
|
||
expect(cues).toEqual([
|
||
{ start: 1, end: 3.5, text: "Bonjour à tous !" },
|
||
{ start: 4, end: 6.25, text: "Découvrez nos nouveautés en magasin" },
|
||
]);
|
||
expect(srtText(cues)).toBe("Bonjour à tous ! Découvrez nos nouveautés en magasin");
|
||
expect(srtEnd(cues)).toBe(6.25);
|
||
});
|
||
|
||
it("accepte les millisecondes séparées par un point et sans numéro", () => {
|
||
expect(parseSrt("00:00:02.5 --> 00:00:04.0\nSalut")).toEqual([{ start: 2.5, end: 4, text: "Salut" }]);
|
||
});
|
||
|
||
it("refuse un fichier sans sous-titre", () => {
|
||
expect(() => parseSrt("pas un srt")).toThrow(/Aucun sous-titre/);
|
||
});
|
||
|
||
it("répartit les mots dans l'intervalle de leur sous-titre", () => {
|
||
const words = srtWords(parseSrt(SAMPLE));
|
||
const second = words.findIndex((w) => w.text === "Découvrez");
|
||
expect(words[0].start).toBe(1);
|
||
expect(words[second - 1].end).toBeCloseTo(3.5);
|
||
expect(words[second].start).toBe(4);
|
||
expect(words[words.length - 1].end).toBeCloseTo(6.25);
|
||
});
|
||
});
|
||
|
||
describe("videoReelParamsSchema avec SRT", () => {
|
||
it("accepte des sous-titres valides et refuse une durée nulle", () => {
|
||
const base = { videoMediaId: "v", pageIds: ["p"] };
|
||
expect(videoReelParamsSchema.safeParse({ ...base, srtCues: [{ start: 0, end: 1, text: "a" }] }).success).toBe(true);
|
||
expect(videoReelParamsSchema.safeParse({ ...base, srtCues: [{ start: 1, end: 1, text: "a" }] }).success).toBe(false);
|
||
});
|
||
});
|