Files
dernier-metro/lol/tcl.js
T
2026-06-13 20:42:03 +02:00

164 lines
5.0 KiB
JavaScript

const DAY_IN_MS = 8.64e+7;
class StopId {
constructor(stopIdString){
let [lineId, direction, stopId] = stopIdString.split(/\//)
this.lineId = lineId
this.stopId = stopId
this.direction = direction
}
}
async function getNextTripJSON(stop_id){
let res = await fetch(`/api/interface/tcl/next-trips/stops/${encodeURIComponent(stop_id.stopId)}/${encodeURIComponent(stop_id.lineId)}/${stop_id.direction}`);
if(!res.ok){
throw new Error(`Server responded with ${res.status} ${res.statusText}`)
}
let result = await res.json();
if(!result.data){
throw new Error(`Stop ${stop_id.stopId} not found`)
}
return result.data[0]
}
async function getStopsJSON(stop_id){
let res = await fetch(`/api/interface/tcl/lines/${encodeURIComponent(stop_id.lineId)}/stops`);
if(!res.ok){
throw new Error(`Server responded with ${res.status} ${res.statusText}`)
}
let result = await res.json();
if(!result.data){
throw new Error(`Line ${stop_id.lineId} not found`)
}
return result.data
}
async function getTimetableJSON(stop_id, date){
let res = await fetch(`/api/interface/tcl/timetables/${encodeURIComponent(stop_id.stopId)}/${encodeURIComponent(stop_id.lineId)}/${stop_id.direction}?date=${date.getFullYear()}-${(date.getMonth()+1).toString().padStart(2, "0")}-${date.getDate().toString().padStart(2, "0")}`);
if(!res.ok){
throw new Error(`Server responded with ${res.status} ${res.statusText}`)
}
let result = await res.json();
if(!result.data){
throw new Error(`Timetable for ${stop_id.lineId} not found`)
}
return result.data
}
async function getLineDetailsJSON(stop_id){
let res = await fetch(`/api/interface/tcl/lines/${encodeURIComponent(stop_id.lineId)}`);
if(!res.ok){
throw new Error(`Server responded with ${res.status} ${res.statusText}`)
}
let result = await res.json();
if(!result.data){
throw new Error(`Line ${stop_id.lineId} not found`)
}
return result.data
}
function getIconURL(stop_id){
return new URL(`/api/valkyrie/assets/lines/${stop_id.lineId}.svg?type=image%2Fsvg%2Bxml`, window.location).toString()
}
async function getLineDetails(stop_id){
let line_json = await getLineDetailsJSON(stop_id)
let route = line_json.routes.find(it => it.direction == stop_id.direction)
let line = {
id: stop_id.lineId,
displayName: route?.name,
picto: getIconURL(stop_id),
name: line_json.code,
direction: route?.name,
timetable: null
}
return line
}
async function getTimetable(stop_id, date){
let timetable_json = await getTimetableJSON(stop_id, date)
let timetable = []
for(let scheduled_time of timetable_json.scheduleTimes){
let time = new Date(scheduled_time.dateTime)
timetable.push({
displayHours: time.getHours().toString().padStart(2, "0"),
displayMinutes: time.getMinutes().toString().padStart(2, "0"),
displayTime: `${time.getHours().toString().padStart(2, "0")}h${time.getMinutes().toString().padStart(2, "0")}`,
time
})
}
return timetable
}
/**
* Get next Bus/Metro/Tram passage of given stop description
* @param {String} stop_description Stop description string
*
* To get stop description go to https://carte-interactive.tcl.fr/public-transport/lines/
* then find your line and your stop in this line.
* Your URL must look like something like this
* https://carte-interactive.tcl.fr/public-transport/lines/line:SYTNEX:C/forward/stop_point:SYTNEX:10787
* Stop description is everything after "lines/" ("line:SYTNEX:C/forward/stop_point:SYTNEX:10787" in example above)
*/
export async function getNextPassage(stop_description, options = {
timetable: +2 // Today and tomorrow
}){
let stopId = new StopId(stop_description);
let proms = [
getLineDetails(stopId),
getNextTripJSON(stopId),
getStopsJSON(stopId),
Promise.resolve([])
]
let timeTableAmount = options?.timetable || +2;
if(timeTableAmount){
for(let dayOffset = 0; dayOffset<timeTableAmount; dayOffset++){
let now = new Date(Date.now()+(dayOffset*DAY_IN_MS))
proms.push(await getTimetable(stopId, now))
}
}
let [line, next_trip, line_stops, ...all_timetables] = await Promise.all(proms);
console.log(stopId)
console.log("line", line)
console.log("next trip", next_trip)
console.log("stop", line_stops)
console.log("timetable", all_timetables)
let line_timetables = []
for(let timetable of all_timetables){
line_timetables.push(...timetable)
}
line.timetable = line_timetables
let stop = line_stops.find(it => it.id == stopId.stopId)
let nextPassage = {
line,
displayName: stop?.name,
displayTime: "<unsupported>",
time: next_trip.schedules?.[0] ? new Date(next_trip.schedules?.[0].dateTime) : null
}
return nextPassage
}