EPG-сервер (XMLTV)¶
Отдельный встроенный HTTP-сервер Perfect Streamer выдаёт полный XMLTV для заданного набора каналов. Эндпоинт предназначен для middleware и плееров, которые хранят программу передач локально и обновляют её редко, файлом целиком — обычно один-два раза в сутки.
Сервер и его клиенты настраиваются в разделе Configuration/EPG/EPG Server.
URL и аутентификация¶
Сервис обслуживается отдельным HTTP-сервером epg-server (не тем,
что /data/*). По умолчанию он слушает порты 10444 (HTTP) и
10445 (HTTPS); порты и SSL настраиваются в разделе
/config/epg-server.
Маршруты:
URL |
Content-Type |
Поведение |
|---|---|---|
|
|
При |
|
|
Всегда возвращает gzip-поток с |
Поддерживаются три способа аутентификации:
HTTP Digest (предпочтительно) — учётная запись из
/config/epg-server/login.Параметры в URL —
?l=<login>&p=<password>(синонимы:login=…,password=…).Loopback — запрос с
127.0.0.1обрабатывается анонимно. Удобно для скриптов, развёрнутых на той же машине.
Предупреждение
Логин и пароль в URL попадают в access-логи reverse-proxy и в историю браузера. Для публичной раздачи XMLTV используйте HTTP Digest либо принимайте запросы только с приватных адресов.
Доступ по channel-set¶
Каждая учётная запись epg-server/login привязана к одному channel-set
из /config/epg-channel-set. EPG в ответе содержит только те каналы,
которые входят в указанный набор. Это позволяет одной инсталляции PSS
выдавать разный XMLTV разным операторам и middleware.
Базовая настройка в UI:
В Configuration/EPG/EPG Channel Sets создайте группу каналов и назначьте в неё нужные каналы у источников EPG.
В Configuration/EPG/EPG Server Clients заведите учётную запись и привяжите к ней созданную группу. Без привязки
channel-setклиенту отдаётся пустой XMLTV.
Дополнительные ограничения для login:
ip-addr— если задан и не wildcard, запрос с другого IP получит403 Forbidden.limit-day— Unix epoch-сек, после которого учётная запись перестаёт обслуживаться (403 Forbidden). Удобно для абонементной модели.pause— временно отключить login без удаления.
Формат ответа¶
Тело ответа — XMLTV-документ с корнем <tv>. Структура
соответствует общепринятой схеме XMLTV DTD:
<?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>
Заметки по полям:
Атрибуты
source-info-nameиsource-info-urlкорня<tv>заполняются из полей EPG Source Name и EPG Source URL в Configuration/EPG/EPG Server.Атрибуты
startиstopоформлены в форматеYYYYMMDDhhmmss ±zone(часовой пояс берётся из поляtime_zoneканала).В
<programme>могут быть несколько<title>/<desc>для разных языков. Атрибутlangпустой, если в исходных данных EPG идентификатор языка не сопоставился со словарём (запись всё равно попадёт в выдачу).Каналы с конфликтующим
channel_id(если один и тот же id пришёл из разных источников) показываются один раз, остальные источники пропускаются с предупреждением в логе сервера.В выдачу попадают только события с
stop_time >= now.
HTTP-заголовки¶
Сервер всегда отправляет:
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
Connection: close
Для /xmltv дополнительно — Content-Encoding: gzip при
Accept-Encoding: gzip в запросе. Для /xmltv.gz —
Content-Disposition: inline; filename="xmltv.xml.gz".
Запрет клиентского кеша сделан намеренно: XMLTV меняется при каждом импорте EIT либо обновлении внешних XMLTV-источников, и плеер не должен держать устаревшие данные у себя бессрочно. Edge-кеш (nginx) при этом вполне допустим — см. раздел про производительность ниже.
Серверный кеш и его сброс¶
Готовый XMLTV кешируется в памяти процесса PSS:
По одной записи на каждый
channel-set; внутри хранятся обе версии тела (raw и gzip) — повторные запросы сAccept-Encoding: gzipили/xmltv.gzне пересжимают данные.Запись помечается счётчиком
update-time. Любое обновление EPG (импорт EIT, обновление XMLTV-источника) увеличивает счётчик, и при следующем запросе кеш перестраивается.
Принудительный сброс кеша:
POST /xmltv/reset-cache
Маршрут обслуживается на admin-сервере (порт 43971/43981),
не на epg-server. Тело — пустое; ответ — 200 OK с JSON-конвертом.
HTTP-коды ответа¶
Код |
Условие |
|---|---|
|
Запрос обработан. Тело — XMLTV-документ (возможно, пустой
|
|
Ни Digest, ни параметры |
|
Login существует, но запрос не с разрешённого IP, либо истёк
|
|
Любой URL, кроме |
|
Метод не GET. |
Тело ошибки — JSON-конверт фиксированного формата:
{"status": 401, "message": "Unauthorized"}
Производительность и масштабирование¶
Серверный кеш¶
Серверный кеш обслуживает повторные обращения к одному channel-set
без обращения к SQLite — копированием готового тела.
Построение XMLTV «с нуля» (cache miss) дороже: для каждого канала
делается отдельный SELECT по channel_name, для каждого события — по
event_text и event_rating. Время построения ориентировочно:
Размер выдачи |
Cache hit |
Cache miss (build) |
|---|---|---|
100 каналов / сутки |
десятки мс |
~0.5–1 с |
500 каналов / сутки |
~50 мс |
2–5 с |
1000+ каналов / неделя |
~100–300 мс |
5–15 с |
Для большинства middleware приемлемо запрашивать XMLTV раз в несколько часов или раз в сутки.
Когда нужен внешний reverse-proxy (nginx)¶
В отличие от /data/epg/channel (короткие JSON-ответы), XMLTV — это
один большой документ на channel-set, идеально подходящий для
edge-кеша:
Десятки и сотни клиентов на один channel-set — внутреннего кеша PSS обычно достаточно, если они опрашивают XMLTV раз в час–сутки.
Тысячи клиентов одновременно — рекомендуется reverse-proxy с кешем. Выдача XMLTV-файла на сотни/тысячи запросов — это в первую очередь сетевая нагрузка (сотни КБ — единицы МБ на ответ), которую стоит снимать с PSS.
Географически распределённая раздача — без CDN/edge-кеша не обойтись независимо от числа клиентов.
PSS отдаёт Cache-Control: no-cache, поэтому в nginx нужно явно
указать nginx игнорировать заголовок upstream-сервера и держать собственный TTL.
Пример конфигурации 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;
}
}
Пояснения и рекомендации¶
TTL ``proxy_cache_valid 200 30m`` — XMLTV редко меняется чаще получаса. Если синхронизация с источниками идёт раз в час и больше, можно поднимать до 1 часа и более; если важна свежесть после
POST /xmltv/reset-cache— снижайте.``proxy_cache_lock_timeout 60s`` — увеличен по сравнению с
/data/epg/channel(где обычно 5 секунд), потому что построение XMLTV для большогоchannel-setзанимает дольше.Отдельный ``keys_zone`` — даже на крупной инсталляции уникальных ключей XMLTV единицы (по числу учётных записей ×
channel-set), 8 МБ хватит с запасом.max_sizeвыбирается по объёму XMLTV, а не по числу ключей.gzip на стороне nginx не нужен: для
/xmltv.gzответ уже сжат, для/xmltvPSS сам ответит gzip-encoded при наличииAccept-Encoding: gzip.HTTPS-терминация на nginx даёт лучшую производительность при многих одновременных TLS-рукопожатиях.