Servidor EPG (XMLTV)¶
Um servidor HTTP integrado separado do Perfect Streamer entrega o XMLTV completo para um dado conjunto de canais. O endpoint é destinado a middleware e players que mantêm o guia localmente e o atualizam com pouca frequência, como arquivo inteiro — normalmente uma ou duas vezes por dia.
O servidor e seus clientes são configurados em Configuration/EPG/EPG Server.
URL e autenticação¶
O serviço é atendido por um servidor HTTP separado epg-server (não o de /data/*). Por padrão, ele escuta nas portas 10444 (HTTP) e 10445 (HTTPS); portas e SSL são configurados em /config/epg-server.
Rotas:
URL |
Content-Type |
Comportamento |
|---|---|---|
|
|
Com |
|
|
Sempre retorna um fluxo gzip com |
São suportados três métodos de autenticação:
HTTP Digest (preferencial) — conta em
/config/epg-server/login.Parâmetros na URL —
?l=<login>&p=<password>(sinônimos:login=…,password=…).Loopback — uma solicitação de
127.0.0.1é tratada anonimamente. Útil para scripts implantados na mesma máquina.
Aviso
Um login e senha na URL acabam nos access-logs do reverse-proxy e no histórico do navegador. Para distribuição pública do XMLTV, use HTTP Digest ou aceite solicitações apenas de endereços privados.
Acesso por channel-set¶
Cada conta epg-server/login está vinculada a um único channel-set em /config/epg-channel-set. O EPG retornado contém apenas os canais desse grupo. Isso permite que uma mesma instalação do PSS forneça XMLTV distintos para diferentes operadoras/middleware.
Configuração básica na IU:
Em Configuration/EPG/EPG Channel Sets, crie um grupo de canais e atribua os canais desejados nas fontes EPG.
Em Configuration/EPG/EPG Server Clients, crie uma conta e vincule o grupo criado a ela. Sem vínculo de
channel-set, o cliente recebe um XMLTV vazio.
Restrições adicionais para um login:
ip-addr— se definido e não for curinga, uma solicitação de outro IP recebe403 Forbidden.limit-day— Unix epoch em s, após o qual a conta deixa de ser atendida (403 Forbidden). Útil para um modelo de assinatura.pause— desativar temporariamente um login sem excluí-lo.
Formato da resposta¶
O corpo da resposta é um documento XMLTV com raiz <tv>. A estrutura segue o 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 os campos:
Os atributos
source-info-nameesource-info-urlda raiz<tv>são preenchidos a partir dos campos EPG Source Name e EPG Source URL em Configuration/EPG/EPG Server.Os atributos
startestopseguem o formatoYYYYMMDDhhmmss ±zone(o fuso horário é obtido do campotime_zonedo canal).Um
<programme>pode conter vários<title>/<desc>para idiomas diferentes. O atributolangfica vazio quando o identificador de idioma dos dados EPG de origem não pôde ser mapeado no dicionário (a entrada ainda aparece na saída).Canais com
channel_idem conflito (quando o mesmo id chega de várias fontes) aparecem uma vez; as fontes restantes são ignoradas com um aviso no log do servidor.Somente eventos com
stop_time >= nowentram na saída.
Cabeçalhos HTTP¶
O servidor sempre envia:
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Connection: close
Para /xmltv, adicionalmente — Content-Encoding: gzip quando Accept-Encoding: gzip está presente na solicitação. Para /xmltv.gz — Content-Disposition: inline; filename="xmltv.xml.gz".
A proibição do cache do lado do cliente é intencional: o XMLTV muda a cada importação EIT ou refresh de fontes XMLTV externas, e o player não deve manter dados desatualizados indefinidamente. Um cache edge (nginx), porém, é perfeitamente aceitável — veja a seção sobre desempenho abaixo.
Cache do servidor e sua limpeza¶
O XMLTV pronto é armazenado em cache na memória do processo PSS:
Uma entrada por
channel-set; ambas as variantes do corpo (raw e gzip) são guardadas — solicitações repetidas comAccept-Encoding: gzipou/xmltv.gznão recomprimem os dados.Cada entrada é marcada com um contador
update-time. Qualquer atualização de EPG (importação EIT, refresh de fonte XMLTV) incrementa o contador, e o cache é reconstruído na próxima solicitação.
Limpeza forçada do cache:
POST /xmltv/reset-cache
A rota é atendida pelo servidor admin (porta 43971/43981), não pelo epg-server. Corpo vazio; a resposta é 200 OK com um envelope JSON.
Códigos de resposta HTTP¶
Código |
Condição |
|---|---|
|
Solicitação processada. O corpo é um documento XMLTV (possivelmente um |
|
Nem Digest nem os parâmetros |
|
O login existe, mas a solicitação não vem de um IP permitido, ou |
|
Qualquer URL além de |
|
Método diferente de GET. |
O corpo do erro é um envelope JSON de formato fixo:
{"status": 401, "message": "Unauthorized"}
Desempenho e escalabilidade¶
Cache do servidor¶
O cache do servidor atende solicitações repetidas a um mesmo channel-set sem acessar o SQLite — copiando o corpo já pronto.
Construir o XMLTV «do zero» (cache miss) é mais caro: para cada canal é feito um SELECT separado em channel_name e, para cada evento, em event_text e event_rating. Tempos de construção aproximados:
Tamanho da saída |
Cache hit |
Cache miss (build) |
|---|---|---|
100 canais / dia |
dezenas de ms |
~0,5–1 s |
500 canais / dia |
~50 ms |
2–5 s |
1000+ canais / semana |
~100–300 ms |
5–15 s |
Para a maioria dos middleware é aceitável buscar o XMLTV a cada algumas horas ou uma vez por dia.
Quando é preciso um reverse-proxy externo (nginx)¶
Ao contrário de /data/epg/channel (respostas JSON curtas), o XMLTV é um único documento grande por channel-set, ideal para um cache edge:
Dezenas a centenas de clientes por channel-set — o cache interno do PSS costuma ser suficiente se eles consultam o XMLTV de hora em hora ou uma vez por dia.
Milhares de clientes simultâneos — recomenda-se um reverse-proxy com cache. Servir um arquivo XMLTV a centenas/milhares de solicitações é, antes de tudo, uma carga de rede (centenas de KB a alguns MB por resposta) que é melhor retirar do PSS.
Entrega geograficamente distribuída — um CDN/cache edge é indispensável independentemente do número de clientes.
O PSS devolve Cache-Control: no-cache, portanto é preciso dizer explicitamente ao nginx para ignorar o cabeçalho do upstream e manter o próprio TTL.
Exemplo de configuração 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;
}
}
Explicações e recomendações¶
TTL ``proxy_cache_valid 200 30m`` — o XMLTV raramente muda com frequência maior que a cada meia hora. Se a sincronização com as fontes ocorre uma vez por hora ou menos, dá para elevar para 1 hora ou mais; se a frescura após
POST /xmltv/reset-cacheimporta, reduza.``proxy_cache_lock_timeout 60s`` — aumentado em relação a
/data/epg/channel(onde 5 segundos é o usual), porque construir o XMLTV de um channel-set grande leva mais tempo.Uma ``keys_zone`` dedicada — mesmo em uma instalação grande, as chaves XMLTV únicas são poucas (número de contas ×
channel-set); 8 MB são suficientes.max_sizeé dimensionado pelo volume de XMLTV, não pela quantidade de chaves.gzip do lado do nginx é desnecessário: para
/xmltv.gza resposta já vem comprimida, e para/xmltvo próprio PSS responde com gzip-encoded quandoAccept-Encoding: gzipestá presente.Terminação HTTPS no nginx oferece melhor desempenho com muitos handshakes TLS simultâneos.