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 it.id == stopId.stopId) let nextPassage = { line, displayName: stop?.name, displayTime: "", time: next_trip.schedules?.[0] ? new Date(next_trip.schedules?.[0].dateTime) : null } return nextPassage }