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:
parent
fb9201b721
commit
3d9a5037c2
1 changed files with 105 additions and 29 deletions
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in a new issue