diff --git a/station_broadcast.lua b/station_broadcast.lua index e329200..724beef 100644 --- a/station_broadcast.lua +++ b/station_broadcast.lua @@ -1,6 +1,6 @@ -- 1. Configuration & Constants -local APP_VERSION_TEXT = "v1.0.71" +local APP_VERSION_TEXT = "v1.0.72" local CONFIG = { CLOUD_URL = "ws://stabadmin.fse-media.group", @@ -3042,6 +3042,45 @@ local function isStationDestination(destName) return true end +local function extractAlphaNumCodes(text) + if not text then return {} end + local s = tostring(text) + local codes = {} + for code in string.gmatch(s, "[%a%d]+%-[%a%d]+") do + codes[code] = true + end + for code in string.gmatch(s, "%a+%d+") do + codes[code] = true + end + for code in string.gmatch(s, "%d+") do + codes[code] = true + end + local list = {} + for k, _ in pairs(codes) do + table.insert(list, k) + end + return list +end + +local function hasSharedAlphaNumCode(a, b) + local codes1 = extractAlphaNumCodes(a) + local codes2 = extractAlphaNumCodes(b) + if #codes1 == 0 or #codes2 == 0 then return false end + for _, c1 in ipairs(codes1) do + for _, c2 in ipairs(codes2) do + if c1 == c2 then return true end + local lc1, lc2 = string.lower(c1), string.lower(c2) + if lc1 == lc2 then return true end + if #lc1 >= 3 and #lc2 >= 3 then + if string.find(lc1, lc2, 1, true) or string.find(lc2, lc1, 1, true) then + return true + end + end + end + end + return false +end + local function looksLikeValidDestinationText(text) if not text then return false end local s = tostring(text) @@ -3053,7 +3092,10 @@ local function looksLikeValidDestinationText(text) 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 + if #s > 0 and questionMarkCount / #s >= 0.5 then + local codes = extractAlphaNumCodes(s) + if #codes == 0 then return false end + end local hasRealChar = false for i = 1, #s do local b = string.byte(s, i) @@ -3066,7 +3108,7 @@ local function looksLikeValidDestinationText(text) return isStationDestination(s) end -local function tryCorrectUpcomingEntryWithCurrentTrain(entry) +local function tryCorrectUpcomingEntryWithCurrentTrain(entry, etaSeconds) if not State.currentTrain or not entry then return entry end local ctId = State.currentTrain.id local ctDest = State.currentTrain.dest @@ -3077,7 +3119,29 @@ local function tryCorrectUpcomingEntryWithCurrentTrain(entry) if ctId and entry.trainName then sameTrain = Utils.isSameTrain(ctId, entry.trainName) end - if not sameTrain and not samePlatform then return entry end + + local platformNum = tonumber((string.gsub(entryPlatform, "%D", ""))) + local ctPlatformNum = tonumber((string.gsub(ctPlatform, "%D", ""))) + local nearbyPlatform = false + if platformNum and ctPlatformNum then + nearbyPlatform = (math.abs(platformNum - ctPlatformNum) <= 1) + end + + local sharedCodeDest = hasSharedAlphaNumCode(entry.dest, ctDest) + local sharedCodeTrain = hasSharedAlphaNumCode(entry.trainName, ctId) + + local etaAtStation = (type(etaSeconds) == "number" and etaSeconds <= 0.5) + local destInvalid = not looksLikeValidDestinationText(entry.dest) + local idInvalid = not looksLikeValidDestinationText(entry.trainName) + + local shouldCorrect = samePlatform or sameTrain + or (sharedCodeDest and (nearbyPlatform or etaAtStation)) + or (sharedCodeTrain and (nearbyPlatform or etaAtStation)) + or ((destInvalid or idInvalid) and etaAtStation) + or (destInvalid and idInvalid and nearbyPlatform) + + if not shouldCorrect then return entry end + local validId = looksLikeValidDestinationText(entry.trainName) local validDest = looksLikeValidDestinationText(entry.dest) @@ -3085,19 +3149,25 @@ local function tryCorrectUpcomingEntryWithCurrentTrain(entry) entry.trainName = ctId end if sameTrain and ctId and ctId ~= "" and tostring(entry.trainName or "") ~= tostring(ctId) then - if Utils.isFuzzyMatch(entry.trainName or "", ctId) or not validId then + if Utils.isFuzzyMatch(entry.trainName or "", ctId) or not validId or sharedCodeTrain then entry.trainName = ctId end end + if ctId and ctId ~= "" and tostring(entry.trainName or "") ~= tostring(ctId) and sharedCodeTrain and (etaAtStation or samePlatform or idInvalid) then + entry.trainName = ctId + end if not validDest and ctDest and ctDest ~= "" then entry.dest = ctDest end - if (sameTrain or samePlatform) and ctDest and ctDest ~= "" and tostring(entry.dest or "") ~= tostring(ctDest) then - if Utils.isFuzzyMatch(entry.dest or "", ctDest) or not validDest then + if (sameTrain or samePlatform or sharedCodeDest) and ctDest and ctDest ~= "" and tostring(entry.dest or "") ~= tostring(ctDest) then + if Utils.isFuzzyMatch(entry.dest or "", ctDest) or not validDest or sharedCodeDest or etaAtStation then entry.dest = ctDest end end + if ctDest and ctDest ~= "" and tostring(entry.dest or "") ~= tostring(ctDest) and sharedCodeDest and (etaAtStation or samePlatform or destInvalid) then + entry.dest = ctDest + end return entry end @@ -3125,6 +3195,16 @@ local function checkIsAtStationWithCurrentTrain(trainName, destination, platform end end end + if not sameTrain and hasSharedAlphaNumCode(trainName, ctId) then + sameTrain = true + end + if not sameTrain and (not looksLikeValidDestinationText(trainName)) and (not looksLikeValidDestinationText(destination)) then + local pNum = tonumber((string.gsub(trainPlatform, "%D", ""))) + local ctPNum = tonumber((string.gsub(ctPlatform, "%D", ""))) + if pNum and ctPNum and math.abs(pNum - ctPNum) <= 1 then + sameTrain = true + end + end if sameTrain then local entryIdValid = looksLikeValidDestinationText(trainName) if entryIdValid then @@ -3136,6 +3216,9 @@ local function checkIsAtStationWithCurrentTrain(trainName, destination, platform if not looksLikeValidDestinationText(destination) then return true end + if hasSharedAlphaNumCode(destination, ctDest) then + return true + end end end return false @@ -3222,20 +3305,6 @@ function Main.loop() else platform = State.stationPlatform or "1" end - - local preCorrected = tryCorrectUpcomingEntryWithCurrentTrain({ - trainName = trainName, - dest = destination, - platform = platform - }) - if preCorrected then - if preCorrected.trainName and tostring(preCorrected.trainName) ~= tostring(trainName) then - trainName = preCorrected.trainName - end - if preCorrected.dest and tostring(preCorrected.dest) ~= tostring(destination) then - destination = preCorrected.dest - end - end if isStationDestination(destination) then local cancelled = false @@ -3261,6 +3330,21 @@ function Main.loop() local etaTicks = realArrival - currentTick local etaSeconds = etaTicks / (State.tickRate or 20) if etaSeconds < 0 then etaSeconds = 0 end + + local preCorrected = tryCorrectUpcomingEntryWithCurrentTrain({ + trainName = trainName, + dest = destination, + platform = platform + }, etaSeconds) + if preCorrected then + if preCorrected.trainName and tostring(preCorrected.trainName) ~= tostring(trainName) then + trainName = preCorrected.trainName + end + if preCorrected.dest and tostring(preCorrected.dest) ~= tostring(destination) then + destination = preCorrected.dest + end + end + local announceKey = normalizeUpcomingKey(trainName, destination) local etaLabel = buildEtaLabel(etaSeconds, etaTextByKey[announceKey]) @@ -3382,25 +3466,8 @@ function Main.loop() if not tName then platform, etaStr, tName, dest = string.match(cleanLine, "^([^%s]+)%s+(.-)%s+([^%s]+)%s+(.*)$") end - - local entryPlatform = platform or State.stationPlatform or "1" - local preCorrectedCT = tryCorrectUpcomingEntryWithCurrentTrain({ - trainName = tName or "", - dest = dest or "", - platform = entryPlatform - }) - if preCorrectedCT then - if preCorrectedCT.trainName and tostring(preCorrectedCT.trainName) ~= tostring(tName or "") then - tName = preCorrectedCT.trainName - end - if preCorrectedCT.dest and tostring(preCorrectedCT.dest) ~= tostring(dest or "") then - dest = preCorrectedCT.dest - end - end if tName and etaStr and isStationDestination(dest) then - local announceKey = normalizeUpcomingKey(tName, dest) - local etaSeconds = -1 local isNow = string.find(etaStr, "现在") @@ -3426,6 +3493,23 @@ function Main.loop() end end + local entryPlatform = platform or State.stationPlatform or "1" + local preCorrectedCT = tryCorrectUpcomingEntryWithCurrentTrain({ + trainName = tName or "", + dest = dest or "", + platform = entryPlatform + }, etaSeconds >= 0 and etaSeconds or 0) + if preCorrectedCT then + if preCorrectedCT.trainName and tostring(preCorrectedCT.trainName) ~= tostring(tName or "") then + tName = preCorrectedCT.trainName + end + if preCorrectedCT.dest and tostring(preCorrectedCT.dest) ~= tostring(dest or "") then + dest = preCorrectedCT.dest + end + end + + local announceKey = normalizeUpcomingKey(tName, dest) + table.insert(newUpcoming, { trainName = tName, dest = dest, @@ -3511,7 +3595,7 @@ function Main.loop() for _, entry in ipairs(newUpcoming) do - tryCorrectUpcomingEntryWithCurrentTrain(entry) + tryCorrectUpcomingEntryWithCurrentTrain(entry, entry.eta) end State.upcomingTrains = newUpcoming