基于 Vue 3 的网络收音机:从本地 stations.json 加载电台清单,在浏览器或 Electron 桌面端 直连公开直播流(MP3 / AAC 等直链与 HLS),无需自建音频后端。
https://github.com/yichuancq/net-redio
https://github.com/yichuancq/net-redio
核心功能点
- 电台列表 :运行时
fetchpublic/stations.json;支持根为数组,或{ "channels": [...] }/{ "stations": [...] }(与 SomaFM channels.json 等字段对齐时可带封面、genre、lastPlaying等)。 - 浏览与搜索 :默认「所有电台」按热度排序;侧栏按大洲/国家筛选(
countrycode);顶栏搜索匹配名称、国家、标签、genre、描述、DJ、在播曲目等。 - 收藏 :顶栏星标进入收藏列表;卡片上星标添加/移除;数据存
localStorage(与stationMergeKey一致)。 - 播放 :选中即播;Icecast 类直链与
.m3u8(hls.js,Safari 可原生 HLS);底栏音量、静音、播放/暂停。 - 主界面 :深浅色主题(
html.theme-light,本地记忆);侧栏可折叠;上方黑胶舞台(可选唱臂、多色唱片底、转速);封面主色轻染舞台背景;下方网格单独滚动;底栏含示意性电平动画(非 Web Audio 真实频谱)、封面与曲目信息。 - 设置页 :主题强调色(色板 + 最近使用,写入
--accent等 CSS 变量);唱片底片颜色/转速;是否显示唱臂、是否显示示波器区域;均持久化localStorage。
主界面截图

项目结构
net-redio/
├── electron/
│ └── main.js # Electron 主进程(窗口、生产环境加载 dist/index.html)
├── public/
│ ├── index.html
│ ├── stations.json # 运行时加载的电台清单(路径与 App.vue 中 fetch 逻辑一致)
│ └── favicon.ico
├── scripts/
│ └── update-somafm-stations.mjs
├── src/
│ ├── App.vue # 根布局、清单/导航/播放/HLS(核心)
│ ├── main.js
│ ├── composables/
│ │ ├── useNetRadioTheme.js # 明暗主题 + html 类名
│ │ ├── useThemeAccentColor.js # 自定义强调色、最近色、CSS 变量
│ │ ├── useVinylAppearance.js # 唱片色/转速、示波器、唱臂;localStorage
│ │ ├── useRadioFavorites.js # 收藏 ID
│ │ └── useStationArtAccent.js # 封面主色采样(canvas,供舞台背景)
│ ├── data/
│ │ ├── stationCatalog.js # 解析、规范化、搜索/排序/按国家
│ │ ├── radioContinentNav.js # 侧栏大洲 → 国家
│ │ ├── continentNavCountries.js # 各洲 ISO2 与中文名
│ │ └── themeAccentPalette.js # 设置页主题色色板
│ ├── styles/
│ │ ├── net-tv-tokens.css # CSS 变量(明暗、强调色默认值等)
│ │ └── net-tv-global.css
│ └── views/net-radio/ # 侧栏、工具栏、舞台、网格、底栏、示波器、设置
├── electron-builder.yml
├── vue.config.js # publicPath、devServer;Electron 构建见上文
├── package.json
└── README.md
实现要点
位置 说明 App.vuestationsCatalog全量;filteredStations由activeNavKey(all/favorites/country:xx)与搜索共同决定。stationMergeKey:UUID 优先,否则u:+URL,作收藏与当前台 id。attachStream先destroyHls(),再区分 HLS 与直链。stationCatalog.jsnormalizeStation须存在url_resolved或url;兼容多种 API 字段;parseStationsPayload识别数组或channels/stations。useThemeAccentColor.js有存储时覆盖 documentElement的--accent、--accent-dim、--brand-end、--card-active-border;无存储则沿用net-tv-tokens.css。useVinylAppearance.js黑胶渐变背景定义在同文件导出的 VINYL_DISC_BACKGROUNDS(NetRadioStage使用)。收藏 useRadioFavorites的 id 与网格stationMergeKey一致;收藏列表从全量stationsCatalog过滤,避免子列表截断导致「收藏消失」。