Serveur EPG (XMLTV)¶
Un serveur HTTP intégré distinct de Perfect Streamer délivre le XMLTV complet pour un ensemble de chaînes donné. L’endpoint est destiné aux middleware et lecteurs qui stockent le guide localement et ne le rafraîchissent que rarement, en bloc — généralement une à deux fois par jour.
Le serveur et ses clients se configurent dans la section Configuration/EPG/EPG Server.
URL et authentification¶
Le service est assuré par un serveur HTTP distinct epg-server (pas celui de /data/*). Par défaut, il écoute sur les ports 10444 (HTTP) et 10445 (HTTPS) ; les ports et SSL se configurent sous /config/epg-server.
Routes :
URL |
Content-Type |
Comportement |
|---|---|---|
|
|
Avec |
|
|
Renvoie toujours un flux gzip avec |
Trois méthodes d’authentification sont prises en charge :
HTTP Digest (recommandé) — compte issu de
/config/epg-server/login.Paramètres dans l’URL —
?l=<login>&p=<password>(synonymes :login=…,password=…).Loopback — une requête depuis
127.0.0.1est traitée anonymement. Pratique pour les scripts déployés sur la même machine.
Avertissement
Un login et un mot de passe dans l’URL finissent dans les logs d’accès du reverse-proxy et dans l’historique du navigateur. Pour la distribution publique du XMLTV, utilisez HTTP Digest ou n’acceptez les requêtes que depuis des adresses privées.
Accès par channel-set¶
Chaque compte epg-server/login est lié à un seul channel-set issu de /config/epg-channel-set. L’EPG renvoyé ne contient que les chaînes appartenant à ce groupe. Cela permet à une même installation PSS de fournir des XMLTV différents à différents opérateurs/middleware.
Configuration de base dans l’IU :
Dans Configuration/EPG/EPG Channel Sets, créez un groupe de chaînes et affectez-y les chaînes voulues au niveau des sources EPG.
Dans Configuration/EPG/EPG Server Clients, créez un compte et liez-y le groupe de chaînes créé. Sans liaison
channel-set, le client reçoit un XMLTV vide.
Restrictions supplémentaires pour un login :
ip-addr— si défini et non joker, une requête depuis une autre IP reçoit403 Forbidden.limit-day— Unix epoch en s, après lequel le compte cesse d’être servi (403 Forbidden). Pratique pour un modèle d’abonnement.pause— désactiver temporairement un login sans le supprimer.
Format de la réponse¶
Le corps de la réponse est un document XMLTV avec la racine <tv>. La structure suit le schéma XMLTV DTD communément utilisé :
<?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>
Remarques sur les champs :
Les attributs
source-info-nameetsource-info-urlde la racine<tv>sont alimentés depuis les champs EPG Source Name et EPG Source URL dans Configuration/EPG/EPG Server.Les attributs
startetstopsont au formatYYYYMMDDhhmmss ±zone(le fuseau horaire est tiré du champtime_zonede la chaîne).Un
<programme>peut contenir plusieurs<title>/<desc>pour différentes langues. L’attributlangest vide quand l’identifiant de langue dans les données EPG sources n’a pas pu être mappé au dictionnaire (l’entrée apparaît tout de même dans la sortie).Les chaînes avec un
channel_iden conflit (lorsque le même id provient de plusieurs sources) sont listées une seule fois, les sources restantes sont ignorées avec un avertissement dans le journal du serveur.Seuls les événements avec
stop_time >= nowsont inclus dans la sortie.
En-têtes HTTP¶
Le serveur envoie toujours :
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Connection: close
Pour /xmltv en plus — Content-Encoding: gzip lorsque Accept-Encoding: gzip est présent dans la requête. Pour /xmltv.gz — Content-Disposition: inline; filename="xmltv.xml.gz".
L’interdiction du cache côté client est intentionnelle : le XMLTV change à chaque import EIT ou rafraîchissement de source XMLTV externe, et le lecteur ne doit pas conserver des données obsolètes indéfiniment. Un cache edge (nginx) reste tout à fait admissible — voir la section performance ci-dessous.
Cache serveur et sa purge¶
Le XMLTV prêt est mis en cache dans la mémoire du processus PSS :
Une entrée par
channel-set; les deux variantes du corps (brute et gzip) sont stockées — les requêtes répétées avecAccept-Encoding: gzipou/xmltv.gzne recompressent pas les données.Chaque entrée est étiquetée avec un compteur
update-time. Toute mise à jour EPG (import EIT, rafraîchissement de source XMLTV) incrémente le compteur, et le cache est reconstruit à la requête suivante.
Purge forcée du cache :
POST /xmltv/reset-cache
La route est servie par le serveur admin (port 43971/43981), pas par epg-server. Corps vide ; la réponse est 200 OK avec une enveloppe JSON.
Codes de réponse HTTP¶
Code |
Condition |
|---|---|
|
Requête traitée. Le corps est un document XMLTV (éventuellement un |
|
Ni Digest ni les paramètres |
|
Le login existe mais la requête ne vient pas d’une IP autorisée, ou |
|
Toute URL autre que |
|
Méthode autre que GET. |
Le corps de l’erreur est une enveloppe JSON de format fixe :
{"status": 401, "message": "Unauthorized"}
Performance et mise à l’échelle¶
Cache serveur¶
Le cache serveur sert les requêtes répétées sur un même channel-set sans accéder à SQLite — en copiant le corps déjà prêt.
Construire le XMLTV « depuis zéro » (cache miss) est plus coûteux : un SELECT distinct sur channel_name par chaîne, et sur event_text et event_rating par événement. Temps de construction indicatifs :
Taille de la sortie |
Cache hit |
Cache miss (build) |
|---|---|---|
100 chaînes / jour |
dizaines de ms |
~0,5–1 s |
500 chaînes / jour |
~50 ms |
2–5 s |
1000+ chaînes / semaine |
~100–300 ms |
5–15 s |
Pour la plupart des middleware, il est acceptable de récupérer le XMLTV toutes les quelques heures ou une fois par jour.
Quand un reverse-proxy externe (nginx) est nécessaire¶
Contrairement à /data/epg/channel (réponses JSON courtes), le XMLTV est un seul gros document par channel-set, idéal pour un cache edge :
Des dizaines à des centaines de clients par channel-set — le cache interne de PSS suffit généralement s’ils interrogent le XMLTV toutes les heures à toutes les 24 h.
Milliers de clients simultanés — un reverse-proxy avec cache est recommandé. Servir un fichier XMLTV à des centaines/milliers de requêtes est avant tout une charge réseau (centaines de Ko à quelques Mo par réponse) qu’il est préférable de retirer à PSS.
Distribution géographiquement répartie — un CDN/cache edge est indispensable quel que soit le nombre de clients.
PSS renvoie Cache-Control: no-cache ; il faut donc indiquer explicitement à nginx d’ignorer l’en-tête upstream et de tenir son propre TTL.
Exemple de configuration 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;
}
}
Explications et recommandations¶
TTL ``proxy_cache_valid 200 30m`` — le XMLTV change rarement plus souvent que toutes les 30 minutes. Si la synchronisation avec les sources est horaire ou moins fréquente, on peut monter à 1 heure et plus ; si la fraîcheur après
POST /xmltv/reset-cacheimporte, baissez-le.``proxy_cache_lock_timeout 60s`` — augmenté par rapport à
/data/epg/channel(où 5 s est habituel), car la construction du XMLTV pour un grand channel-set est plus longue.Une ``keys_zone`` dédiée — même sur une grande installation, les clés XMLTV uniques se comptent sur les doigts (nombre de comptes ×
channel-set) ; 8 Mo suffisent largement.max_sizese dimensionne selon le volume XMLTV, pas selon le nombre de clés.inutile d’activer gzip côté nginx : pour
/xmltv.gzla réponse est déjà compressée et pour/xmltvPSS répond lui-même en gzip siAccept-Encoding: gzipest présent.Terminaison HTTPS sur nginx offre de meilleures performances en cas de nombreux handshakes TLS simultanés.