Use navitia IDFM API directly
This commit is contained in:
parent
b77f1cd0d0
commit
a7f428ace1
161
modules/ratp.py
161
modules/ratp.py
@ -9,6 +9,28 @@ import urllib.request
|
|||||||
|
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
from PIL import Image, ImageDraw, ImageFont
|
||||||
|
|
||||||
|
def whenStr(date, now):
|
||||||
|
if date < now + timedelta(days=1):
|
||||||
|
return date.hours() + "h" + date.minutes()
|
||||||
|
elif date < now + timedelta(days=7):
|
||||||
|
weekday = date.weekday()
|
||||||
|
if weekday == 0:
|
||||||
|
return "lundi"
|
||||||
|
elif weekday == 1:
|
||||||
|
return "mardi"
|
||||||
|
elif weekday == 2:
|
||||||
|
return "mercredi"
|
||||||
|
elif weekday == 3:
|
||||||
|
return "jeudi"
|
||||||
|
elif weekday == 4:
|
||||||
|
return "vendredi"
|
||||||
|
elif weekday == 5:
|
||||||
|
return "samedi"
|
||||||
|
else:
|
||||||
|
return "dimanche"
|
||||||
|
else:
|
||||||
|
return date.strftime("%d %b")
|
||||||
|
|
||||||
class IDFMAPI:
|
class IDFMAPI:
|
||||||
|
|
||||||
fnt_R_path = "./fonts/Parisine-Regular.ttf"
|
fnt_R_path = "./fonts/Parisine-Regular.ttf"
|
||||||
@ -65,24 +87,13 @@ class IDFMAPI:
|
|||||||
self.cache_timeout = config.cache_timeout
|
self.cache_timeout = config.cache_timeout
|
||||||
self.max_cache_timeout = config.max_cache_timeout
|
self.max_cache_timeout = config.max_cache_timeout
|
||||||
|
|
||||||
def fromIVtoPRIM(src, line):
|
def fromHTMLDisruption(src):
|
||||||
cleanr = re.compile('<.*?>')
|
cleanr = re.compile('<.*?>')
|
||||||
cleanrA = re.compile('<a.*?>.*?</a>')
|
cleanrA = re.compile('<a.*?>.*?</a>')
|
||||||
return {
|
period = re.compile('Période :[^.]+. ')
|
||||||
"InfoChannelRef": {
|
period2 = re.compile('Dates? :[^.]+. ')
|
||||||
"value": "Perturbation" if src["severity"] >= 2 else ("Travaux" if src["severity"] == 1 else "Message"),
|
more = re.compile(" Plus d'informations sur [^.]+.")
|
||||||
},
|
return re.sub(cleanr, '', re.sub(cleanrA, '', re.sub(period, '', re.sub(period2, '', re.sub(more, '', src.replace(' ', ' ').replace(' ', ' ').replace('’', "'").replace('à', 'à').replace('é', 'é').replace('è', 'è').replace('ê', 'ê').replace('û', 'û').replace('Î', 'Î').replace('<br>', ' ').replace('</p>', ' ').replace('Information Ile de France Mobilités :', '').replace("Les horaires du calculateur d'itinéraire tiennent compte des travaux. ", '').replace("à la demande de la Préfecture de Police et d'Île-de-France Mobilités, et ", '')))))).strip()
|
||||||
"Content": {
|
|
||||||
"Message": [{
|
|
||||||
"MessageType": "SHORT_MESSAGE",
|
|
||||||
"MessageText": {
|
|
||||||
"id": src["id"],
|
|
||||||
"title": src["title"].replace("Métro " + line + " : ", '').replace("Ligne " + line + " : ", '').replace("Tramway " + line + " : ", ''),
|
|
||||||
"value": re.sub(cleanr, '', re.sub(cleanrA, '', src["message"].replace(' ', ' ').replace('’', "'").replace('à', 'à').replace('é', 'é').replace('è', 'è').replace('<br>', ' ').replace('</p>', ' ').replace('Information Ile de France Mobilités :', ''))).strip(),
|
|
||||||
}
|
|
||||||
}],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def get_schedules(self, mode, line, station, way="A+R"):
|
def get_schedules(self, mode, line, station, way="A+R"):
|
||||||
if mode == "M":
|
if mode == "M":
|
||||||
@ -128,16 +139,6 @@ class IDFMAPI:
|
|||||||
return [m for m in res["result"]["schedules"] if "message" in m and m["message"] != "Train sans arrêt"]
|
return [m for m in res["result"]["schedules"] if "message" in m and m["message"] != "Train sans arrêt"]
|
||||||
|
|
||||||
def get_weather(self):
|
def get_weather(self):
|
||||||
ret = {}
|
|
||||||
|
|
||||||
for mode in IDFMAPI.lines:
|
|
||||||
ret[mode] = {}
|
|
||||||
for line in IDFMAPI.lines[mode]:
|
|
||||||
ret[mode][line] = self.get_line_weather(mode, line)
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def get_line_weather(self, mode, line):
|
|
||||||
cache_file = self._cached_file % ("ratp-disruptions")
|
cache_file = self._cached_file % ("ratp-disruptions")
|
||||||
# Read the mod time
|
# Read the mod time
|
||||||
statinfo = None
|
statinfo = None
|
||||||
@ -148,7 +149,8 @@ class IDFMAPI:
|
|||||||
|
|
||||||
if statinfo is None or datetime.fromtimestamp(statinfo.st_mtime, tz=timezone.utc) + timedelta(minutes=self.cache_timeout) < datetime.now(tz=timezone.utc):
|
if statinfo is None or datetime.fromtimestamp(statinfo.st_mtime, tz=timezone.utc) + timedelta(minutes=self.cache_timeout) < datetime.now(tz=timezone.utc):
|
||||||
# Do the request and save it
|
# Do the request and save it
|
||||||
req = urllib.request.Request("https://api-iv.iledefrance-mobilites.fr/disruptions")
|
req = urllib.request.Request(self.baseurl + "/navitia/line_reports/coverage/fr-idf/line_reports?count=2000")
|
||||||
|
req.headers["apikey"] = self.apikey
|
||||||
try:
|
try:
|
||||||
with urllib.request.urlopen(req) as f:
|
with urllib.request.urlopen(req) as f:
|
||||||
with open(cache_file, 'wb') as fd:
|
with open(cache_file, 'wb') as fd:
|
||||||
@ -169,11 +171,29 @@ class IDFMAPI:
|
|||||||
with open(cache_file) as f:
|
with open(cache_file) as f:
|
||||||
res = json.load(f)
|
res = json.load(f)
|
||||||
|
|
||||||
for l in res["currentIT"]:
|
disruptions = {}
|
||||||
if "id" in l:
|
for d in res["disruptions"]:
|
||||||
if l["id"] == "line:IDFM:" + IDFMAPI.lines[mode][line]:
|
disruptions[d["id"]] = d
|
||||||
for d in l["disruptions"]:
|
|
||||||
yield IDFMAPI.fromIVtoPRIM(d, line)
|
ret = {}
|
||||||
|
|
||||||
|
for mode in IDFMAPI.lines:
|
||||||
|
ret[mode] = {}
|
||||||
|
for line in IDFMAPI.lines[mode]:
|
||||||
|
ret[mode][line] = self.get_line_weather(res, disruptions, mode, line)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def get_line_weather(self, res, disruptions, mode, line):
|
||||||
|
for l in res["line_reports"]:
|
||||||
|
if "line" not in l:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if "id" in l["line"]:
|
||||||
|
if l["line"]["id"] == "line:IDFM:" + IDFMAPI.lines[mode][line]:
|
||||||
|
for link in l["line"]["links"]:
|
||||||
|
if disruptions[link["id"]]["status"] != "past":
|
||||||
|
yield disruptions[link["id"]]
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -230,26 +250,56 @@ class RATPWeatherModule:
|
|||||||
return image
|
return image
|
||||||
return icon
|
return icon
|
||||||
|
|
||||||
for info in weather[mode][line]:
|
for disruption in weather[mode][line]:
|
||||||
if "InfoChannelRef" not in info or (info["InfoChannelRef"]["value"] != "Perturbation" and info["InfoChannelRef"]["value"] != "Travaux"):
|
if "messages" not in disruption:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if "Message" not in info["Content"]:
|
if disruption["status"] != "active" and "application_periods" not in disruption:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for msg in info["Content"]["Message"]:
|
title = ""
|
||||||
if "MessageType" not in msg or msg["MessageType"] != "SHORT_MESSAGE":
|
subtitle = ""
|
||||||
continue
|
content = ""
|
||||||
|
|
||||||
if "id" in msg["MessageText"]:
|
if "application_periods" in disruption:
|
||||||
if msg["MessageText"]["id"] in id_seens:
|
now = datetime.now()
|
||||||
|
nextweek = now + timedelta(days=1)
|
||||||
|
|
||||||
|
application_periods = []
|
||||||
|
for ap in disruption["application_periods"]:
|
||||||
|
ap["begin"] = datetime.fromisoformat(ap["begin"])
|
||||||
|
ap["end"] = datetime.fromisoformat(ap["end"])
|
||||||
|
|
||||||
|
if ap["end"] < now:
|
||||||
continue
|
continue
|
||||||
id_seens.append(msg["MessageText"]["id"])
|
elif ap["begin"] > nextweek:
|
||||||
yield {
|
continue
|
||||||
"title": msg["MessageText"]["title"] if "title" in msg["MessageText"] else "",
|
elif len(application_periods) > 0 and application_periods[0]["begin"] + timedelta(hours=16) < ap["begin"]:
|
||||||
"description": msg["MessageText"]["value"].replace(" ", " "),
|
continue
|
||||||
"icon": alert_icon(mode, line),
|
else:
|
||||||
}
|
application_periods.append(ap)
|
||||||
|
|
||||||
|
if len(application_periods) == 0:
|
||||||
|
continue
|
||||||
|
elif len(application_periods) == 1:
|
||||||
|
if application_periods[0]["begin"] > now:
|
||||||
|
subtitle = "De " + whenStr(application_periods[0]["begin"], now) + " à " + whenStr(application_periods[0]["end"], now)
|
||||||
|
elif application_periods[0]["end"] > now:
|
||||||
|
subtitle = "Fin " + whenStr(application_periods[0]["end"], now)
|
||||||
|
|
||||||
|
for msg in disruption["messages"]:
|
||||||
|
if msg["channel"]["name"] == "titre":
|
||||||
|
title = msg["text"]
|
||||||
|
elif msg["channel"]["name"] == "moteur":
|
||||||
|
content = IDFMAPI.fromHTMLDisruption(msg["text"])
|
||||||
|
elif len(content) == "":
|
||||||
|
content = IDFMAPI.fromHTMLDisruption(msg["text"])
|
||||||
|
yield {
|
||||||
|
"title": title,
|
||||||
|
"subtitle": subtitle,
|
||||||
|
"description": content,
|
||||||
|
"icon": alert_icon(mode, line),
|
||||||
|
}
|
||||||
|
|
||||||
def draw_module(self, config, width, height, line_height=19):
|
def draw_module(self, config, width, height, line_height=19):
|
||||||
image = Image.new('RGB', (width, height), '#fff')
|
image = Image.new('RGB', (width, height), '#fff')
|
||||||
@ -275,11 +325,22 @@ class RATPWeatherModule:
|
|||||||
align_y += line_height + 6
|
align_y += line_height + 6
|
||||||
|
|
||||||
states = []
|
states = []
|
||||||
for info in weather[mode][line]:
|
for disruption in weather[mode][line]:
|
||||||
if "InfoChannelRef" in info:
|
if disruption["status"] != "active":
|
||||||
states.append(info["InfoChannelRef"]["value"])
|
continue
|
||||||
|
if "severity" in disruption:
|
||||||
|
if disruption["cause"] == "travaux" and "line" not in [x["pt_object"]["embedded_type"] for x in disruption["impacted_objects"]]:
|
||||||
|
states.append(disruption["severity"]["effect"] + " " + disruption["cause"])
|
||||||
|
else:
|
||||||
|
states.append(disruption["severity"]["effect"])
|
||||||
|
|
||||||
fill = "black" if "Perturbation" in states else ("gray" if "Travaux" in states else "darkgray")
|
fill = "darkgray"
|
||||||
|
if "NO_SERVICE" in states:
|
||||||
|
fill = "black"
|
||||||
|
elif "REDUCED_SERVICE" in states or "UNKNOWN_EFFECT" in states or "OTHER_EFFECT" in states:
|
||||||
|
fill = "teal"
|
||||||
|
elif len(states) > 0:
|
||||||
|
fill = "gray"
|
||||||
|
|
||||||
icon = IDFMAPI.get_line_icon(mode, line, line_height, fill=fill)
|
icon = IDFMAPI.get_line_icon(mode, line, line_height, fill=fill)
|
||||||
image.paste(icon, (align_x, align_y), icon)
|
image.paste(icon, (align_x, align_y), icon)
|
||||||
|
Loading…
Reference in New Issue
Block a user