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

186 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { getNextPassage } from "./tcl.js";
const MIN_TIME_BETWEEN_DAYS = 2 * 60 * 60000 // 2 hours
const MAX_LAST_PASSAGE_TIME = 30 * 60000 // 30 min
const MAX_DERNIER_METRO_MESSAGE = 3
let tracked_stops = [
"line:SYTNEX:A/forward/stop_point:SYTNEX:46052", // Metro A dir Vaulx, Hotel de ville
"line:SYTNEX:A/backward/stop_point:SYTNEX:42743", // Metro A dir Perrache, Hotel de ville
"line:SYTNEX:9/forward/stop_point:SYTNEX:2494", // Bus 9 dir Satoney, Pont de lattre RD
"line:SYTNEX:9/backward/stop_point:SYTNEX:2494", // Bus 9 dir cordeliers, Pont de lattre RD
"line:SYTNEX:C/forward/stop_point:SYTNEX:10787", // Métro C dir Cuire, Croix-Paquet
"line:SYTNEX:C6/forward/stop_point:SYTNEX:2496", // Bus C6 arret Pont de lattre RD campus lyon ouest
"line:SYTNEX:C6/backward/stop_point:SYTNEX:2495", // Bus C6 arret Pont de lattre RD Gare part dieu v. merle
"line:SYTNEX:C13/forward/stop_point:SYTNEX:10169", // Bus C13 arret Austerlitz montessuy gutemberg
"line:SYTNEX:C13/backward/stop_point:SYTNEX:10169", // Bus C13 arret Austerlitz vers grange blanche
"line:SYTNEX:PL2/backward/stop_point:SYTNEX:10889", // Bus PL2 arret Pont de lattre RD vers Musée des confluences
"line:SYTNEX:PL2/forward/stop_point:SYTNEX:10169", // BUS PL2 arret Austerlitz vers Cuire
"line:SYTNEX:C23/backward/stop_point:SYTNEX:10889", // Bus C13 arret Pont de lattre RD vers Flachet - Alain Gilles
"line:SYTNEX:C23/forward/stop_point:SYTNEX:10889", // Bus C13 arret Pont de lattre RD vers Cite internationale
]
let stops_cache = {}
async function shuffleStops(){
tracked_stops = tracked_stops
.map(value => ({ value, sort: Math.random() }))
.sort((a, b) => a.sort - b.sort)
.map(({ value }) => value)
}
async function getNextStop(){
let stop = tracked_stops.shift()
tracked_stops.push(stop)
return stop
}
async function showNextLine(){
let stop = await getNextStop()
let nextPassage = await getNextPassage(stop)
stops_cache[stop] = nextPassage
let time = nextPassage.time
if(!time){
time = nextPassage.line.timetable.find(it => it.time.getTime() > Date.now())?.time
}
if(!time){
return
}
let modal = document.getElementById("next-line")
modal.hidden = false
modal.querySelector(".line-picto").src = nextPassage.line.picto
modal.querySelector(".line-name").textContent = nextPassage.line.displayName
modal.querySelector(".stop-name").textContent = nextPassage.displayName
let timeFormatter = new Intl.DateTimeFormat("fr-FR", {
timeStyle: "short"
});
let timeEl = modal.querySelector(".stop-passage-time")
timeEl.textContent = timeFormatter.format(time)
let relativeTimeFOrmatter = new Intl.RelativeTimeFormat("fr-FR", {
style: "short",
numeric: "auto"
});
let time_minutes = Math.floor((time.getTime() - Date.now()) / 60000)
let relative_time_str;
if(time_minutes > 60) {
let time_hours = Math.floor(time_minutes / 60)
time_minutes -= time_hours * 60
relative_time_str = relativeTimeFOrmatter.format(
time_hours,
"hours"
)
if(time_minutes > 0){
relative_time_str += ` et ${Math.abs(time_minutes)} min`
}
} else {
relative_time_str = relativeTimeFOrmatter.format(
time_minutes,
"minutes"
)
}
modal.querySelector(".stop-passage-time-relative").textContent = relative_time_str
setTimeout(() => modal.hidden = true, 15000)
}
function getLastPassageTime(stopOrLine){
let timetable = stopOrLine.timetable || stopOrLine.line.timetable
if(!timetable){
return
}
let now = new Date()
let last_passage = timetable
.find((it, i) => {
if((timetable[i+1]) && it.time.getTime() > now && (it.time.getTime() + MIN_TIME_BETWEEN_DAYS) < timetable[i+1].time.getTime()){
return true
} else {
return false
}
})
return last_passage
}
async function updateLastMetro(){
let last_passage_list = Object.values(stops_cache)
.map(it => [it, getLastPassageTime(it)])
.filter(([_, lastPassage]) => lastPassage && (lastPassage.time.getTime() - Date.now()) < MAX_LAST_PASSAGE_TIME)
let hidden_offset = 0
let last_hidden = true
for(let el of document.querySelectorAll("#last-passage > .last-passage")){
if(last_hidden && el.hidden){
hidden_offset++
} else {
last_hidden = false
}
el.remove()
}
let container = document.getElementById("last-passage")
let template = document.querySelector("#last-passage template.last-passage-template");
if(hidden_offset >= last_passage_list.length){
hidden_offset = 0
}
if(last_passage_list.length > 0){
let i = 0
for(let [stop, last_passage] of last_passage_list){
let el = template.content.cloneNode(true)
el.children[0].hidden = i < hidden_offset || i >= hidden_offset + MAX_DERNIER_METRO_MESSAGE;
el.querySelector(".line-picto").src = stop.line.picto
el.querySelector(".line-name").textContent = stop.line.displayName
el.querySelector(".stop-name").textContent = stop.displayName
let timeFormatter = new Intl.DateTimeFormat("fr-FR", {
timeStyle: "short"
});
let timeEl = el.querySelector(".stop-passage-time")
timeEl.textContent = timeFormatter.format(last_passage.time)
timeEl.datetime = last_passage.time.toISOString()
let relativeTimeFormatter = new Intl.RelativeTimeFormat("fr-FR", {
style: "short",
numeric: "auto"
});
el.querySelector(".stop-passage-time-relative").textContent = relativeTimeFormatter.format(
Math.floor((last_passage.time.getTime() - Date.now()) / 60000),
"minutes"
)
container.prepend(el)
i++;
}
container.hidden = false
} else {
container.hidden = true
}
}
shuffleStops()
.then(() => showNextLine())
.then(() => updateLastMetro())
setInterval(() => showNextLine(), 17000)
setInterval(() => updateLastMetro(), 60000)