Compare commits

..
195 Commits
Author SHA1 Message Date
Henry_Du 3c69740470 fix(audio,schedule): 音乐只扫 audio/music 避免错播短提示音假失败 + 远端主机完全离线时通过 HTTP REST + WS 主动推送拿到时刻表
- listMusicTracks/getPlaybackAudioByBaseName 彻底去掉 audio/beep fallback:空目录就空,提示音 wav(fc1/ksts) 不再出现在音乐列表,杜绝 API 返回 sent=1 但实际播放 0.25s 导致用户以为失败
- music enqueue 优先级从 0 下调到 -1,approaching/alert/arrival 永远干净抢占,equal-prio 不会把整首歌切成碎段
- 新增 4 套取时刻表的兜底方法(最远端主机完全加载不到也能用):
  1. POST/GET /api/stations/:name/schedule — 管理员或远端屏幕 HTTP 拉/手动注入 upcomingTrains+currentTrain,完全不依赖本地 Lua block-reader
  2. GET /api/stations/schedule(?line=CE) — 批量按线路拉取全量时刻表摘要
  3. 同站点 schedule TTL 10min 鲜度字段 scheduleIsStale / scheduleFreshForMs 返回给客户端自行判断
  4. 每次 heartbeat/station_schedule_sync 触发 WS 广播 station_schedule_available + same_cable_group_schedule 推送到同站/同线缆分组全部连接(不只 master)
- normalizeStationRecord + POST schedule 新站自动补 lastScheduleSyncedAt=0 避免 500
2026-08-17 20:10:54 +08:00
Henry_Du 9c5d6e9659 fix(audio): 修复线缆 token 死锁(holder=CE-01) + 同组 approaching 等优先级饿死 + 线缆太长前端主机听不到
1. releaseCableToken(L688): 去掉 audioId 严格匹配, 只要 stationName 对就释放
   修复: CE-01 因 audioId 在 setTimeout/release 分支里 miss-match, token 永远不释放,
   导致同组其它站 approaching 100% 被 deny reason=lower_priority holder=CE-01

2. acquireCableToken(L549): 新增 equal-prio-timeout 抢占, 同一线缆分组多站连续
   approaching(p=2) 时不会再出现 holder 永远持住的死锁: 旧 token 持有超过
   max(30s, durHint+30s) 后, 等优先级新请求可强制切换 (日志 WARN: equal-prio switch)

3. Cable token watchdog(每20s扫描): holder 站点所有连接断开立刻强制释放
   (holder_offline); 最长持有 10min 兜底强制释放 (max_hold_timeout). 彻底避免
   音乐循环/循环临时广播 崩溃后 token 泄漏永远释放不了的情况

4. 线缆太长前端主机听不到 (架构修复):
   旧方案: sendAudioBufferToStation / sendLiveWavChunksToStation 里全部 WS 消息
   (audio_start + audio_chunk + audio_end) 只发给站点唯一 masterWs 连接, 若
   master 物理位置在线缆尾部, 中间节点断链, 线缆最前面主机就完全收不到音频
   新方案: 新增 sendWsToAllConnectionsOfStation + sendBinaryToAllConnectionsOfStation
   (L503-L520), 所有 (audio_start/end, cable_token_granted, audio_preempt) JSON 消息
   及所有 binary WAV 分块, 广播到该站点 getAllStationConnections 返回的 *所有*
   已连接 WS node, 每台主机独立从云端服务器拿一份流, 不再依赖线缆上 master 转发
   对 10 站长线缆场景, 只要 node 还连着云端, 就肯定能收到音频, 彻底避免前端
   主机因线缆中段节点断网/掉电听不到音频的故障

端到端单元测试 5/5 PASS:
  A releaseCableToken audioId 不严格匹配 PASS
  B p=2 approaching dur=8s age=70s 时 equal-prio 切换 PASS
  B2 p=2 age=5s 时不抢占 PASS (防抖动)
  C watchdog holder_offline 检测后立刻释放 PASS
  D 同站 4 个 node 同时都收到 audio_start 消息 PASS (前端主机不漏消息)

v1.0.114
2026-08-17 19:48:36 +08:00
Henry_Du dc8f94ce22 fix(broadcast): 修复播放音乐失败 + 临时广播失败 (group.memberNames nodeId/stationName 语义混淆)
根因: getStationGroups (L881) + resolveStationGroup 单站分支 (L942) 错误地把
  memberNames = nodes.map(n => n.nodeId || '')
填成了 nodeId 数组 (n_msx5ieg9_9iy1dw 这类), 但下游 4 处消费方
  /api/music/start, /api/music/stop, /api/temp-broadcast/publish
全部把 memberNames[i] 当 stationName 用:
  getStationWs(memberName) → stations[n_xxx] = undefined → null
  stopStationMusic(memberName) → 按错 key 清队列
  stationMusicStates.set(memberName) → 按错 key 存状态
  enqueueStationAudioTask(memberName) → 按错 station 名入队

后果: 所有成员永远被判为 offline (reason=offline), 所以 API 返回 sent=0 failed=1,
音乐和临时广播 100% 无法触发推流, 端到端链路完全中断.

修法: 对 CC station group 语义来说 memberNames = 该 group 包含的每个子站的
stationName 数组 (同 cable group 的 stationNames 语义). 单站 selector 只包含
一个成员 [st.name], 无论这个站挂了多少个 node 连接, 最终 enqueue 都是按
stationName 维度合并到同一个队列, 不会重复推多次.

端到端验证通过:
  MUSIC START: sent=1 failed=0 ✓
  TEMP PUBLISH: success=true sent=1 failed=0 ✓
  Live WAV chunk stream start/end 两条日志完整闭合, 说明 ffmpeg 分块
  → WS 推送 → 结束 全链路走通.
2026-08-17 19:34:10 +08:00
Henry_Du 8c9c72fcba feat(display): 优化外接显示器小屏自适应显示方案
- 新增 textScale 自动分级:根据显示器实际尺寸在 1.0/0.75/0.5 间自适应选择
- 实现 L/M/S 三档布局模式:L(大屏双栏完整)、M(中屏单栏精简)、S(小屏极简核心信息)
- 小屏模式隐藏日志、即将到达列车等次要信息,优先展示当前列车和发车倒计时
- 音频状态标签在小屏下进一步压缩缩写 (Sta Ann / Sp Ann)
- 版本升级至 v1.0.113
2026-08-17 19:17:40 +08:00
Henry_Du 0335e245e1 fix(audio): 修复终点站/下一站漏播 + 广播卡顿跳音 + 音频wav多变体查找
- 新增 findAudioFileSmart 多变体模糊匹配: ch-/ja- 语言前缀剥离, CE- 线路前缀剥离,
  连字符/下划线/空格互转, station-/line-/voice-/stn- 通用前缀补全, 每 token 生成
  16+ 文件名变体匹配, 彻底解决 ch-ce-13 命不中 13.wav/station-ch-ce13.wav 漏播
- 新增 getAudioDirIndex 目录文件索引缓存 (mtime+size 失效), 避免每次查找递归读盘
- 补全 buildConcatListFile 致命缺失函数, 之前 local HLS 模式直接 ReferenceError
- 重写 clearLocalHlsStreamDir: 只清理 30min 前的旧 TS, 新广播使用唯一前缀
  b_<ts>_<rand>-seg-<n>.ts, 新旧广播段永不重名, 修复新广播删/覆盖旧段导致的卡/跳音
- server.listen 启动时预执行 ensureSilenceWav, 避免第一次广播阻塞生成静音段开头卡
- handleApproaching/Arrival/Departure 全链路结构化 DEBUG 日志: Station-Audio-Code
  (destCode/nextCode 提取链) -> audio tokens 完整序列 -> Sequence resolve 清单
  (searched 目录+missing 列表), 以后再漏播四行日志 100% 定位根因
- resolveStationAudioCode 3 级兜底链不变, 确保 destCode/nextCode 正确进入 audio seq
2026-08-17 18:34:15 +08:00
Henry_Du 1179130656 fix(cablemanager): 修复线缆分组详情编辑时成员被自动刷新打回且保存无效的问题
根因:
- cablemanager 每 900ms scheduleAutoReload() 通过 WS state_update 触发 reloadAll({silent:true}),之前 reloadAll 在 detail-view 场景下每次都会无条件把 detailTempMembers 从服务器读回、selectedAvailable/selectedMembers 清空,所以用户刚把某站台 » 加进成员,下一次被动刷新到了就立刻还原(视觉上就是「点过去又跳回来」)
- 保存 saveDetail() PUT 本身是能成功的(server PUT /api/audio-cable-groups/:id 的 stationNames 接口契约没问题),但保存之后 loadGroups() 拉完数据又立刻触发 broadcastUpdate()→WS state_update→scheduleAutoReload→又一次 reloadAll()→把刚保存的 detailTempMembers 用服务器值覆盖掉,用户看起来就是「保存无效」
修复 (cablemanager.html reloadAll):
1. 保存 refresh 前后的 prevGroups/prevStations 快照,只有 name/color/description 或站台列表真的变了(groupListChanged/ stationListChanged)才重绘列表和快选,避免心跳、lastSeen、tokenHolder 这些纯瞬时字段反复重绘
2. 区分 silent (被动自动刷) vs 非 silent (用户手动点刷新):
   - 非 silent:保持原语义,完全用服务器值覆盖所有本地编辑(用户主动点刷新就是要回到当前后台状态)
   - silent:
     * 只在 metaChanged 时同步 name/description/color(并且不抢焦点的 input,避免正在打字被重置)
     * 只在 membersChanged(后台 stationNames 真的跟上次不一样)时才同步成员到 detailTempMembers,否则保持用户未保存的成员编辑不变;同时清理 selected 中已不存在的名字
     * renderDualLists 仅在 membersChanged || stationListChanged || metaChanged 才调用,其余时间完全不重绘详情
3. 服务器 PUT 端再验证过 stationNames 接口契约没问题:前端 saveDetail 发 {name,color,description,stationNames} 对得上 server PUT handler,保存完 /api/audio-cable-groups 读回 stationNames 正确
APP_VERSION_TEXT bump 到 v1.0.111
2026-08-17 18:11:57 +08:00
Henry_Du a58632272e fix(announce): 修复进站预告音频终点站名字被跳过的问题
根因链:
- station_broadcast.lua 通过 BlockReader / CreateTarget 两个分支触发 train_approaching 发送时,只带 destination (中文名/站名),未带 destCode;server 端只能走 getStationCodeFromName(destination) 正则解析,正则没匹配到就会得到 UNK → ch-UNK.wav / ja-UNK.wav 不存在 → 整条目的地段音频被 ffmpeg concat 跳过
- 对比 train_arrival (Peripherals.station 分支) 是有 destCode 字段的(由 Utils.getStationCode + schedule 解析得到),所以到站广播终点站名能正常播出,预告(走 Display/BlockReader 分支)不能
修复:
1. station_broadcast.lua 四处 train_approaching / train_alert Network.send 全部补 destCode = Utils.getStationCode(destination):
   - L4053 (alert, blockreader) / L4091 (approach, blockreader)
   - L4221 (alert, createTarget) / L4257 (approach, createTarget)
2. server.js 新增 resolveStationAudioCode(rawCode, rawName) 三级兜底解析:
   - L1: 直接用 raw destCode(优先级最高,客户端算好的)
   - L2: 正则解析 destination 名字抽取 code(parens/dash/下划线模式)
   - L3: 把 destination 名拿去 findStationByFlexibleName 已注册站台表里 fuzzy 匹配,取其 code
   - 解析不到就打 WARN 日志,提示会跳过这一段
3. handleTrainApproaching / handleTrainArrival / handleTrainDeparture 三个 handler 的 destCode / nextCode 全部切到 resolveStationAudioCode 统一入口,不再各写一遍正则,所有预告/到站/发车音频用同一条解析链,保证结果一致
APP_VERSION_TEXT bump 到 v1.0.110
2026-08-17 18:05:21 +08:00
Henry_Du fb17de6493 fix(cablemanager): 修复 cablemanager 无法操作 + 一直刷新的问题
- 根因1: GET /api/audio-cable-groups 服务端返回 {groups: list},但前端 loadGroups() 读 data.audioCableGroups → 永远读到 undefined → 始终空列表
  修复: 服务端 L3447 同时返回 groups 和 audioCableGroups 两个别名;前端 loadGroups() 优先读 audioCableGroups,不存在则回退 groups
- 根因2: WebSocket onmessage 收到 init_state/state_update 立即 reloadAll(带 toast),若事件频繁会反复 re-render + 连弹『数据已刷新』toast → 看起来一直刷新且输入框总被重置
  修复: 新增 scheduleAutoReload() 节流(两次自动刷新之间至少间隔 900ms);且自动刷新统一走 reloadAll({silent:true}) 不弹成功/失败 toast;仅用户点刷新按钮才弹提示
- 本地实测: PORT=8999 启动 server 后 /api/stations → {success:true, stations:[]},/api/audio-cable-groups → {success:true, groups:[], audioCableGroups:[]},两个端点均 200 且响应结构含双别名 key
- APP_VERSION_TEXT bump 到 v1.0.109
2026-08-17 17:55:09 +08:00
Henry_Du a3ff8664ee fix(station_broadcast): 修复 Utils 为 nil 导致启动崩溃的前向引用问题
- 原因: Lua local 变量按声明顺序起作用域,Peripherals.init() 在 L96 定义(体内 L188 引用 Utils.log),而 local Utils={} 原本在 L195 才声明,导致函数体内引用成 _G.Utils(全局,nil)
- 修复: 在文件 L71 附近集中前向声明所有顶层模块(Peripherals / Utils / Display / Audio / Network / Main),删除各章节头部重复的 local Module = {},保证 Lua 解析时能正确捕获 local 上值
- APP_VERSION_TEXT bump 到 v1.0.108
2026-08-17 17:39:15 +08:00
Henry_Du 5e466f4553 fix(ui): 补齐 generator.html 和 listmanager.html 的问号剥离兜底
- generator.html: 新增 ds() 钩子,在 renderList / batch 预览 / showToast 三个渲染点统一问号剥离
- listmanager.html: 新增 ds() 钩子,在 renderList / renderSequence / 自定义 select 选项 / showToast 四个点统一问号剥离
- APP_VERSION_TEXT bump 到 v1.0.107
2026-08-17 17:32:01 +08:00
Henry_Du 4c049050ce feat(ui): 显示层去问号化 + 网页统一 CableManager 风格 + 补齐 select 下拉样式
需求:
1. 客户端与网页端所有展示到屏幕上的内容,去掉 ???、Unknown、未知版本、未选择、未合成、暂无在线 等占位问号/疑问式字符;
2. 网页端所有页面统一 cablemanager.html 那套风格(色板、硬边边框、圆角 6/8、顶栏渐变字/下边框分隔、shadow、body 径向渐变);
3. 补齐 <select>/option 下拉样式(appearance none、内联 SVG 箭头、padding-right 留位、ring focus、option 背景与主色一致),不再沿用系统默认。

改动:
1. station_broadcast.lua:
   - 新增 Utils.sanitizeDisplay:统一把任意显示字符串内的 ? 全部剥离并 trim 空白,空串返回 '-'
   - Display.render 里 truncL / truncR 从直接 tostring 改为走 sanitizeDisplay,保证所有监视器内容 0 问号
   - Display.render 底部 3 条日志(drawLeft)和 Display.renderTerminal 顶部日志全部走 sanitizeDisplay

2. CloudServer/public/:
   - index.html:
     * :root 色板对齐 cablemanager(--bg-panel #121214、--text-primary #f4f4f5、--text-muted #a1a1aa、加 --bg-input/--ring-color、radius 8px)
     * body 改 radial-gradient 背景
     * .btn / .btn-primary / .btn-danger 统一成 cablemanager 同款尺寸(10x14、radius 6、font-weight 500/600)
     * 新增 input[type=text|number|password] + textarea + select + option 完整样式组(cablemanager 同款)
     * 清理 display 层的 Unknown/未知/未发布:
       - stationVersion || '未知版本' 改为 || ''(空版本号直接省略,不写未知)
       - seqHtml fallback 从 'Unknown sequence' 改为 ''
       - localVersion 从 '未知' 改为 '-',targetVersion/publishedAt 从 '未发布' 改为 ''(空即省略)
   - infoboard.html:
     * :root 对齐 cablemanager,加 --bg-input、--ring-color、加 body radial-gradient
     * 车次目的地 fallback 从 '未知终点' 改为 ''(没终点就空白)
   - music.html:
     * :root / body / layout-wrapper / topbar / title / btn / panel / card-title / badge / input+select+textarea 全对齐 cablemanager
     * track_badge 默认占位从 '未选择' 改空(badge:empty 直接不显示)
     * 空站台列表占位从 '暂无在线/已注册站台' 改为 '-'
     * 补了完整 scrollbar 样式
     * 最外层 body 内加 .layout-wrapper(对齐 cablemanager max-width 1280 + 居中)
   - tempbroadcast.html:
     * 所有风格同步 music.html(与 cablemanager 一致)
     * build_badge 默认 '未合成' 改为空,失败分支也清空(只在合成成功/合成中写入),同时 .badge:empty {display:none}
     * 空站台列表占位 '-'
     * 补 select 下拉外观样式

客户端 bump v1.0.105 -> v1.0.106。
server.js node -c 通过;所有修改 HTML 仅改 style 段与少量占位文本,不影响 API 契约。
2026-08-17 16:17:38 +08:00
Henry_Du e0a1252db6 chore(ui): 首页导航黄色按钮从 Full Info Board 换成 Cable Manager 入口
把 index.html 文件管理器工具栏的黄色 var(--warning) 按钮:
- href: /infoboard.html -> /cablemanager.html
- 文案: Full Info Board -> Cable Manager
- 保留 target=_blank(新标签打开线缆分组管理页,避免丢当前文件视图)

客户端 bump v1.0.104 -> v1.0.105
2026-08-17 15:53:13 +08:00
Henry_Du b2c415f253 fix(server): 彻底放弃 :path(*) 等参数化通配路由,改用 app.use + req.path 手动截取,解决 path-to-regexp v8.3 启动崩溃
服务器环境 path-to-regexp 实际版本是 8.3.0(Express 5.2.1 内置),
该版本既不接受裸 '*'、也不接受 ':name(.*)' 自定义正则、也不接受
':name(*)' 单段通配修饰符,参数路由只要带修饰符就会在 new Layer
阶段直接抛 PathError。

解决方案(这次本地用真实 node_modules 实装 require 整份 server.js
模拟启动,已确认不崩溃,http.createServer 正常被调用 3 次):
- 7 条 /media/* 路由全部删除 app.get('/prefix/:path(*)', ...)
- 改为 app.use('/prefix', middleware) + 在中间件里用 req.path
  手动去掉前置 '/' 得到相对路径,再 decodeURIComponent();只处理
  GET 请求,其他方法 next()
- static 命中优先(fallthrough),未命中时继续调用原
  sendBinaryFile / sendBinaryFileFromCandidates 兜底,保持
  Content-Type / Range / Accept-Ranges / Content-Length 等头
  与旧行为完全一致
- 涉及:general / beep / music / voice / line / station / temp

客户端 bump v1.0.103 -> v1.0.104
2026-08-17 15:49:59 +08:00
Henry_Du a6d9b6c418 fix(server): 修复 serve-static 不接受数组 root、改为按请求逐个挂载,避免启动时 TypeError: root path must be a string
上一轮把 getBeepAudioDirs() 这个数组直接塞进 express.static(),
但 serve-static 签名要求 root 必须是字符串,会在 app 启动注册
中间件时直接抛错(甚至在接收请求前)。

修复方式:
- /media/audio/general 和 /media/audio/beep 改为动态中间件:
  请求进来时再依次对每个目录调用一次 express.static(root, {fallthrough})
- 单目录的 music/voice/line/station/temp 保留 express.static
  但统一包一层 String(xxx || '') 保证就算路径解析异常也是空
  字符串而不是 undefined
- 后备的 7 条 app.get(':path(*)') 路由不变,仍然负责 sendBinaryFile /
  sendBinaryFileFromCandidates 兜底(含 range、Content-Length 等头)

客户端 bump v1.0.102 -> v1.0.103
2026-08-17 15:44:38 +08:00
Henry_Du 5c462a4d09 fix(server): 改用 Express 5 + path-to-regexp v7 兼容的通配写法,避免路由启动崩溃
Express 5 内置的 path-to-regexp v7 不再支持裸 '*',也不支持
自定义正则 '.*'(会报 Missing parameter name)。Express 5
官方兼容的单段全通写是 ':name(*)',并且路由注册会在 app 启动
第一时间完成(出错会直接崩)。

同时为了兼容旧 URL 行为,保留 express.static 前置挂载 +
显式 app.get 后备两条路径,因为 Audio 模块可能需要带
Cache-Control / Range / Content-Type 等头的 custom sendBinaryFile
处理(例如 station 动态裁剪音频),所以不能直接用 static 替代。

修复 7 条路由:
  /media/audio/general/:path(*)
  /media/audio/beep/:path(*)
  /media/audio/music/:path(*)
  /media/audio/voice/:path(*)
  /media/audio/line/:path(*)
  /media/audio/station/:path(*)
  /media/temp/:path(*)

参数解码加 decodeURIComponent(),兼容中文/空格文件名。
客户端 bump v1.0.101 -> v1.0.102
2026-08-17 15:41:36 +08:00
Henry_Du fc66e43379 fix: 修复新版 path-to-regexp 不兼容 '*' 通配符导致启动崩溃
新版 express/router 依赖的 path-to-regexp 不再接受裸 '*' 路径语法,
改为命名通配参数 :relPath(.*),并同步把 req.params[0] 改为
req.params.relPath。涉及 7 条 /media/* 静态路由:
- /media/audio/general/*
- /media/audio/beep/*
- /media/audio/music/*
- /media/audio/voice/*
- /media/audio/line/*
- /media/audio/station/*
- /media/temp/*

客户端版本号 bump v1.0.100 -> v1.0.101
2026-08-17 15:38:41 +08:00
Henry_Du c9d8994942 chore: 版本号升到 v1.0.100 2026-08-17 15:33:54 +08:00
Henry_Du 4c7d94f2c9 feat(A1+B1): 引入站台多主机识别、音频线缆分组互斥令牌、本地Modem仲裁、线缆分组管理WebUI
服务端 A1 改动(CloudServer/server.js):
- stations 改为 nodes[] 多连接存储,同站台名的多台 CC 主机归入同一组(纯 stationName 精确分组)
- 新增 getStationMaster():hasStationPeripheral + lastSeen 加权选 Master,音频只下发给 Master
- 新增 audioCableGroups 数据结构(持久化到 server-data.json)
- 新增 acquireCableToken/releaseCableToken:同线缆组全局互斥,高优先级发送 audio_preempt 抢占
- 新增 7 路由 REST API:/api/audio-cable-groups CRUD + 批量/单个站台成员管理 + PUT /stations/:name/cable-group 直接改组
- sendAudioControl 给同站组所有节点全量下发(stop/状态同步)
- init_state / state_update 携带 audioCableGroups 给前端
- WS close 自动 removeStationWs 清理节点 + 释放令牌

客户端 B1 改动(station_broadcast.lua v1.0.99):
- Peripherals 新增 wiredModems 扫描(排除无线),自动 rednet.open
- 新增 LocalBus 命名空间:
  - station_hello 每 10s 广播 + 30s 超时清理邻居
  - 同站台名自动组 stationGroup,按 hasStationPeripheral + nodeId 升序选 Master
  - 新增 Utils.isLocalStationMaster(),所有列车上报(arrival/approaching/alert/departure/schedule_sync)仅 Master 执行,彻底解决重复广播
  - acquireLocalToken:audio_probe -> 80ms 收响应 -> 必要时 audio_preempt 抢占 -> token_grant
  - 令牌持有期间每 2s 广播 audio_playing 心跳,30s 超时自动判死回收
- Audio.playerLoop 在 playItem 前获取本地令牌,失败则跳过该音频
- Audio.stop() 自动释放本地令牌
- WS 新增下行处理:audio_preempt / cable_token_denied / station_group_state
- station_identity.cfg 支持 audio_cable_group= 字段,saveStationIdentity 写回
- Network.register/heartbeat 携带 cableGroup 供服务端回填分组

Web 管理端(CloudServer/public/cablemanager.html,单文件无外部依赖):
- 极简硬边风格,对齐 listmanager.html 配色和字体
- 分组网格卡片:色标/名称/描述/成员数/当前令牌持有者 + 编辑删除
- 新增/编辑 Modal:名称+描述+8色预设色板+自定义#RRGGBB
- 分组详情双栏 Dual List:左栏全部站台(搜索+在线状态+在其他组标签)/ 右栏成员,中间批量添加移除按钮
- 顶部快捷操作:站台下拉+组下拉+确认,直接 PUT /stations/:name/cable-group
- WebSocket 监听 state_update 实时刷新,Toast 提示反馈
2026-08-17 15:32:20 +08:00
Henry_Du 6ac05d3a84 feat(server): 实施 A1 方案 - 多连接存储、站台分组 Master 选举、audioCableGroup 互斥令牌机制
- stations 存储改造:stations[name] = { name, code, platform, audioCableGroup, version, lastSeen, nodes: [] } 结构,每个 node 含 ws/hasStationPeripheral/stationPeripheralSide/hasBlockReader/hasCreateTarget/identityMode/nodeId/wsId/connectedAt
- 新增 audioCableGroups:{ id, name, color, description, stationNames: [] } 分组,及 audioCableTokens 互斥令牌 Map(cableGroupId -> { holderStationName, holderAudioId, holderPriority, acquiredAt, cancelToken })
- 新增核心函数:upsertStationNode(按 wsId 去重更新 node、聚合计时表级 schedule)、removeStationWs(WS 关闭时清理 node + 释放令牌 + 下发 group_state)、getStationMaster(hasStationPeripheral=1000加权 + lastSeen小数加权 两轮选举 OPEN ws)、getAllStationConnections、getGroupKeyForStation(纯 stationName 分组,不再 code@@platform)、acquireCableToken(无持者直给/同 holder 更新/高优先级 audio_preempt + 200ms 延迟抢占/低优先级拒绝+denied 消息)、releaseCableToken
- 发送策略改造:sendAudioControl 遍历组内所有节点 ws 全发(同名站同步 stop 等指令);sendAudioBufferToStation/sendLiveWavChunksToStation 只发送 master ws,发送前后 acquire/release token,durationSec 后 setTimeout 延迟释放,audio_start 消息新增 cableGroupId 字段
- enqueueStationAudioQueue 增加 cableGrp 兜底释放;loadData 兼容旧 stations 单值结构导入 nodes=[] 数组新结构 + audioCableGroups 双向回填;saveData 剥离 nodes 中 ws 对象后保存,新增 audioCableGroups 字段持久化
- WS 层改造:wss close 事件调用 removeStationWs;console_connect init_state 增加 audioCableGroups 数组;handleStationRegister/handleHeartbeat/handleScheduleSync 改为调用 upsertStationNode;station_register_ack 返回 nodeId/audioCableGroup
- broadcastUpdate state_update 增加 audioCableGroups 字段;新增 WS 下行 audio_preempt / cable_token_granted / cable_token_denied / station_group_state 四种消息类型
- getStationGroups 完全重写:按 stationName 精确分组,返回 members/nodes 数组(每个 node 带 nodeId/wsId/online/isMaster/connectedAt/lastSeen/hasStationPeripheral/hasBlockReader/hasCreateTarget/identityMode/tickRate/memberTags),增加 masterNodeId、audioCableGroup{id,name,color}、cableGroupId 字段;resolveStationGroup memberNames 返回 nodeId 列表
- REST API 新增 9 个路由:GET/POST/PUT/DELETE /api/audio-cable-groups,POST /api/audio-cable-groups/:id/stations(批量加站台,含 prev cableGroup 自动清理)、DELETE /api/audio-cable-groups/:id/stations/:stationName、PUT /api/stations/:name/cable-group(stations.audioCableGroup 与 group.stationNames 双向同步),stations DELETE 自动同步 cable group 清理
- 兼容性:旧 stations[name].ws 统一改为 getStationMaster(name).ws;TTS、HLS、temp-broadcast、音乐播放、version 管理等功能不受破坏;Lua 客户端版本号提升至 v1.0.99
2026-08-17 15:15:23 +08:00
Henry_Du 55f0312314 feat(audio): 支持斜杠格式的车站编号和模糊搜索匹配
- 修改TTS音频导入逻辑,保留编号中的斜杠(/)格式(如 CH-01/CE-12),自动创建子目录
- 移除generator.html中单文件和批量导入时的斜杠转横杠逻辑
- 新增sanitizeStationCode和ensureDirForFile辅助函数,确保路径安全
- 重写findFileCaseInsensitive,支持递归子目录搜索与末尾段模糊匹配
- 新增listAllFilesRecursive和resolveAudioPathWithFuzzy工具函数
- 修改getPlaybackAudioByBaseName/findWavByBaseName支持模糊搜索查找
- 修改resolveManagedPath允许子路径访问,getManagedFiles递归扫描子目录
- 媒体路由从:file参数改为通配符/*形式,safeRelativeToBase确保路径安全
- 升级版本号至v1.0.98
2026-08-17 14:54:21 +08:00
Henry_Du 849b43af39 fix: 修复音乐和临时广播无法播放(AUDIO FREE)的问题
- 重写 waitForInterruptibleDelay/waitForNativeSpeakersEmpty 使用 os.clock()
  轮询,替换会抢占 websocket_message 事件的 os.pullEvent()
- 重写 queueSamplesSynchronized/playChunkOnSpeakers 重试循环使用
  os.sleep() 轮询,不再调用 pullEvent 吞掉音频分块事件
- 重写 Audio.createStream().read() 与 Audio.playerLoop 使用 sleep 轮询,
  不再使用 os.pullEvent('audio_chunk')/'audio_queue' 抢事件
- 修复 Audio.playItem 将 wav-stream/wav-stream-live 错误路由到
  playPcmS16LEItem,改为路由到 playWavStreamItem(服务端分块每块
  带完整 44 字节 WAV 头,需 decodeWavChunkToSamples)
- Network.messageLoop audio_start 分支将 wav-stream-live 加入流式
  接收判定,避免走 chunks 缓冲逻辑
- 版本号升级至 v1.0.97
2026-08-17 14:30:54 +08:00
Henry_Du e9819d4894 fix(multiplayer): normalize CRN BlockReader NBT structure with unwrapNbtObject helper to handle SP vs MP differences (single-player wraps every nested object as { [1] = obj } one-element arrays, while multiplayer uses direct maps without [1] wrapper)
- New unwrapNbtObject(obj): detects whether the table actually has a [1] wrapper AND outer table has exactly 1 key AND the inner [1] is useful, then returns inner object; otherwise returns obj unchanged - works transparently for both SP and MP structures
- Replace ALL hard-coded [1] dereferences in BlockReader parsing:
  - stop.Station -> unwrapNbtObject(stop.Station)
  - st.RealTimeStation -> unwrapNbtObject(st.RealTimeStation)
  - st.ScheduledStation -> unwrapNbtObject(st.ScheduledStation)
  - rtStation.StationInfo -> unwrapNbtObject(rtStation.StationInfo)
  - schStation.StationInfo -> unwrapNbtObject(schStation.StationInfo)
  - stop.Train -> unwrapNbtObject(stop.Train)
  - stop.Stopovers[i] entries: deep-unwrap if table, try StationName/Name fields to get string destination from potential NBT compound stopovers
  - tr.Status entries: unwrap each element before reading as string
- This eliminates the MP-only failure where st=nil (because SP-style Station[1] didn't exist) causing the whole TrainStop loop to skip inserting anything into newUpcoming and render UPCOMING as ???

Bump to v1.0.76
2026-08-16 14:35:18 +08:00
Henry_Du 66683f6d13 fix(upcoming): prevent UPCOMING freeze caused by NBT parsing errors in CC environment
- Eliminate empty-then block in Stopovers fallback logic: rewrite nested if/else with empty body to elseif chain to avoid parser error in reduced CC Lua dialect (was silently caught by pcall causing newUpcoming to remain empty)
- Add pcall protection to the standalone CreateTarget.dump() path (previously unprotected), with fallback to empty lines table on failure
- Add explicit WARN log on BlockReader.getBlockData pcall failure so user can diagnose errors via terminal output instead of silent data=nil
- Wrap each TrainStop iteration inside its own pcall so a malformed entry cannot abort the whole loop; failures are logged with stop index

Bump to v1.0.75
2026-08-16 14:23:43 +08:00
Henry_Du 50746ce766 fix(nbt): unwrap single-element arrays in CRN BlockReader NBT parsing (Station[1]/RealTimeStation[1]/ScheduledStation[1]/StationInfo[1]/Train[1]) to get real TrainName/Destination/StationName/Platform; fallback destination to precise StationName code (e.g. CE-03 2) when Destination is invalid or is CRN aggregated tag name. Bump to v1.0.74 2026-08-16 14:15:24 +08:00
Henry_Du 0de59531f9 test(br): diagnose block_reader instead of bailing
When no block_reader is found by exact type name, list all connected
peripherals (getType/getMethods/getName) into the output txt so the real
peripheral name can be identified on the target machine.
2026-08-16 14:07:13 +08:00
Henry_Du 926db04a3e test: add block_reader NBT dumper for advanced display
Reads the adjacent block (Advanced Display) via Advanced Peripherals block_reader
and writes registry name, block state, and NBT data as structured text to
blockreader_display_nbt.txt.
2026-08-16 14:02:38 +08:00
Henry_Du ae213a84a1 feat: 从机站台吸附识别与时刻表自动同步 v1.0.73
- Lua端: 新增定期外设重扫描(PERIPHERAL_SCAN_INTERVAL=15s),支持热插拔站台方块
- Lua端: 新增定期身份同步,站台外设热插/热拔时自动刷新身份并重新register
- Lua端: 新增独立的schedule sync coroutine与station_schedule_sync消息类型(SCHEDULE_SYNC_INTERVAL=10s)
- Lua端: 扩展heartbeat携带hasStationPeripheral/stationPeripheralSide/hasBlockReader/hasCreateTarget/identityMode/upcomingTrains/currentTrain等字段
- 从机若吸附有站台方块(train_station外设),则自动进入主机逻辑: 识别到发、停靠列车检测,数据通过WS推送到服务器
- server端: 新增assignDeviceFields工具函数统一写入设备字段与时刻表
- server端: 新增handleScheduleSync处理station_schedule_sync消息,数据写入stations[name]并broadcast
- server端: 扩展handleHeartbeat与handleStationRegister,均调用assignDeviceFields存储设备状态和时刻表摘要
- server端: 扩展getStationGroups分组视图,新增hostCount/slaveCount/hasAnyStationPeripheral/upcomingTrains/currentTrain/members详细信息
- 时刻表合并: 同一站台组多节点的upcomingTrains按trainName@@dest@@platform去重合并; currentTrain优先主机数据
- 版本升级: v1.0.72 -> v1.0.73
2026-08-16 13:33:10 +08:00
Henry_Du cd5b1d47b0 fix(crn): 修复CRN聚合站(如「千叶」)在CC中文环境下变????导致校正匹配失败引发终点站广播漏播
- 新增 extractAlphaNumCodes / hasSharedAlphaNumCode: 提取并比对字母数字代码(CB-03,CE-09等), 在中文变问号乱码环境下仍可通过代码完成跨源匹配
- looksLikeValidDestinationText: 放宽校验, 若问号超过50%但仍存在有效字母数字代码(如「????CB-03 6」)时不直接判为无效——保留代码供后续 hasSharedAlphaNumCode 匹配
- tryCorrectUpcomingEntryWithCurrentTrain:
  1) 新增 etaSeconds 形参用于识别在站列车(eta≤0.5s), 据此触发校正
  2) 新增 nearbyPlatform 条件: 站台号数字差≤1 时也进入校正候选
  3) 新增 sharedCodeDest / sharedCodeTrain: 即使车次/站台全不匹配, 只要 dest 或 id 含有与权威值相同的字母数字代码即可触发
  4) 新增兜底触发: (dest或id无效且eta=0)  |  (双无效且相邻站台)  —— 专门覆盖CRN聚合名????这种彻底无代码的场景
  5) 新增校正分支: 只要 sharedCodeTrain/sharedCodeDest 命中且 (etaAtStation|samePlatform|invalid) 即直接覆盖原值, 无需 fuzzy match 再次通过
- checkIsAtStationWithCurrentTrain:
  1) 无 sameTrain 时用 hasSharedAlphaNumCode 二次匹配车次
  2) 若车次/目的地双乱码 + 站台相邻, 也视为同车
  3) 乱码目的地分支新增 hasSharedAlphaNumCode 成功即判停靠成功
- BlockReader/CreateTarget 两处预校正均移至 etaSeconds 计算之后, 并将 eta 传入函数, 确保看门条件里的 etaAtStation 可生效
- 全局校正循环也传入 entry.eta

版本升级至 v1.0.72
2026-08-16 13:25:39 +08:00
Henry_Du 716a23cad5 fix(data): 修复权威时刻表与NBT显示粒度不一致导致终点站漏播(「千叶」聚合名 vs「千叶CB-03 6」具体站台)
- tryCorrectUpcomingEntryWithCurrentTrain: 校正逻辑从『仅无效乱码才覆盖』改为『同站fuzzy匹配且字符串不等即覆盖』,使schedule中的具体站台名优先于NBT中的粗糙聚合名
- 新增trainName的同粒度校正:车次信息不一致时,同车次fuzzy匹配成功即采用权威id
- BlockReader/CreateTarget两处预校正:解除『looksLikeValidDestinationText为false才替换』的限制,只要tryCorrect...返回的值与原值不同即替换——确保聚合名「千叶」这类『有效但粗糙』的文本也会被升级为具体站台名
- announceKey生成前的预校正与upcomingTrains赋值前的全局校正双保险,使冷却去重key与显示/广播目的地均完全对齐权威时刻表

版本升级至 v1.0.71
2026-08-16 13:05:57 +08:00
Henry_Du ae96c86288 feat: departure广播新增下一站播报 + 客户端预解析station code 2026-08-16 13:01:32 +08:00
Henry_Du 17b03ce0f7 fix(data): 修复NBT(BlockReader/CreateTarget)与车站时刻表数据源不一致导致终点站广播漏播的问题
- 新增 looksLikeValidDestinationText: 检测目的地/车次名是否有效(过滤Unknown和高比例问号乱码)
- 新增 tryCorrectUpcomingEntryWithCurrentTrain: 用权威State.currentTrain数据校正 upcoming 条目中的乱码车次/目的地
- 新增 checkIsAtStationWithCurrentTrain: 增强 isAtStation 匹配鲁棒性, 优先站台号+车次ID匹配, 乱码时降级到目的地模糊匹配
- 提前预校正: 在生成 announceKey 前就校正乱码字段, 确保 approaching/alarm 冷却去重 key 一致
- 后置全局校正: 在赋值 State.upcomingTrains 前再次对所有条目做权威校正, 保证显示和广播使用的终点站信息一致

版本升级至 v1.0.70
2026-08-16 12:44:09 +08:00
Henry_Du 32b2c8ce9d fix: 终点站到达时下一站广播播放异常 + getNextStation 不回绕起点
1. Utils.getNextStation: 移除终点站回绕到起点的逻辑(非环线)
   - 此前当前站是 END 时会从 schedule.entries 开头再找,把起点当下一站
   - 修复后在终点站返回 nil,明确表示无后续站

2. 服务端 handleTrainArrival: 智能区分普通站/终点站广播序列
   - 新增 hasNextStation / finalNextCode 判断:只有当下一站有效时
     才在 seq 中插入 ch-nextsta + ch- 片段
   - 终点站(finalNextCode 为 null):直接删除 nextsta 和下一站代码,
     仅保留 站台-站台-线路-方向-终点站-警示 片段
   - 避免 ch-UNK 等无效资源或回绕起点站名被播放

3. 日志增强:arrival 处理时额外打印 nextStation 和 nextCode,
   便于快速确认服务端是否收到正确的下一站信息

版本号 v1.0.69 -> v1.0.70
2026-08-16 12:41:19 +08:00
Henry_Du 34d9ed00d6 fix: 解决自动更新无限重启循环 + 终点站列车不显示在预测列表
1. CloudServer: publishStationUpdate 发布时同步 Gitea 最新脚本到本地副本
   - 新增 fetchGiteaScript() 一次下载全文
   - 发布更新时将 Gitea 脚本内容写入 stationScriptPath
   - 保证 targetVersion 与 /downloads/station_broadcast.lua 内容版本一致

2. 客户端 AutoUpdate.apply: 下载后校验版本一致性
   - 从下载内容正则提取 APP_VERSION_TEXT
   - 若 downloadedVersion ~= targetVersion 则中止更新,防止 reboot loop
   - 写入错误日志便于排查

3. 预测显示: 在站列车(尤其终点站)强制插入 upcomingTrains 列表头部
   - CRN 可能从 TrainStops 提前移除终点站列车
   - 使用 normalizeUpcomingKey 去重避免重复条目
   - 固定 ETA=0,确保 CURREN T TRAIN 对应列车能在 UPCOMING 中可见

版本号 v1.0.68 -> v1.0.69
2026-08-16 12:32:11 +08:00
Henry_Du 82a4ecd3e8 fix: 确保在站列车(包括终点站列车)始终显示在预测列表中
- 当 State.currentTrain 存在时,手动将其信息插入 upcomingTrains 列表头部
- 解决终点站列车被 CRN 导航系统从 TrainStops 提前移除导致预测区无显示的问题
- 使用 normalizeUpcomingKey 去重,避免重复条目
- 版本号 v1.0.68 -> v1.0.69
2026-08-16 12:22:50 +08:00
Henry_Du 1b958c25df feat(display): 标注终点站[END]与下一站[NEXT]并修复多项显示bug
- 修复所有站误标[END]:原来用instruction.id判断是错误的,Create中每个停靠站都是create:destination;现在改为用Utils.getDestination()匹配或取列表最后一个站作为终点站
- 过滤包含NaN的无效站点名
- 当前站匹配:先尝试『站名+站台号』严格匹配(避免CB-03 5和CB-03 6同时高亮,匹配不到再退化到站名匹配
- 新增『下一站』标识:~前缀 + 橙色 + [NEXT]后缀
- 新增『终点站』标识:黄色 + [END]后缀
- 当前站:>前缀 + 绿色 + << 标记
- 未到达站:*前缀 + 白色
- 已过站:浅灰色
- 版本号升级至 v1.0.68
2026-08-16 12:01:04 +08:00
Henry_Du 1d99634957 fix(audio): 修复导致完全没有声音的回归错误,添加超时防止挂起,修复等待缓冲区清空的逻辑 2026-08-16 11:58:31 +08:00
Henry_Du af00d57e68 feat: 发布更新时优先使用远程 Gitea 仓库的版本号 2026-08-16 11:54:29 +08:00
Henry_Du 4b972c3ae6 fix(display): 修复时刻表不显示的多个问题
- 将宽度阈值从 50 降低到 30,适配更小的 monitor
- 重构 schedule.entries 解析逻辑:兼容非纯数字索引(用 pairs 收集后排序)
- 修复视觉逻辑 bug:已到达站(浅灰) vs 未到达站(白) 颜色搞反
- 增加 schedule 为 nil/invalid 时的错误提示显示
- 增加调试日志输出 monitor 尺寸和提取到的站点数
- 版本号升级至 v1.0.65
2026-08-16 11:50:44 +08:00
Henry_Du 71f6800a2a feat(display): 列车进站后在屏幕右侧显示时刻表信息
- 新增 Utils.extractAllStationsFromSchedule() 从时刻表提取所有站点
- 重构 Display.render() 实现左右分栏布局
- 列车存在且屏幕宽度>=50时启用右侧时刻表面板
- 使用颜色区分:已过站(浅灰)/当前站(绿色高亮+>)/未到站(白)/终点站(黄色+[END])
- 版本号升级至 v1.0.64
2026-08-16 11:45:37 +08:00
Henry_Du b74eb252e3 feat: 在后端增加解析远程 Gitea 最新版本号的接口并展示在前端 2026-08-16 11:40:47 +08:00
Henry_Du 298308b7f3 fix(audio): 修复非高音质环境下 PCM 音频分片播放时的爆音问题
1. 移除 server.js 生成的每个音频分片携带的 44 字节 WAV 头,防止将其作为音频样本解码导致每 0.25 秒出现点击声 ('哒')。 2. 优化 playAudio 队列满时的轮询机制,从原先阻塞等待 speaker_audio_empty(会导致扬声器饥饿)改为使用 0.05 秒的定时器定期尝试,以保持缓冲区处于满载状态。 3. 同步修复了 station_broadcast-warning.lua 中潜在的相同轮询饥饿问题。 4. 版本号递增至 v1.0.62。
2026-08-16 11:32:00 +08:00
Henry_Du 6b1a531b77 fix(audio): 修复在没有高音质模块时,回退播放实时音频流产生刺耳噪音及可能导致卡死的问题 2026-08-15 23:30:09 +08:00
Henry_Du 2eddc9fefe 1.0.61 2026-08-15 23:13:10 +08:00
Henry_Du 51968cc825 fix(audio): 当扬声器不支持高音质时退回使用默认原版解码播放 2026-08-15 23:11:25 +08:00
Henry_Du 8f70c1f1d3 fix: 发车音乐列表过长时自动换行显示,修复 UI 溢出重叠问题 2026-08-04 13:13:03 +08:00
Henry_Du d8eee041c8 feat: 明确音频优先级,优化发车音频触发时机
- 到达与发车最高优先级(3),其次是进站预告(2),然后是延误警告(1),最低为背景音乐(0)

- 将发车音乐的触发时机从固定时间改为动态计算(音频时长+1.5秒补偿),确保音频结束时列车刚好发车

- 拆分 handleTrainApproaching 与 handleTrainAlert 逻辑,解耦进站与延误的优先级

- 版本号提升至 v1.0.59
2026-08-04 13:00:04 +08:00
Henry_Du 01ac488aef fix(client): 解决终端配置界面文字重叠与停站状态进站预告误报问题
1. 修复配置界面 UI 布局:当发车音乐可用列表过长时导致与后续输入提示重叠的问题,通过拆分显示并换行解决。
2. 彻底解决停站时误报进站预告:当 CC 电脑检测到当前站台已有列车停靠(`State.currentTrain ~= nil`)时,无论显示器上显示的是该站台的当前列车发车倒计时,还是被阻塞的下一班列车的到达倒计时,均强制抑制针对该站台的“进站预告”触发,直至站台被清空。
2026-08-04 11:29:45 +08:00
Henry_Du c86fca8449 feat(client): 全面增强站名模糊匹配逻辑,支持中英文混排关键词提取
1. 新增 `Utils.getKeywords(text)`:自动提取所有关键信息:
   - 包含中划线的字母数字组合(如 CE-03)
   - 连续的字母数字(如 CRH01)
   - 中文字符串,并在提取时自动过滤掉“站台”、“轨道”、“号”、“线”等噪音词。
2. 将 `Utils.getKeywords` 的匹配逻辑集成至 `Utils.isFuzzyMatch` 的最终校验中,即使在 `Utils.getBaseName` 无法精确比较的情况下,也能通过核心关键字(特别是纯中文关键字)判断两者是否为同一站台。
3. 将列车在站判定(`isAtStation`)对未知列车的目的站比较逻辑统一切换为使用强化的 `Utils.isFuzzyMatch`,保证时刻表、列车站名、NBT、显示器等来源的中英文站名信息均能互相精准匹配。
2026-08-04 07:42:57 +08:00
Henry_Du 6398146ee6 fix(client): 优化停站预告判断条件,彻底解决停站倒秒重复播报
修复由于列车时刻表中的目的站字符串与 NBT 或显示器获取到的目的地字符串不完全匹配,导致 `isAtStation` 判断失败的问题。
现在判断列车是否在站(`isAtStation`)主要依据 `trainName` 与 `State.currentTrain.id` 是否匹配。
对于未命名列车(如 ??? 或 Unknown),会额外通过模糊匹配或基础名称匹配目的地,从而保证当任何一列车在站台停留期间,系统正确识别它已停站,并忽略它因为离站倒数带来的 `etaSeconds > 0` 从而错误触发进站预告。
2026-08-04 07:37:11 +08:00
Henry_Du 86e58a5c59 feat(蜂鸣音频资源): 添加 fc2 至 fc14 共13个蜂鸣音效文件 2026-08-03 19:45:57 +08:00
Henry_Du aa10f0ebe1 chore(server): 屏蔽 HLS RTMP 推流失败的错误日志
由于当前环境未配置 RTMP 服务器,当 ffmpeg 尝试推送音频流到 127.0.0.1:1935 时会一直报错 `Connection refused` 从而导致控制台刷屏。
现将该错误日志注释屏蔽,使控制台保持清爽。
2026-08-03 12:35:16 +08:00
Henry_Du effcd30291 1 2026-08-03 12:33:59 +08:00
Henry_Du 3c25040a84 chore(client): 优化日志输出并清理测试代码
1. 引入全局 `CONFIG.DEBUG` 配置项(默认为 `false`),将所有 `Utils.log(DEBUG, ...)` 的大量扫描和推算日志默认隐藏,避免刷屏 CC 终端,需要时可通过配置文件开启。
2. 移除了排查 NBT 结构时添加的 `stop_dump.json` 导出逻辑,保持主机系统文件整洁。
2026-08-03 12:27:37 +08:00
Henry_Du fdbcfa3b9b fix(client): 优化停站时间获取,并在列车停站时禁用进站预告
1. 修复 `Utils.getStopTime` 和 `Utils.getNextStation` 会误匹配“非车站指令”(如修改最高速度等指令)中的文本的问题,现在仅在 `instruction.id == create:station`
或 `create:destination` 的条目中扫描,保证了 CC 电脑从 `create:track_station`
获取到的时刻表信息(包括计算出的停站时间)100% 准确。
2. 修复显示器(Display Board / NBT)在列车停站后依然显示“离站倒计时 ETA”,导致触发 `train_approaching` 的问题:如果当前列车已经在站内(`State.currentTrain` 存在且匹配),将强制忽略该列车的 `train_approaching` 触发逻辑,彻底解决列车停站时倒秒导致的重复播报。
2026-08-03 12:20:54 +08:00
Henry_Du 87fda31485 fix(client): 在 NBT 分支中也应用非车站指令过滤
将 `isStationDestination` 的过滤逻辑同时应用于 Block Reader(读取车站方块 NBT)的分支,
确保无论是通过显示屏还是 NBT 读取,都不会把“设置最高速度”等非停站指令当作列车进站播报。
同时已包含 `etaSeconds > 0` 修复,解决完全停站后重复播报的问题。
2026-08-03 12:09:08 +08:00
Henry_Du f846004091 fix(client): 过滤非车站指令并修复列车停站后重复播报进站预告的问题
1. 新增 `isStationDestination` 过滤器,在通过显示屏(Create Target)读取时刻表时,
   自动忽略包含“速度”、“重命名”、“时刻表”、“等待”、“卸载”等关键字的非车站指令,
   防止将这些指令当作车站并错误触发进站预告。
2. 修复显示屏读取到的负数 ETA 被错误解析为正数的问题(增加可选负号匹配)。
3. 将触发进站预告的条件从 `etaSeconds >= 0` 修改为 `etaSeconds > 0`。
   这样当列车完全停站(ETA=0或负数)时,将不再触发进站预告,彻底解决停站时间
   超过冷却期后导致的重复播报“进站预告”的问题。
2026-08-03 12:04:13 +08:00
Henry_Du 439ed9ea3c chore(client): 增加调试日志以导出 NBT stop 结构
用于排查非停站指令(如设置最高速度、新建时刻表区段)的 NBT 结构,
以便后续在代码中精准过滤这些非车站指令。
2026-08-03 11:28:32 +08:00
Henry_Du eb018dbae9 fix(client): 修复多个同名同目的地的列车互相清除 pending 状态的问题
当存在多个列车(如无名列车 ??? 开往同一目的地)时:
- 第二个 ETA 较远的列车会因为 `etaSeconds > 45` 走进 `else` 分支
- 原逻辑在 `else` 分支会直接清空该 key 的 pending 状态
- 导致排在前面的列车永远无法积累 5 秒的稳定期

修改:
1. 移除 `else` 分支,统一交由末尾的清理循环处理
2. 使用 `if not seenApproachKeys[announceKey]` 确保同一个 tick 只有 ETA 最近(排最前)的列车更新状态
2026-08-03 11:14:40 +08:00
Henry_Du 619d4e9a20 杂项(station_broadcast): 更新版本至v1.0.50并添加列车ETA调试日志
该调试日志会打印列车名称、ETA秒数、计时tick数及服务器tick率,仅在列车ETA不超过60秒且未触发过接近播报时输出,用于辅助排查列车接近播报的逻辑问题
2026-08-03 11:09:44 +08:00
Henry_Du 3c71d64f79 chore(station_broadcast): 升级版本至v1.0.49并调整ETA触发阈值
调整列车接近播报的ETA更新阈值,从3秒改为15秒以减少频繁触发
2026-08-03 10:40:12 +08:00
Henry_Du a36b21cfaf fix(server): 完善列车接近音频的处理与日志记录
新增列车接近音频入队和构建失败的日志输出
调整音频任务优先级为1,中断模式改为ifLower
修复音频构建为空时的静默失败问题
2026-08-03 10:22:04 +08:00
Henry_Du 101d392840 fix(CloudServer/server): 修复列车接近处理的ch序列遗漏的站台编号参数 2026-08-03 09:59:58 +08:00
Henry_Du c8681417a8 refactor(音频模块): 重构wav音频播放与解码逻辑
移除冗余的流式wav解码工具函数,复用现有decodeWavChunkToSamples
简化playChunkOnSpeakers实现,移除固定帧拆分逻辑与无用常量
优化音频日志与错误处理,解码失败时回退至HQ播放路径
调整应用版本号从v1.0.50回退至v1.0.47
2026-08-03 09:51:33 +08:00
Henry_Du bf1895ebc5 perf(audio): 优化音频播放帧处理逻辑,升级版本至v1.0.50
- 为test.lua添加标准文件头部注释
- 将station_broadcast.lua版本从v1.0.49更新至v1.0.50
- 新增NATIVE_AUDIO_FRAME_SAMPLES常量,将音频处理拆分为128样本每帧
- 修复空音频样本输入的边界异常问题
- 优化原生扬声器播放的循环逻辑,提升兼容性与执行效率
2026-08-03 09:49:01 +08:00
Henry_Du 394f81b9fa 1 2026-08-03 09:39:00 +08:00
Henry_Du 5fb81e3998 feat(audio): 实现流式WAV解码器并优化音频播放逻辑
将应用版本更新至v1.0.48;新增WAV头部解析与流式解码逻辑,替换原有的单块解码方案;添加扬声器speakWav兼容性检测,无支持设备时输出错误日志;优化WAV解码错误处理与日志输出,仅首次打印音频格式信息。
2026-08-03 09:37:00 +08:00
Henry_Du e89b82a8b4 1 2026-08-03 09:27:51 +08:00
Henry_Du 5dbd3d667f fix: restore speaker peripheral detection
Re-add speaker discovery during peripheral init so installed speakers are available for playback and log the detected count at startup.
2026-08-03 09:24:58 +08:00
Henry_Du 6964e7a47d refactor(station_broadcast): 清理冗余代码与注释,移除无用文件并更新gitignore
- 清理station_broadcast.lua中的冗余注释、废弃代码块,移除无用的节分隔注释
- 删除不再使用的austream.lua文件
- 更新.gitignore,新增临时文件与转储文件的忽略规则
2026-08-02 22:03:06 +08:00
Henry_Du 59865138c7 11 2026-08-02 21:26:41 +08:00
Henry_Du b2888c6c88 chore(安装脚本与文档): 修改安装脚本下载源并新增教程视频
将install_station_broadcast.lua中的旧下载地址替换为gitea仓库的https新源,同时新增FSE铁路广播系统教程视频文件
2026-08-02 21:24:57 +08:00
Henry_Du aef63ca444 fix: install updater alongside startup script
Download the update helper during install and expose it from the cloud server so new hosts can run manual updates immediately.
2026-08-02 21:20:28 +08:00
Henry_Du 10d15dfddc feat: add station auto update publishing
Publish the latest station script from the console so online hosts download and reboot immediately while offline hosts update on their next load.
2026-08-02 20:04:55 +08:00
Henry_Du 52a643a868 tune: shorten delay alert confirmation to 15 seconds 2026-08-02 19:48:01 +08:00
Henry_Du e29cc0c2ba tune: trigger approaching announcement earlier 2026-08-02 19:34:27 +08:00
Henry_Du 73f0ba8e69 tune: trigger stable approaching announcement at 45 seconds 2026-08-02 19:29:26 +08:00
Henry_Du 22ea43c1c1 tune: stabilize approaching trigger and show precise ETA 2026-08-02 19:25:57 +08:00
Henry_Du fb1256fbcc tune: add delay confirmation and approaching cooldown 2026-08-02 19:22:01 +08:00
Henry_Du 04591fc0c8 fix: dedupe delay alerts to reduce music stutter 2026-08-02 19:19:00 +08:00
Henry_Du 906594008a fix: remove ch-min from delay announcement 2026-08-02 19:06:20 +08:00
Henry_Du 126aaaf02f fix: trigger delay alerts from displayed CRN delay 2026-08-02 19:04:10 +08:00
Henry_Du 278de7de6b feat: announce delay alerts as soon as they appear 2026-08-02 18:58:54 +08:00
Henry_Du ea22c79008 fix: rename Japanese delay reason audio files 2026-08-02 18:52:43 +08:00
Henry_Du 39dc446958 功能(站点广播): 实现延误与停运列车的双语广播功能
添加所有中日文广播所需的音频资源文件
将应用版本更新至v1.0.37
修复列车状态原因映射逻辑,补充广播所需的缺失字段
实现根据延误、停运状态生成对应双语广播序列的逻辑
更新测试脚本以适配区块阅读器并正确解析CRN的NBT数据
添加示例NBT转储文件作为参考
2026-08-02 18:50:49 +08:00
Henry_Du f922ace154 fix: trigger approaching broadcast under 30 seconds 2026-08-02 17:42:49 +08:00
Henry_Du b7be4cd00d fix: use NBT ETA and clean monitor debug output 2026-08-02 17:33:05 +08:00
Henry_Du 9060e79006 fix: use earlier realtime tick for arrival ETA 2026-08-02 17:14:51 +08:00
Henry_Du 426e55a7f0 fix: normalize upcoming ETA keys before text override 2026-08-02 17:11:31 +08:00
Henry_Du db818209f2 debug: show raw create target line and eta fields 2026-08-02 17:08:59 +08:00
Henry_Du a1db54b295 fix: parse CRN ETA as value plus unit 2026-08-02 17:05:53 +08:00
Henry_Du 96222ebf06 debug: expand text ETA parsing and show raw eta string 2026-08-02 17:03:43 +08:00
Henry_Du 9f2dc5bb3d debug: compare text and NBT ETA keys on monitor 2026-08-02 17:00:24 +08:00
Henry_Du 4b95c86af6 fix: align NBT destination with CRN display stopovers 2026-08-02 16:55:15 +08:00
Henry_Du 432b82eae9 feat: prefer CRN display ETA text when available 2026-08-02 16:48:42 +08:00
Henry_Du 23196cd59d fix: compute ETA using measured tick rate 2026-08-02 16:44:12 +08:00
Henry_Du ea288b6572 feat: show delay reason/status from CRN NBT on monitor 2026-08-02 16:41:01 +08:00
Henry_Du 61576a7d9e fix: detect advanced peripherals block reader by type or method 2026-08-02 16:33:50 +08:00
Henry_Du b725c74e1d debug: add upcoming trains data probe 2026-08-02 16:31:07 +08:00
Henry_Du c13a0c9dcc fix: avoid monitor log overlap and show upcoming status 2026-08-02 16:24:32 +08:00
Henry_Du 5134a4ebf0 fix: restore main loop block structure 2026-08-02 16:22:44 +08:00
Henry_Du 544179758e fix: restore goto label required by earlier logic 2026-08-02 16:19:56 +08:00
Henry_Du 95e550441e fix: ensure trailing newline at end of file 2026-08-02 16:17:33 +08:00
Henry_Du 8a431147ec fix: remove unused goto continue label causing lint error 2026-08-02 16:15:23 +08:00
Henry_Du d28b0eec30 fix: correctly assign State.upcomingTrains before display link fallback 2026-08-02 16:10:52 +08:00
Henry_Du ad70f4adbc feat: display upcoming trains and delay info on monitor 2026-08-02 16:07:48 +08:00
Henry_Du e92348b4db feat: add real-time ETA interpolation for block reader 2026-08-02 16:04:41 +08:00
Henry_Du 13dc054a01 feat: use block reader for accurate ETA and delay data 2026-08-02 15:57:14 +08:00
Henry_Du c573260e5d feat: Implement exact 45s pre-arrival broadcast by delaying 1min signal 2026-08-02 14:59:07 +08:00
Henry_Du dbf259efe5 fix: Re-enable train pre-arrival broadcast on '1 min' to provide sufficient advance notice 2026-08-02 12:08:16 +08:00
Henry_Du 5c899b30bb fix: Trigger train pre-arrival broadcast only on '现在' or '0' instead of '1 min' 2026-08-02 12:02:44 +08:00
Henry_Du 53b4d1b296 fix: Reduce train pre-arrival debounce timeout to 1 minute 2026-08-02 11:57:57 +08:00
Henry_Du b52776fe09 fix: Reduce train pre-arrival debounce timeout to 2.5 minutes 2026-08-02 11:56:20 +08:00
Henry_Du 43a2a4deaf fix: Increase train pre-arrival debounce timeout to 5 minutes to prevent multiple broadcasts for fuzzy ETA 2026-08-02 11:54:23 +08:00
Henry_Du 712d8bb84d fix: Ensure platform is stripped of non-digit chars for audio file matching 2026-08-02 11:52:27 +08:00
Henry_Du 26003844b9 特性(音频与脚本): 添加8条语音音频文件与火车站点监测脚本
添加4条中文、4条日文语音音频文件,新增脚本用于ComputerCraft下的Create模组火车站点监测
2026-08-02 11:45:24 +08:00
Henry_Du ef75671527 feat: Add train pre-arrival broadcast via CRN create_target 2026-08-02 11:37:41 +08:00
Henry_Du 805aba9f37 fix: remove 3.0 fallback and strictly apply AUDIO_VOLUME=100 directly to HQ speaker APIs 2026-08-02 09:07:12 +08:00
Henry_Du faa25bbb3c fix: safely apply CONFIG.AUDIO_VOLUME to all HQ speaker APIs (speakWavAll, speakHLS, etc.) with 3.0 fallback 2026-08-02 08:57:20 +08:00
Henry_Du ac8405e300 fix: use pcall to uncapped AUDIO_VOLUME for HQ speakers while keeping 3.0 fallback for vanilla speakers 2026-08-02 08:53:49 +08:00
Henry_Du 832658ad58 feat: apply 5x volume boost to all FFmpeg audio processing (broadcast sequences, HLS, DFPWM) to maximize loudness 2026-08-02 08:50:28 +08:00
Henry_Du 8aec4c6a84 chore: set default AUDIO_VOLUME to 100 for maximum HQ speaker distance/volume (v1.0.19) 2026-08-02 08:42:13 +08:00
Henry_Du fb49925a9b chore(Audio/voice): 更新日语语音文件ja-zt.wav 2026-08-02 08:21:04 +08:00
Henry_Du 66ce214f51 Perf: fix audio playback stuttering by increasing pre-buffer to 5 chunks and optimizing multi-speaker synchronization without forced gaps 2026-08-01 23:19:37 +08:00
Henry_Du 944f00f521 Fix: correctly parse nextStation by checking both create:station and create:destination, and handle schedule loop 2026-08-01 23:10:06 +08:00
Henry_Du 90c108b1d7 Update: remove ja-xl and ch-line from train arrival broadcast sequence 2026-08-01 23:05:39 +08:00
Henry_Du 01b367fa8b 杂项(Audio/voice): 更新一批语音音频文件 2026-08-01 23:02:10 +08:00
Henry_Du 4b3bd91023 Fix: implement case-insensitive file matching for broadcast audio sequences to fix missing uppercase line and station names 2026-08-01 22:54:10 +08:00
Henry_Du 2fae7305f6 Fix: use filter_complex for sequence concatenation to fix sample rate mismatch causing speed up and noise 2026-08-01 22:46:23 +08:00
Henry_Du e009f05a61 Fix: use wav-stream-live for train arrivals and departures to fix CC client audio playback 2026-08-01 22:34:29 +08:00
Henry_Du 81f58b58bb Fix: Lua client config screen overwritten by logs, and fix temp broadcast preview URL 2026-08-01 22:15:59 +08:00
Henry_Du 5c78b20163 Fix: include audioLineDir and audioVoiceDir when building broadcast sequence 2026-08-01 22:09:40 +08:00
Henry_Du 1043d46fb8 Fix: correctly setup line audio directory, routing, and upload handling 2026-08-01 18:41:29 +08:00
Henry_Du 440a8366ca Feat: CC client auto-detects and displays available departure beeps from server 2026-08-01 18:37:52 +08:00
Henry_Du 495b3cedb9 Fix: save line audio to voice directory instead of beep 2026-08-01 18:30:59 +08:00
Henry_Du 2741b2d321 Revert TTS generation to backend with fixed local proxy 127.0.0.1:7890 2026-08-01 18:25:50 +08:00
Henry_Du c76538e4bd feat: switch to client-side fetch for Fish Audio API to bypass server network restrictions 2026-08-01 17:58:20 +08:00
Henry_Du a516976e35 Revert "feat: use pure direct connection to official api.fish.audio without any forced proxies"
This reverts commit 3ecae7b0bc.
2026-08-01 17:57:00 +08:00
Henry_Du 3ecae7b0bc feat: use pure direct connection to official api.fish.audio without any forced proxies 2026-08-01 17:55:30 +08:00
Henry_Du b8aee4d766 fix: revert to server proxy logic and add resilient fallback for win32 to prevent 500 errors 2026-08-01 17:51:08 +08:00
Henry_Du 038662c15e Revert "feat: switch to client-side fetch for Fish Audio API to bypass server network restrictions"
This reverts commit dedb37e22b.
2026-08-01 17:49:57 +08:00
Henry_Du dedb37e22b feat: switch to client-side fetch for Fish Audio API to bypass server network restrictions 2026-08-01 17:45:48 +08:00
Henry_Du 1b6a2b7e33 feat: switch Fish Audio API endpoint to user's custom proxy domain (fishaudio.fse-media.group) 2026-08-01 17:42:24 +08:00
Henry_Du 7bfff51919 revert: switch back to direct Fish Audio API due to Vercel IP block 2026-08-01 17:37:52 +08:00
Henry_Du f4c22cb713 feat: switch Fish Audio API endpoint to Vercel proxy to resolve ETIMEDOUT issues on server 2026-08-01 17:34:55 +08:00
Henry_Du 52ecdc8a16 Revert "fix: remove hardcoded windows proxy fallback that causes 500 error when proxy is unavailable"
This reverts commit 62ecf5642b.
2026-08-01 16:00:00 +08:00
Henry_Du 62ecf5642b fix: remove hardcoded windows proxy fallback that causes 500 error when proxy is unavailable 2026-08-01 15:57:30 +08:00
Henry_Du 6150050f69 revert: move TTS generation back to server-side due to CORS issues 2026-08-01 12:01:38 +08:00
Henry_Du 6f122c7a2c feat: add FISH_AUDIO_BASE env support for reverse proxy 2026-08-01 11:59:15 +08:00
Henry_Du e3a88acf9b Revert "feat: migrate TTS generation to frontend to utilize local browser proxy"
This reverts commit 5e600bb75d.
2026-08-01 11:58:20 +08:00
Henry_Du 5e600bb75d feat: migrate TTS generation to frontend to utilize local browser proxy 2026-08-01 11:55:31 +08:00
Henry_Du 1d0c0e0703 fix: fallback to 127.0.0.1:7890 proxy on windows for local TTS generation 2026-08-01 11:50:18 +08:00
Henry_Du c0f100a833 fix(console): map Beep files to Audio/beep
Store and present Beep assets under Audio/beep while keeping legacy Audio/general reads working so existing files remain accessible during the directory transition.
2026-08-01 11:42:38 +08:00
Henry_Du 545c19335f ksts 2026-08-01 11:34:52 +08:00
Henry_Du 86b6ba180e feat: implement train arrival/departure sequence logic and add departure beep config in client 2026-08-01 11:28:52 +08:00
Henry_Du 810dff3f0e feat: update station broadcast logic 2026-08-01 11:23:55 +08:00
Henry_Du e66f39284f feat: Add Line Audio Generation and Line List Manager 2026-08-01 11:20:58 +08:00
Henry_Du b140aafa2d fix(audio): prebuffer live wav stream startup
Buffer a couple of live wav chunks before beginning playback so startup jitter is reduced when the stream first begins feeding speakers.
2026-08-01 11:11:22 +08:00
Henry_Du eb0adfc2e0 feat: handle line.txt and train arrival/departure events 2026-08-01 11:10:17 +08:00
Henry_Du a990a2da0c fix(console): align music upload field name
Use the musicAudioFiles form field on music.html so the page matches the multer configuration for /api/upload/music-audio and stops returning Unexpected field.
2026-08-01 11:04:13 +08:00
Henry_Du a92fb55f60 fix(station): detect create stations by capability
Use the Create station method set from the CC:Tweaked integration docs to identify attached train stations even when the peripheral type string is not reported as train_station.
2026-08-01 10:46:26 +08:00
Henry_Du b51e31e00f fix(station): sync identity config from physical station
Detect train station peripherals from all discovered names and automatically write station_identity.cfg from the physical station identity so attached main hosts stop falling back to manual slave setup.
2026-08-01 10:27:36 +08:00
Henry_Du 777e6f3371 fix(station): detect train station peripherals on any side
Avoid prompting manual slave setup on main hosts when the train station block is attached somewhere other than the back side, and log the detected side for easier diagnosis.
2026-08-01 09:45:13 +08:00
Henry_Du f7de7717dc fix(tts): rename japanese station audio suffix to ja
Switch generated station audio entries from en-* to ja-* and update the generator flow so Chinese plus Japanese audio imports use the new suffix consistently.
2026-08-01 09:02:18 +08:00
Henry_Du a2408da417 feat(tts): switch broadcast generation to s2.1-pro-free
Update the generator and temp broadcast flows to send the new Fish Audio model and reference IDs so Chinese and secondary-language audio use the latest requested voice configuration.
2026-08-01 08:50:13 +08:00
Henry_Du 529c871b0e fix(station): allow music to restart after stop
Keep the active music stream attached until Audio.stop runs so stop requests finish the stream reader cleanly and the next music playback can start again without getting stuck behind the previous stream.
2026-08-01 08:36:01 +08:00
Henry_Du 69badb6853 feat(console): adapt main console for mobile screens
Stack the console layout vertically on smaller screens, wrap the action toolbar, collapse file rows into compact mobile cards, and make the bottom console, modal, and toast areas usable on phones without desktop splitters.
2026-08-01 08:26:50 +08:00
Henry_Du 578cff6dc2 feat(station): allow slave nodes to run without monitors
Make monitors optional so slave nodes can boot and play audio in terminal-only mode, while still using the monitor UI automatically when one is present.
2026-08-01 07:59:06 +08:00
Henry_Du 918e0c68e5 feat(station): add first-run slave identity setup
Remove station_name from the slave identity config and prompt for station code and platform on startup when no train station peripheral and no usable identity file are present, so slave nodes can be configured interactively on first boot.
2026-08-01 07:54:56 +08:00
Henry_Du 6315e1eaa1 feat(station): support manual identity for slave nodes
Allow station_broadcast to run without a train station peripheral on the back, add a local station_identity.cfg override for station name/code/platform, and display the active station code, platform, and identity mode so slave nodes can be grouped to a platform manually.
2026-08-01 07:51:59 +08:00
Henry_Du 304d413482 feat(station): group slave nodes by station target
Merge stations with the same station code and platform into one logical target, and expand music and temp broadcast playback to all online slave nodes while the console and picker UIs show grouped station entries with node counts.
2026-08-01 07:44:38 +08:00
Henry_Du fd53eaef97 feat(console): add voice folder to file manager
Add an Audio/voice directory with upload and preview support, and expose it in the console file manager so the structure now shows Configuration, Music, Voice, Beep, and Station.
2026-08-01 07:21:47 +08:00
Henry_Du 1f4be7c10b feat(console): split audio files into music and beep folders
Add an Audio/music path for uploaded music, keep the existing general audio directory as the Beep group, and update the console and music page so the file manager now shows Configuration, Music, Beep, and Station with matching upload and preview routes.
2026-08-01 07:18:14 +08:00
Henry_Du 1554adf5f1 feat(audio): support more upload and music formats
Allow the console and music page to upload common audio formats, expand music track detection and playback source selection beyond wav/dfpwm, and update station list name normalization so common extensions resolve consistently. Bump the station build to v1.0.6.
2026-08-01 06:39:18 +08:00
Henry_Du 6610b168d7 fix(music): synchronize multi-speaker wav streaming
Bump the station build to v1.0.5, reduce live WAV chunks to 0.25 seconds, and queue decoded samples in a synchronized multi-speaker mode so multiple speakers stay aligned during streaming playback.
2026-08-01 00:25:26 +08:00
Henry_Du 841f127005 fix(music): smooth wav chunk streaming playback
Bump the station build to v1.0.4, reduce live WAV chunk size to 0.5 seconds, and keep native speaker queues fed during streaming instead of draining after every chunk so playback is less jittery and stays closer to real time.
2026-08-01 00:21:39 +08:00
Henry_Du 43962aceb0 fix(station): prefer native speaker.playAudio for decoded chunks
Bump the station build to v1.0.3 and send decoded WAV samples through each speaker's native playAudio path before falling back to controller.playAudioAll, with logs to show which output path was used.
2026-08-01 00:18:06 +08:00
Henry_Du e6fa681339 fix(station): decode wav chunks to speaker samples
Bump the station build to v1.0.2 and decode streamed WAV chunks into PCM samples on the client before feeding playAudioAll/playAudio, while keeping the HQ WAV path as a fallback for decode failures.
2026-08-01 00:04:18 +08:00
Henry_Du f09e5af698 修复git钩子 2026-07-31 23:49:50 +08:00
Henry_Du 447388662b 修改版本号 2026-07-31 23:33:01 +08:00
Henry_Du 5d2397db7c feat(station): add visible build version reporting
Add a station build version counter, show it on the monitor and terminal header, log it at startup, and report it to the server during register and heartbeat so deployed client versions are visible during troubleshooting.
2026-07-31 23:30:41 +08:00
Henry_Du 87e45de15b fix(music): add wav chunk diagnostics and larger chunks
Increase live WAV chunk size to one second and log chunk acceptance, queue depth, and retry state on stations so the HQ speaker path can be diagnosed from runtime logs.
2026-07-31 22:46:47 +08:00
Henry_Du f7755953b4 feat(music): stream live wav chunks to HQ speakers
Slice realtime WAV audio into small self-contained chunks on the server and feed them into the HQ speaker WAV queue on stations so music can start playing before the full file finishes transferring.
2026-07-31 22:08:11 +08:00
Henry_Du d86c74f0cc fix(music): stream live dfpwm instead of pcm
Move live music streaming back onto the proven DFPWM playback path and silently ignore legacy train_arrival, train_departure, and play_sequence messages from older station clients so they no longer spam logs.
2026-07-31 22:03:35 +08:00
Henry_Du 218aaabb50 fix(station): remove arrival and departure preview audio flow
Delete the station-side arrival/departure announcement requests and drop the server handlers for train arrival, train departure, and play_sequence messages so preview audio no longer interrupts live music.
2026-07-31 21:53:12 +08:00
Henry_Du fd154afd82 fix(music): remove HLS fallback from station playback
Keep music playback on the direct PCM or DFPWM paths so music requests no longer trigger RTMP/HLS push attempts when a WAV source is unavailable.
2026-07-31 21:17:04 +08:00
Henry_Du 709388ec3a feat(music): switch station music to live PCM streaming
Move music playback off the HLS/download-first path and stream 48k mono PCM chunks over WebSocket so stations can start playing immediately. Add station-side PCM chunk playback support and stream lifecycle logging to make no-audio issues easier to trace.
2026-07-31 21:00:29 +08:00
Henry_Du 6d65b8216a feat(station-broadcast, cloud-server): 添加HLS播放与循环播放支持,更新脚本拉取地址
调整两个工具脚本的远程拉取地址,将固定commit哈希链接改为main分支链接;为云服务端添加loop参数与HLS音频播放支持,重构音频播放逻辑简化冗余代码;为station_broadcast.lua新增hls格式支持与循环播放控制,完善网络消息参数处理。
2026-07-31 20:42:22 +08:00
Henry_Du 3f58d03d15 feat(media server & broadcast): 新增/media接口并修复广播音频处理问题
- 新增/media GET接口,返回可用的媒体路由信息
- 为音频下载成功添加info日志,显示下载字节数
- 修正扬声器调用结果的条件判断逻辑
- 修复HQ扬声器音频提交失败的日志文案
2026-07-31 20:25:00 +08:00
Henry_Du 3bcc04332a feat(station_broadcast): 新增远程音频流下载与mp3、ogg格式播放支持
新增downloadAudioBytes工具函数用于从远程URL下载音频数据并提取文件扩展名
重构stream格式音频的处理逻辑,先下载资源再根据扩展名适配播放格式
补充mp3和ogg格式的播放适配,覆盖主扬声器控制器与单个扬声器
2026-07-31 20:20:32 +08:00
Henry_Du 952efbc2c7 feat: add stream audio broadcast support
- 添加stream音频格式的客户端播放逻辑与网络消息解析
- 新增云服务端媒体静态服务端点,重构音频处理逻辑以返回流URL替代原始音频缓冲区
- 更新所有相关业务接口适配新的流音频播放流程
- 新增API基础地址环境变量配置
2026-07-31 20:15:21 +08:00
Henry_Du cd22b1ca3e feat: 新增列表文件访问端点并兼容旧路径
服务器新增/list.txt接口提供列表文件访问,客户端优先请求该路径,失败时回退到原/uploads/list.txt路径
2026-07-31 20:02:24 +08:00
Henry_Du fcf6970e90 delet startCtmClient() 2026-07-31 19:45:38 +08:00
Henry_Du f530d7e045 refactor: 重构文件存储路径并清理冗余代码
- 将项目文件存储从 public/uploads 迁移至项目根目录专用目录
- 更新所有前端页面的路径提示文本与API请求路径
- 移除冗余的列车详情展开收起功能及相关代码
- 重构服务器端文件路径处理逻辑,增强路径访问安全性
- 清理旧注释和未使用的变量与函数
2026-07-31 19:41:26 +08:00
Henry_Du d6e5ce5a93 feat: 重构音频系统,移除外部依赖并新增WAV格式支持
- 移除install和update脚本中的aukit/austream下载配置与目标,不再部署辅助脚本
- 替换station_broadcast.lua的aukit库为CC内置dfpwm模块,重写音频播放逻辑
- 添加原生扬声器API支持,支持WAV格式音频播放
- 重写云端服务器音频处理逻辑,支持直接传输WAV文件无需预转换
- 新增WAV文件时长解析、音频序列合成等辅助功能
2026-07-31 19:30:25 +08:00
Henry_Du c73bceaec7 feat: 重构音频系统,移除外部依赖并新增WAV格式支持
- 移除install和update脚本中的aukit/austream下载配置与目标,不再部署辅助脚本
- 替换station_broadcast.lua的aukit库为CC内置dfpwm模块,重写音频播放逻辑
- 添加原生扬声器API支持,支持WAV格式音频播放
- 重写云端服务器音频处理逻辑,支持直接传输WAV文件无需预转换
- 新增WAV文件时长解析、音频序列合成等辅助功能
2026-07-31 19:29:38 +08:00
191 changed files with 10197 additions and 5353 deletions
+9 -1
View File
@@ -3,4 +3,12 @@
list.txt
CloudServer/node_modules/
CloudServer/tmp/
CloudServer/server-data.json
CloudServer/server-data.json
Audio/general/
Audio/music/
Audio/station/
tmp_vercel_proxy/
nbt_dump.txt
test.lua
temp-broadcast/
debug-upcoming-data-missing.md
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More