IPTVnator 本地 XMLTV 文件作为 EPG 源:绝对路径、`file://` 与原生文件选择器全解析

发布时间:2026/11/5 21:47:00

IPTVnator 本地 XMLTV 文件作为 EPG 源:绝对路径、`file://` 与原生文件选择器全解析 IPTVnator 本地 XMLTV 文件作为 EPG 源绝对路径、file://与原生文件选择器全解析【免费下载链接】iptvnator:tv: Cross-platform IPTV player application with multiple features, such as support of m3u and m3u8 playlists, favorites, TV guide, TV archive/catchup and more.项目地址: https://gitcode.com/GitHub_Trending/ip/iptvnator导读本文基于 IPTVnator 仓库的.changes/epg-local-xmltv-sources.md变更记录系统讲解新版 EPG电子节目指南源如何从只能填 URL扩展为本地 XMLTV 文件也可直接使用的完整能力包括支持的三种引用形式绝对路径、file://链接、原生文件选择器、接受的两种压缩格式.xml与.xml.gz、一次性的原生授权确认流程以及背后主进程授权器、路径归一化与 gzip 探测的源码级实现。读完本文你将掌握在 Settings → EPG 或播放列表的 EPG 列表中安全添加本地节目单文件的具体操作与底层原理。功能背景EPG 源不再必须是 URL在 IPTVnator 中EPG 数据源XMLTV 节目单以往通过 URL 方式接入用户要么提供一个远程http(s)地址要么依赖 M3U 播放列表头部声明的url-tvg属性。这一方式对本地已有节目单文件的场景并不友好——用户需要在本地起一个 HTTP 服务或者把文件上传到某处才能喂给播放器。本次变更类型feature影响区域epg亮点标注 Local XMLTV files as EPG sources解除了这一限制Settings → EPG 或播放列表的 EPG 列表都可以直接指向计算机上的 XMLTV 文件支持以下三种引用方式绝对路径例如/home/you/epg/guide.xmlPOSIX或C:\epg\guide.xml.gzWindowsfile://链接例如file:///home/you/epg/guide.xml新的文件夹按钮通过系统原生文件对话框直接选择文件。同时纯文本.xml与 gzip 压缩的.xml.gz两种格式都被支持手输的路径在被读取前会经过一次原生对话框确认设置页会明确列出可接受的格式示例。三种本地引用形式与两类压缩格式形式一绝对路径直接把文件系统的绝对路径粘贴进 EPG 源输入框即可。为了在不同平台上都能工作源码中的引用分类工具classifyEpgSourceReference支持三类本地绝对路径见 epg-source-reference.util.ts平台/类型匹配模式示例POSIX 绝对路径^\/[^\0]$/home/you/epg/guide.xmlWindows 盘符路径^[a-z]:[\\/][^\0]*$不区分大小写C:\epg\guide.xml.gzWindows UNC 路径^\\\\[^\\/\0]\\.\\NAS\epg\guide.xml值得注意的是相对路径如epg/guide.xml会被有意拒绝——主进程没有可解释的工作目录来解析相对路径因此只接受绝对形式见 epg-source-reference.util.ts 注释及对应的 epg-source-reference.util.spec.ts 测试。形式二file://链接file://URL 同样被识别为本地源与普通绝对路径在归一化后等价。在 epg-local-source-path.ts 中resolveLocalEpgSourcePath对file:前缀的值调用 Node.js 的fileURLToPath后再resolve对普通路径则要求isAbsolute通过后resolve。因此以下写法会归一化到同一个文件file:///home/you/epg/guide.xml/home/you/epg/guide.xml其单元测试明确断言maps a file URL and the plain path to the same normalized path见 epg-local-source-path.spec.ts同时验证了带空格的文件名guide v2.xml.gz与首尾空白也能正确处理。而https://…、相对路径、空字符串和裸file://则返回null表示不是本地文件引用。形式三原生文件选择器文件夹按钮在设置页 EPG 源列表的每一行新增了一个文件浏览按钮模板中为browseEpgSource输出见 settings-epg-section.component.html。点击后Angular 侧通过EpgRuntimeBridgeService.pickEpgFile()调用主进程的EPG_OPEN_FILE_DIALOGIPC见 settings-epg.facade.ts。主进程用 Electron 的dialog.showOpenDialog弹出原生对话框见 epg.events.ts文件过滤器如下dialog.showOpenDialog({ properties: [openFile], filters: [ { name: XMLTV, extensions: [xml, gz, xmltv] }, { name: All Files, extensions: [*] }, ], });可见除了.xml、.gz外.xmltv扩展名也被视为 XMLTV 文件类型用户取消时返回null设置行的值保持不变。选中的文件路径会立即通过授权器写入信任列表authorize保证后续刷新不再弹窗。格式与压缩.xml与.xml.gz均支持设置页会明确展示可接受的格式提示与示例。在 settings-epg-section.component.html 中data-test-idepg-source-formats区域呈现了四种示例https://example.org/guide.xml.gz /home/you/epg/guide.xml C:\epg\guide.xml.gz file:///…/guide.xml本地文件读取时gzip 解压不依赖扩展名而是通过文件自身的魔数magic signature探测。在 epg-source-stream.ts 的注释中明确说明gzip is detected from the files own signature, soguide.xml,guide.xml.gzand a gzip file without the extension all work——也就是说即使一个 gzip 文件没有.gz后缀只要内容确实是 gzip 压缩的 XMLTV也能被正确解压。手输路径的一次性原生确认授权模型本地文件读取最大的安全问题是如果渲染进程Renderer能把任意路径当作 EPG 源提交给主进程一个被攻破或恶意构造的页面就能让应用读取磁盘上任意文件。为此本次变更引入了一套主进程授权门禁与导出播放列表时save-file-dialog→write-file的安全模式一致见 epg-local-source-authorizer.ts 的注释。授权器接口与默认拒绝策略核心接口EpgLocalSourceAuthorizer定义了两个方法epg-local-source-authorizer.tsauthorize(filePath)用户在原生选择器中选中的文件立即信任无需弹窗ensureAllowed(filePath)判断路径是否可读手输路径首次触发一次原生确认弹窗。在 epg-worker.service.ts 中worker 服务初始化时挂载的是DENY_ALL_EPG_LOCAL_SOURCES拒绝一切本地文件直到epg.events.ts注册阶段才替换为真实的持久化授权器。这意味着任何未正确接线的情况都会失败关闭fail closed而不是放行。持久化与并发去重真实的实现是PersistedEpgLocalSourceAuthorizerepg-local-source-authorizer.ts允许列表持久化在主进程的配置存储中键为TRUSTED_LOCAL_EPG_SOURCES见 epg.events.ts因此应用启动时的自动刷新不再需要重新弹窗确认使用pendingPromptsMap 对同一文件并发请求例如设置页保存与启动刷新同时触发共享同一个弹窗避免堆叠多个对话框。原生确认对话框手输路径第一次读取时会弹出原生消息框epg-local-source-authorizer.ts标题Allow local EPG file?消息Read this file as an EPG source?详情展示完整路径并提示 IPTVnator will read the XMLTV guide data in this file. Only allow files you added yourself.按钮Allow默认/Cancel取消对话框通过BrowserWindow.getFocusedWindow() ?? BrowserWindow.getAllWindows()[0]挂到当前窗口。若用户拒绝worker 会返回固定的错误文案Reading this local file was not allowed. Retry to be asked again.EPG_LOCAL_SOURCE_REFUSED_MESSAGEepg-local-source-authorizer.ts并把该次抓取标记为失败——拒绝视为未读取不能伪装成已完成的抓取。渲染进程旗标被剥离防止越权在 epg-worker.service.ts 的startFetch中有两道关键防线从渲染进程传来的allowLocalFile旗标被显式解构剥离const { allowLocalFile: _rendererFlag, ...trustOptions } options渲染进程无法用它解锁本地分支只有resolveLocalEpgSourcePath判定为本地路径、且ensureAllowed返回true之后worker 才会构造{ ...trustOptions, allowLocalFile: true }并交给底层抓取逻辑。openEpgSourceStream端还有兜底校验epg-source-stream.ts即便走到了本地分支若allowLocalFile ! true也会抛错Local EPG file was not authorized。读取与解码流水线从路径到节目单数据EPG 抓取统一由openEpgSourceStream入口分流epg-source-stream.ts本地引用走磁盘读取其余走经过校验的远程 HTTP 客户端。本地分支async function openLocalEpgSource(filePath: string): PromiseReadable { const info await stat(filePath); // 不存在则抛 EPG file not found if (!info.isFile()) { // 目录则抛 EPG source is not a file throw new Error(EPG source is not a file: ${filePath}); } pipeline( createReadStream(filePath), // 流式读取避免整文件驻留内存 createOptionalEpgGunzip(), // 依据文件魔数自动探测 gzip output, (error) { if (error) output.destroy(error); } ); return output; }关键点epg-source-stream.ts先stat校验存在性与是文件而非目录ENOENT/ENOTDIR会给出友好错误使用createReadStream流式读取经createOptionalEpgGunzip()后送入PassThrough后续的流式 XML 解析器可以直接消费大节目单文件也不会一次性载入内存gzip 探测依据的是文件签名而非扩展名。远程分支对比远程源走requestWithValidatedRedirects每个重定向都被校验且访问私网/局域网源需要操作者显式开启信任isPrivateNetworkUrlAccessAllowed()或该 URL 在trustedPrivateNetworkEpgUrls白名单中见 epg-source-stream.ts。响应还会依据Content-Encoding与 URL/文件名判断是否需要 gunzip。两分支最终都产出已解码的 XMLTV 字节流交给共享的流式解析器。M3U 头部 URL 与本地文件的安全边界本地源只可能来自用户手工输入Settings → EPG、播放列表对话框。从 M3U 头部url-tvg属性提取的 EPG URL 在入库前会被过滤为仅远程链接extractM3uEpgUrls因此下载一个播放列表永远不会把 EPG 导入器指向用户磁盘上的任意文件见 epg-source-stream.ts 与 epg-source-reference.util.ts 注释。表单校验设置页与播放列表对话框共用同一套规则本地源在表单层就做了前置校验。validateEpgSourceReferenceControl作为无 Angular 依赖的结构化校验器epg-source-reference.util.ts被 Settings 的 EPG 列表和播放列表 EPG 对话框共用空值合法与Validators.pattern行为一致允许用户留空非空值必须能通过classifyEpgSourceReference分类remote或local否则返回epgSourceReference校验错误。这意味着用户在保存前就能发现相对路径/非法字符串问题而不是等到抓取阶段才报错。刷新与新鲜度本地文件同样遵守 12 小时阈值本地文件源与远程源共享同一套抓取编排handleFetchEpg见 epg-fetch.service.tsEPG_FRESHNESS_MAX_AGE_HOURS 12存储的 EPG 数据超过 12 小时即视为过期需要重新抓取每个源按sourceUrl对本地文件就是归一化后的绝对路径记录updatedAtcheckEpgFreshness据此区分freshUrls与staleUrls多个 URL顺序抓取避免 SQLite 数据库锁冲突抓取进度通过sendProgressToRenderer推送queued/loading/…等状态手动刷新按钮走EPG_FORCE_FETCH先删除已抓取标记再强制抓取绕过 12 小时阈值。由于信任列表已持久化应用重启后的启动刷新对已授权文件不会再次弹窗用户几乎无感。源码速览本次特性的关键文件关注点文件变更记录.changes/epg-local-xmltv-sources.md引用分类与表单校验libs/shared/interfaces/src/lib/epg-source-reference.util.ts、epg-source-reference.util.spec.ts路径归一化file:/绝对路径apps/electron-backend/src/app/util/epg-local-source-path.ts、epg-local-source-path.spec.ts主进程授权器与原生确认框apps/electron-backend/src/app/events/epg-local-source-authorizer.tsIPC 注册与原生文件选择器apps/electron-backend/src/app/events/epg.events.tsWorker 侧授权门禁与旗标剥离apps/electron-backend/src/app/events/epg-worker.service.ts本地/远程流打开与 gzip 探测apps/electron-backend/src/app/workers/epg-source-stream.ts抓取编排与新鲜度阈值apps/electron-backend/src/app/events/epg-fetch.service.ts设置页 UI格式提示示例apps/web/src/app/settings/settings-epg-section.component.html设置页浏览动作browseapps/web/src/app/settings/settings-epg.facade.ts使用小结在 IPTVnatorElectron 桌面端中接入本地 XMLTV 节目单按如下步骤即可打开Settings → EPG或进入某个播放列表的EPG 列表在 EPG 源输入框中粘贴绝对路径/home/you/epg/guide.xml、C:\epg\guide.xml.gz或file://链接也可以点击文件夹按钮通过原生对话框选择支持.xml、.gz、.xmltv若为手输路径首次保存/刷新时会弹出一次原生确认框选择Allow后即可读取后续不再询问文件格式支持纯文本.xml与 gzip 压缩的.xml.gz解压依据文件签名自动判断与扩展名无关之后与远程源一样受 12 小时新鲜度机制管理可手动强制刷新。这套实现的价值在于在不牺牲安全性的前提下主进程授权、默认拒绝、渲染进程旗标剥离、M3U 头部过滤把 EPG 数据源从必须联网扩展到本地离线文件让没有互联网环境或已有现成 XMLTV 文件的用户能够直接利用本地节目单数据。【免费下载链接】iptvnator:tv: Cross-platform IPTV player application with multiple features, such as support of m3u and m3u8 playlists, favorites, TV guide, TV archive/catchup and more.项目地址: https://gitcode.com/GitHub_Trending/ip/iptvnator创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/10/31 4:07:06

HCIA-Datacom实战:数据封装、VLAN与NAT配置详解

简介:HCIA-Datacom核心技术笔记总结是一份面向网络工程师、网络管理员、学生及企业IT人员的系统学习资料,针对网络协议理解不深、配置经验不足等常见痛点。笔记以清晰的章节结构从网络基础讲起,依次涵盖数据封装、OSI与TCP/IP模型、Wireshark…

2026/10/25 5:25:16

从SNMP到NetFlow:构建可落地的监控采集链路

简介:以信息技术运维管理基础知识为主题的幻灯片学习教案,面向运维入门者、技术培训讲师和希望系统梳理运维知识的学习者。内容围绕监控软件与采集协议展开,涵盖SNMP、RMON、Syslog、Telnet/SSH、ODBC/JDBC、WMI等十余种常用协议,…

2026/10/26 1:02:22

Copilot替代方案本质是开发范式迁移:从补全到Agent

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 16:51:33

EasyU优启通PE维护盘实战指南:制作、启动与核心操作全解析

1. 为什么一个PE维护盘值得单独拿出来聊装系统、修引导、救数据、清病毒,这些活儿但凡干过几次的人都知道,真正决定效率的往往不是你手速多快,而是手边那套PE环境靠不靠谱。EasyU(圈内习惯叫优启通)就是在这个场景下被…

2026/11/5 16:26:13

Rust原来很简单二:所有权系统

Part 2 核心篇 —— 所有权系统 本篇覆盖 第 6 ~ 10 章:所有权、借用与引用、生命周期、字符串与切片、内存模型。 ⚠️ 这是全书最重要的一篇。 把它吃透,Rust 从此“很简单”;跳过它,你会处处碰壁。请慢下来,动手敲每一段代码。 第 6 章 所有权:Rust 的第一性原理 6…

2026/11/5 15:00:49

基于Hadoop+Spark的民宿智能推荐系统设计与实现

1. 项目概述:大数据时代的民宿智能推荐这个毕业设计项目融合了当前大数据领域最主流的技术栈,构建了一个完整的民宿推荐系统解决方案。作为一名长期从事大数据系统开发的工程师,我认为这个选题非常贴合实际应用场景——随着旅游业的复苏和共享…

2026/11/5 14:10:30

ADS122U04IPWR+STM32F427ZI工业级温度测量信号链设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 14:10:30

UART接口24位ADC搭配RS485,解决远距离温度监控难题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 14:10:30

UART接口24位ADC搭配PIC18F46K22的RTD与热电偶测温实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/5 0:02:07

多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中…

2026/11/5 0:02:07

大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#…

2026/11/5 0:02:07

鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的…

2026/11/5 15:39:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/4 21:04:25

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑