Files
Socialflow/shared/srt.test.ts
T
Claude f5e2461da1 feat(reels): import d'un fichier SRT lu par la voix à son minutage
- 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
2026-09-27 08:19:44 +00:00

55 lines
1.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
});
});