feat: Arbeitsordner je Video, Quellenangabe und automatisches Video-Glossar

- Ohne -o/-d schreiben yt_untertitel.py, extract_text.py und
  abschrift_korrigieren.py -u in abschriften/<Name>/ (ein Ordner je
  Video, auch für alle Ausschnitte).
- Beim Download entsteht neben dem Rohtext <Rohtext>.quelle.json mit
  Titel, Kanal, Datum und URL, für den Quellenkopf des fertigen Textes.
- Ein Glossar, das wie sein Ordner heißt (abschriften/<Name>/<Name>.glossar.txt),
  nutzen abschrift_korrigieren.py, glossar_vorschlag.py und aenderungen.py
  automatisch, nach den mit -g angegebenen gemeinsamen Glossaren.
- .gitignore: abschriften/, fertig/, *.quelle.json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-10-11 23:24:32 +02:00
commit 3aa04fff4b

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python3
"""Lädt die Untertitel eines YouTube-Videos als VTT-Datei herunter (über yt-dlp),
als Eingabe für vtt2txt.py bzw. abschrift_korrigieren.py."""
from datetime import date
from pathlib import Path
import argparse
import json
@ -14,6 +15,7 @@ YT_DLP = "yt-dlp"
NAME_WORD = re.compile(r"\w+(?:[-.]\w+)*") # keeps "Krone-Schmalz", "28.03.2026"
MAX_CHANNEL_CHARS = 40
MAX_TITLE_CHARS = 60
WORK_DIR = Path("abschriften") # ein Arbeitsordner je Video: abschriften/<Name>/
def run_yt_dlp(arguments):
@ -112,6 +114,31 @@ def default_name(info):
return "_".join(p for p in parts if p) or info.get("id") or "video"
def work_folder(name):
"""Working folder of one video: abschriften/<Name>/"""
return WORK_DIR / name
def write_source(info, path):
"""Store where a transcript comes from (<Name>.quelle.json), for the
header of the finished result."""
url = info.get("webpage_url") or (
f"https://www.youtube.com/watch?v={info['id']}" if info.get("id") else None
)
source = {
"titel": info.get("title"),
"kanal": info.get("channel") or info.get("uploader"),
"datum": info.get("upload_date"),
"url": url,
"id": info.get("id"),
"dauer": info.get("duration"),
"abgerufen": date.today().isoformat(),
}
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(source, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
return path
def available_tracks(info):
"""Manual tracks and the automatic ones usable for this program."""
manual = sorted((info.get("subtitles") or {}).keys())
@ -164,8 +191,8 @@ def parse_args():
"-l", "--lang", default="de", help="Sprache der Untertitel (Standard: de)"
)
parser.add_argument(
"-d", "--dir", type=Path, default=Path("."),
help="Zielverzeichnis (Standard: aktuelles Verzeichnis)",
"-d", "--dir", type=Path,
help="Zielverzeichnis (Standard: Arbeitsordner abschriften/<Name>/)",
)
args = parser.parse_args()
@ -189,9 +216,12 @@ def main():
kind = "automatische" if is_auto else "manuelle"
print(f"Lade {kind} Untertitel „{track}“ …", flush=True)
args.dir.mkdir(parents=True, exist_ok=True)
target_base = args.dir / (args.name or default_name(info))
name = args.name or default_name(info)
folder = args.dir or work_folder(name)
folder.mkdir(parents=True, exist_ok=True)
target_base = folder / name
download(args.url, track, is_auto, target_base)
write_source(info, folder / f"{name}.quelle.json")
target = Path(f"{target_base}.{track}.vtt")
if not target.is_file():