Files
Curator/makov-cam/setup.md
T

176 lines
7.2 KiB
Markdown
Raw 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.
# Makov webkamera → Jellyfin (Live TV)
Restreamuje YouTube live přenos ("Krmítko", https://www.youtube.com/watch?v=F0fsV1GGZ3M)
do lokálního HLS, na který se Jellyfin dívá přes stabilní adresu. Když YouTube
odkaz vyprší nebo spadne, systemd proces sám restartuje a natáhne novou URL —
divák/Jellyfin si ničeho nevšimne.
## 0) Kam skript patří
Toto **musí běžet na stejném stroji (resp. za stejnou veřejnou IP), jako
Jellyfin** — YouTube vrací streamovací URL svázanou s IP adresou, ze které
byla vyžádána (`yt-dlp -g`). Pokud poběží jinde než Jellyfin, `ffmpeg` dostane
403 a nikdy se nerozjede.
## 1) Závislosti
```bash
sudo apt install -y ffmpeg python3
sudo pip install -U yt-dlp # nebo pipx install yt-dlp — apt verze bývá stará
# a YouTube ji rád rozbije
```
Ověř, že `yt-dlp` a `ffmpeg` jedou z shellu bez chyby:
```bash
yt-dlp --version
ffmpeg -version
```
## 2) Uživatel a oprávnění
Vlastní, neprivilegovaný systémový účet — obě služby pod ním běží:
```bash
sudo useradd --system --no-create-home --shell /usr/sbin/nologin makov-cam
sudo mkdir -p /var/lib/jellyfin-iptv/hls
sudo chown -R makov-cam:makov-cam /var/lib/jellyfin-iptv
```
Pokud je `yt-dlp` nainstalované přes **snap** (`which yt-dlp` ukazuje
`/snap/bin/yt-dlp`), potřebuje při startu zapisovatelný domovský adresář —
a to i přes `--no-create-home`, protože domov si zjišťuje přímo z
`/etc/passwd`, ne z proměnné `$HOME` (tu přenastavenou v service souboru
ignoruje). Bez toho skončí na `Permission denied: mkdir /home/makov-cam`.
Vytvoř mu ho ručně:
```bash
sudo mkdir -p /home/makov-cam
sudo chown makov-cam:makov-cam /home/makov-cam
sudo chmod 750 /home/makov-cam
```
(Pokud `yt-dlp` instaluješ přes `pip`/`pipx` dle kroku 1, tenhle problém
nenastává a krok lze přeskočit.)
## 3) Nasazení souborů
```bash
sudo install -m 755 makov-cam.sh /usr/local/bin/makov-cam.sh
sudo install -m 644 makov-cam.service /etc/systemd/system/
sudo install -m 644 makov-cam-http.service /etc/systemd/system/
sudo systemctl daemon-reload
```
## 4) Spuštění
```bash
sudo systemctl enable --now makov-cam.service
sudo systemctl enable --now makov-cam-http.service
```
Ověření:
```bash
systemctl status makov-cam.service makov-cam-http.service
journalctl -u makov-cam.service -f # živě sleduj log ffmpeg/yt-dlp
# do pár vteřin by se měl objevit playlist a segmenty:
ls -la /var/lib/jellyfin-iptv/hls/
# a mělo by jít stáhnout přes HTTP:
curl -sI http://127.0.0.1:8888/hls/makov.m3u8
```
`makov-cam-http.service` je svázaná (`BindsTo=`) na `makov-cam.service` — když
restream spadne/restartuje, HTTP server padne/naskočí s ním, ať nikdy
neservíruje mrtvý/prázdný playlist. Pozor: `BindsTo=` jen zajišťuje, že HTTP
server *spadne*, když spadne hlavní služba — nezajišťuje, že se s ní i sám
*nastartuje*. Po `enable --now` obou služeb to není problém (obě se spustí),
ale pokud jen restartuješ `makov-cam.service` ručně, zkontroluj/restartuj i
`makov-cam-http.service`.
HTTP server poslouchá jen na jedné IP (`--bind`), ne na `0.0.0.0` — nemá cenu
ho vystavovat celé síti, stačí odkud se na něj bude dívat Jellyfin:
- **Jellyfin běží přímo na hostu** (ne v kontejneru): `--bind 127.0.0.1`
stačí.
- **Jellyfin běží v Docker kontejneru na tomtéž hostu** (běžný případ) —
`127.0.0.1` uvnitř kontejneru je jeho *vlastní* loopback, ne hostitelův,
takže na hostitelův HTTP server se tak nedostane. Zjisti gateway IP té
docker sítě, na které kontejner běží, a naviaž se na ni:
```bash
docker inspect <jellyfin-container> --format '{{.HostConfig.NetworkMode}}'
docker inspect <jellyfin-container> --format '{{json .NetworkSettings.Networks}}'
# z výstupu vezmi "Gateway", např. 172.19.0.1 — tam se z kontejneru dostaneš
```
a použij `--bind <ta-gateway-IP>` (viz `makov-cam-http.service`). Pokud by
Jellyfin běžel v jiné VM, změň `--bind` na IP, na které je pro ni
dosažitelný, a případně otevři firewall jen pro tenhle port a jen z její
IP.
## 5) Playlist pro Jellyfin
`WorkingDirectory` HTTP služby je `/var/lib/jellyfin-iptv` (rodič `hls/`), aby
šel přes stejný server servírovat i samotný `.m3u` playlist — to se hodí,
pokud Jellyfin (typicky v kontejneru) nevidí souborový systém hostitele a
tuner tak musí načíst playlist přes HTTP URL, ne lokální cestou.
Vytvoř `/var/lib/jellyfin-iptv/makov.m3u`:
```
#EXTM3U
#EXTINF:-1 tvg-id="makov-krmitko" tvg-name="Makov - Krmítko",Makov - Krmítko
http://<BIND_IP>:8888/hls/makov.m3u8
```
kde `<BIND_IP>` je stejná adresa, na kterou je navázaný `makov-cam-http.service`
(viz krok 4).
## 6) Nastavení v Jellyfinu
1. **Dashboard → Live TV → Tuner Devices → +** (Add)
2. Typ: **M3U Tuner**
3. File or URL:
- Jellyfin na hostu s přístupem k souborovému systému: lokální cesta
`/var/lib/jellyfin-iptv/makov.m3u`.
- Jellyfin v kontejneru (nevidí hostitelův FS): HTTP URL
`http://<BIND_IP>:8888/makov.m3u` (viz krok 5).
4. **Save** → Jellyfin načte kanál "Makov - Krmítko" do Live TV
5. Doporučeno: **Dashboard → Live TV → Guide Providers** — pro tenhle kanál
žádného není třeba (žádný EPG), Jellyfin ho ukáže jako kanál bez programu,
což nevadí.
6. Zkontroluj přehrávání v **Live TV** sekci hlavního rozhraní.
Protože kanál pořád ukazuje na stejnou lokální adresu, odpadá starost o
obnovování guide dat nebo expiraci URL na Jellyfin straně — o to se stará jen
`makov-cam.service` na pozadí.
## 7) Autostart po restartu serveru
`enable` v kroku 4 už zajistil start při bootu. Rychlá kontrola:
```bash
systemctl is-enabled makov-cam.service makov-cam-http.service
```
## Řešení problémů
- **`ffmpeg` pořád padá / v logu 403 od googlevideo.com** — nejčastěji IP
mismatch (viz bod 0): stroj, co spouští `yt-dlp -g`/`ffmpeg`, musí mít
stejnou veřejnou IP jako to, odkud by se stream normálně přehrával.
Zkontroluj `journalctl -u makov-cam.service -n 50`.
- **`yt-dlp: command not found` v service logu** — systemd nepoužívá tvůj
interaktivní `$PATH`; ověř `which yt-dlp` a případně uprav `ExecStart` v
`makov-cam.sh`/skriptu na plnou cestu (`/usr/local/bin/yt-dlp` apod.), nebo
nainstaluj přes `sudo pip install`, aby šel do `/usr/local/bin`.
- **Playlist v Jellyfinu jede, ale sekundy/minuty výpadku při refreshi** —
normální, `hls_list_size 6` × `hls_time 4s` drží ~24s okno; při restartu
streamu je pár vteřin díra, než naběhnou nové segmenty. Jde zkrátit/prodloužit
úpravou těch dvou hodnot ve skriptu.
- **YouTube někdy dočasně rozbije `yt-dlp` novou verzí přehrávače** — drž
`yt-dlp` aktuální (`sudo pip install -U yt-dlp`, klidně jako týdenní cron).
- **`ERROR: Requested format is not available`** — stream v tu chvíli nenabízí
žádný kombinovaný (progresivní) formát, jen oddělené video-only/audio-only
HLS řady (ověř přes `yt-dlp -F <url>`). Skript proto primárně používá
`-f 'bestvideo+bestaudio/best'` a při dvou vrácených URL pustí `ffmpeg` se
dvěma `-i` vstupy (`-map 0:v -map 1:a`); jedna URL = fallback na progresivní
formát, pokud se zase objeví.