Compare commits

..

21 Commits

Author SHA1 Message Date
tfa
04475f8158 MAJ json arrêts 2025-09-29 15:49:00 +02:00
tfa
85b059702f MAJ version 2025-09-29 15:38:44 +02:00
tfa
aa1813533e Changement codes lignes 2025-09-29 15:38:07 +02:00
tfa
d66213275f Gestion retour null dans le json 2023-07-03 09:26:11 +02:00
tfa
2b73d5b251 horaire peut être écrit au singulier 2023-03-22 08:32:06 +01:00
tfa
53dd903886 Meilleur affichage des messages long 2023-03-21 16:27:03 +01:00
tfa
37e239a252 Ajout sécurité si aucune alerte sur le réseau + filtre multiple messages identiques 2023-03-21 10:24:32 +01:00
tfa
82426e7c69 Demande de 300 résultats pour les alertes trafic 2023-01-18 09:45:29 +01:00
tfa
6cdde8dfce Correction lignes en majuscules, MAJ help, MAJ version 2023-01-05 17:21:39 +01:00
tfa
d02eee7340 Ajout des horaires théoriques si les estimés pas dispo 2023-01-04 16:37:03 +01:00
tfa
bdc2a516d6 Meilleur affichage et plus rapide 2023-01-04 14:33:28 +01:00
tfa
014da4fc29 Suppression affichage terminus vers terminus 2023-01-04 14:12:14 +01:00
tfa
41a99facd6 Réparation conneries, putain de python 2023-01-04 14:03:47 +01:00
tfa
d4dbb6a99f Revert "Correction message aide"
This reverts commit b1ae69ebfa.
2023-01-04 13:05:06 +01:00
tfa
5e5c81fd8b Suppression affichage terminus vers terminus 2023-01-04 10:54:06 +01:00
tfa
949607a96e Amélioration horaires, prend les valeurs théoriques et estimées (pour la ligne B notamment) 2023-01-04 10:29:26 +01:00
tfa
b1ae69ebfa Correction message aide 2023-01-04 09:33:54 +01:00
tfa
f98f3429d8 Ligne passé en majuscule avant la recherche 2022-12-21 08:40:14 +01:00
tfa
0e7800ab7d Fichier d'arrêt en chemin relatif 2022-12-19 14:17:18 +01:00
tfa
96786dc28c Ajout texte aide et nettoyage 2022-12-19 14:08:42 +01:00
tfa
d595c4d1d6 Réponse en md plutôt que html pour un meilleur rendu sur Element 2022-12-19 11:10:21 +01:00
3 changed files with 158 additions and 51229 deletions

View File

@@ -1,6 +1,6 @@
maubot: 0.1.0 maubot: 0.1.0
id: tfa.tcl id: tfa.tcl
version: 0.0.1 version: 1.1.0
license: AGPL-3.0-or-later license: AGPL-3.0-or-later
modules: modules:
- tcl - tcl

223
tcl.py
View File

@@ -8,15 +8,26 @@ import asyncio
import json import json
import base64 import base64
import difflib import difflib
import re
class Terminus: class Terminus:
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
self.horaires = [] self.horaires = []
self.estimated = False
def add_horaire(self, horaire): def add_horaire(self, horaire, est):
self.horaires.append(horaire) if self.estimated == False:
if est == "E":
self.horaires = []
self.horaires.append(horaire)
self.estimated = True
else:
self.horaires.append(horaire)
else:
if est == "E":
self.horaires.append(horaire)
def get_horaires(self): def get_horaires(self):
return self.sort_horaires() return self.sort_horaires()
@@ -34,6 +45,9 @@ class Terminus:
inth.sort() inth.sort()
return inth return inth
def get_estimated(self):
return self.estimated
class Ligne: class Ligne:
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
@@ -57,7 +71,6 @@ class Ligne:
return self.name return self.name
class Config(BaseProxyConfig): class Config(BaseProxyConfig):
def do_update(self, helper: ConfigUpdateHelper) -> None: def do_update(self, helper: ConfigUpdateHelper) -> None:
helper.copy("mail") helper.copy("mail")
@@ -68,19 +81,33 @@ class Tcl(Plugin):
async def start(self) -> None: async def start(self) -> None:
self.config.load_and_update() self.config.load_and_update()
def help_msg(self):
return(
"""
!tcl alerte ligne -> Retourne les alertes TCL sur la ligne donnée
ligne peut être :
- Metros : A, B, C, D
- Trams : T1, T2 ...
- Renforcés : C1, C2 ...
- Bus : 1, 2 ...
- Funis : F1, F2
ATTENTION : Le bot ne vérifie pas que la ligne existe
!tcl horaires arrêt (-- ligne) -> Retourne les horaires à l'arrêt (et filtre par ligne)
La réponse indique si les horaires sont théoriques (T) ou estimés (E)
Les horaires estimés sont préférés, si pas dispo, les horaires théoriques
sont affichés
Optionnellement le paramètre "-- ligne" permet de filtrer l'affichage pour ne garder que la ligne souhaitée
"""
)
@command.new(name="tcl", help="") @command.new(name="tcl", help="Permet d'avoir des informations sur les TCL")
@command.argument("pattern", pass_raw=True, required=True) @command.argument("pattern", pass_raw=True, required=True)
async def tclInfos(self, evt: MessageEvent, pattern: str) -> None: async def tclInfos(self, evt: MessageEvent, pattern: str) -> None:
await evt.mark_read() await evt.mark_read()
strToEncode = self.config["mail"] + ':' + self.config["password"] strToEncode = self.config["mail"] + ':' + self.config["password"]
base64string = base64.b64encode(strToEncode.encode('utf-8')) base64string = base64.b64encode(strToEncode.encode('utf-8'))
if not pattern: if not pattern:
await evt.respond( await evt.respond(self.help_msg())
"""
!tcl alerte ligne -> Retourne les alertes TCL sur la ligne donnée
"""
)
else: else:
self.log.info("Commande : " + pattern) self.log.info("Commande : " + pattern)
if pattern.__contains__("alerte"): if pattern.__contains__("alerte"):
@@ -89,9 +116,16 @@ class Tcl(Plugin):
await evt.respond( await evt.respond(
""" """
!tcl alerte ligne -> Retourne les alertes TCL sur la ligne donnée !tcl alerte ligne -> Retourne les alertes TCL sur la ligne donnée
ligne peut être :
- Metros : A, B, C, D
- Trams : T1, T2 ...
- Renforcés : C1, C2 ...
- Bus : 1, 2 ...
- Funis : F1, F2
ATTENTTION : Le bot ne vérifie pas que la ligne existe
""" """
) )
url = 'https://download.data.grandlyon.com/ws/rdata/tcl_sytral.tclalertetrafic_2/all.json?maxfeatures=200&start=1' url = 'https://data.grandlyon.com/fr/datapusher/ws/rdata/tcl_sytral.tclalertetrafic_2/all.json?maxfeatures=300&start=1'
resp = await self.http.get(url, headers={'Authorization' : 'Basic ' + base64string.decode('utf-8')}) resp = await self.http.get(url, headers={'Authorization' : 'Basic ' + base64string.decode('utf-8')})
ans = await resp.text() ans = await resp.text()
try: try:
@@ -103,35 +137,52 @@ class Tcl(Plugin):
try: try:
values = objet["values"] values = objet["values"]
alerte=False alerte=False
for value in values: if(len(objet["values"]) == 0):
if(value["ligne_cli"] == chunks[1]): await evt.respond("<h3>Erreur, aucune réponse</h3>", allow_html=True)
alerte=True else:
debut = datetime.fromisoformat(value["debut"]) msg = []
fin = datetime.fromisoformat(value["fin"]) for value in values:
respText = "<h3>" + value["type"] + "</h3><p><strong>" + value["titre"] + "</strong></p><p>" \ if(value["ligne_cli"] == chunks[1].upper()):
+ value["message"] + "</p><strong>" + debut.strftime("%d/%m/%Y à %H:%M") + " au " \ alerte=True
+ fin.strftime("%d/%m/%Y à %H:%M") + "</strong></p>" #Il peut y avoir 100 fois le même message...
await evt.respond(respText, allow_html=True) if value["message"] not in msg:
if(alerte==False): msg.append(value["message"])
await evt.respond("<h3>Pas d'alerte sur cette ligne</h3>", allow_html=True) debut = datetime.fromisoformat(value["debut"])
fin = datetime.fromisoformat(value["fin"])
newMsg = value["message"].replace('\t', '<br>')
newMsg = re.sub(r"(?<![ '-])[A-Z]", r"<br>\g<0>", newMsg)
newMsg = newMsg.replace('<br> <br>', '<br>')
self.log.info(newMsg)
respText = "<h3>" + value["type"] + "</h3><p><strong>" + value["titre"] + "</strong></p><p>" \
+ newMsg + "</p><strong>" + debut.strftime("%d/%m/%Y à %H:%M") + " au " \
+ fin.strftime("%d/%m/%Y à %H:%M") + "</strong></p>"
await evt.respond(respText, allow_html=True)
if(alerte==False):
await evt.respond("<h3>Pas d'alerte sur cette ligne</h3>", allow_html=True)
except KeyError: except KeyError:
await evt.respond("Erreur d'analyse JSON ") await evt.respond("Erreur d'analyse JSON ")
elif pattern.__contains__("horaires"): elif pattern.__contains__("horaire"):
chunks = pattern.split(None, 1) chunks = pattern.split(None, 1)
if len(chunks) != 2: if len(chunks) != 2:
await evt.respond( await evt.respond(
""" """
!tcl horaires arrêt -> Retourne les horaires à l'arrêt !tcl horaires arrêt (-- ligne) -> Retourne les horaires à l'arrêt (et filtre par ligne)
La réponse indique si les horaires sont théoriques (T) ou estimés (E)
Les horaires estimés sont préférés, si pas dispo, les horaires théoriques
sont affichés
Optionnellement le paramètre "-- ligne" permet de filtrer l'affichage pour ne garder que la ligne souhaitée
""" """
) )
return return
with open("/home/tfa/maubot/tcl/tcl_sytral.tclarret.json") as file: with open("./tcl/tcl_sytral.tclarret.json") as file:
objet = json.load(file) objet = json.load(file)
values = objet["values"] values = objet["values"]
arrets = [] arrets = []
for value in values: for value in values:
arrets.append(value["nom"].lower()) arrets.append(value["nom"].lower())
arret = difflib.get_close_matches(chunks[1].lower(),arrets,n=1,cutoff=0.8)
subCmd = chunks[1].split("--",1)
arret = difflib.get_close_matches(subCmd[0].lower(),arrets,n=1,cutoff=0.8)
if len(arret) == 0: if len(arret) == 0:
await evt.respond("Arrêt non trouvé") await evt.respond("Arrêt non trouvé")
return return
@@ -139,13 +190,12 @@ class Tcl(Plugin):
nomArret = "" nomArret = ""
for value in values: for value in values:
if value["nom"].lower() == arret[0]: if value["nom"].lower() == arret[0]:
self.log.info(value["id"])
nomArret = value["nom"] nomArret = value["nom"]
Ids.append(value["id"]) Ids.append(value["id"])
url ='https://data.grandlyon.com/fr/datapusher/ws/rdata/tcl_sytral.tclpassagearret/all.json?maxfeatures=30000&start=1'
url = 'https://download.data.grandlyon.com/ws/rdata/tcl_sytral.tclpassagearret/all.json?maxfeatures=2000&start=1' respText = "### Prochains départs " + nomArret + " :\n"
respText = "<h3>Prochains départs " + nomArret + " :</h3><ul>"
self.log.info(respText)
lines = [] lines = []
while len(url) > 0: while len(url) > 0:
resp = await self.http.get(url, headers={'Authorization' : 'Basic ' + base64string.decode('utf-8')}) resp = await self.http.get(url, headers={'Authorization' : 'Basic ' + base64string.decode('utf-8')})
@@ -164,61 +214,96 @@ class Tcl(Plugin):
for value in values: for value in values:
if value["id"] in Ids: if value["id"] in Ids:
if value["type"] == "E": #Filtré sur les estimés et non théoriques # Les metros ont leur propre code
# Les metros ont leur propre code code = value["coursetheorique"].split('_')[0]
if value["coursetheorique"].split('-')[0] == "301A" : if code == "301" :
transport = "A" transport = "A"
elif value["coursetheorique"].split('-')[0] == "303" : elif code == "303" :
transport = "C" transport = "C"
elif value["coursetheorique"].split('-')[0] == "325" : elif code == "325" :
transport = "F1" transport = "F1"
elif value["coursetheorique"].split('-')[0] == "326" : elif code == "326" :
transport = "F2" transport = "F2"
elif value["coursetheorique"].split('-')[0] == "304" : elif code == "304" :
transport = "D" transport = "D"
elif value["coursetheorique"].split('-')[0] == "302A" : elif code == "302" :
transport = "B" transport = "B"
elif code == "520" :
transport = "T1"
elif code == "530" :
transport = "T2"
elif code == "540" :
transport = "T3"
elif code == "550" :
transport = "T4"
elif code == "570" :
transport = "T5"
elif code == "590" :
transport = "T6"
elif code == "510" :
transport = "T7"
elif code.isdigit() and int(code) >= 900:
transport = "C" + str(int(code) - 900)
else:
l = value["coursetheorique"].split('_')[0]
if l[-1:].isdigit():
transport = l
else: else:
transport = value["coursetheorique"].split('-')[0][:-1] transport = value["coursetheorique"].split('-')[0][:-1]
if value["delaipassage"].find('min') < 0 :
found = False continue
for line in lines: found = False
if line.get_name() == transport: for line in lines:
term = line.get_terminus(value["direction"]) if line.get_name() == transport:
if term is None: term = line.get_terminus(value["direction"])
newterm = Terminus(value["direction"]) if term is None:
newterm.add_horaire(value["delaipassage"]) newterm = Terminus(value["direction"])
line.add_terminus(newterm) newterm.add_horaire(value["delaipassage"], value["type"])
else: line.add_terminus(newterm)
term.add_horaire(value["delaipassage"]) else:
found = True term.add_horaire(value["delaipassage"], value["type"])
if not found : found = True
newLine = Ligne(transport) if not found :
newterm = Terminus(value["direction"]) newLine = Ligne(transport)
newterm.add_horaire(value["delaipassage"]) newterm = Terminus(value["direction"])
newLine.add_terminus(newterm) newterm.add_horaire(value["delaipassage"], value["type"])
lines.append(newLine) newLine.add_terminus(newterm)
respText += "<ul>" lines.append(newLine)
for line in lines: for line in lines:
if len(subCmd) == 2:
if line.get_name() != "".join(subCmd[1].split()).upper():
continue
self.log.info("Ligne " + line.get_name()) self.log.info("Ligne " + line.get_name())
respText += "<li><h5>Ligne " + line.get_name() + "</h5></li>" respText += "#### Ligne " + line.get_name() + "\n"
terms = line.get_all_terminus() terms = line.get_all_terminus()
for t in terms: for t in terms:
self.log.info(t.get_name()) self.log.info(t.get_name())
respText += "<b>Direction " + t.get_name() + "</b><ul>" if t.get_name() == nomArret:
continue
if t.get_name() is not None:
respText += "***Direction " + t.get_name()
else:
respText += "***Direction ?"
if t.get_estimated() == True:
respText += " (E)***\n"
else:
respText += " (T)***\n"
hs = t.get_horaires() hs = t.get_horaires()
hs.sort() hs.sort()
for idx, h in enumerate(hs): for idx, h in enumerate(hs):
self.log.info(h) self.log.info(h)
if h == 0: if h == 0:
respText += "<li>Proche</li>" respText += "- Proche\n"
else: else:
respText += "<li>" + str(h) + " min</li>" respText += "- " + str(h) + " min\n"
if idx == 2: ##On limite à 3 items if idx == 2: ##On limite à 3 items
break break
respText += "</ul>" respText += "\n"
respText += "</ul>" await evt.respond(respText)
await evt.respond(respText, allow_html=True)
else:
await evt.respond(self.help_msg())
@classmethod @classmethod

File diff suppressed because one or more lines are too long