EPG 与 XMLTV 是什么

EPG(Electronic Program Guide,电子节目单)是 IPTV 用户最看重的体验之一。当你在 TiviMate 里看到"央视一套 19:00 新闻联播"这种节目表,背后靠的就是 EPG 数据。

XMLTV 是一个开源项目,定义了一套 XML 格式用于交换电视节目单数据,已成为 IPTV 的事实标准,几乎所有播放器都支持。

数据从哪里来

节目单数据常见来源:

版权提醒:节目单本身是节目信息,使用问题不大,但频道流可能涉及版权,本站不提供任何流地址。

XMLTV 文件格式

一个最小化的 XMLTV 文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">
<tv source-info-url="https://52iptv.cn">
  <channel id="cctv1">
    <display-name>CCTV-1 综合</display-name>
    <icon src="https://example.com/cctv1.png" />
  </channel>

  <programme start="20260810120000 +0800" stop="20260810123000 +0800"
             channel="cctv1">
    <title>新闻 30 分</title>
    <desc>综合当日重大新闻</desc>
    <category>新闻</category>
  </programme>

  <programme start="20260810190000 +0800" stop="20260810193000 +0800"
             channel="cctv1">
    <title>新闻联播</title>
    <category>新闻</category>
  </programme>
</tv>

关键字段:

使用 tv_grab 抓取

XMLTV 自带许多 grabber,Linux 安装:

apt install -y xmltv

# 列出所有 grabber
tv_grab_* --version

# 以欧洲 DVB 为例,首次交互式配置
tv_grab_eu_tvradio --configure

# 抓取最近 2 天的节目单
tv_grab_eu_tvradio --output epg.xml --days 2

国内频道通常需要自己写脚本抓取。一个简单的 Python 示例:

import requests, datetime
from xml.etree import ElementTree as ET

def now(n):
    return (datetime.datetime.now() + datetime.timedelta(days=n)).strftime("%Y%m%d%H%M%S +0800")

tv = ET.Element("tv", {"source-info-url": "https://52iptv.cn"})

# 写一个频道
ch = ET.SubElement(tv, "channel", {"id": "cctv1"})
ET.SubElement(ch, "display-name").text = "CCTV-1 综合"

# 写一条节目
p = ET.SubElement(tv, "programme", {
    "start": now(0), "stop": now(0).replace("+0800", " +0800"),
    "channel": "cctv1"
})
ET.SubElement(p, "title").text = "新闻联播"

ET.ElementTree(tv).write("epg.xml", encoding="UTF-8", xml_declaration=True)
定时更新:EPG 应每天凌晨更新一次,使用 crontab:
0 3 * * * /usr/local/bin/refresh_epg.sh >> /var/log/epg.log 2>&1

接入播放器

把生成的 epg.xml 放到 Nginx 静态目录:

location /epg.xml {
    alias /var/www/epg/epg.xml;
    add_header Cache-Control "public, max-age=3600";
    add_header Access-Control-Allow-Origin *;
}

在播放器中填入:

同时 m3u 播放列表中每个频道需要带 tvg-id

#EXTM3U
#EXTINF:-1 tvg-id="cctv1" tvg-name="CCTV-1" tvg-logo="https://example.com/cctv1.png" group-title="央视",CCTV-1 综合
https://example.com/live/cctv1.m3u8

tvg-id 必须与 XMLTV 中 channel 的 id 严格一致,否则节目单对不上号。

结尾

有了 EPG,IPTV 看起来就更像"电视"而不是"视频列表"了。下一篇文章我们聊 SIP 安全,敬请关注。