
# Jellyfin IPTV met één grote M3U → nette groepen (incl. PVR/Opnames)
*Voor TrueNAS SCALE — stap‑voor‑stap, beginnerproof.*  
Auteur: **Marco Salentijn & ChatGPT** · Server-IP in dit voorbeeld: **192.168.2.84** · Basispad: **`/mnt/Applications/Apps/`**

---

## 0) Wat gaan we bouwen?
Je hebt **één grote M3U** (IPTV‑playlist) met `group-title`’s (bijv. *NL*, *UK*, *Sports*, *Kids*, *XXX*). Jellyfin groepeert zelf niet, dus we gebruiken een **tussenlaag** die:

1. **Je master-M3U inleest**,  
2. **Per groep** een **schone, gefilterde M3U** uitgeeft,  
3. Die we in **Jellyfin** als **aparte tuners** toevoegen (NL/UK/Sports/…),
4. Met **EPG (XMLTV)** en **PVR/Opnames** in Jellyfin óf in de tussenlaag.

Je kunt kiezen uit **xTeVe** (licht & simpel) of **TVHeadend** (krachtig, met ingebouwde PVR).  
> **Korte keuzehulp**: wil je zo snel mogelijk werken en *simpel filteren* → **xTeVe**. Wil je **geavanceerde gids/PVR** met tags, timeshift, tuner‑prioriteiten → **TVHeadend**.

---

## 1) Voorwaarden & voorbereiding
- **Jellyfin draait al** op je TrueNAS (Docker/Custom App).
- Je hebt een **M3U‑URL** en indien mogelijk een **XMLTV‑EPG‑URL** van je provider(s).
- **Netwerk**: we gebruiken poorten 34400+ (xTeVe) of 9981/9982 (TVHeadend).
- **Paden** (pas aan als je zelf andere gebruikt):
  - xTeVe config: `/mnt/Applications/Apps/xteve/<instantie>`
  - TVHeadend config: `/mnt/Applications/Apps/tvheadend/config`
  - TVHeadend opnames: `/mnt/Applications/Apps/tvheadend/recordings`
  - Jellyfin opnames (als je Jellyfin-PVR gebruikt): bijvoorbeeld `/mnt/Applications/Apps/jellyfin/recordings`

**Kanaalnummers (advies):**
- NL **101–199**, UK **201–299**, Sports **401–499**, Kids **501–549**, Docs **551–599**, XXX **901–999**.  
Je kunt dit in je M3U regelen met `tvg-chno=""` of later in Jellyfin.

**Voorbeeldregel** (werkt met iedere methode):
```m3u
#EXTINF:-1 tvg-id="npo1.nl" tvg-name="NL · NPO 1" tvg-chno="101" group-title="NL",NL · NPO 1
http://provider.example/stream.m3u8
```

---

## 2) Methode A — xTeVe (eenvoudig & lichtgewicht)
xTeVe geeft **per instantie** één gefilterde playlist aan Jellyfin. We draaien **meerdere instanties** (bv. *all*, *nl*, *uk*, *sports*), allemaal lezend van **dezelfde master-M3U**.

### 2.1 Docker Compose (TrueNAS SCALE Custom App)
Sla dit bestand op als **`/mnt/Applications/Apps/xteve/docker-compose.yml`**:

```yaml
services:
  xteve_all:
    image: ghcr.io/xteve-project/xteve:latest
    container_name: xteve-all
    ports: ["34400:34400"]      # WebUI
    environment:
      - TZ=Europe/Amsterdam
      - PUID=1000
      - PGID=1000
    volumes:
      - /mnt/Applications/Apps/xteve/all:/config
    restart: unless-stopped

  xteve_nl:
    image: ghcr.io/xteve-project/xteve:latest
    container_name: xteve-nl
    ports: ["34401:34400"]
    environment:
      - TZ=Europe/Amsterdam
      - PUID=1000
      - PGID=1000
    volumes:
      - /mnt/Applications/Apps/xteve/nl:/config
    restart: unless-stopped

  xteve_uk:
    image: ghcr.io/xteve-project/xteve:latest
    container_name: xteve-uk
    ports: ["34402:34400"]
    environment:
      - TZ=Europe/Amsterdam
      - PUID=1000
      - PGID=1000
    volumes:
      - /mnt/Applications/Apps/xteve/uk:/config
    restart: unless-stopped

  xteve_sports:
    image: ghcr.io/xteve-project/xteve:latest
    container_name: xteve-sports
    ports: ["34403:34400"]
    environment:
      - TZ=Europe/Amsterdam
      - PUID=1000
      - PGID=1000
    volumes:
      - /mnt/Applications/Apps/xteve/sports:/config
    restart: unless-stopped
```

> **Starten:** in TrueNAS → *Apps → Launch Docker Compose App* → wijs naar het YAML-bestand. (Of gebruik je bestaande Custom App-proces.)

### 2.2 Eerste configuratie per instantie
Open de WebUI’s:
- **All:** `http://192.168.2.84:34400`
- **NL:** `http://192.168.2.84:34401`
- **UK:** `http://192.168.2.84:34402`
- **Sports:** `http://192.168.2.84:34403`

**Wizardschermen (per instantie):**
1. **Playlist** → plak je **grote M3U‑URL** (of upload bestand).  
2. **EPG/XMLTV** → voeg je XMLTV‑URL toe (zelfde voor alle instanties, tenzij je wilt splitsen).  
3. **Filters** → klik *Filter* en maak **Include‑regels**:
   - *xteve_nl*: Include **Group contains** `NL` of `Netherlands`  
   - *xteve_uk*: Include **Group contains** `UK` of `United Kingdom`  
   - *xteve_sports*: Include **Group contains** `Sports`  
   - (Optioneel) Exclude **Group equals** `XXX` bij instanties voor familiegebruik.
4. **Mapping** → controleer dat alleen de gewenste kanalen aanwezig zijn.
5. **Opslaan** → xTeVe toont een **Playlist‑URL** (de *virtuele M3U* van die instantie). Noteer deze.

> **Tip:** In xTeVe → *Settings → Buffer* kun je **Segment Buffer** of **RingBuffer** kiezen. Laat standaard staan tenzij je bufferingproblemen hebt.

### 2.3 Jellyfin koppelen (per groep = 1 tuner)
In Jellyfin (Admin):
1. **Dashboard → Live TV → Add** → **M3U Tuner**.
2. **File or URL** → de **xTeVe‑Playlist‑URL** van de instantie.
3. **Naam** → `M3U — NL` / `M3U — UK` / `M3U — Sports` …
4. **Simultaneous stream limit** → zetten naar je providerlimiet (of 0).
5. **Allow stream sharing** → **aan** (meerdere kijkers op 1 kanaal = 1 backendstream).
6. **Ignore DTS** → **aan** (fix voor streams met gescheiden A/V‑timestamps).
7. **Save**.

**EPG toevoegen in Jellyfin:**
- *Live TV → Guide Data → Add → XMLTV*: plak dezelfde **XMLTV‑URL**.  
- *Map Channels*: koppel zender ↔ gidsvermelding (Jellyfin onthoudt dit).

**Kanaalnummers & namen:**
- Werk met **prefixes** en **blokken** (NL 101–199, UK 201–299 etc.).  
- Zet `tvg-chno` in je bron‑M3U óf wijzig nummers in *Live TV → Channels*.

---

## 3) Methode B — TVHeadend (krachtiger + ingebouwde PVR)
TVHeadend kan je grote M3U inlezen, **Services → Channels** mappen, **Channel Tags** (NL/UK/Sports/…) maken, **EPG** samenvoegen en **opnames plannen**. Je kunt óf TVH’s eigen PVR gebruiken, óf Jellyfin laten opnemen (via de door TVH geëxporteerde M3U).

### 3.1 Docker Compose
Bestand: **`/mnt/Applications/Apps/tvheadend/docker-compose.yml`**

```yaml
services:
  tvheadend:
    image: lscr.io/linuxserver/tvheadend:latest
    container_name: tvheadend
    ports:
      - "9981:9981"   # WebUI
      - "9982:9982"   # HTSP
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Amsterdam
    volumes:
      - /mnt/Applications/Apps/tvheadend/config:/config
      - /mnt/Applications/Apps/tvheadend/recordings:/recordings
    restart: unless-stopped
```

Start de app in TrueNAS.

### 3.2 Eerste setup (wizard)
1. Ga naar `http://192.168.2.84:9981` → kies **Admin user + wachtwoord**.
2. *Configuration → DVB Inputs → Networks* → **Add → IPTV Automatic Network**: plak je **grote M3U‑URL** (en evt. je XMLTV‑URL bij *EPG Grabber Modules* / *XMLTV*).
3. Wacht tot *Services* verschijnen → *Map Services to Channels*.
4. *Configuration → Channel / EPG → Channel tags* → maak tags: `NL`, `UK`, `Sports`, `Kids`, `XXX`, …
5. Selecteer kanalen → koppel aan de juiste **Tag**(s).
6. (Optioneel) **EPG**: combineer meerdere bronnen, prioriteiten instellen.

### 3.3 TVHeadend → Jellyfin koppelen
- *Configuration → General → Base* (of *EPG / Channels*): kopieer **Playlist/M3U per Tag** (TVH kan per Tag een **filter‑M3U** aanbieden).  
- In **Jellyfin**: voeg **per Tag** een **M3U Tuner** toe (zoals bij xTeVe).

> **Alternatief:** gebruik **HTSP** (TVH’s native protocol) via een Jellyfin plugin/connector. Als je dat niet wilt, blijft M3U+XMLTV universeel en eenvoudig.

### 3.4 PVR met TVHeadend (aanrader als je TVH gebruikt)
- *Configuration → Recording → Digital Video Recorder Profiles*: stel profiel **Default** in:
  - **Recording system path**: `/recordings`
  - **Pre/Post padding**: bijv. 2–3 min (of meer bij onzekere gids).
  - **Stream type**: *Pass‑through* (bewaar origineel) of transcodeerprofiel (optioneel).
- In de EPG of via *Timers* plan je **Series/Once recordings**.  
- **Jellyfin ziet de opnames** als je de map `/mnt/Applications/Apps/tvheadend/recordings` toevoegt als **Library** (TV Shows / Movies) en een scanschema instelt.

---

## 4) PVR/Opnames in Jellyfin (zonder TVHeadend)
Wil je **Jellyfin zelf laten opnemen** vanaf je M3U‑tuners (xTeVe of TVH‑export)?

1. **Opnamepad** (maak deze map en mount hem in je Jellyfin‑container):
   - Voorbeeld: `/mnt/Applications/Apps/jellyfin/recordings`
   - In **Jellyfin → Dashboard → Live TV → Recording**:
     - **Recordings path**: die map
     - **Pre/Post padding**: bijv. 2–3 min
     - **Keep**: bv. *until space needed* of *keep N recordings*
2. **Transcoderen of kopiëren?**
   - Standaard probeert Jellyfin te **kopiëren** (pass-through) als het containerformaat/codec geschikt is; anders transcodeert het via FFmpeg.
   - Voor **minimale CPU**: zorg dat je streams al in **H.264/AAC** zitten en **Allow stream sharing** aan staat.
3. **Programmeren:**
   - *Live TV → Guide* → klik een programma → **Record** (once/series).
   - *Live TV → Series* of *Scheduled* om regels te beheren.
4. **Metadata & bibliotheek:**
   - Voeg het opnamepad **ook** toe als Jellyfin **Library** (TV/Movies), zodat posters/metadata en seizoensweergave werken.

**Let op (IPTV‑valkuilen):**
- Sommige HLS‑streams hebben **discontinuities** → opnames kunnen niet altijd goed seeken. Overweeg **TVHeadend PVR** als je veel issues ziet.
- Streams met **DTS‑gaten/timestamps** → zet in tuner **Ignore DTS** aan (zoals in jouw screenshot).

---

## 5) Rechten, performance & prioriteit
- **User-Agent / headers**: sommige providers vereisen een specifieke UA → stel dit per **Jellyfin‑tuner** in.
- **Streamlimieten**: gebruik **Simultaneous stream limit** per tuner om banrisico te beperken.
- **Tuner priority** in Jellyfin: geef je **beste/voorkeursbron** een hogere prioriteit (bij doublures).
- **Hardware**: opnames zijn I/O‑gebonden; transcoding vraagt **CPU/GPU**. Gebruik iGPU (QSV/VAAPI) in Jellyfin alleen als je **moet** transcoderen.

---

## 6) Beheer & beveiliging
- **xTeVe**: zet de WebUI achter je LAN/VPN; xTeVe heeft beperkte auth → beperk toegang via je router/Traefik/NGINX.
- **TVHeadend**: heeft eigen **users/profiles**; zet **Admin** met sterk wachtwoord en maak **Streaming‑users**.
- **Back‑ups**: bewaar `/config` en je playlists/EPG‑URL’s.  
- **Logging**: check bij problemen xTeVe/TVH logs (en Jellyfin *Activity* en `ffmpeg` logs).

---

## 7) Troubleshooting (snel)
- **Zender speelt niet** → test de directe stream‑URL in VLC; als die hapert, ligt het aan de bron.  
- **Geen EPG** → verifieer XMLTV‑URL, tijdzone, en *Map Channels*.  
- **Dubbele kanalen** → verlaag prioriteit van de ongewenste tuner of *disable* het kanaal.  
- **Opnames corrupt** → probeer TVHeadend‑PVR, verhoog padding, of kies een alternatieve zender/bron.

---

## 8) Snelle checklist
- [ ] xTeVe/TVHeadend draait en leest **één master‑M3U**.  
- [ ] Per groep is er **een eigen output‑M3U** (xTeVe‑instantie of TVH‑Tag).  
- [ ] In Jellyfin is **per groep één M3U‑tuner** toegevoegd.  
- [ ] **XMLTV** is toegevoegd in Jellyfin (en gemapt).  
- [ ] **Kanaalnummers** en namen logisch ingesteld.  
- [ ] **PVR** ingesteld in Jellyfin **of** in TVHeadend (opnamepad & padding).  
- [ ] Opnames‑map als **Library** toegevoegd in Jellyfin.

---

## 9) Bonus: voorbeelden van filters en groepering
**xTeVe – NL include + XXX exclude:**  
- Include → Field: *Group*, Operator: *contains*, Value: `NL`  
- Exclude → Field: *Group*, Operator: *equals*, Value: `XXX`

**TVHeadend – Tags automatisch vullen op group-title:**  
- Exporteer kanalenlijst, groeperen op `group-title`, importeer als Channel Tags (of handmatig selecteren per groep).

---

## 10) Veelgestelde vragen
**Kan Jellyfin “secties” tonen?** Nee, Jellyfin mengt alles in één gids. Met **meerdere tuners** (NL/UK/…) houd je het beheerbaar, en met **kanaalnummers/prefixes** blijft het overzichtelijk.  
**Is één grote M3U slim?** Ja — dankzij xTeVe/TVHeadend heb je centraal beheer en gefilterde uitgangen.  
**Waar laat ik opnames?**  
- Jellyfin‑PVR: map (bijv. `/mnt/Applications/Apps/jellyfin/recordings`) mounten in Jellyfin en als Library toevoegen.  
- TVHeadend‑PVR: op `/mnt/Applications/Apps/tvheadend/recordings` en die map als Library toevoegen in Jellyfin.

---

> Klaar voor een **kant‑en‑klare Compose** met *alle* groepen die jij wilt (NL/UK/Sports/Kids/Docs/XXX) en voorbeeldfilters? Geef je groepennamen door; ik lever direct een tailor‑made YAML + screenshots‑walkthrough.
