Files
2026-06-17 15:06:06 +02:00

121 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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/<id>-<slug>/{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/<id>-<slug>/<typ>/<soubor>`.
- 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 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
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 `<iframe>` (u Vimea se zachová
`?h=` hash), dokumenty z přímých odkazů i `/redirect/<base64>`.
- Metadata z bloků `lecture-info-label``lecture-info-mark`.
## Úskalí
- **Vimeo** dává oddělené video/audio HLS → nutný ffmpeg (řeší static-ffmpeg).
Domain-restricted videa se stahují s referer `https://www.euni.cz/`.
- **Soukromá videa** (autor je zamkl) nejdou stáhnout — skript je označí
`preskoceno` s důvodem, nepadá.
- Anotace kurzu na stránce není (jen obecný text webu) → neukládá se.
- Diakritika v názvech: v konzoli cp1250 OK; výpis má pojistku proti pádu.