折腾笔记[63]-电视自动播放软件
摘要
本文记录如何从零造一个"插上就能放电视"的软件 ThreeStarTV,解决长辈不会操作网络电视的问题:Windows 电脑开机后自动全屏、带声音播放 CCTV-1 高清直播,全程零操作。软件基于 .NET 8 WinForms + WebView2,内嵌 hls.js 播放 m3u8 直播流,直播流连续失败时自动回退央视网网页播放器并自动点击"全屏",最终由 .NET Framework 4.8 启动器内嵌 .NET 8 运行时与主程序,分发为单个便携式 exe,完全离线安装运行。
声明
本文人类为第一作者, 龙虾为通讯作者. 本文有AI生成内容.
工程仓库
- 完整源码: [https://github.com/qsbye/ThreeStarTV/]
- 直接下载(单个便携式 exe,内嵌 .NET 8 运行时安装包 + 主程序): [https://github.com/qsbye/ThreeStarTV/releases/download/v1/ThreeStarTV_202609202010.exe]
简介
本软件脱胎于一个相机 HMI 查看器项目(多路 WebView2 网格、主题切换、中英文、配置持久化等基础设施直接复用),将每一路的"相机画面"换成了"电视直播"。核心诉求只有一个:长辈按一下开机键,电视自己响起来。
m3u8 简介
m3u8 是 HLS(HTTP Live Streaming,Apple 提出的自适应码率流媒体协议)使用的播放列表文件格式,本质是一个 UTF-8 文本清单:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:175835760
#EXTINF:2.000,
/live/cctv1/20260920/175835760_0000.ts
#EXTINF:2.000,
/live/cctv1/20260920/20260920_0001.ts
...
播放器不断轮询 m3u8 清单、按序下载 .ts 视频分片并拼接播放,即可实现低延迟直播。央视各频道的直播源本质上就是一个个 m3u8 地址,例如本文使用的 CCTV-1 高清流:
https://ldncctvwbcdbd.a.bdydns.com/ldncctvwbcd/cdrmldcctv1_1/index.m3u8
m3u8 的痛点在于浏览器兼容性:Safari 和 iOS 全系原生支持,但 Windows 上的 Chromium(Chrome / Edge / WebView2)不支持原生播放 HLS——<video> 标签直接指向 m3u8 只会报错。这正是需要 hls.js 的原因。
hls.js 简介
[https://github.com/video-dev/hls.js]
hls.js 是流传最广的 HLS 纯 JS 播放器:用 JavaScript 实现完整的 m3u8 解析、分片下载、TS 解封装与 MSE(Media Source Extensions)喂帧,把"浏览器不会播的 HLS"变成"浏览器原生会播的 MP4 流"。它不依赖任何浏览器插件,一条 <script> 引入即可工作:
if (Hls.isSupported()) {
var hls = new Hls();
hls.loadSource('https://example.com/live/index.m3u8');
hls.attachMedia(videoElement);
}
对本项目还有两个关键性质:
- 可内嵌分发:hls.js 是单文件 UMD 库(约 600KB),可以作为嵌入资源打进 exe,运行时
NavigateToString注入播放器页面,不依赖任何 CDN,离线也能放; - 错误事件完备:
Hls.Events.ERROR区分网络错误/媒体错误/其他致命错误,data.fatal标记是否不可恢复,为"失败自动回退"提供了钩子。
WebView2 简介
WebView2 是微软基于 Chromium(Edge 同款内核)提供的 Windows 原生控件,可在 WinForms/WPF 应用中嵌入一个完整的现代浏览器。本项目所有播放能力都建立在 WebView2 之上:
- 播放 m3u8:加载内嵌 hls.js 的播放器 HTML 页;
- 回退播放:直接导航央视网直播网页(
tv.cctv.com/live/cctv1); - 自动全屏、自动取消静音、加载计时:全部通过 WebView2 的脚本注入与
chrome.webview消息通道完成。
它的两个特性对本项目至关重要:
- 启动参数可定制:
--autoplay-policy=no-user-gesture-required解除 Chromium 的自动播放限制,实现"开机即有声音"; - 用户数据目录可持久化:所有格子共享一个环境实例后,央视网页面的 JS/CSS 等静态依赖第二次启动起直接走本地 HTTP 缓存,显著加快出画面速度。
央视直播网址
央视网官方直播页规律非常整齐,tv.cctv.com/live/cctvX/ 即 CCTV-X 的网页播放器:
| 频道 | 网页播放器 | 说明 |
|---|---|---|
| CCTV-1 综合 | https://tv.cctv.com/live/cctv1/ |
本文默认频道 |
| CCTV-2 财经 | https://tv.cctv.com/live/cctv2/ |
依次类推至 CCTV-13 |
| CCTV-13 新闻 | https://tv.cctv.com/live/cctv13/ |
网址收藏中已内置 1~13 |
软件内置的"网址收藏"默认包含 CCTV-1 的 m3u8 推流地址与 CCTV-1~13 的网页地址,双击可复制到每一路播放格。
工程
1. 内嵌 hls.js 播放器页(m3u8 → 画面)
CameraCell.Navigate() 检测到地址以 .m3u8 结尾时,不再直接导航(Chromium 播不了),而是 NavigateToString 一个内嵌播放器页;hls.js 在编译期作为嵌入资源烘焙进 exe,运行时读取注入:
ThreeStarTV/CameraCell.cs(播放器页构造,节选)
private static string LoadEmbeddedScript(string suffix)
{
var asm = System.Reflection.Assembly.GetExecutingAssembly();
foreach (var name in asm.GetManifestResourceNames())
{
if (name.EndsWith(suffix))
{
using var s = asm.GetManifestResourceStream(name);
using var r = new System.IO.StreamReader(s, System.Text.Encoding.UTF8);
return r.ReadToEnd();
}
}
return "";
}
// WebView2(Chromium) 不支持原生播放 HLS,用内嵌的 hls.js 包装 m3u8 地址(无需外网加载播放器)
private static string BuildHlsPlayerHtml(string streamUrl)
{
var jsonUrl = System.Text.Json.JsonSerializer.Serialize(streamUrl);
var jsonFallback = System.Text.Json.JsonSerializer.Serialize(ConfigService.FallbackWebUrl);
var mutedAttr = ConfigService.App.autoUnmute ? "" : " muted";
var unmuteJs = ConfigService.App.autoUnmute
? "v.addEventListener('canplay', function(){ v.muted = false; });"
: "";
return @"<!DOCTYPE html><html><head><meta charset=""utf-8"">
<style>html,body{margin:0;height:100%;background:#000;overflow:hidden}video{width:100%;height:100%}</style>
<script>" + LoadHlsJsScript() + @"</script>
</head><body><video id=""v"" autoplay playsinline" + mutedAttr + @"></video><script>
var url = " + jsonUrl + @";
var fallbackUrl = " + jsonFallback + @";
var retries = 0;
var v = document.getElementById('v');
function fail(){
retries++;
if (retries >= 3) { location.replace(fallbackUrl); return; } // 连续失败则回退到央视网网页
setTimeout(function(){ location.reload(); }, 3000);
}
function start(){
if (window.Hls && Hls.isSupported()) {
var h = new Hls({ liveSyncDurationCount: 3 });
h.loadSource(url); h.attachMedia(v);
h.on(Hls.Events.ERROR, function(e, data){
if (data && data.fatal) fail();
});
} else if (v.canPlayType('application/vnd.apple.mpegurl')) {
v.src = url;
} else {
fail();
}
}
" + unmuteJs + @"
v.addEventListener('error', fail);
v.addEventListener('playing', function(){ try { chrome.webview.postMessage({__player:'playing'}); } catch(e){} });
start();
</script></body></html>";
}
几个关键点:
- 零 CDN 依赖:hls.js 内嵌后,播放器页完全自包含,弱网/离线(有流地址可达的前提下)都能播;
- 自动取消静音:Chromium 要求自动播放必须静音,因此
<video>先muted起播,监听canplay后解除静音;配合 WebView2 启动参数--autoplay-policy=no-user-gesture-required,实现开机即有声; - 直播低延迟:
liveSyncDurationCount: 3让播放点只落后直播边缘 3 个分片; - 起播通知:
playing事件通过chrome.webview.postMessage通知 C# 侧隐藏加载遮罩。
2. 失败自动回退央视网网页播放器
直播 CDN 地址不是永久的,可能挂掉或地域不可用。播放器页内置重试与回退逻辑:致命错误/视频错误重试 2 次(间隔 3 秒),第 3 次仍失败则 location.replace 跳转到央视网 CCTV-1 网页播放器——网页播放器是官方页面,稳定性远高于裸流地址:
function fail(){
retries++;
if (retries >= 3) { location.replace(fallbackUrl); return; } // 连续失败则回退到央视网网页
setTimeout(function(){ location.reload(); }, 3000);
}
回退页加载完成后,还需要帮长辈点掉"全屏"按钮——见下一节。
3. 央视网回退页自动全屏
央视网网页播放器的全屏按钮要等播放器渲染出来才存在,且不同期页面 class 名有变化。注入脚本每秒扫描一次 DOM,找到 title/class/id 含"全屏"或"full"的可见元素即点击一次,然后自我注销:
ThreeStarTV/CameraCell.cs(AutoFullscreenScript,AddScriptToExecuteOnDocumentCreated 注入,仅 cctv.com 域名生效)
(function(){
if (/cctv\.com$|\.cctv\.com$/.test(location.hostname)) {
var timer = setInterval(function(){
try {
var els = document.querySelectorAll('[title*="全屏"], [class*="full"], [id*="full"]');
for (var i = 0; i < els.length; i++) {
var b = els[i], t = (b.title || '') + ' ' + (b.className || '') + ' ' + (b.id || '');
if (/全屏|full/i.test(t) && b.offsetParent !== null) { b.click(); clearInterval(timer); return; }
}
} catch (e) {}
}, 1000);
}
})();
offsetParent !== null 用于过滤隐藏元素,避免点到页面里同名的不可见占位节点。
4. 开机启动与启动设置(零操作的核心)
四个启动设置全部持久化到 AppConfig.json:自动取消静音(默认开)、开机启动、窗口置顶、启动时最大化。开机启动通过在 shell:startup 目录维护快捷方式实现,只创建/只删除指向本程序的快捷方式,绝不碰用户自己的其他快捷方式:
ThreeStarTV/AutoStartService.cs(节选)
public static void Enable()
{
if (IsEnabled()) return; // 已存在且指向本程序,不重复创建
CreateShortcut(ShortcutPath, Application.ExecutablePath);
}
public static void Disable()
{
if (!File.Exists(ShortcutPath)) return;
// 只删除指向本程序的快捷方式,用户自建的其他快捷方式不动
if (string.Equals(GetShortcutTarget(ShortcutPath),
Application.ExecutablePath, StringComparison.OrdinalIgnoreCase))
{
File.Delete(ShortcutPath);
}
}
首次启动时若无配置文件,自动生成"1 路、CCTV-1 m3u8、无加载延迟"的默认配置(ConfigService.Load()),即装即播;App.Main() 启动时调用 AutoStartService.SyncWithConfig() 自动修复快捷方式与配置不一致的情况。
5. 启动提速:共享 WebView2 环境 + 预热预取 + 加载遮罩
长辈的耐心以秒计,启动速度是硬指标。三层优化叠加:
共享环境:全部播放格共享一个 CoreWebView2Environment,用户数据目录默认持久化——央视网页面的 JS/CSS 等静态依赖第二次启动起直接走本地 HTTP 缓存,不再重复下载:
private static async Task<CoreWebView2Environment> GetSharedEnvAsync()
{
if (sharedEnv == null)
{
var options = new CoreWebView2EnvironmentOptions(
additionalBrowserArguments: "--autoplay-policy=no-user-gesture-required");
sharedEnv = await CoreWebView2Environment.CreateAsync(null, null, options);
}
return sharedEnv;
}
启动预热:App.Main() 后台提前请求直播流清单与央视网回退页,完成 DNS 解析与 TLS 握手(系统 DNS 缓存 Chromium 可复用),首个画面的等待显著缩短:
private static void WarmupPrefetch()
{
Task.Run(async () =>
{
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
foreach (var url in new[] { ConfigService.DefaultStreamUrl, ConfigService.FallbackWebUrl })
{
using var req = new HttpRequestMessage(HttpMethod.Get, url);
req.Headers.UserAgent.ParseAdd("Mozilla/5.0");
using var resp = await client.SendAsync(req, HttpCompletionOption.ResponseHeadersRead);
_ = await resp.Content.ReadAsByteArrayAsync(); // 完整读取以复用/关闭连接
}
});
}
加载遮罩:暗色遮罩 + 进度条 + "加载中 xxx ms" 实时计时(100ms 刷新,伪进度条按用时推进,封顶 90%);m3u8 页等到播放器 playing 消息、普通网页导航完成即隐藏,60 秒超时兜底,避免永久遮挡。
6. 单文件分发:.NET 4.8 启动器内嵌运行时与主程序
长辈的电脑上不可能预装 .NET 8。解决方案是一个 .NET Framework 4.8(Win10/11 系统自带)写的启动器外壳:检测 Microsoft.WindowsDesktop.App 8.x 运行时 → 缺失则静默安装内嵌的运行时安装包(/install /quiet /norestart,完全离线)→ 将内嵌的主程序 exe 释放到 %LOCALAPPDATA%\ThreeStarTV\App\ 并启动。主程序与运行时安装包都以嵌入资源形式打进启动器,最终产物只有一个 exe:
ThreeStarTV.Launcher/Program.cs(流程骨架)
private const string RuntimeResource = "DotNet8Runtime.exe";
private const string AppResource = "ThreeStarTV.exe";
// 1. 运行时检测:dotnet --list-runtimes 输出包含 Microsoft.WindowsDesktop.App 8.
// 2. 缺失则静默安装内嵌安装包(10 分钟超时兜底)
int code = await InstallRuntimeAsync(form);
// 3. 释放并启动主程序
string appDir = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"ThreeStarTV", "App");
ExtractResource(AppResource, Path.Combine(appDir, "ThreeStarTV.exe"));
Process.Start(new ProcessStartInfo { FileName = appPath, WorkingDirectory = appDir, UseShellExecute = true });
释放主程序前若文件被占用(上次崩溃的残留进程),先结束 ThreeStarTV 进程再重试删除,最多 4 次——这是实践踩出的坑:崩溃后重启曾提示"访问被拒绝"。
7. 构建
需要 .NET SDK 8+ 与 MSBuild(Visual Studio 或 .NET Framework 4.8 自带):
bash build-with-timestamp.sh
build-with-timestamp.sh(流程)
# [1/3] 发布主程序(net8.0-windows,win-x64 单文件,框架依赖)
dotnet publish ThreeStarTV/ThreeStarTV.csproj -c Release -r win-x64 --self-contained false \
-p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish/app
# [2/3] 编译启动器(内嵌运行时安装包与主程序两个资源)
MSBuild.exe ThreeStarTV.Launcher/ThreeStarTV.Launcher.csproj //p:Configuration=Release
# [3/3] 输出便携式单文件 dist/ThreeStarTV_<yyyyMMddHHmm>.exe
产物 dist/ThreeStarTV_<时间戳>.exe 直接拷贝到目标机器即可运行。
常见问题
Q: 首次运行黑屏/提示需要安装 WebView2?
A: 主程序依赖 WebView2 运行时。Win10 2004+ / Win11 一般已预装;精简版系统可能缺失。首次运行需联网下载,或另行部署 WebView2 离线包(Evergreen Standalone Installer)。
Q: 直播流地址失效了怎么办?
A: 播放器页连续 3 次失败会自动回退央视网网页播放器(见第 2 节),通常无感知。若长期播放央视网页,可在 设置 → 网址收藏 里找到新的 m3u8 地址替换,或在每一路格子直接改地址;CCTV-1~13 的网页地址收藏中均已内置。
Q: 回退到央视网页后没有自动全屏?
A: 自动全屏脚本依赖页面 DOM 中"全屏"按钮的实际渲染(约需几秒到十几秒),期间画面已是正常播放状态,只是带网页边框。若央视改版导致按钮特征变化,脚本的匹配规则(title/class/id 含"全屏/full")需要同步更新。
Q: 开机后没声音 / 没有最大化?
A: 检查 设置 → 软件设置 → 启动设置 中的"自动取消静音"与"启动时最大化"是否开启(默认开)。无声的另一个常见原因是系统音量合成器里 WebView2 被单独静音。
Q: 杀毒软件报毒?
A: 启动器会静默安装运行时、写 %LOCALAPPDATA% 并拉起子进程,部分杀软会拦截。添加信任即可;运行时安装包为微软官方原版。
Q: 如何改成默认播放其他频道?
A: 首次启动前删除配置目录(便携模式为 exe 旁 Configs/,否则为 %LOCALAPPDATA%\ThreeStarTV\)下的 CameraConfig.json,或直接在格子中把地址改为目标频道的 m3u8/网页地址并锁定。
运行效果图
实拍环境:Windows 虚拟机,软件启动后回退至央视网网页播放器自动全屏播放 CCTV-1。
| 运行截图1 | 运行截图2 |
|---|---|
![]() |
![]() |

本文记录如何从零造一个"插上就能放电视"的软件 **ThreeStarTV**,解决长辈不会操作网络电视的问题:Windows 电脑开机后自动全屏、带声音播放 CCTV-1 高清直播,全程零操作。软件基于 .NET 8 WinForms + WebView2,内嵌 hls.js 播放 m3u8 直播流,直播流连续失败时自动回退央视网网页播放器并自动点击"全屏",最终由 .NET Framework 4.8 启动器内嵌 .NET 8 运行时与主程序,分发为**单个便携式 exe**,完全离线安装运行。


浙公网安备 33010602011771号