feat: Standard-Dateiname aus Kanal, Titel und Datum des Videos

- yt_untertitel.default_name(): <Kanal>_<Titel>_<Datum>, z. B.
  John_Mearsheimer_Offensive_Realism_Episode_1_Origins_of_the_War_In_Ukraine_2026-07-30
- Bindestriche/Punkte im Wort bleiben, Kanal max. 40, Titel max. 60 Zeichen
  an Wortgrenze; ohne Kanal und Titel die Video-ID
- Gilt ohne -o/-n in extract_text.py (statt output.txt), yt_untertitel.py
  und rede_korrigieren.py -u (statt Video-ID)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-10-10 21:03:14 +02:00
commit 3d9a5037c2

View file

@ -4,12 +4,17 @@ als Eingabe für vtt2txt.py bzw. rede_korrigieren.py."""
from pathlib import Path
import argparse
import json
import re
import shutil
import subprocess
import tempfile
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
def run_yt_dlp(arguments):
"""Run yt-dlp in a temporary working directory.
@ -80,6 +85,33 @@ def choose_track(info, lang):
return None
def name_part(text, limit):
"""Words of `text` joined by "_", cut at a word boundary after `limit` chars."""
words = NAME_WORD.findall(text or "")
part = ""
for word in words:
candidate = f"{part}_{word}" if part else word
if len(candidate) > limit:
break
part = candidate
# A single overlong word is cut rather than dropped
return part or (words[0][:limit] if words else "")
def default_name(info):
"""File name without extension from channel, title and upload date.
"John_Mearsheimer_Offensive_Realism_Episode_1_Origins_of_the_War_In_Ukraine_2026-07-30"
"""
date = info.get("upload_date") or ""
parts = [
name_part(info.get("channel") or info.get("uploader"), MAX_CHANNEL_CHARS),
name_part(info.get("title"), MAX_TITLE_CHARS),
f"{date[:4]}-{date[4:6]}-{date[6:]}" if re.fullmatch(r"\d{8}", date) else "",
]
return "_".join(p for p in parts if p) or info.get("id") or "video"
def available_tracks(info):
"""Manual tracks and the automatic ones usable for this program."""
manual = sorted((info.get("subtitles") or {}).keys())
@ -126,7 +158,7 @@ def parse_args():
parser.add_argument("-u", "--url", required=True, help="YouTube-URL des Videos")
parser.add_argument(
"-n", "--name",
help="Dateiname ohne Endung, z. B. Lahnstein (Standard: Video-ID)",
help="Dateiname ohne Endung, z. B. Lahnstein (Standard: <Kanal>_<Titel>_<Datum>)",
)
parser.add_argument(
"-l", "--lang", default="de", help="Sprache der Untertitel (Standard: de)"
@ -158,7 +190,7 @@ def main():
print(f"Lade {kind} Untertitel „{track}“ …", flush=True)
args.dir.mkdir(parents=True, exist_ok=True)
target_base = args.dir / (args.name or info["id"])
target_base = args.dir / (args.name or default_name(info))
download(args.url, track, is_auto, target_base)
target = Path(f"{target_base}.{track}.vtt")