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

# 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 |
| --- | --- | --- |
| `GET /xmltv` | `text/xml` | Com `Accept-Encoding: gzip` a resposta é comprimida em tempo real (`Content-Encoding: gzip`); caso contrário, é entregue como XML sem compressão. |
| `GET /xmltv.gz` | `application/octet-stream` | Sempre retorna um fluxo gzip com `Content-Disposition: inline; filename="xmltv.xml.gz"` — prático para salvar como arquivo. |

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:

1. Em **Configuration/EPG/EPG Channel Sets**, crie um grupo de canais e atribua os canais desejados nas fontes EPG.
2. 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 recebe `403 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](http://wiki.xmltv.org/index.php/XMLTVFormat) habitual:

```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>
```

Notas sobre os campos:

- Os atributos `source-info-name` e `source-info-url` da raiz `<tv>` são preenchidos a partir dos campos **EPG Source Name** e **EPG Source URL** em **Configuration/EPG/EPG Server**.
- Os atributos `start` e `stop` seguem o formato `YYYYMMDDhhmmss ±zone` (o fuso horário é obtido do campo `time_zone` do canal).
- Um `<programme>` pode conter vários `<title>`/`<desc>` para idiomas diferentes. O atributo `lang` fica 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_id` em 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 >= now` entram 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 com `Accept-Encoding: gzip` ou `/xmltv.gz` nã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 |
| --- | --- |
| `200 OK` | Solicitação processada. O corpo é um documento XMLTV (possivelmente um `<tv></tv>` vazio em caso de falha transitória da BD). |
| `401 Unauthorized` | Nem Digest nem os parâmetros `l/p` passaram na verificação (para solicitações não loopback). |
| `403 Forbidden` | O login existe, mas a solicitação não vem de um IP permitido, ou `limit-day` expirou. |
| `404 Not Found` | Qualquer URL além de `/xmltv` e `/xmltv.gz`. |
| `405 Method Not Allowed` | Método diferente de GET. |

O corpo do erro é um envelope JSON de formato fixo:

```json
{"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

```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-cache` importa, 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.gz` a resposta já vem comprimida, e para `/xmltv` o próprio PSS responde com gzip-encoded quando `Accept-Encoding: gzip` está presente.
- **Terminação HTTPS** no nginx oferece melhor desempenho com muitos handshakes TLS simultâneos.

## Endpoints relacionados

- `POST /xmltv/reset-cache` — limpeza forçada do cache XMLTV do servidor (no servidor admin `43971`/`43981`).
- `POST /data/epg/update?s=<src_id>` — atualização forçada de uma fonte XMLTV externa; após sucesso, o cache XMLTV do servidor é limpo automaticamente.
- `GET /data/epg/channel?…` — saída EPG em JSON para um canal por um dia; veja a seção separada.

A lista completa e a descrição detalhada da API HTTP estão em `manual/http_data_api.txt`.
