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
7 changed files with 105 additions and 29 deletions

View file

@ -62,19 +62,36 @@ Zwischenschritt im temporären Verzeichnis. Die Spurwahl ist dieselbe wie bei
`yt_untertitel.py`, nur ist die Standardsprache die des Original-Audios. `yt_untertitel.py`, nur ist die Standardsprache die des Original-Audios.
```bash ```bash
./extract_text.py -u 'https://www.youtube.com/watch?v=rm6lADgf6GQ' # → output.txt ./extract_text.py -u 'https://www.youtube.com/watch?v=0LmCveTM788'
# → John_Mearsheimer_Offensive_Realism_Episode_1_Origins_of_the_War_In_Ukraine_2026-07-30.txt
./extract_text.py -u URL -l de -o testdaten/rede.txt # Sprache und Ziel ./extract_text.py -u URL -l de -o testdaten/rede.txt # Sprache und Ziel
./extract_text.py -u URL -f -o rede.txt # lesbarer Fließtext ./extract_text.py -u URL -f -o rede.txt # lesbarer Fließtext
./rede_korrigieren.py -i output.txt # → output.korrigiert.txt ./rede_korrigieren.py -i rede.txt # → rede.korrigiert.txt
``` ```
| Option | Bedeutung | | Option | Bedeutung |
|---|---| |---|---|
| `-u`, `--url` | YouTube-URL, Pflicht | | `-u`, `--url` | YouTube-URL, Pflicht |
| `-l`, `--lang` | Sprache; Standard: Sprache des Original-Audios (`<sprache>-orig`) | | `-l`, `--lang` | Sprache; Standard: Sprache des Original-Audios (`<sprache>-orig`) |
| `-o`, `--output` | Ausgabedatei (Verzeichnisse werden angelegt, vorhandene Datei überschrieben); Standard: `output.txt` | | `-o`, `--output` | Ausgabedatei (Verzeichnisse werden angelegt, vorhandene Datei überschrieben); Standard: `<Kanal>_<Titel>_<Datum>.txt`, siehe unten |
| `-f`, `--fliesstext` | Fließtext, auf 80 Zeichen umbrochen (Wörter werden nie getrennt), statt der kurzen Untertitelzeilen; beides versteht `rede_korrigieren.py` | | `-f`, `--fliesstext` | Fließtext, auf 80 Zeichen umbrochen (Wörter werden nie getrennt), statt der kurzen Untertitelzeilen; beides versteht `rede_korrigieren.py` |
### Standard-Dateinamen für YouTube-Videos
Ohne `-o` bzw. `-n` bilden `extract_text.py`, `yt_untertitel.py` und
`rede_korrigieren.py -u` den Namen aus Kanal, Titel und Hochladedatum:
| Video | Name |
|---|---|
| John Mearsheimer, „Episode 1: Origins of the War In Ukraine“ | `John_Mearsheimer_Offensive_Realism_Episode_1_Origins_of_the_War_In_Ukraine_2026-07-30` |
| GGBLahnstein, „Prof. Gabriele Krone-Schmalz – Respekt geht anders – …“ | `GGBLahnstein_Prof_Gabriele_Krone-Schmalz_Respekt_geht_anders_2026-07-30` |
Wörter werden mit `_` verbunden. Bindestriche und Punkte im Wort bleiben
(„Krone-Schmalz“), andere Zeichen fallen weg. Der Kanal wird auf 40, der Titel auf
60 Zeichen an einer Wortgrenze gekürzt. Ohne verwertbaren Kanal und Titel gilt die
Video-ID. Gleiches Video ergibt immer denselben Namen; eine vorhandene Datei wird
überschrieben (ein mit `-u` gespeicherter, abweichender Rohtext aber nie).
### Untertitel herunterladen: `yt_untertitel.py` ### Untertitel herunterladen: `yt_untertitel.py`
Lädt die Untertitel eines YouTube-Videos über `yt-dlp` als VTT-Datei, ohne das Lädt die Untertitel eines YouTube-Videos über `yt-dlp` als VTT-Datei, ohne das
@ -94,14 +111,14 @@ gehören zur Synchronisation und werden nicht genommen. Sprachen werden auch mit
Region gefunden: `-l en` findet manuelle Untertitel `en-US`. Region gefunden: `-l en` findet manuelle Untertitel `en-US`.
```bash ```bash
./yt_untertitel.py -u URL # → <Video-ID>.de-orig.vtt ./yt_untertitel.py -u URL # → <Kanal>_<Titel>_<Datum>.de-orig.vtt
./yt_untertitel.py -u URL -n Lahnstein -d testdaten # → testdaten/Lahnstein.de-orig.vtt ./yt_untertitel.py -u URL -n Lahnstein -d testdaten # → testdaten/Lahnstein.de-orig.vtt
``` ```
| Option | Bedeutung | | Option | Bedeutung |
|---|---| |---|---|
| `-u`, `--url` | YouTube-URL, Pflicht | | `-u`, `--url` | YouTube-URL, Pflicht |
| `-n`, `--name` | Dateiname ohne Endung; Standard: Video-ID | | `-n`, `--name` | Dateiname ohne Endung; Standard: `<Kanal>_<Titel>_<Datum>` |
| `-l`, `--lang` | Sprache; Standard: `de` | | `-l`, `--lang` | Sprache; Standard: `de` |
| `-d`, `--dir` | Zielverzeichnis (wird angelegt); Standard: aktuelles Verzeichnis | | `-d`, `--dir` | Zielverzeichnis (wird angelegt); Standard: aktuelles Verzeichnis |
@ -139,7 +156,7 @@ werden trotzdem umgewandelt; der Exit-Code ist dann 1.
./rede_korrigieren.py -i rede.txt -g rede.glossar.txt # mit Glossar ./rede_korrigieren.py -i rede.txt -g rede.glossar.txt # mit Glossar
./rede_korrigieren.py -i rede.txt -g allgemein.glossar.txt -g rede.glossar.txt # kombiniert ./rede_korrigieren.py -i rede.txt -g allgemein.glossar.txt -g rede.glossar.txt # kombiniert
./rede_korrigieren.py -i rede.de.vtt # VTT direkt → rede.de.korrigiert.txt ./rede_korrigieren.py -i rede.de.vtt # VTT direkt → rede.de.korrigiert.txt
./rede_korrigieren.py -u URL # YouTube → <Video-ID>.korrigiert.txt ./rede_korrigieren.py -u URL # YouTube → <Kanal>_<Titel>_<Datum>.korrigiert.txt
./rede_korrigieren.py -i speech.txt -l en # englische Rede ./rede_korrigieren.py -i speech.txt -l en # englische Rede
``` ```
@ -148,7 +165,7 @@ werden trotzdem umgewandelt; der Exit-Code ist dann 1.
| `-i`, `--input` | Eingabedatei: Rohabschrift (`.txt`) oder Untertitel (`.vtt`, wird wie mit `vtt2txt.py` umgewandelt) | | `-i`, `--input` | Eingabedatei: Rohabschrift (`.txt`) oder Untertitel (`.vtt`, wird wie mit `vtt2txt.py` umgewandelt) |
| `-u`, `--url` | statt `-i`: YouTube-URL; Untertitel wie bei `extract_text.py`. Der Rohtext wird neben der Ausgabe gespeichert (`rede.korrigiert.txt` → `rede.txt`, sonst `<Name>.roh.txt`), eine vorhandene, abweichende Datei aber nie überschrieben | | `-u`, `--url` | statt `-i`: YouTube-URL; Untertitel wie bei `extract_text.py`. Der Rohtext wird neben der Ausgabe gespeichert (`rede.korrigiert.txt` → `rede.txt`, sonst `<Name>.roh.txt`), eine vorhandene, abweichende Datei aber nie überschrieben |
| `-l`, `--lang` | Sprache der Rede: `de` oder `en` (auch mit Region, z. B. `en-US`); wählt Prompts und Prüfmarke. Mit `-u` zugleich die Sprache der Untertitel. Standard: `de`, mit `-u` die Sprache des Original-Audios | | `-l`, `--lang` | Sprache der Rede: `de` oder `en` (auch mit Region, z. B. `en-US`); wählt Prompts und Prüfmarke. Mit `-u` zugleich die Sprache der Untertitel. Standard: `de`, mit `-u` die Sprache des Original-Audios |
| `-o`, `--output` | Ausgabedatei; Standard: `<Eingabe ohne Endung>.korrigiert.txt` neben der Eingabe, mit `-u` `<Video-ID>.korrigiert.txt` | | `-o`, `--output` | Ausgabedatei; Standard: `<Eingabe ohne Endung>.korrigiert.txt` neben der Eingabe, mit `-u` `<Kanal>_<Titel>_<Datum>.korrigiert.txt` |
| `-g`, `--glossar` | Glossar mit festen Ersetzungen und Schreibweisen; mehrfach angeben zum Kombinieren (Ersetzungen in Reihenfolge der Angabe) | | `-g`, `--glossar` | Glossar mit festen Ersetzungen und Schreibweisen; mehrfach angeben zum Kombinieren (Ersetzungen in Reihenfolge der Angabe) |
| `-m`, `--model` | Ollama-Modell; Standard: `qwen3:32b` (Konstante `MODEL`) | | `-m`, `--model` | Ollama-Modell; Standard: `qwen3:32b` (Konstante `MODEL`) |
| `--kein-bericht` | keinen Änderungsbericht schreiben | | `--kein-bericht` | keinen Änderungsbericht schreiben |

View file

@ -9,7 +9,8 @@ import textwrap
from vtt2txt import vtt_to_lines from vtt2txt import vtt_to_lines
from yt_untertitel import ( from yt_untertitel import (
YT_DLP, choose_track, download, fetch_info, no_track_message, original_language, YT_DLP, choose_track, default_name, download, fetch_info, no_track_message,
original_language,
) )
FLOW_WIDTH = 80 # Zeilenbreite für --fliesstext FLOW_WIDTH = 80 # Zeilenbreite für --fliesstext
@ -25,8 +26,8 @@ def parse_args():
help="Sprache der Untertitel, z. B. de (Standard: Sprache des Original-Audios)", help="Sprache der Untertitel, z. B. de (Standard: Sprache des Original-Audios)",
) )
parser.add_argument( parser.add_argument(
"-o", "--output", type=Path, default=Path("output.txt"), "-o", "--output", type=Path,
help="Ausgabedatei (Standard: output.txt)", help="Ausgabedatei (Standard: <Kanal>_<Titel>_<Datum>.txt)",
) )
parser.add_argument( parser.add_argument(
"-f", "--fliesstext", action="store_true", "-f", "--fliesstext", action="store_true",
@ -34,7 +35,7 @@ def parse_args():
) )
args = parser.parse_args() args = parser.parse_args()
if args.output.is_dir(): if args.output is not None and args.output.is_dir():
parser.error(f"-o/--output ist ein Verzeichnis: {args.output}") parser.error(f"-o/--output ist ein Verzeichnis: {args.output}")
if shutil.which(YT_DLP) is None: if shutil.which(YT_DLP) is None:
parser.error(f"{YT_DLP} nicht gefunden (Installation: pip install yt-dlp).") parser.error(f"{YT_DLP} nicht gefunden (Installation: pip install yt-dlp).")
@ -73,7 +74,8 @@ def fetch_text(url, lang=None):
def main(): def main():
args = parse_args() args = parse_args()
_, lines = fetch_text(args.url, args.lang) info, lines = fetch_text(args.url, args.lang)
output = args.output or Path(f"{default_name(info)}.txt")
if args.fliesstext: if args.fliesstext:
# Never split words, not even at hyphens ("EU-Gipfel") # Never split words, not even at hyphens ("EU-Gipfel")
@ -84,10 +86,10 @@ def main():
else: else:
text = "\n".join(lines) text = "\n".join(lines)
args.output.parent.mkdir(parents=True, exist_ok=True) output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(text + "\n", encoding="utf-8") output.write_text(text + "\n", encoding="utf-8")
print( print(
f"Gespeichert: {args.output} " f"Gespeichert: {output} "
f"({len(text.splitlines())} Zeilen, {len(text.split())} Wörter)" f"({len(text.splitlines())} Zeilen, {len(text.split())} Wörter)"
) )

View file

@ -13,7 +13,7 @@ import urllib.request
from aenderungen import REVIEW_MARK, print_summary, report_path, write_report from aenderungen import REVIEW_MARK, print_summary, report_path, write_report
from extract_text import fetch_text from extract_text import fetch_text
from vtt2txt import vtt_to_lines from vtt2txt import vtt_to_lines
from yt_untertitel import YT_DLP, base_language, original_language from yt_untertitel import YT_DLP, base_language, default_name, original_language
MODEL = "qwen3:32b" MODEL = "qwen3:32b"
OLLAMA_URL = "http://127.0.0.1:11434/api/chat" OLLAMA_URL = "http://127.0.0.1:11434/api/chat"
@ -452,7 +452,7 @@ def parse_args():
parser.add_argument( parser.add_argument(
"-o", "--output", type=Path, "-o", "--output", type=Path,
help="Ausgabedatei (Standard: <Eingabe ohne Endung>.korrigiert.txt, " help="Ausgabedatei (Standard: <Eingabe ohne Endung>.korrigiert.txt, "
"mit -u <Video-ID>.korrigiert.txt)", "mit -u <Kanal>_<Titel>_<Datum>.korrigiert.txt)",
) )
parser.add_argument( parser.add_argument(
"-g", "--glossar", type=Path, action="append", default=[], "-g", "--glossar", type=Path, action="append", default=[],
@ -516,7 +516,7 @@ def read_source(args):
raise SystemExit( raise SystemExit(
f"Die Rede ist auf „{lang}“; unterstützt: {', '.join(PROMPTS)} (-l)." f"Die Rede ist auf „{lang}“; unterstützt: {', '.join(PROMPTS)} (-l)."
) )
target = args.output or Path(f"{info['id']}.korrigiert.txt") target = args.output or Path(f"{default_name(info)}.korrigiert.txt")
raw = "\n".join(lines) + "\n" raw = "\n".join(lines) + "\n"
save_raw_text(raw_text_path(target), raw) save_raw_text(raw_text_path(target), raw)
return raw, target, lang return raw, target, lang

View file

@ -17,6 +17,8 @@ VTT = (
GERMAN_VIDEO = { GERMAN_VIDEO = {
"id": "abc123", "id": "abc123",
"title": "Eine Rede", "title": "Eine Rede",
"channel": "Kanal",
"upload_date": "20260328",
"subtitles": {"en": []}, "subtitles": {"en": []},
"automatic_captions": {"de-orig": [], "de": [], "en": []}, "automatic_captions": {"de-orig": [], "de": [], "en": []},
} }
@ -36,14 +38,14 @@ def test_default_language_is_original_audio(fake_yt_dlp, tmp_path, monkeypatch,
monkeypatch.chdir(tmp_path) monkeypatch.chdir(tmp_path)
run_main(monkeypatch, "-u", URL) run_main(monkeypatch, "-u", URL)
text = (tmp_path / "output.txt").read_text(encoding="utf-8") text = (tmp_path / "Kanal_Eine_Rede_2026-03-28.txt").read_text(encoding="utf-8")
assert text == "Guten Abend.\nSchön, dass Sie da sind.\n" assert text == "Guten Abend.\nSchön, dass Sie da sind.\n"
assert "de-orig" in run.calls[1] assert "de-orig" in run.calls[1]
assert "--write-auto-subs" in run.calls[1] assert "--write-auto-subs" in run.calls[1]
out = capsys.readouterr().out out = capsys.readouterr().out
assert "output.txt (2 Zeilen, 7 Wörter)" in out assert "Kanal_Eine_Rede_2026-03-28.txt (2 Zeilen, 7 Wörter)" in out
# Only the text file remains, no VTT # Only the text file remains, no VTT
assert [p.name for p in tmp_path.iterdir()] == ["output.txt"] assert [p.name for p in tmp_path.iterdir()] == ["Kanal_Eine_Rede_2026-03-28.txt"]
def test_default_language_ignores_dubbed_tracks(fake_yt_dlp, tmp_path, monkeypatch): def test_default_language_ignores_dubbed_tracks(fake_yt_dlp, tmp_path, monkeypatch):

View file

@ -378,7 +378,10 @@ def test_correct_chunk_sends_model(monkeypatch):
URL = "https://www.youtube.com/watch?v=abc123" URL = "https://www.youtube.com/watch?v=abc123"
VIDEO = {"id": "abc123", "title": "Rede", "subtitles": {}, "automatic_captions": {"de-orig": []}} VIDEO = {
"id": "abc123", "title": "Rede", "channel": "Kanal", "upload_date": "20260328",
"subtitles": {}, "automatic_captions": {"de-orig": []},
}
VTT = ( VTT = (
"WEBVTT\n\n00:00:01.000 --> 00:00:02.000\nDer Kremmel ist in Moskau.\n\n" "WEBVTT\n\n00:00:01.000 --> 00:00:02.000\nDer Kremmel ist in Moskau.\n\n"
"00:00:02.000 --> 00:00:03.000\nDer Kremmel ist in Moskau.\nDas ist bekannt.\n" "00:00:02.000 --> 00:00:03.000\nDer Kremmel ist in Moskau.\nDas ist bekannt.\n"
@ -397,11 +400,11 @@ def test_main_url_default_names(from_url, tmp_path, monkeypatch):
monkeypatch.chdir(tmp_path) monkeypatch.chdir(tmp_path)
run_main(monkeypatch, "-u", URL, "-g", SHARED_GLOSSARY) run_main(monkeypatch, "-u", URL, "-g", SHARED_GLOSSARY)
raw = (tmp_path / "abc123.txt").read_text(encoding="utf-8") raw = (tmp_path / "Kanal_Rede_2026-03-28.txt").read_text(encoding="utf-8")
assert raw == "Der Kremmel ist in Moskau.\nDas ist bekannt.\n" assert raw == "Der Kremmel ist in Moskau.\nDas ist bekannt.\n"
result = (tmp_path / "abc123.korrigiert.txt").read_text(encoding="utf-8") result = (tmp_path / "Kanal_Rede_2026-03-28.korrigiert.txt").read_text(encoding="utf-8")
assert result == "Der Kreml ist in Moskau. Das ist bekannt.\n" assert result == "Der Kreml ist in Moskau. Das ist bekannt.\n"
assert (tmp_path / "abc123.aenderungen.html").is_file() assert (tmp_path / "Kanal_Rede_2026-03-28.aenderungen.html").is_file()
def test_main_url_output_option_and_kept_raw_text(from_url, tmp_path, monkeypatch, capsys): def test_main_url_output_option_and_kept_raw_text(from_url, tmp_path, monkeypatch, capsys):

View file

@ -12,6 +12,8 @@ URL = "https://www.youtube.com/watch?v=abc123"
AUTO_ONLY = { AUTO_ONLY = {
"id": "abc123", "id": "abc123",
"title": "Eine Rede", "title": "Eine Rede",
"channel": "Kanal",
"upload_date": "20260328",
"subtitles": {}, "subtitles": {},
"automatic_captions": {"de-orig": [], "de": [], "en": []}, "automatic_captions": {"de-orig": [], "de": [], "en": []},
} }
@ -86,6 +88,24 @@ def test_original_language_with_dubbed_audio(info, expected):
assert yt.original_language(info) == expected assert yt.original_language(info) == expected
@pytest.mark.parametrize("info, expected", [
({"channel": "John Mearsheimer - Offensive Realism",
"title": "Episode 1: Origins of the War In Ukraine", "upload_date": "20260730"},
"John_Mearsheimer_Offensive_Realism_Episode_1_Origins_of_the_War_In_Ukraine_2026-07-30"),
# Title cut at a word boundary after 60 characters; hyphens and dots in words stay
({"channel": "GGBLahnstein", "upload_date": "20260730",
"title": "Prof. Gabriele Krone-Schmalz – Respekt geht anders – "
"GGB-Gesundheitstage, Lahnstein 28.03.2026"},
"GGBLahnstein_Prof_Gabriele_Krone-Schmalz_Respekt_geht_anders_2026-07-30"),
({"uploader": "Ein Kanal", "title": "A/B: Krieg & Frieden 🎤?"}, "Ein_Kanal_A_B_Krieg_Frieden"),
({"title": "Nur Titel", "upload_date": "kaputt"}, "Nur_Titel"),
({"id": "abc123", "title": "🎤 – …"}, "abc123"),
({"title": "x" * 80}, "x" * 60),
])
def test_default_name(info, expected):
assert yt.default_name(info) == expected
def test_available_tracks_hides_dubs(): def test_available_tracks_hides_dubs():
assert yt.available_tracks(DUBBED) == (["en-US"], ["en"]) assert yt.available_tracks(DUBBED) == (["en-US"], ["en"])
@ -124,13 +144,13 @@ def test_yt_dlp_runs_in_temporary_directory(fake_yt_dlp, tmp_path, monkeypatch):
assert (tmp_path / "Rede.de-orig.vtt").is_file() assert (tmp_path / "Rede.de-orig.vtt").is_file()
def test_main_prefers_manual_and_defaults_to_video_id(fake_yt_dlp, tmp_path, monkeypatch): def test_main_prefers_manual_and_default_name(fake_yt_dlp, tmp_path, monkeypatch):
info = dict(AUTO_ONLY, subtitles={"de": []}) info = dict(AUTO_ONLY, subtitles={"de": []})
run = fake_yt_dlp(info) run = fake_yt_dlp(info)
monkeypatch.setattr(yt.subprocess, "run", run) monkeypatch.setattr(yt.subprocess, "run", run)
run_main(monkeypatch, "-u", URL, "-d", tmp_path) run_main(monkeypatch, "-u", URL, "-d", tmp_path)
assert (tmp_path / "abc123.de.vtt").is_file() assert (tmp_path / "Kanal_Eine_Rede_2026-03-28.de.vtt").is_file()
assert "--write-subs" in run.calls[1] assert "--write-subs" in run.calls[1]

View file

@ -4,12 +4,17 @@ als Eingabe für vtt2txt.py bzw. rede_korrigieren.py."""
from pathlib import Path from pathlib import Path
import argparse import argparse
import json import json
import re
import shutil import shutil
import subprocess import subprocess
import tempfile import tempfile
YT_DLP = "yt-dlp" 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): def run_yt_dlp(arguments):
"""Run yt-dlp in a temporary working directory. """Run yt-dlp in a temporary working directory.
@ -80,6 +85,33 @@ def choose_track(info, lang):
return None 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): def available_tracks(info):
"""Manual tracks and the automatic ones usable for this program.""" """Manual tracks and the automatic ones usable for this program."""
manual = sorted((info.get("subtitles") or {}).keys()) 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("-u", "--url", required=True, help="YouTube-URL des Videos")
parser.add_argument( parser.add_argument(
"-n", "--name", "-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( parser.add_argument(
"-l", "--lang", default="de", help="Sprache der Untertitel (Standard: de)" "-l", "--lang", default="de", help="Sprache der Untertitel (Standard: de)"
@ -158,7 +190,7 @@ def main():
print(f"Lade {kind} Untertitel „{track}“ …", flush=True) print(f"Lade {kind} Untertitel „{track}“ …", flush=True)
args.dir.mkdir(parents=True, exist_ok=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) download(args.url, track, is_auto, target_base)
target = Path(f"{target_base}.{track}.vtt") target = Path(f"{target_base}.{track}.vtt")