---
title: EPG-Server (XMLTV)
url: https://doc.pstreamer.tv/de/manual/epg_server.html
lang: de
product: Perfect Streamer
version: 1.13.3.445
---

# EPG-Server (XMLTV)

Ein separater integrierter HTTP-Server in Perfect Streamer liefert das vollständige XMLTV für einen vorgegebenen Kanalsatz. Der Endpunkt ist für Middleware und Player gedacht, die das Programm lokal vorhalten und es selten aktualisieren — als ganze Datei, typischerweise ein- bis zweimal täglich.

Der Server und seine Clients werden unter **Configuration/EPG/EPG Server** konfiguriert.

## URL und Authentifizierung

Der Dienst wird von einem **separaten** HTTP-Server `epg-server` bereitgestellt (nicht von dem für `/data/*`). Standardmäßig lauscht er auf den Ports `10444` (HTTP) und `10445` (HTTPS); Ports und SSL werden unter `/config/epg-server` konfiguriert.

Routen:

| URL | Content-Type | Verhalten |
| --- | --- | --- |
| `GET /xmltv` | `text/xml` | Bei `Accept-Encoding: gzip` wird die Antwort spontan komprimiert (`Content-Encoding: gzip`), sonst als unkomprimiertes XML ausgeliefert. |
| `GET /xmltv.gz` | `application/octet-stream` | Liefert stets einen Gzip-Stream mit `Content-Disposition: inline; filename="xmltv.xml.gz"` — praktisch zum Speichern als Datei. |

Drei Authentifizierungsmethoden werden unterstützt:

- **HTTP Digest** (bevorzugt) — Konto aus `/config/epg-server/login`.
- **URL-Parameter** — `?l=<login>&p=<password>` (Synonyme: `login=…`, `password=…`).
- **Loopback** — eine Anfrage von `127.0.0.1` wird anonym behandelt. Praktisch für Skripte, die auf derselben Maschine laufen.

> **Warnung**
>
> Login und Passwort in der URL landen in den Access-Logs des Reverse-Proxys und im Browserverlauf. Für die öffentliche XMLTV-Verteilung verwenden Sie HTTP Digest oder lassen Sie Anfragen nur von privaten Adressen zu.

## Zugriff per channel-set

Jedes `epg-server/login`-Konto ist an **ein** `channel-set` aus `/config/epg-channel-set` gebunden. Das EPG in der Antwort enthält nur die Kanäle des angegebenen Sets. So kann eine einzige PSS-Installation unterschiedlichen Betreibern/Middleware unterschiedliches XMLTV ausliefern.

Grundeinrichtung in der UI:

1. Erstellen Sie unter **Configuration/EPG/EPG Channel Sets** eine Kanalgruppe und weisen Sie die gewünschten Kanäle bei den EPG-Quellen zu.
2. Legen Sie unter **Configuration/EPG/EPG Server Clients** ein Konto an und binden Sie die erstellte Gruppe daran. Ohne `channel-set`-Bindung erhält der Client ein leeres XMLTV.

Zusätzliche Einschränkungen für einen Login:

- `ip-addr` — wenn gesetzt und kein Platzhalter, erhält eine Anfrage von einer anderen IP `403 Forbidden`.
- `limit-day` — Unix-Epoche-Sek., nach der das Konto nicht mehr bedient wird (`403 Forbidden`). Praktisch für ein Abonnementmodell.
- `pause` — einen Login vorübergehend deaktivieren, ohne ihn zu löschen.

## Antwortformat

Der Antwortkörper ist ein XMLTV-Dokument mit der Wurzel `<tv>`. Die Struktur folgt dem gängigen [XMLTV DTD](http://wiki.xmltv.org/index.php/XMLTVFormat)-Schema:

```xml
<?xml version="1.0" encoding="utf-8"?>
<tv source-info-name="..." source-info-url="...">
  <channel id="channel.one">
    <display-name lang="en">Channel One</display-name>
    <icon src="https://.../channel-one.png"/>
  </channel>
  ...
  <programme start="20260504060000 +0300"
             stop ="20260504070000 +0300"
             channel="channel.one">
    <title lang="en">Morning News</title>
    <desc  lang="en">Overview of the day's events</desc>
    <rating system="MPAA"><value>PG</value></rating>
  </programme>
  ...
</tv>
```

Hinweise zu Feldern:

- Die Attribute `source-info-name` und `source-info-url` der `<tv>`-Wurzel werden aus den Feldern **EPG Source Name** und **EPG Source URL** unter **Configuration/EPG/EPG Server** gefüllt.
- Die Attribute `start` und `stop` werden im Format `YYYYMMDDhhmmss ±zone` angegeben (die Zeitzone stammt aus dem Feld `time_zone` des Kanals).
- Ein `<programme>` darf mehrere `<title>`/`<desc>` für verschiedene Sprachen enthalten. Das Attribut `lang` ist leer, wenn die Sprach-ID aus den EPG-Quelldaten nicht im Wörterbuch zugeordnet werden konnte (der Eintrag erscheint dennoch in der Ausgabe).
- Kanäle mit einem konfliktbehafteten `channel_id` (wenn dieselbe ID aus mehreren Quellen kommt) werden einmal angezeigt, die übrigen Quellen werden mit einer Warnung im Serverlog übersprungen.
- Nur Ereignisse mit `stop_time >= now` werden in die Ausgabe aufgenommen.

## HTTP-Header

Der Server sendet immer:

```
Cache-Control: no-cache, no-store, must-revalidate
Pragma:        no-cache
Expires:       0
Connection:    close
```

Für `/xmltv` zusätzlich — `Content-Encoding: gzip` bei vorhandenem `Accept-Encoding: gzip` in der Anfrage. Für `/xmltv.gz` — `Content-Disposition: inline; filename="xmltv.xml.gz"`.

Das Verbot des clientseitigen Cachens ist beabsichtigt: XMLTV ändert sich bei jedem EIT-Import oder Refresh externer XMLTV-Quellen, und der Player darf veraltete Daten nicht unbegrenzt vorhalten. Ein Edge-Cache (nginx) ist hingegen voll akzeptabel — siehe Abschnitt zur Leistung weiter unten.

## Server-Cache und sein Zurücksetzen

Das fertige XMLTV wird im Speicher des PSS-Prozesses gecacht:

- Ein Eintrag pro `channel-set`; intern werden beide Körpervarianten (raw und gzip) vorgehalten — wiederholte Anfragen mit `Accept-Encoding: gzip` oder `/xmltv.gz` komprimieren die Daten nicht erneut.
- Jeder Eintrag erhält einen `update-time`-Zähler. Jede EPG-Aktualisierung (EIT-Import, XMLTV-Quellen-Refresh) erhöht den Zähler, und der Cache wird bei der nächsten Anfrage neu aufgebaut.

Cache erzwungen leeren:

```
POST /xmltv/reset-cache
```

Die Route wird vom **Admin-Server** (Port `43971`/`43981`) bedient, nicht vom epg-server. Der Anfragekörper ist leer; die Antwort ist `200 OK` mit einem JSON-Umschlag.

## HTTP-Antwortcodes

| Code | Bedingung |
| --- | --- |
| `200 OK` | Anfrage verarbeitet. Der Körper ist ein XMLTV-Dokument (eventuell ein leeres `<tv></tv>` bei einem vorübergehenden DB-Fehler). |
| `401 Unauthorized` | Weder Digest noch `l/p`-Parameter haben die Prüfung bestanden (für nicht-Loopback-Anfragen). |
| `403 Forbidden` | Der Login existiert, aber die Anfrage kommt nicht von einer erlaubten IP, oder `limit-day` ist abgelaufen. |
| `404 Not Found` | Jede URL außer `/xmltv` und `/xmltv.gz`. |
| `405 Method Not Allowed` | Methode ist nicht GET. |

Der Fehlerkörper ist ein JSON-Umschlag mit festem Format:

```json
{"status": 401, "message": "Unauthorized"}
```

## Leistung und Skalierung

### Server-Cache

Der Server-Cache bedient wiederholte Anfragen an dasselbe `channel-set` ohne SQLite-Zugriff — durch Kopieren des fertigen Körpers.

Der XMLTV-Aufbau „von Grund auf“ (Cache-Miss) ist teurer: pro Kanal ein eigenes SELECT über `channel_name`, pro Ereignis eines über `event_text` und `event_rating`. Anhaltspunkte zur Bauzeit:

| Ausgabegröße | Cache hit | Cache miss (build) |
| --- | --- | --- |
| 100 Kanäle / Tag | einige Dutzend ms | ~0,5–1 s |
| 500 Kanäle / Tag | ~50 ms | 2–5 s |
| 1000+ Kanäle / Woche | ~100–300 ms | 5–15 s |

Für die meiste Middleware ist es akzeptabel, XMLTV alle paar Stunden oder einmal täglich abzufragen.

### Wann ein externer Reverse-Proxy (nginx) nötig ist

Im Gegensatz zu `/data/epg/channel` (kurze JSON-Antworten) ist XMLTV ein einziges großes Dokument pro `channel-set` und damit ideal für einen Edge-Cache:

- **Zehn bis Hunderte Clients pro channel-set** — der interne PSS-Cache reicht meist aus, wenn sie XMLTV stündlich bis täglich abfragen.
- **Tausende gleichzeitige Clients** — ein cachender Reverse-Proxy wird empfohlen. Das Ausliefern einer XMLTV-Datei an Hunderte/Tausende Anfragen ist in erster Linie eine Netzwerklast (Hunderte KB – einige MB pro Antwort), die man besser von PSS fernhält.
- **Geografisch verteilte Auslieferung** — ohne CDN/Edge-Cache geht es nicht, unabhängig von der Clientzahl.

PSS sendet `Cache-Control: no-cache`, daher muss nginx explizit angewiesen werden, den Upstream-Header zu ignorieren und einen eigenen TTL zu führen.

### Beispielkonfiguration für nginx

```nginx
# /etc/nginx/conf.d/pss-xmltv.conf

proxy_cache_path /var/cache/nginx/pss-xmltv
                 levels=1:2
                 keys_zone=pss_xmltv:8m
                 max_size=4g
                 inactive=2h
                 use_temp_path=off;

upstream pss_epg {
    server 127.0.0.1:10444;
    keepalive 16;
}

server {
    listen 80;
    # listen 443 ssl http2;     # SSL termination makes sense here
    server_name epg-files.example.com;

    # Do not enable gzip on: /xmltv.gz is already compressed, and /xmltv
    # arrives gzip-encoded from PSS — re-compressing is pointless.

    location ~ ^/xmltv(\.gz)?$ {
        proxy_pass http://pss_epg;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # PSS returns no-cache; force-cache it at the edge.
        proxy_ignore_headers Cache-Control Expires Set-Cookie;
        proxy_hide_header   Cache-Control;
        proxy_hide_header   Pragma;
        proxy_hide_header   Expires;

        # Cache key = full URL including query (login/password in /xmltv?l=...&p=...)
        # produce distinct keys for different accounts with different channel-sets.
        proxy_cache_key     "$scheme$host$request_uri";

        proxy_cache         pss_xmltv;
        proxy_cache_valid   200      30m;       # XMLTV changes infrequently
        proxy_cache_valid   401 403  1m;
        proxy_cache_lock           on;          # coalesce cache misses
        proxy_cache_lock_timeout   60s;         # XMLTV build may take seconds
        proxy_cache_use_stale      error timeout updating
                                   http_500 http_502 http_503;

        # Large buffer: XMLTV for a big channel-set can reach
        # several megabytes.
        proxy_buffering      on;
        proxy_buffers        16 256k;
        proxy_buffer_size    256k;
        proxy_busy_buffers_size 1m;

        # Let the client cache for a short period.
        add_header Cache-Control "public, max-age=600";
        add_header X-Cache-Status $upstream_cache_status always;
    }
}
```

### Erläuterungen und Empfehlungen

- **TTL ``proxy_cache_valid 200 30m``** — XMLTV ändert sich selten häufiger als alle halbe Stunde. Erfolgt die Synchronisation mit den Quellen stündlich oder seltener, kann der Wert auf 1 Stunde und mehr angehoben werden; ist Frische nach `POST /xmltv/reset-cache` wichtig, senken Sie ihn.
- **``proxy_cache_lock_timeout 60s``** — gegenüber `/data/epg/channel` erhöht (dort üblich sind 5 Sekunden), weil der Aufbau eines XMLTV für ein großes channel-set länger dauert.
- **Eine dedizierte ``keys_zone``** — selbst bei einer großen Installation sind eindeutige XMLTV-Schlüssel rar (Anzahl Logins × `channel-set`), 8 MB reichen mit Reserve. `max_size` wird nach dem XMLTV-Volumen, nicht nach der Schlüsselanzahl bemessen.
- **gzip auf nginx-Seite ist unnötig**: Für `/xmltv.gz` ist die Antwort bereits komprimiert, für `/xmltv` antwortet PSS selbst gzip-encoded bei vorhandenem `Accept-Encoding: gzip`.
- **HTTPS-Terminierung** auf nginx liefert bessere Leistung bei vielen gleichzeitigen TLS-Handshakes.

## Verwandte Endpunkte

- `POST /xmltv/reset-cache` — erzwungenes Leeren des serverseitigen XMLTV-Caches (auf dem Admin-Server `43971`/`43981`).
- `POST /data/epg/update?s=<src_id>` — erzwungene Aktualisierung einer externen XMLTV-Quelle; nach einer erfolgreichen Aktualisierung wird der serverseitige XMLTV-Cache automatisch geleert.
- `GET /data/epg/channel?…` — JSON-EPG-Ausgabe für einen Kanal pro Tag; siehe separaten Abschnitt.

Die vollständige Liste und ausführliche Beschreibung der HTTP-API finden Sie in `manual/http_data_api.txt`.
