|
| 1 | +"""Transcript text stays literal while generated karaoke markup remains active.""" |
| 2 | +import json |
| 3 | +import shutil |
| 4 | +import subprocess |
| 5 | + |
| 6 | +import pytest |
| 7 | + |
| 8 | +from tools.subtitle.subtitle_gen import SubtitleGen |
| 9 | + |
| 10 | + |
| 11 | +@pytest.mark.parametrize("style", ["none", "word_by_word", "karaoke"]) |
| 12 | +def test_transcript_markup_is_escaped(tmp_path, style): |
| 13 | + fmt = "vtt" |
| 14 | + output = tmp_path / f"captions.{fmt}" |
| 15 | + result = SubtitleGen().execute({ |
| 16 | + "segments": [{"words": [ |
| 17 | + {"word": "<b>tag</b>", "start": 0, "end": 1}, |
| 18 | + {"word": "&", "start": 1, "end": 2}, |
| 19 | + ]}], |
| 20 | + "format": fmt, |
| 21 | + "highlight_style": style, |
| 22 | + "output_path": str(output), |
| 23 | + }) |
| 24 | + assert result.success, result.error |
| 25 | + content = output.read_text() |
| 26 | + assert "<b>tag</b>" in content |
| 27 | + assert "&amp;" in content |
| 28 | + if style == "karaoke": |
| 29 | + assert "<b><b>tag</b></b>" in content |
| 30 | + else: |
| 31 | + assert "<b>" not in content |
| 32 | + |
| 33 | + |
| 34 | +def test_caption_json_keeps_raw_text(tmp_path): |
| 35 | + output = tmp_path / "captions.json" |
| 36 | + result = SubtitleGen().execute({ |
| 37 | + "segments": [{"text": "<b>tag</b> &", "start": 0, "end": 1}], |
| 38 | + "format": "json", "output_path": str(output), |
| 39 | + }) |
| 40 | + assert result.success, result.error |
| 41 | + assert json.loads(output.read_text())["cues"][0]["text"] == "<b>tag</b> &" |
| 42 | + |
| 43 | + |
| 44 | +@pytest.mark.skipif(shutil.which("ffmpeg") is None, reason="ffmpeg not installed") |
| 45 | +@pytest.mark.parametrize("style", ["none", "word_by_word", "karaoke"]) |
| 46 | +def test_srt_remains_compatible_with_ffmpeg(tmp_path, style): |
| 47 | + source = tmp_path / "captions.srt" |
| 48 | + output = tmp_path / "captions.ass" |
| 49 | + result = SubtitleGen().execute({ |
| 50 | + "segments": [{"words": [{"word": "AT&T", "start": 0, "end": 1}]}], |
| 51 | + "format": "srt", "highlight_style": style, "output_path": str(source), |
| 52 | + }) |
| 53 | + assert result.success, result.error |
| 54 | + subprocess.run(["ffmpeg", "-v", "error", "-y", "-i", str(source), str(output)], |
| 55 | + check=True, capture_output=True, timeout=10) |
| 56 | + rendered = output.read_text() |
| 57 | + assert "AT&T" in rendered |
| 58 | + assert "&" not in rendered |
0 commit comments