# Euni — stahování a tracking kurzů z euni.cz Přihlásí se na euni.cz, projde kurzy, vytěží odkazy + metadata a stahuje obsah (PDF/prezentace a videa Vimeo/YouTube). Vše se trackuje v **MongoDB EUNI**, takže stahování je idempotentní — skript ví, co už má, a netahá dvakrát. ## Soubory | Soubor | Popis | |--------|-------| | `euni_stahni.py` | hlavní pipeline: login → scrape → ingest do Mongo → stahování → záloha do SeaweedFS | | `euni_db.py` | připojení a operace nad MongoDB EUNI (kolekce, indexy, upserty) | | `euni_seaweed.py` | nahrávání/stahování souborů do SeaweedFS (filer HTTP API) | | `euni_restore.py` | obnova všech souborů ze SeaweedFS na disk (na jakémkoli PC) | | `euni_report.py` | dashboard: přehled stavu (kolik staženo/čeká/přeskočeno) | | `.env` | `EUNI_USERNAME`, `EUNI_PASSWORD` (v .gitignore) | | `euni_kurzy.json` | poslední inventura (záloha; primární zdroj je Mongo) | | `stazeno/` | stažený obsah, `stazeno/-/{dokumenty,videa}/` | ## Závislosti ```bat python -m pip install -U requests beautifulsoup4 python-dotenv yt-dlp static-ffmpeg pymongo ``` Video stahuje sdílený modul `../Video/stahni_video.py` (yt-dlp + static-ffmpeg, soukromá videa sám přeskočí). ## MongoDB EUNI Server `mongodb://192.168.1.76:27017` (bez hesla), DB `EUNI`. Lze přepsat env proměnnou `EUNI_MONGO_URI`. ### Kolekce `kurzy` (1 dokument na kurz) `_id` = euni ID kurzu. Pole: `slug, nazev, url, profese[], autor, autor_medailonek_url, datum_publikace, revidovano, akreditace, kredity, pocet_videi, pocet_dokumentu, first_seen, updated_at`. ### Kolekce `materialy` (1 dokument na soubor) Unikátní index `{kurz_id, klic}`. Pole: `kurz_id, kurz_nazev, druh (video|dokument), platforma (vimeo|youtube), klic (vimeo:ID / youtube:ID / doc:hash), zdroj_url, watch_url, popis, pripona, stav, duvod, soubor, velikost_b, pokusy, posledni_chyba, first_seen, updated_at, stazeno_at`. **Stavy:** `ceka` → `stazeno` / `preskoceno` (soukromé video) / `chyba`. **SeaweedFS reference** (po nahrání kopie): `seaweed_path` (cesta ve filer = identifikátor pro vyžádání, např. `euni/5618-.../dokumenty/x.pdf`), `seaweed_fids` (fid chunků = čísla souborů v SeaweedFS), `seaweed_md5`, `seaweed_size`, `seaweed_at`. ## SeaweedFS záloha + obnova Každý stažený soubor se nahraje do **SeaweedFS** (filer na Unraidu, default `http://192.168.1.50:8888`, přepíše env `EUNI_FILER`). Do Mongo se k materiálu uloží `seaweed_path` + `seaweed_fids`, takže soubor lze kdykoli vyžádat. - Strukturu na disku zrcadlí cesta: `euni/-//`. - Filer metadata (mapa cesta→chunky) jsou v Mongo DB `seaweedfs` na 192.168.1.76; bloby na poli Unraidu. (Setup: `U:\\PythonProject\\Janssen\\SeaweedFS\\`.) - Pozn.: přímý přístup přes raw fid/volume zvenčí nefunguje (volume se uvnitř Dockeru jmenuje `seaweed-volume`); proto se čte/zapisuje přes filer. **Obnova kdekoliv** (stačí síť na Mongo + filer): ```bat python euni_restore.py # vše → ./obnoveno python euni_restore.py --out D:\Euni # jiný cíl python euni_restore.py --kurz 5618 # jen jeden kurz python euni_restore.py --dry-run # jen výpis ``` **Backfill** (dohrát do SeaweedFS soubory stažené dřív): ```bat python euni_stahni.py --seaweed-backfill --from-json ``` ### Idempotence - Scrape dělá *upsert*: nový materiál → `ceka`; existující si **drží stav** (nepřepíše stažené). Lze tedy bez obav scrapovat opakovaně. - Stahování bere jen `stav: ceka` (a volitelně `chyba` pro retry). ## Použití Nejjednodušší: **`python euni_menu.py`** — interaktivní menu s volbami 1–9 (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 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 # scrape + dokumenty + videa python euni_stahni.py --from-json --no-videos # přeskočí scrape, stáhne z Mongo/JSON 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 --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 --soukroma # seznam přeskočených videí ``` ## Jak to funguje (ověřeno) - **Login** `/sign/` — formulář se parsuje (kopírují se skrytá Nette pole `_do`). - **Seznam kurzů** — signál `studyAreaList-nextPage` vrací JSON snippet, stránkuje se dokud přibývají kurzy (profese: 2=Lékař, 4=Farmaceut, 5/6=studenti, 7=NLZP). - **Detail kurzu** — server-rendered HTML; videa z `