#!/usr/bin/env python3 """Convert a YouTube .vtt (manual or auto-captions) into clean [HH:MM:SS] transcript lines. Usage: vtt_to_transcript.py Handles the rolling-duplicate problem in auto-captions: each cue repeats the tail of the previous cue, so we keep only newly-added words per cue and emit one line per cue start time. Strips inline <00:00:00.000> word-timing tags and HTML tags. """ import sys, re, html from pathlib import Path def safe_user_path(path_value, base_dir="."): """Resolve a CLI path under the current workspace.""" if base_dir != ".": raise ValueError("Custom base directories are not supported for CLI paths") base_path = Path.cwd().resolve() resolved_path = Path(path_value).expanduser().resolve() try: resolved_path.relative_to(base_path) except ValueError as exc: raise ValueError(f"Path escapes allowed directory: {path_value}") from exc return resolved_path TS=re.compile(r'(\d{2}):(\d{2}):(\d{2})\.\d{3}\s*-->\s*(\d{2}):(\d{2}):(\d{2})') INLINE=re.compile(r'<[^>]+>') def hhmmss(h,m,s): return f"[{int(h):02d}:{int(m):02d}:{int(s):02d}]" def clean(text): text=INLINE.sub('',text) text=html.unescape(text) return re.sub(r'\s+',' ',text).strip() def main(): if len(sys.argv)!=3: sys.exit("usage: vtt_to_transcript.py ") raw=safe_user_path(sys.argv[1]).open(encoding='utf-8',errors='replace').read().splitlines() cues=[] # (start_label, text) i=0; cur=None while i {sys.argv[2]}") if __name__=="__main__": main()