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:
+17
-7
@@ -2139,7 +2139,10 @@ function handleTrainArrival(ws, data) {
|
|||||||
|
|
||||||
const lineCode = data.lineCode || (stationCode ? stationCode.split('-')[0] : 'UNK');
|
const lineCode = data.lineCode || (stationCode ? stationCode.split('-')[0] : 'UNK');
|
||||||
const destCode = data.destCode || getStationCodeFromName(data.destination) || '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 existingIndex = activeTrains.findIndex(t => t.trainId === trainId);
|
||||||
const trainData = {
|
const trainData = {
|
||||||
@@ -2155,7 +2158,7 @@ function handleTrainArrival(ws, data) {
|
|||||||
activeTrains.push(trainData);
|
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();
|
saveData();
|
||||||
broadcastUpdate();
|
broadcastUpdate();
|
||||||
|
|
||||||
@@ -2173,11 +2176,18 @@ function handleTrainArrival(ws, data) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Broadcast Audio Logic
|
// Broadcast Audio Logic
|
||||||
const seq = [
|
const seq = ['ksts'];
|
||||||
'ksts',
|
if (finalNextCode) {
|
||||||
`ja-${finalPlatform}`, 'ja-zt', `ja-${lineCode}`, `ja-${destCode}`, 'ja-to', 'ja-nextsta', `ja-${nextCode}`, 'ja-warn',
|
seq.push(
|
||||||
`ch-${finalPlatform}`, 'ch-zt', `ch-${lineCode}`, 'ch-to', `ch-${destCode}`, 'ch-nextsta', `ch-${nextCode}`, 'ch-warn'
|
`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);
|
enqueueHlsPush(stationName, seq);
|
||||||
|
|
||||||
|
|||||||
+100
-46
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
-- 1. Configuration & Constants
|
-- 1. Configuration & Constants
|
||||||
local APP_VERSION_TEXT = "v1.0.69"
|
local APP_VERSION_TEXT = "v1.0.70"
|
||||||
|
|
||||||
local CONFIG = {
|
local CONFIG = {
|
||||||
CLOUD_URL = "ws://stabadmin.fse-media.group",
|
CLOUD_URL = "ws://stabadmin.fse-media.group",
|
||||||
@@ -975,7 +975,6 @@ function Utils.getNextStation(schedule, currentStationName)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if matchFoundIndex then
|
if matchFoundIndex then
|
||||||
-- Search forward
|
|
||||||
for i = matchFoundIndex + 1, maxIdx do
|
for i = matchFoundIndex + 1, maxIdx do
|
||||||
local entry = schedule.entries[i]
|
local entry = schedule.entries[i]
|
||||||
if entry and entry.instruction then
|
if entry and entry.instruction then
|
||||||
@@ -985,16 +984,6 @@ function Utils.getNextStation(schedule, currentStationName)
|
|||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -3053,6 +3042,99 @@ local function isStationDestination(destName)
|
|||||||
return true
|
return true
|
||||||
end
|
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()
|
function Main.loop()
|
||||||
while true do
|
while true do
|
||||||
local now = os.epoch("utc")
|
local now = os.epoch("utc")
|
||||||
@@ -3204,23 +3286,7 @@ function Main.loop()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local isAtStation = false
|
local isAtStation = checkIsAtStationWithCurrentTrain(trainName, destination, platform)
|
||||||
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
|
|
||||||
if not isAtStation and etaSeconds > 0 and etaSeconds <= 45 then
|
if not isAtStation and etaSeconds > 0 and etaSeconds <= 45 then
|
||||||
if not seenApproachKeys[announceKey] then
|
if not seenApproachKeys[announceKey] then
|
||||||
seenApproachKeys[announceKey] = true
|
seenApproachKeys[announceKey] = true
|
||||||
@@ -3358,23 +3424,7 @@ function Main.loop()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local isAtStation = false
|
local isAtStation = checkIsAtStationWithCurrentTrain(tName, dest, platform or State.stationPlatform or "1")
|
||||||
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
|
|
||||||
if not isAtStation and etaSeconds > 0 and etaSeconds <= 45 then
|
if not isAtStation and etaSeconds > 0 and etaSeconds <= 45 then
|
||||||
if not seenApproachKeys[announceKey] then
|
if not seenApproachKeys[announceKey] then
|
||||||
seenApproachKeys[announceKey] = true
|
seenApproachKeys[announceKey] = true
|
||||||
@@ -3424,6 +3474,10 @@ function Main.loop()
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
for _, entry in ipairs(newUpcoming) do
|
||||||
|
tryCorrectUpcomingEntryWithCurrentTrain(entry)
|
||||||
|
end
|
||||||
|
|
||||||
State.upcomingTrains = newUpcoming
|
State.upcomingTrains = newUpcoming
|
||||||
|
|
||||||
if not Peripherals.station then
|
if not Peripherals.station then
|
||||||
|
|||||||
Reference in New Issue
Block a user