#!/usr/bin/env python3 """Lädt die Untertitel eines YouTube-Videos und speichert ihren Text als Datei (yt_untertitel.py + vtt2txt.py in einem Schritt).""" from pathlib import Path import argparse import shutil import tempfile import textwrap from vtt2txt import vtt_to_lines from yt_untertitel import ( YT_DLP, choose_track, download, fetch_info, no_track_message, original_language, ) FLOW_WIDTH = 80 # Zeilenbreite für --fliesstext def parse_args(): parser = argparse.ArgumentParser( description="Lädt die Untertitel eines YouTube-Videos und speichert den Text." ) parser.add_argument("-u", "--url", required=True, help="YouTube-URL des Videos") parser.add_argument( "-l", "--lang", help="Sprache der Untertitel, z. B. de (Standard: Sprache des Original-Audios)", ) parser.add_argument( "-o", "--output", type=Path, default=Path("output.txt"), help="Ausgabedatei (Standard: output.txt)", ) parser.add_argument( "-f", "--fliesstext", action="store_true", help=f"Fließtext, auf {FLOW_WIDTH} Zeichen umbrochen, statt Untertitelzeilen", ) args = parser.parse_args() if args.output.is_dir(): parser.error(f"-o/--output ist ein Verzeichnis: {args.output}") if shutil.which(YT_DLP) is None: parser.error(f"{YT_DLP} nicht gefunden (Installation: pip install yt-dlp).") return args def fetch_text(url, lang=None): """Download the subtitles of a video; return (video info, text lines). Without `lang` the language of the original audio is used. """ info = fetch_info(url) print(f"Video: {info.get('title', '?')}") lang = lang or original_language(info) chosen = choose_track(info, lang) if lang else None if chosen is None: raise SystemExit(no_track_message(info, lang)) track, is_auto = chosen kind = "automatische" if is_auto else "manuelle" print(f"Lade {kind} Untertitel „{track}“ …", flush=True) # The VTT file is only an intermediate step with tempfile.TemporaryDirectory() as tmp: target_base = Path(tmp) / "untertitel" download(url, track, is_auto, target_base) vtt = Path(f"{target_base}.{track}.vtt") if not vtt.is_file(): raise SystemExit("yt-dlp hat keine Untertitel-Datei geschrieben.") lines = vtt_to_lines(vtt.read_text(encoding="utf-8-sig")) if not lines: raise SystemExit("Die Untertitel enthalten keinen Text.") return info, lines def main(): args = parse_args() _, lines = fetch_text(args.url, args.lang) if args.fliesstext: # Never split words, not even at hyphens ("EU-Gipfel") text = textwrap.fill( " ".join(lines), width=FLOW_WIDTH, break_long_words=False, break_on_hyphens=False, ) else: text = "\n".join(lines) args.output.parent.mkdir(parents=True, exist_ok=True) args.output.write_text(text + "\n", encoding="utf-8") print( f"Gespeichert: {args.output} " f"({len(text.splitlines())} Zeilen, {len(text.split())} Wörter)" ) if __name__ == "__main__": main()