
# Jellyfin + IPTV + VOD (Movies/Series) — Volledige Handleiding (TrueNAS SCALE)

**Stack:** Jellyfin (met iGPU), M3U-Splitter + NGINX, VOD .STRM Generator  
**Opslag:** QNAP TL‑D800C → **`/mnt/QNAP-TL-D800C/Media`**  
**Opnames (DVR):** **`/mnt/QNAP-TL-D800C/Media/DVR`**  
**Voorbeeld NAS-IP:** `192.168.2.84`

Deze gids zet je complete Live‑TV én VOD‑setup neer vanuit één grote M3U, met nette groepen, goede EPG‑mapping en opnames naar jouw DVR‑pool. Ook nemen we jouw **Movies.m3u** en **Series.m3u** mee en zetten die om naar **.strm** bibliotheken.

---

## 0) Wat je gaat bouwen (plaatje in woorden)
1. **M3U Splitter**: leest je **grote M3U** en maakt **1 M3U per `group-title`** (Netherlands, UK News, Canada Sports, …).  
2. **NGINX**: serveert die M3U’s op **poort 8099** → je voegt in Jellyfin **één tuner per groep** toe.  
3. **VOD .STRM Generator**: leest **Movies.m3u** en **Series.m3u** (met `group-title` en/of `#EXTGRP:` zoals `Action;Comedy;Crime`) en bouwt **.strm-mappen** voor Jellyfin‑bibliotheken.  
4. **Jellyfin PVR**: opnames naar **`/mnt/QNAP-TL-D800C/Media/DVR/Jellyfin`** (en optioneel **TVHeadend** naar `/mnt/QNAP-TL-D800C/Media/DVR/TVHeadend`).

---

## 1) Voorbereiden (TrueNAS SCALE)
### 1.1 Mappen aanmaken
Maak (via **Datasets** of SMB) deze paden aan:
```
/mnt/Applications/Apps/m3u-splitter/{data,out,config,app}
/mnt/Applications/Apps/m3u-vod-strm/{data,out,app}
/mnt/QNAP-TL-D800C/Media/DVR/{Jellyfin,TVHeadend}
```
> *Rechten*: Jellyfin en de helper‑containers moeten **schrijven**. In onze compose gebruiken we meestal UID/GID 1000 of root (python:alpine). Als je problemen met rechten ziet, geef tijdelijk 0775 of 0777 en verfijn later.

### 1.2 Bestanden plaatsen
- Master M3U → `/mnt/Applications/Apps/m3u-splitter/data/master.m3u` *(of gebruik een M3U‑URL in de compose)*
- Movies M3U → `/mnt/Applications/Apps/m3u-vod-strm/data/movies.m3u`
- Series M3U → `/mnt/Applications/Apps/m3u-vod-strm/data/series.m3u`
- (Optioneel) `include_groups.txt` en `exclude_groups.txt` in `m3u-splitter/config` (zie §3.3).

---

## 2) Alles in één keer starten
Gebruik de meegeleverde **`jellyfin-all-in-one.compose.yaml`** (Jellyfin + Splitter + NGINX + VOD‑generator).  
Start als **Custom App** (TrueNAS) of via CLI:
```bash
docker compose -f jellyfin-all-in-one.compose.yaml up -d
```
**Controle:**  
- Splitter index: `http://192.168.2.84:8099/m3u/index.html`  
  → je ziet 1 M3U per groep (bijv. *Netherlands.m3u*, *UK News.m3u*, *Canada Sports.m3u*, *XXX.m3u*, …).  
- VOD generator vult:  
  - **Movies** onder: `/mnt/Applications/Apps/m3u-vod-strm/out/Movies`  
  - **TV** onder: `/mnt/Applications/Apps/m3u-vod-strm/out/TV`

---

## 3) Live TV in Jellyfin
### 3.1 Tuners toevoegen (per groep één)
1. **Dashboard → Live TV → Add → M3U Tuner**  
2. **File or URL**: pak de juiste Splitter‑URL, bijv.:  
   - Netherlands → `http://192.168.2.84:8099/m3u/Netherlands.m3u`  
   - UK News → `http://192.168.2.84:8099/m3u/UK%20News.m3u`  
   - Canada Sports → `http://192.168.2.84:8099/m3u/Canada%20Sports.m3u`  
   - …etc. (zie Splitter index)
3. **Naam**: `M3U — Netherlands` (enz.)
4. **Simultaneous stream limit**: volgens je provider (of 0).  
5. **Allow stream sharing**: **aan** (meerdere kijkers ≈ 1 backendstream).  
6. **Ignore DTS**: **aan** (voorkomt A/V‑sync issues bij HLS).  
7. **Fallback max stream bitrate**: 20–30 Mbps (1080p), 8–12 voor mobiel.

### 3.2 EPG (XMLTV)
- **Live TV → Guide Data → Add → XMLTV**: plak je XMLTV‑URL.  
- **Map Channels**: koppel kanaal ↔ gidsvermelding. Eén EPG kan alle tuners bedienen.

### 3.3 Groepen beperken/uitsluiten (optioneel)
In de Splitter:
- `/mnt/Applications/Apps/m3u-splitter/config/include_groups.txt` → **whitelist** (één groep per regel).  
- `/mnt/Applications/Apps/m3u-splitter/config/exclude_groups.txt` → **blacklist**.  
> In de bundle is `exclude_groups.txt` vooraf gevuld met **`XXX`**. `include_groups.txt` is **leeg** = **alles meenemen**. Er is ook een **family_preset_include_groups.txt** met veelgebruikte, niet‑XXX groepen.

### 3.4 Kanaalnummers & dubbelen
- Werk met blokken: **NL 101–199**, **UK 201–299**, **Sports 401–499**, **Kids 501–549**, **Docs 551–599**, **XXX 901–999**.  
- Je kunt nummers alvast in de M3U zetten met `tvg-chno="101"`, of achteraf in **Live TV → Channels**.  
- **Dubbele zenders**: gebruik **Tuner priority** (betere bron hoger) of **Disable** het duplicaat.

---

## 4) PVR/Opnames in Jellyfin (→ `/mnt/QNAP-TL-D800C/Media/DVR/Jellyfin`)
De compose voor Jellyfin bevat de bind‑mount:
```
/mnt/QNAP-TL-D800C/Media/DVR/Jellyfin:/recordings
```
**In Jellyfin → Live TV → Recording:**
- **Recordings path**: `/recordings`
- **Pre/Post padding**: 2–3 min (meer bij onzekere gids)
- **Keep**: *until space needed* of *keep N recordings*

Plan opnames vanuit **Guide** (Once/Series).  
Voeg het pad **ook** toe als **Library** (Movies/TV) voor metadata/posters:
```
/mnt/QNAP-TL-D800C/Media/DVR/Jellyfin
```

> **Tip:** Zie je veel corrupte/lastige opnames met HLS? Overweeg **TVHeadend** (§5) voor robuustere PVR.

---

## 5) (Optioneel) TVHeadend PVR (→ `/mnt/QNAP-TL-D800C/Media/DVR/TVHeadend`)
- Compose mount:  
  `/mnt/QNAP-TL-D800C/Media/DVR/TVHeadend:/recordings`
- WebUI: `http://192.168.2.84:9981`
- Wizard: **Admin** maken → **IPTV Automatic Network** met je master M3U → **Map Services to Channels** → **Channel Tags** (Netherlands/UK/Sports/XXX).  
- **PVR**: *Recording → DVR Profiles* → path `/recordings`, padding 2–3 min, stream **Pass‑through**.  
- Geef aan Jellyfin **ofwel** HTSP **of** per Tag een export‑M3U als tuner.  
- Voeg `/mnt/QNAP-TL-D800C/Media/DVR/TVHeadend` toe als Library in Jellyfin om opnames netjes te zien.

---

## 6) VOD: Movies & Series uit M3U → .STRM bibliotheken
Je provider hanteert vaak:
- **`group-title="Action;Horror;Western"`** op de `#EXTINF` regel, en/of
- **`#EXTGRP:Action;Horror;Western`** **tussen** `#EXTINF` en de URL.
De VOD‑generator begrijpt beide. Bij meerdere genres nemen we **het eerste** als **hoofdmappennaam** (*Action* in dit voorbeeld).

### 6.1 Hoe de generator mappen maakt
- **Films** → `/Movies/<Hoofdgenre>/<Titel (Jaar)>/<Titel (Jaar)>.strm`  
  - Jaar wordt uit de titel **gehaald** (bijv. “They Call Her Death 2025” → `(2025)`).  
  - `tvg-logo` wordt **`poster.jpg`** naast de .strm.
- **Series** → `/TV/<Hoofdgenre>/<Serie>/Season 01/<Serie S01E01>.strm`  
  - **Detectie** van `SxxEyy`. Als het ontbreekt (latenight show of daily), zetten we het in **Season 01** en gebruiken we de titel als bestandsnaam.
  - `tvg-logo` wordt **poster op seriemap**.

> **Voorbeeld M3U** (uit jouw screenshots):
```
#EXTM3U
#EXTINF:5539 tvg-logo=".../poster1.jpg" group-title="Action;Horror;Western",They Call Her Death 2025
#EXTGRP:Action;Horror;Western
https://thunderbolt-40gbps.com/movie/.../900039487
#EXTINF:2457 tvg-logo=".../noposter.jpg" group-title="Talk",Seth Meyers 2025 09 04
#EXTGRP:Talk
https://thunderbolt-40gbps.com/movie/.../990180113
#EXTINF:2314 tvg-logo=".../noposter.jpg" group-title="Soap",Betty la Fea, the Story Continues S02E07
#EXTGRP:Soap
https://thunderbolt-40gbps.com/movie/.../990180112
```

### 6.2 Bibliotheken toevoegen in Jellyfin
Na opstarten van de **VOD .STRM** service:
```
Movies → /mnt/Applications/Apps/m3u-vod-strm/out/Movies
TV Shows → /mnt/Applications/Apps/m3u-vod-strm/out/TV
```
Laat Jellyfin een **Library Scan** doen; posters komen mee via `poster.jpg`.  
**Filters** (optioneel): gebruik env‑vars in de compose om alleen bepaalde genres te genereren:
```
MOVIES_INCLUDE=Action,Comedy
MOVIES_EXCLUDE=XXX
SERIES_INCLUDE=Talk,Crime
SERIES_EXCLUDE=XXX
```

---

## 7) Best‑practices & tips
- **User‑Agent**: sommige providers vereisen specifieke UA → stel in per Jellyfin‑tuner *User agent* veld.  
- **Streamlimieten**: respecteer provider; zet *Simultaneous stream limit*.  
- **Tuner priority**: beste bron bovenaan.  
- **Transcoding**: vermijd; pass‑through is lichter. Als nodig, zet iGPU (QSV/VAAPI) in Jellyfin aan.  
- **Security**: NGINX (8099), TVH (9981/9982) **alleen LAN** of achter VPN/Reverse Proxy.  
- **Back‑ups**: bewaar `/config` mappen en compose‑files.  
- **EPG‑kwaliteit**: meerdere XMLTV’s combineren (TVH is hierin sterk) of betrouwbare bron kiezen.

---

## 8) Troubleshooting
- **Kanaal speelt niet** → test URL in VLC; vaak bron of geo‑lock.  
- **EPG leeg** → check XMLTV‑URL; tijdzone; **Map Channels** opnieuw.  
- **Stotteren** → *Allow stream sharing* aan, lagere **Fallback bitrate**, of gebruik TVHeadend.  
- **Opname corrupt** → padding verhogen; alternatieve zender; TVHeadend‑PVR overwegen.  
- **VOD ontbreekt** → check paden en of `.strm` mappen gevuld zijn; forceer Jellyfin library‑rescan.

---

## 9) Snel‑checklist
- [ ] Splitter draait → `http://NAS:8099/m3u/index.html` toont groepen.  
- [ ] Jellyfin tuners per groep toegevoegd; **sharing** + **Ignore DTS** aan.  
- [ ] XMLTV toegevoegd en **mapped**.  
- [ ] Jellyfin PVR → **/recordings** (mount naar `/mnt/QNAP-TL-D800C/Media/DVR/Jellyfin`).  
- [ ] VOD .STRM generator draait; bibliotheken toegevoegd (Movies/TV).  
- [ ] Optioneel: TVHeadend → `/mnt/QNAP-TL-D800C/Media/DVR/TVHeadend` en zichtbaar in Jellyfin.

---

## 10) Juridisch
Gebruik alleen streams/bestanden waarvoor je **rechten/abonnement** hebt. Controleer de lokale wetgeving en de voorwaarden van je aanbieder.


---

## EPG toevoegen
Gebruik deze **XMLTV**-bron:
- **Remote**: https://epg.iptv.cat/epg.xml
- **Lokaal gespiegeld** (aanbevolen, via epg_fetcher + NGINX): `http://192.168.2.84:8099/epg.xml`

**Jellyfin → Live TV → Guide Data → Add → XMLTV**: plak bij voorkeur de **lokale** URL. Daarna **Map Channels**.


---

## Extra exports (volledig)
- **TUNERS-ALL-URLs.txt** — alle groep-URL’s voor Jellyfin tuners (via de Splitter/NGINX).
- **CHANNELS-ALL.csv** — elk kanaal uit je master (kolommen: group, tvg-id, tvg-name, tvg-logo, name, url).
