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
This commit is contained in:
2026-08-16 12:41:19 +08:00
parent 34d9ed00d6
commit 32b2c8ce9d
2 changed files with 117 additions and 53 deletions
+17 -7
View File
@@ -2139,7 +2139,10 @@ function handleTrainArrival(ws, data) {
const lineCode = data.lineCode || (stationCode ? stationCode.split('-')[0] : 'UNK');
const destCode = data.destCode || getStationCodeFromName(data.destination) || 'UNK';
const nextCode = data.nextCode || getStationCodeFromName(data.nextStation) || 'UNK';
const nextStationRaw = data.nextStation ? String(data.nextStation).trim() : '';
const nextCodeRaw = data.nextCode ? String(data.nextCode).trim() : (nextStationRaw ? getStationCodeFromName(nextStationRaw) : '');
const hasNextStation = nextStationRaw && nextStationRaw !== '' && nextCodeRaw && nextCodeRaw !== 'UNK' && nextCodeRaw !== '';
const finalNextCode = hasNextStation ? nextCodeRaw : null;
const existingIndex = activeTrains.findIndex(t => t.trainId === trainId);
const trainData = {
@@ -2155,7 +2158,7 @@ function handleTrainArrival(ws, data) {
activeTrains.push(trainData);
}
log('INFO', `Train ${trainId} arrived at ${stationName}. Broadcasting...`);
log('INFO', `Train ${trainId} arrived at ${stationName}. Broadcasting... nextStation=${nextStationRaw || '(none/terminal)'} nextCode=${finalNextCode || '(none)'}`);
saveData();
broadcastUpdate();
@@ -2173,11 +2176,18 @@ function handleTrainArrival(ws, data) {
}));
// Broadcast Audio Logic
const seq = [
'ksts',
`ja-${finalPlatform}`, 'ja-zt', `ja-${lineCode}`, `ja-${destCode}`, 'ja-to', 'ja-nextsta', `ja-${nextCode}`, 'ja-warn',
`ch-${finalPlatform}`, 'ch-zt', `ch-${lineCode}`, 'ch-to', `ch-${destCode}`, 'ch-nextsta', `ch-${nextCode}`, 'ch-warn'
];
const seq = ['ksts'];
if (finalNextCode) {
seq.push(
`ja-${finalPlatform}`, 'ja-zt', `ja-${lineCode}`, `ja-${destCode}`, 'ja-to', 'ja-nextsta', `ja-${finalNextCode}`, 'ja-warn',
`ch-${finalPlatform}`, 'ch-zt', `ch-${lineCode}`, 'ch-to', `ch-${destCode}`, 'ch-nextsta', `ch-${finalNextCode}`, 'ch-warn'
);
} else {
seq.push(
`ja-${finalPlatform}`, 'ja-zt', `ja-${lineCode}`, `ja-${destCode}`, 'ja-warn',
`ch-${finalPlatform}`, 'ch-zt', `ch-${lineCode}`, 'ch-to', `ch-${destCode}`, 'ch-warn'
);
}
enqueueHlsPush(stationName, seq);
+100 -46
View File
@@ -1,6 +1,6 @@
-- 1. Configuration & Constants
local APP_VERSION_TEXT = "v1.0.69"
local APP_VERSION_TEXT = "v1.0.70"
local CONFIG = {
CLOUD_URL = "ws://stabadmin.fse-media.group",
@@ -975,7 +975,6 @@ function Utils.getNextStation(schedule, currentStationName)
end
if matchFoundIndex then
-- Search forward
for i = matchFoundIndex + 1, maxIdx do
local entry = schedule.entries[i]
if entry and entry.instruction then
@@ -985,16 +984,6 @@ function Utils.getNextStation(schedule, currentStationName)
end
end
end
-- Loop around to beginning
for i = 1, matchFoundIndex - 1 do
local entry = schedule.entries[i]
if entry and entry.instruction then
local inst = entry.instruction
if inst.id == "create:station" or inst.id == "create:destination" then
return (inst.data and inst.data.text) or inst.text
end
end
end
end
return nil
@@ -3053,6 +3042,99 @@ local function isStationDestination(destName)
return true
end
local function looksLikeValidDestinationText(text)
if not text then return false end
local s = tostring(text)
if s == "" then return false end
local lower = string.lower(s)
if lower == "unknown" then return false end
local questionMarkCount = 0
for i = 1, #s do
local c = string.sub(s, i, i)
if c == "?" then questionMarkCount = questionMarkCount + 1 end
end
if #s > 0 and questionMarkCount / #s >= 0.5 then return false end
local hasRealChar = false
for i = 1, #s do
local b = string.byte(s, i)
if b and b >= 48 and b <= 57 then hasRealChar = true break end
if b and b >= 65 and b <= 90 then hasRealChar = true break end
if b and b >= 97 and b <= 122 then hasRealChar = true break end
if b and b >= 128 then hasRealChar = true break end
end
if not hasRealChar then return false end
return isStationDestination(s)
end
local function tryCorrectUpcomingEntryWithCurrentTrain(entry)
if not State.currentTrain or not entry then return entry end
local ctId = State.currentTrain.id
local ctDest = State.currentTrain.dest
local ctPlatform = tostring(State.stationPlatform or State.currentTrain.platform or "1")
local entryPlatform = tostring(entry.platform or "1")
local samePlatform = (entryPlatform == ctPlatform)
local sameTrain = false
if ctId and entry.trainName then
sameTrain = Utils.isSameTrain(ctId, entry.trainName)
end
if not sameTrain and not samePlatform then return entry end
local validId = looksLikeValidDestinationText(entry.trainName)
local validDest = looksLikeValidDestinationText(entry.dest)
if not validId and ctId and ctId ~= "" then
entry.trainName = ctId
end
if not validDest and ctDest and ctDest ~= "" then
entry.dest = ctDest
elseif sameTrain and ctDest and ctDest ~= "" then
if not Utils.isFuzzyMatch(entry.dest or "", ctDest) then
local entryDestValid = looksLikeValidDestinationText(entry.dest)
if not entryDestValid then
entry.dest = ctDest
end
end
end
return entry
end
local function checkIsAtStationWithCurrentTrain(trainName, destination, platform)
if not State.currentTrain then return false end
local ctId = State.currentTrain.id
local ctDest = State.currentTrain.dest
local ctPlatform = tostring(State.stationPlatform or State.currentTrain.platform or "1")
local trainPlatform = tostring(platform or "1")
if trainPlatform == ctPlatform then
return true
end
local sameTrain = false
if ctId and trainName then
if ctId == trainName then
sameTrain = true
else
local validCT = looksLikeValidDestinationText(ctId)
local validEntry = looksLikeValidDestinationText(trainName)
if validCT and validEntry then
sameTrain = Utils.isSameTrain(ctId, trainName)
elseif (not validEntry) and validCT then
sameTrain = Utils.isFuzzyMatch(ctDest or "", destination or "")
end
end
end
if sameTrain then
local entryIdValid = looksLikeValidDestinationText(trainName)
if entryIdValid then
return true
else
if Utils.isFuzzyMatch(ctDest or "", destination or "") then
return true
end
if not looksLikeValidDestinationText(destination) then
return true
end
end
end
return false
end
function Main.loop()
while true do
local now = os.epoch("utc")
@@ -3204,23 +3286,7 @@ function Main.loop()
end
end
local isAtStation = false
local trainPlatform = tostring(platform or State.stationPlatform or "1")
local currentPlatform = tostring(State.stationPlatform or "1")
if State.currentTrain then
if trainPlatform == currentPlatform then
isAtStation = true
elseif State.currentTrain.id == trainName then
if trainName == "???" or trainName == "Unknown" or trainName == "" then
if Utils.isFuzzyMatch(State.currentTrain.dest, destination) then
isAtStation = true
end
else
isAtStation = true
end
end
end
local isAtStation = checkIsAtStationWithCurrentTrain(trainName, destination, platform)
if not isAtStation and etaSeconds > 0 and etaSeconds <= 45 then
if not seenApproachKeys[announceKey] then
seenApproachKeys[announceKey] = true
@@ -3358,23 +3424,7 @@ function Main.loop()
end
end
local isAtStation = false
local trainPlatform = tostring(platform or State.stationPlatform or "1")
local currentPlatform = tostring(State.stationPlatform or "1")
if State.currentTrain then
if trainPlatform == currentPlatform then
isAtStation = true
elseif State.currentTrain.id == tName then
if tName == "???" or tName == "Unknown" or tName == "" then
if Utils.isFuzzyMatch(State.currentTrain.dest, dest) then
isAtStation = true
end
else
isAtStation = true
end
end
end
local isAtStation = checkIsAtStationWithCurrentTrain(tName, dest, platform or State.stationPlatform or "1")
if not isAtStation and etaSeconds > 0 and etaSeconds <= 45 then
if not seenApproachKeys[announceKey] then
seenApproachKeys[announceKey] = true
@@ -3424,6 +3474,10 @@ function Main.loop()
end
for _, entry in ipairs(newUpcoming) do
tryCorrectUpcomingEntryWithCurrentTrain(entry)
end
State.upcomingTrains = newUpcoming
if not Peripherals.station then