RishiKar210's picture
Deploy backend incl. missing-dialogue detection + character creation
03090ce verified
Raw
History Blame Contribute Delete
2.24 kB
"""Parse a SubRip (.srt) subtitle file into a ScriptDoc.
SRT has no native speaker column, so we extract a character from a leading
"NAME:" or "[NAME]" / "(NAME)" tag on the cue when present; otherwise the
segment is left unattributed (characters=[]).
"""
from __future__ import annotations
import re
from pathlib import Path
from .base import ScriptDoc, ScriptSegment, normalize_character, parse_timecode
_TIME_LINE = re.compile(r"(\d{1,2}:\d{2}:\d{2}[.,]\d{1,3})\s*-->\s*(\d{1,2}:\d{2}:\d{2}[.,]\d{1,3})")
# Speaker tag: "NAME:" or "- NAME:" at line start, or "[NAME]" / "(NAME)".
_SPEAKER_PREFIX = re.compile(r"^\s*-?\s*([A-Z][A-Za-z0-9 _'\-/&]{0,30}):\s*(.*)$")
_SPEAKER_BRACKET = re.compile(r"^\s*[\[(]([A-Za-z0-9 _'\-/&]{1,30})[\])]\s*(.*)$")
def _strip_tags(s: str) -> str:
return re.sub(r"<[^>]+>", "", s).strip()
def parse(path: Path) -> ScriptDoc:
raw = path.read_text(encoding="utf-8-sig", errors="ignore")
blocks = re.split(r"\r?\n\r?\n+", raw.strip())
segments: list[ScriptSegment] = []
n = 0
for block in blocks:
lines = [ln for ln in block.splitlines() if ln.strip() != ""]
if not lines:
continue
# Optional leading numeric index line.
if lines[0].strip().isdigit():
lines = lines[1:]
if not lines:
continue
m = _TIME_LINE.search(lines[0])
if not m:
continue
start_s, end_s = parse_timecode(m.group(1)), parse_timecode(m.group(2))
if end_s <= start_s:
continue
text = " ".join(_strip_tags(ln) for ln in lines[1:]).strip()
character_raw = ""
sm = _SPEAKER_PREFIX.match(text) or _SPEAKER_BRACKET.match(text)
if sm:
character_raw = sm.group(1).strip()
text = sm.group(2).strip()
segments.append(ScriptSegment(
index=n, start_s=round(start_s, 3), end_s=round(end_s, 3),
character_raw=character_raw,
characters=normalize_character(character_raw) if character_raw else [],
text=text,
))
n += 1
if not segments:
raise ValueError("No cues parsed from SRT")
return ScriptDoc(source_format="srt", fps=None, segments=segments)