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:
parent
acf9e33382
commit
3aa04fff4b
1 changed files with 195 additions and 34 deletions
|
|
@ -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():
|
||||
|
|
|
|||
Loading…
Reference in a new issue