Skip to content

Commit

Permalink
Fixing something about italian trains (#17)
Browse files Browse the repository at this point in the history
* Update viaggiatreno API and fix warnings

* Better itinerary layout

* Disable plotly

* Fix stats

* Fix an issue with multiple trains having the same number

* Fix find train by number

* Use matplotlib and re-enable delay graphs

* Better graphs

* More better graphs

* Use boxing char instead of minus
  • Loading branch information
giuseppeM99 authored Jan 31, 2023
1 parent 105705b commit 0c049ef
Show file tree
Hide file tree
Showing 9 changed files with 116 additions and 100 deletions.
Binary file added data/img/logo_white_with_name_transparent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 3 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@ services:
redis:
image: redis
container_name: orariotreni_redis
volumes:
volumes:
- ./redis-data:/data
expose:
- "6379"



bot:
build: .
container_name: orariotreni_bot
links:
- redis

2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ botogram2
wikipedia
dateutils
progressbar2
plotly==2.0.8
matplotlib
image
pyowm
103 changes: 57 additions & 46 deletions src/updates/callback.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/updates/deeplinking.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def process_deeplinking(bot, message, args):

if arguments[0] == "train":
departure_station, train = arguments[1].split('_')[0:2]
raw = api.call('andamentoTreno', departure_station, train)
raw = api.andamentoTreno(departure_station, train)

u.increaseStat('stats_trains_bynum')

Expand Down
10 changes: 5 additions & 5 deletions src/updates/inline.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ def default_answer():
"\n⏺ <i>Cerca treni, stazioni e itinerari in qualsiasi chat</i>"
"\nPer usare questa funzione basta che scrivi <code>@{username} query</code> in qualsiasi chat: "
"si aprirà un pop-up da dove potrai selezionare il risultato desiderato."
"\n➖➖️ <b>Cerca treni e stazioni</b>"
"\n━━️ <b>Cerca treni e stazioni</b>"
"\nScrivi il <b>numero del treno</b> o il <b>nome della stazione</b>, "
"per esempio <code>@{username} 9650</code> o <code>@{username} Roma Termini</code>"
"\n➖➖️ <b>Cerca itinerari</b>"
"\n━━️ <b>Cerca itinerari</b>"
"\nScrivi la <b>stazione di partenza</b>, un <b>trattino -</b> e la <b>stazione di arrivo</b>: "
"per esempio <code>@{username} Milano Centrale - Roma Termini</code>"
"\n<i>Gli itinerari cercati inline sono basati sull'orario attuale</i>"
Expand Down Expand Up @@ -91,10 +91,10 @@ def not_found_answer():
"\n⏺ <i>Cerca treni, stazioni e itinerari in qualsiasi chat</i>"
"\nPer usare questa funzione basta che scrivi <code>@{username} query</code> in qualsiasi chat: "
"si aprirà un pop-up da dove potrai selezionare il risultato desiderato."
"\n➖➖️ <b>Cerca treni e stazioni</b>"
"\n━━️ <b>Cerca treni e stazioni</b>"
"\nScrivi il <b>numero del treno</b> o il <b>nome della stazione</b>, "
"per esempio <code>@{username} 9650</code> o <code>@{username} Roma Termini</code>"
"\n➖➖️ <b>Cerca itinerari</b>"
"\n━━️ <b>Cerca itinerari</b>"
"\nScrivi la <b>stazione di partenza</b>, un <b>trattino -</b> e la <b>stazione di arrivo</b>: "
"per esempio <code>@{username} Milano Centrale - Roma Termini</code>"
"\n<i>Gli itinerari cercati inline sono basati sull'orario attuale</i>"
Expand Down Expand Up @@ -131,7 +131,7 @@ def not_found_answer():

inline_results = []
for result in results:
raw = api.call('andamentoTreno', result[1], iq.query)
raw = api.andamentoTreno(result[1], iq.query)
text = format.formatTrain(raw)
inline_results.append(
{
Expand Down
2 changes: 1 addition & 1 deletion src/updates/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def process_messages(bot, message, u):
elif len(results) == 1:
u.increaseStat('stats_trains_bynum')

raw = api.call('andamentoTreno', results[0][1], message.text) # andamentoTreno; departure station; number
raw = api.andamentoTreno(results[0][1], message.text) # andamentoTreno; departure station; number
u.addRecentElement('trains', results[0][1] + "_" + message.text + "@" + raw['compNumeroTreno'])
text = format.formatTrain(raw)
bot.api.call('sendMessage', {
Expand Down
68 changes: 30 additions & 38 deletions src/viaggiatreno/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@
from datetime import datetime

import botogram
import plotly
import plotly.graph_objs as go
import plotly.plotly as py
import pyowm
import wikipedia
from PIL import Image
from wikipedia.exceptions import PageError
import matplotlib.pyplot as plt

import config
from . import dateutils
Expand All @@ -42,8 +40,7 @@
api = viaggiatreno.API()
utils = viaggiatreno.Utils()
bot = botogram.create(config.BOT_TOKEN)
owm = pyowm.OWM(config.OWM_API_KEY)
plotly.tools.set_credentials_file(username=config.PLOTLY_USERNAME, api_key=config.PLOTLY_API_KEY)
owm = pyowm.OWM(config.OWM_API_KEY).weather_manager()

wikipedia.set_lang("it")

Expand Down Expand Up @@ -104,7 +101,7 @@ def getWeather(station_id: str):
return ""

code = owm.weather_at_coords(station_coords[station_id]["lat"], station_coords[station_id]["lon"])\
.get_weather().get_weather_code()
.weather.weather_code

path = os.getcwd() + '/'.join(['', 'data', 'owm', 'weather_codes_it.json'])
with open(path, 'r') as fp:
Expand Down Expand Up @@ -259,7 +256,7 @@ def formatDepartures(raw: dict, station: str, xrange: int):
platform = "<i>sconosciuto</i> (errore Trenitalia)"

text += (
"\n\n➖➖ <b>Treno {n}</b> ({href})"
"\n\n━━ <b>Treno {n}</b> ({href})"
"\n🚉 <b>Destinazione</b>: {d}"
"\n🛤 <b>Binario</b>: {b}"
"\n🕒 <b>Orario di partenza</b>: {dt}"
Expand Down Expand Up @@ -313,7 +310,7 @@ def formatArrivals(raw: dict, station: str, xrange: int):
platform = "<i>sconosciuto</i> (errore Trenitalia)"

text += (
"\n\n➖➖ <b>Treno {n}</b> ({href})"
"\n\n━━ <b>Treno {n}</b> ({href})"
"\n🚉 <b>Origine</b>: {d}"
"\n🛤 <b>Binario</b>: {b}"
"\n🕒 <b>Orario di arrivo</b>: {dt}"
Expand Down Expand Up @@ -347,16 +344,17 @@ def formatItinerary(raw: dict):
break

x += 1
text += "\n\n➖➖ <b>Soluzione {n}</b>".format(n=x)
text += "\n┏━━ <b>Soluzione {n}</b>".format(n=x)
duration = solution.get('durata', '<i>sconosciuta</i>')
text += "\n🕑 <b>Durata</b>: {t}".format(t=duration if duration is not None else '<i>sconosciuta</i>')
text += "\n🕑 <b>Durata</b>: {t}".format(t=duration if duration is not None else '<i>sconosciuta</i>')
for vehicle in solution['vehicles']:
start_time = datetime.strptime(vehicle['orarioPartenza'], '%Y-%m-%dT%H:%M:%S').strftime('%H:%M')
end_time = datetime.strptime(vehicle['orarioArrivo'], '%Y-%m-%dT%H:%M:%S').strftime('%H:%M')

text += "\n➖ <b>Treno {n}</b> ({href})".format(n=vehicle['numeroTreno'], href=gDLHREF(gTCQ(vehicle)))
text += "\n🚉 <b>Stazione di partenza</b>: {d} ({dh})".format(d=vehicle['origine'], dh=start_time)
text += "\n🚉 <b>Stazione di arrivo</b>: {a} ({ah})".format(a=vehicle['destinazione'], ah=end_time)
text += "\n┣━ <b>{t} {n}</b> ({href})".format(t=vehicle['categoriaDescrizione'], n=vehicle['numeroTreno'], href=gDLHREF(gTCQ(vehicle)))
text += "\n┃ 🚉 <b>Stazione di partenza</b>: {d} ({dh})".format(d=vehicle['origine'], dh=start_time)
text += "\n┃ 🚉 <b>Stazione di arrivo</b>: {a} ({ah})".format(a=vehicle['destinazione'], ah=end_time)
text +="\n┗"

return text

Expand All @@ -374,7 +372,7 @@ def __toBool(__str: str) -> bool:
if not __toBool(news['primoPiano']):
continue
text += (
"\n\n{pinned}➖➖ <b>{title}</b>"
"\n\n{pinned}━━ <b>{title}</b>"
"\n<b>Data</b>: {date}"
"\n{text}"
.format(
Expand All @@ -390,7 +388,7 @@ def __toBool(__str: str) -> bool:
continue

text += (
"\n\n{pinned}➖➖ <b>{title}</b>"
"\n\n{pinned}━━ <b>{title}</b>"
"\n<b>Data</b>: {date}"
"\n{text}"
.format(
Expand Down Expand Up @@ -530,8 +528,9 @@ def generateTrainGraph(raw: dict):
def apply(a, b):
base = Image.open(a)
logo = Image.open(b)
logo.thumbnail((120, 120), Image.ANTIALIAS)
base.paste(logo, (580, 5), mask=logo)
logo.thumbnail((150, 150), Image.ANTIALIAS)
img_width, img_height = base.size
base.paste(logo, (0, -15), mask=logo)
base.save(a)

stops = []
Expand All @@ -547,28 +546,21 @@ def apply(a, b):
if len(stops) < 2 or len(delays) < 2:
return False

line = go.Scatter(
x=stops,
y=delays,
name='Ritardo',
line=dict(
color='rgb(205, 12, 24)',
width=2,
)
)

title = '<b>Ritardo del treno {train}</b>'.format(train=raw['compNumeroTreno'])
layout = dict(
title=title,
xaxis=dict(title='Fermata'),
yaxis=dict(title='Ritardo (minuti)')
)
title = 'Ritardo del treno {train}'.format(train=raw['compNumeroTreno'])
fig, ax = plt.subplots(dpi=200)

filename = os.getcwd() + ''.join(
random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(10)) + '.png'
ax.axhline(y=0, color='gray', linestyle='--')
if any(x >= 60 for x in delays):
ax.axhline(y=60, color='red', linestyle='--')

fig = dict(data=[line], layout=layout)
py.image.save_as(fig, filename=filename)
ax.plot(stops, delays, marker='o')
ax.set_title(title)
ax.set_xticks(stops, stops, rotation=45, ha='right')
ax.set_ylabel('Ritardo (minuti)')

apply(filename, os.getcwd() + "/data/img/logo_white_with_name.png")
fig.tight_layout()
filename = os.getcwd() + '/' + ''.join(
random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(10)) + '.png'
fig.savefig(filename)
apply(filename, os.getcwd() + "/data/img/logo_white_with_name_transparent.png")
return filename
21 changes: 18 additions & 3 deletions src/viaggiatreno/viaggiatreno.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ def _decode_lines(s, linefunc):

def _decode_cercaNumeroTrenoTrenoAutocomplete(s):
def linefunc(line):
r = re.search('^(\d+)\s-\s(.+)\|(\d+)-(.+)$', line)
r = re.search('^(\d+)\s-\s(.+)\|(\d+)-(\w+)-(\d+)', line)
if r is not None:
return r.group(2, 4)
return r.group(2, 4, 5)

return _decode_lines(s, linefunc)

Expand All @@ -128,6 +128,7 @@ def __init__(self, **options):
'partenze': _decode_json,
'arrivi': _decode_json,
'news': _decode_json,
'cercaNumeroTreno': _decode_json,
}
self.__default_decoder = lambda x: x

Expand All @@ -139,7 +140,7 @@ def call(self, function, *params, **options):
plain = options.get('plainoutput', self.__plainoutput)
verbose = options.get('verbose', self.__verbose)

base = 'http://www.viaggiatreno.it/viaggiatrenonew/resteasy/viaggiatreno/'
base = 'http://www.viaggiatreno.it/infomobilita/resteasy/viaggiatreno/'
path = '/'.join(quote(str(p)) for p in params)
url = base + function + '/' + path

Expand All @@ -156,3 +157,17 @@ def call(self, function, *params, **options):
return data
else:
return self.__checkAndDecode(function, data)

def cercaNumeroTreno(self, numeroTreno):
return self.call('cercaNumeroTreno', numeroTreno)

def andamentoTreno(self, codOrigine, numeroTreno, dataPartenza=None):
if dataPartenza is None:
infoTreni = self.call('cercaNumeroTrenoTrenoAutocomplete', numeroTreno)

for infoTreno in infoTreni:
if codOrigine == infoTreno[1]:
dataPartenza = infoTreno[2]
break

return self.call('andamentoTreno', codOrigine, numeroTreno, dataPartenza)

0 comments on commit 0c049ef

Please sign in to comment.