This commit is contained in:
2026-06-17 15:06:06 +02:00
parent 26e44fc721
commit 0beaffec45
3 changed files with 117 additions and 6 deletions
+8
View File
@@ -81,6 +81,12 @@ python euni_stahni.py --seaweed-backfill --from-json
## Použití ## Použití
Nejjednodušší: **`python euni_menu.py`** — interaktivní menu s volbami 19
(test / dokumenty / vše / 720p / dashboard / obnova / backfill / re-scrape).
Po doběhnutí akce se vrátí do menu, `Ctrl+C` přeruší jen aktuální akci.
Ručně přes CLI:
```bat ```bat
python euni_stahni.py --scrape-only # jen inventura → Mongo + JSON python euni_stahni.py --scrape-only # jen inventura → Mongo + JSON
python euni_stahni.py --no-videos # scrape + stáhne jen dokumenty python euni_stahni.py --no-videos # scrape + stáhne jen dokumenty
@@ -89,6 +95,8 @@ python euni_stahni.py --from-json --no-videos # přeskočí scrape, stáhne z M
python euni_stahni.py --professions all # všechny profese (2,4,5,6,7) python euni_stahni.py --professions all # všechny profese (2,4,5,6,7)
python euni_stahni.py --limit 3 # jen prvních 3 kurzy (test) python euni_stahni.py --limit 3 # jen prvních 3 kurzy (test)
python euni_stahni.py --no-mongo # bez zápisu do Mongo python euni_stahni.py --no-mongo # bez zápisu do Mongo
python euni_stahni.py --frags 20 # víc paralelních HLS fragmentů (rychlejší)
python euni_stahni.py --video-format "bestvideo[height<=720]+bestaudio/best" # 720p
python euni_report.py # přehled stavu python euni_report.py # přehled stavu
python euni_report.py --soukroma # seznam přeskočených videí python euni_report.py --soukroma # seznam přeskočených videí
``` ```
+96
View File
@@ -0,0 +1,96 @@
#!/usr/bin/env python3
"""
euni_menu.py — interaktivní menu pro stahování kurzů z euni.cz.
Spuštění:
python euni_menu.py
Jen vyber číslo a Enter. Každá volba spustí příslušný skript a po doběhnutí
se vrátíš do menu (Ctrl+C přeruší aktuální akci, ne celé menu).
"""
import os
import subprocess
import sys
from pathlib import Path
for _s in (sys.stdout, sys.stderr):
try:
_s.reconfigure(errors="backslashreplace")
except Exception:
pass
SKRIPT_DIR = Path(__file__).resolve().parent
PY = sys.executable
# klíč -> (popis, skript, argumenty)
AKCE = {
"1": ("Test - 3 kurzy, jen dokumenty (rychle)",
"euni_stahni.py", ["--from-json", "--no-videos", "--limit", "3"]),
"2": ("Vsechny dokumenty (PDF/prezentace)",
"euni_stahni.py", ["--from-json", "--no-videos"]),
"3": ("Vse vcetne videi - nejvyssi kvalita (1080p, velke)",
"euni_stahni.py", ["--from-json"]),
"4": ("Vse vcetne videi - 720p (mensi, rychlejsi)",
"euni_stahni.py",
["--from-json", "--video-format",
"bestvideo[height<=720]+bestaudio/best"]),
"5": ("Jen videa (1080p)",
"euni_stahni.py", ["--from-json", "--no-docs"]),
"6": ("Prehled stavu (dashboard)", "euni_report.py", []),
"7": ("Obnova ze SeaweedFS na disk", "euni_restore.py", []),
"8": ("Backfill - dohrat chybejici kopie do SeaweedFS",
"euni_stahni.py", ["--seaweed-backfill", "--from-json"]),
"9": ("Aktualizovat seznam kurzu (znovu scrape do Mongo)",
"euni_stahni.py", ["--scrape-only"]),
}
def vycisti_obrazovku():
os.system("cls" if os.name == "nt" else "clear")
def vypis_menu():
print("=" * 60)
print(" EUNI - stahovani kurzu z euni.cz")
print("=" * 60)
print()
for k in sorted(AKCE):
print(f" {k}) {AKCE[k][0]}")
print()
print(" 0) Konec")
print()
def main():
while True:
vycisti_obrazovku()
vypis_menu()
try:
volba = input("Vyber cislo a stiskni Enter: ").strip()
except (EOFError, KeyboardInterrupt):
print()
break
if volba in ("0", "q", "exit", "konec"):
break
akce = AKCE.get(volba)
if not akce:
continue
_, skript, args = akce
print()
try:
subprocess.run([PY, str(SKRIPT_DIR / skript), *args],
cwd=str(SKRIPT_DIR))
except KeyboardInterrupt:
print("\nPreruseno uzivatelem.")
try:
input("\n=== HOTOVO. Stiskni Enter pro navrat do menu ===")
except (EOFError, KeyboardInterrupt):
break
if __name__ == "__main__":
main()
+13 -6
View File
@@ -376,21 +376,23 @@ def stahni_dokument(s, url, out_dir: Path, label=""):
return ("staženo", dest.name) return ("staženo", dest.name)
def stahni_video(embed, out_dir: Path, referer): def stahni_video(embed, out_dir: Path, referer, fmt="bestvideo*+bestaudio/best",
"""Stáhne video přes yt-dlp; soukromé/nedostupné přeskočí. Vrací (stav, info).""" frags=10):
"""Stáhne video přes yt-dlp; soukromé/nedostupné přeskočí. Vrací (stav, info, fp)."""
if sv is None: if sv is None:
return ("chyba", "modul stahni_video není dostupný") return ("chyba", "modul stahni_video není dostupný", None)
try: try:
import yt_dlp import yt_dlp
from yt_dlp.utils import DownloadError from yt_dlp.utils import DownloadError
except ImportError: except ImportError:
return ("chyba", "yt-dlp není nainstalován") return ("chyba", "yt-dlp není nainstalován", None)
out_dir.mkdir(parents=True, exist_ok=True) out_dir.mkdir(parents=True, exist_ok=True)
ff_dir = sv.priprav_ffmpeg() ff_dir = sv.priprav_ffmpeg()
opts = { opts = {
"outtmpl": str(out_dir / "%(title)s [%(id)s].%(ext)s"), "outtmpl": str(out_dir / "%(title)s [%(id)s].%(ext)s"),
"format": "bestvideo*+bestaudio/best", "format": fmt,
"concurrent_fragment_downloads": frags, # paralelní HLS fragmenty = rychlejší
"merge_output_format": "mp4", "merge_output_format": "mp4",
"logger": sv._TichyLogger(), "logger": sv._TichyLogger(),
"progress_hooks": [sv._progress_hook], "progress_hooks": [sv._progress_hook],
@@ -458,6 +460,10 @@ def main():
help="přeskočí scrape, použije existující euni_kurzy.json") help="přeskočí scrape, použije existující euni_kurzy.json")
p.add_argument("--no-videos", action="store_true", help="nestahovat videa") p.add_argument("--no-videos", action="store_true", help="nestahovat videa")
p.add_argument("--no-docs", action="store_true", help="nestahovat dokumenty") p.add_argument("--no-docs", action="store_true", help="nestahovat dokumenty")
p.add_argument("--video-format", default="bestvideo*+bestaudio/best",
help="yt-dlp formát videa (např. \"bestvideo[height<=720]+bestaudio/best\")")
p.add_argument("--frags", type=int, default=10,
help="počet paralelně stahovaných HLS fragmentů videa (default 10)")
p.add_argument("--limit", type=int, default=0, help="jen prvních N kurzů (test)") p.add_argument("--limit", type=int, default=0, help="jen prvních N kurzů (test)")
p.add_argument("--out", default=str(SKRIPT_DIR / "stazeno"), help="výstupní adresář") p.add_argument("--out", default=str(SKRIPT_DIR / "stazeno"), help="výstupní adresář")
p.add_argument("--json", default=str(SKRIPT_DIR / "euni_kurzy.json"), p.add_argument("--json", default=str(SKRIPT_DIR / "euni_kurzy.json"),
@@ -602,7 +608,8 @@ def main():
if not a.no_videos: if not a.no_videos:
for v in c.get("videos", []): for v in c.get("videos", []):
klic = material_klic("video", v)[0] klic = material_klic("video", v)[0]
stav, info, fp = stahni_video(v["embed"], folder / "videa", c["url"]) stav, info, fp = stahni_video(v["embed"], folder / "videa", c["url"],
fmt=a.video_format, frags=a.frags)
if stav == "staženo": if stav == "staženo":
stat["vid_ok"] += 1 stat["vid_ok"] += 1
print(f" [VIDEO] {info}") print(f" [VIDEO] {info}")