Servidor EPG (XMLTV)¶
Un servidor HTTP integrado e independiente de Perfect Streamer devuelve el XMLTV completo para un conjunto dado de canales. El endpoint está pensado para middleware y reproductores que guardan la guía localmente y la actualizan con poca frecuencia, como archivo completo — normalmente una o dos veces al día.
El servidor y sus clientes se configuran en Configuration/EPG/EPG Server.
URL y autenticación¶
El servicio lo ofrece un servidor HTTP independiente epg-server (no el que atiende /data/*). Por defecto escucha en los puertos 10444 (HTTP) y 10445 (HTTPS); los puertos y SSL se configuran en /config/epg-server.
Rutas:
URL |
Content-Type |
Comportamiento |
|---|---|---|
|
|
Con |
|
|
Siempre devuelve un flujo gzip con |
Se admiten tres métodos de autenticación:
HTTP Digest (preferido) — cuenta de
/config/epg-server/login.Parámetros en la URL —
?l=<login>&p=<password>(sinónimos:login=…,password=…).Loopback — una solicitud desde
127.0.0.1se trata como anónima. Útil para scripts implantados en la misma máquina.
Advertencia
Un login y una contraseña en la URL acaban en los access-logs del reverse-proxy y en el historial del navegador. Para distribución pública de XMLTV utilice HTTP Digest o acepte solicitudes únicamente desde direcciones privadas.
Acceso por channel-set¶
Cada cuenta epg-server/login está vinculada a un único channel-set de /config/epg-channel-set. El EPG devuelto contiene solo los canales del grupo indicado. Esto permite que una misma instalación de PSS sirva XMLTV distintos a distintos operadores/middleware.
Configuración básica en la UI:
En Configuration/EPG/EPG Channel Sets cree un grupo de canales y asigne los canales deseados en las fuentes EPG.
En Configuration/EPG/EPG Server Clients cree una cuenta y vincúlela al grupo creado. Sin vincular un
channel-set, el cliente recibe un XMLTV vacío.
Restricciones adicionales para un login:
ip-addr— si está definido y no es un comodín, una solicitud desde otra IP recibe403 Forbidden.limit-day— Unix epoch en s, después del cual la cuenta deja de ser atendida (403 Forbidden). Útil para un modelo de suscripción.pause— desactivar temporalmente un login sin eliminarlo.
Formato de la respuesta¶
El cuerpo de la respuesta es un documento XMLTV con raíz <tv>. La estructura sigue el esquema XMLTV DTD habitual:
<?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>
Notas sobre los campos:
Los atributos
source-info-nameysource-info-urlde la raíz<tv>se completan con los campos EPG Source Name y EPG Source URL de Configuration/EPG/EPG Server.Los atributos
startystopsiguen el formatoYYYYMMDDhhmmss ±zone(la zona horaria se toma del campotime_zonedel canal).Un
<programme>puede contener varios<title>/<desc>en distintos idiomas. El atributolangqueda vacío cuando el identificador de idioma del EPG original no se pudo asignar al diccionario (la entrada igualmente aparece en la salida).Los canales con un
channel_iden conflicto (si el mismo id procede de varias fuentes) se muestran una sola vez; las fuentes restantes se omiten con una advertencia en el log del servidor.Solo se incluyen en la salida los eventos con
stop_time >= now.
Encabezados HTTP¶
El servidor siempre envía:
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Connection: close
Para /xmltv adicionalmente — Content-Encoding: gzip cuando Accept-Encoding: gzip está presente en la solicitud. Para /xmltv.gz — Content-Disposition: inline; filename="xmltv.xml.gz".
El veto al caché del cliente es intencional: el XMLTV cambia con cada importación EIT o refresco de fuentes XMLTV externas, y el reproductor no debe conservar datos obsoletos de forma indefinida. Una caché edge (nginx), sin embargo, es perfectamente aceptable — véase la sección sobre rendimiento más abajo.
Caché del servidor y su vaciado¶
El XMLTV listo se almacena en la memoria del proceso PSS:
Una entrada por cada
channel-set; se guardan ambas variantes del cuerpo (cruda y gzip) — las solicitudes repetidas conAccept-Encoding: gzipo/xmltv.gzno recomprimen los datos.Cada entrada lleva un contador
update-time. Cualquier actualización de EPG (importación EIT, refresco de fuente XMLTV) incrementa el contador y la caché se reconstruye en la siguiente solicitud.
Vaciado forzado de la caché:
POST /xmltv/reset-cache
La ruta la atiende el servidor admin (puerto 43971/43981), no el epg-server. Cuerpo vacío; la respuesta es 200 OK con un envoltorio JSON.
Códigos de respuesta HTTP¶
Código |
Condición |
|---|---|
|
Solicitud procesada. El cuerpo es un documento XMLTV (posiblemente un |
|
Ni Digest ni los parámetros |
|
El login existe pero la solicitud no proviene de una IP permitida, o ha expirado |
|
Cualquier URL distinta de |
|
Método distinto de GET. |
El cuerpo del error es un envoltorio JSON de formato fijo:
{"status": 401, "message": "Unauthorized"}
Rendimiento y escalado¶
Caché del servidor¶
La caché del servidor atiende las solicitudes repetidas sobre un mismo channel-set sin acceder a SQLite — copiando el cuerpo ya preparado.
Construir XMLTV «desde cero» (cache miss) es más costoso: por cada canal se hace un SELECT aparte por channel_name, y por cada evento por event_text y event_rating. Tiempos de construcción aproximados:
Tamaño de salida |
Cache hit |
Cache miss (build) |
|---|---|---|
100 canales / día |
decenas de ms |
~0,5–1 s |
500 canales / día |
~50 ms |
2–5 s |
1000+ canales / semana |
~100–300 ms |
5–15 s |
Para la mayoría de los middleware es aceptable solicitar XMLTV cada pocas horas o una vez al día.
Cuándo se necesita un reverse-proxy externo (nginx)¶
A diferencia de /data/epg/channel (respuestas JSON cortas), XMLTV es un único documento grande por channel-set, ideal para una caché edge:
Decenas o cientos de clientes por channel-set — la caché interna de PSS suele bastar si consultan el XMLTV cada hora o cada día.
Miles de clientes simultáneos — se recomienda un reverse-proxy con caché. Servir un archivo XMLTV a cientos/miles de solicitudes es, ante todo, una carga de red (cientos de KB a unos pocos MB por respuesta) que conviene quitar de PSS.
Distribución geográficamente repartida — un CDN/caché edge es ineludible sin importar el número de clientes.
PSS devuelve Cache-Control: no-cache, por lo que hay que indicarle explícitamente a nginx que ignore la cabecera del upstream y mantenga su propio TTL.
Ejemplo de configuración 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;
}
}
Explicaciones y recomendaciones¶
TTL ``proxy_cache_valid 200 30m`` — el XMLTV rara vez cambia con mayor frecuencia que cada media hora. Si la sincronización con las fuentes es horaria o menos frecuente, puede subirse a 1 hora o más; si importa la frescura tras
POST /xmltv/reset-cache, redúzcalo.``proxy_cache_lock_timeout 60s`` — incrementado respecto a
/data/epg/channel(donde lo habitual son 5 segundos), porque construir el XMLTV de un channel-set grande lleva más tiempo.Una ``keys_zone`` dedicada — incluso en una instalación grande, las claves XMLTV únicas son pocas (número de cuentas ×
channel-set); 8 MB sobran.max_sizese dimensiona por el volumen de XMLTV, no por el número de claves.gzip en el lado de nginx no hace falta: para
/xmltv.gzla respuesta ya está comprimida y para/xmltvPSS responde directamente con gzip-encoded si está presenteAccept-Encoding: gzip.Terminación HTTPS en nginx ofrece mejor rendimiento ante muchos handshakes TLS simultáneos.