service.py

Sun, 11 Jun 2017 01:28:25 +0300

author
Teemu Piippo <teemu@hecknology.net>
date
Sun, 11 Jun 2017 01:28:25 +0300
changeset 20
3199e289ae62
parent 19
16fa9fb20b32
child 21
6a0394d5a159
permissions
-rwxr-xr-x

- Sivusto hieman edustuksellisempi
- Aikataulut ottavat edelliselle päivälle merkitty, mutta nykyiselle päivälle "vuotavat" vuorot huomioon (yölinjat)

#!/usr/bin/env python3
from flask import Flask, render_template, abort, send_from_directory
from datetime import datetime, date, time, timedelta
from os import path, listdir
from configparser import ConfigParser
import locale

from misc import *
from busroute import supista_reitti

app = Flask(__name__)

# Varmista ettei järjestelmän kieliasetukset sotke muotoiluja
def reset_locale():
	locale.setlocale(locale.LC_ALL, locale.getdefaultlocale())

def activate_locale(language = None):
	language = language or language_for_page()
	class result:
		def __enter__(self):
			locale.setlocale(locale.LC_ALL, tr('locale', 'other', language = language))
		def __exit__(self, *args):
			reset_locale()
	return result()

reset_locale()

# Lataa käännökset
class Translator:
	def __init__(self):
		self.languages = {}
	def load_language(self, file_path):
		language_name = path.splitext(path.basename(file_path))[0]
		ini = ConfigParser()
		ini.read(path.join(file_path))
		self.languages[language_name] = ini
	def __call__(self, name, section, language = None):
		language = language or language_for_page()
		try:
			return self.languages[language][section][name]
		except KeyError:
			return name

tr = Translator()
for file in listdir('tr'):
	tr.load_language(path.join('tr', file))

def language_for_page():
	from flask import request
	if request.args.get('kääntämätön') is not None:
		return None
	else:
		for language_name in tr.languages:
			if request.args.get(language_name) is not None:
				return language_name
		else:
			return 'fi'

def sign(schedule_entry):
	from math import ceil
	sign = supista_reitti(schedule_entry['trip'].suppea_reitti(schedule_entry['stop']))
	sign = [tr(paikka, 'paikat') for paikka in sign]
	sign_representation = ' - '.join(sign)
	if len(sign_representation) > 25:
		k = ceil(len(sign) / 2)
		sign_representation = ' - '.join(sign[:k]) + '\n' + ' - '.join(sign[k:])
	return sign_representation

@app.route('/pysäkki/<tunniste>')
def pysäkkiaikataulu(tunniste):
	from buses import pysäkit
	aikataulu = []
	try:
		pysäkki = pysäkit[tunniste]
	except KeyError:
		abort(404)
	for schedule_entry in pysäkki.schedule(100):
		aikataulu.append({
			'aika': time_representation(schedule_entry['time']),
			'linja': schedule_entry['trip'].linja.viite,
			'kyltti': sign(schedule_entry),
			'ajovuoro': schedule_entry['stop'].ajo.nimi,
			'yö': is_night_time(schedule_entry['time']),
		})
	return render_template(
		'pysäkki.html',
		aikataulu = aikataulu,
		nimi = tunniste + ' ' + tr(pysäkki.nimi, 'pysäkit'),
		linkki_karttaan = pysäkki.sijainti.link_to_map,
		alue = pysäkki.alue,
		sijainti = pysäkki.sijainti,
		cluster = pysäkki.cluster.name if len(pysäkki.cluster.stops) > 1 else None,
		tr = tr,
	)

def time_representation(aika, suhteellinen = True):
	erotus = aika - nyt()
	if suhteellinen and erotus < timedelta(minutes = 1):
		return tr('right-now', 'misc-text')
	elif suhteellinen and erotus < timedelta(minutes = 10):
		return '%dm' % round(erotus.seconds / 60)
	elif aika.date() == tänään():
		return '%d:%02d' % (aika.hour, aika.minute)
	elif erotus < timedelta(7):
		with activate_locale():
			return aika.strftime('%-a %H:%M')
	else:
		with activate_locale():
			return aika.strftime('%-d.%-m. %H:%M')

@app.route('/pysäkkiryhmä/<cluster_name>')
def cluster_schedule(cluster_name):
	from buses import pysäkit, clusters_by_name
	aikataulu = []
	try:
		cluster = clusters_by_name[cluster_name]
	except KeyError:
		abort(404)
	for schedule_entry in cluster.schedule(100):
		aikataulu.append({
			'aika': time_representation(schedule_entry['time']),
			'linja': schedule_entry['trip'].linja.viite,
			'kyltti': sign(schedule_entry),
			'ajovuoro': schedule_entry['stop'].ajo.nimi,
			'yö': is_night_time(schedule_entry['time']),
			'stop_id': schedule_entry['stop'].pysäkki.tunniste,
			'stop_name': tr(schedule_entry['stop'].pysäkki.nimi, 'pysäkit'),
		})
	return render_template(
		'cluster.html',
		aikataulu = aikataulu,
		nimi = 'Yhdistetty pysäkkiaikataulu ' + cluster_name,
		linkki_karttaan = cluster.center.link_to_map,
		sijainti = cluster.center,
		stops_in_cluster = sorted(
			({
				'id': stop.tunniste,
				'name': tr(stop.nimi, 'pysäkit'),
			} for stop in cluster.stops),
			key = lambda stop: (len(stop['id']), stop['id'])
		),
		tr = tr,
	)

@app.route('/ajovuoro/<numero>')
def ajoreitti(numero):
	from flask import request
	from buses import ajot
	try:
		ajovuoro = ajot[numero]
	except KeyError:
		abort(404)
	suppea = request.args.get('suppea') is not None
	reitti = []
	suppea_reitti = []
	käydyt_alueet = set()
	for pysähdys in ajovuoro.reitti:
		aika = datetime.combine(tänään(), time()) + pysähdys.saapumisaika
		muotoiltu_aika = time_representation(aika)
		reitti.append({
			'aika': muotoiltu_aika,
			'tunniste': pysähdys.pysäkki.tunniste,
			'alue': tr(pysähdys.pysäkki.alue or '', 'paikat'),
			'nimi': tr(pysähdys.pysäkki.nimi, 'pysäkit'),
		})
		alue = pysähdys.pysäkki.alue
		if alue:
			if alue not in käydyt_alueet:
				suppea_reitti.append({
					'aika': muotoiltu_aika,
					'alue': alue,
				})
				käydyt_alueet.add(alue)
	kyltti = supista_reitti([k['alue'] for k in suppea_reitti], kokonainen = True)
	sivu = suppea and 'ajovuoro-suppea.html' or 'ajovuoro.html'
	return render_template(sivu,
		reitti = reitti,
		suppea_reitti = suppea_reitti,
		numero = numero,
		linja = ajovuoro.linja.viite,
		selite = ' - '.join(tr(paikka, 'paikat') for paikka in kyltti),
		yö = is_night_time(datetime.combine(tänään(), time()) + ajovuoro.reitti[-1].saapumisaika),
		tr = tr,
		)

@app.route('/static/<path:path>')
def static_file(path):
	return send_from_directory(path.join('static', path))

if __name__ == '__main__':
	from argparse import ArgumentParser
	parser = ArgumentParser()
	parser.add_argument('-p', '--port', type = int, default = 5000)
	parser.add_argument('-d', '--debug', action = 'store_true')
	args = parser.parse_args()
	app.run(debug = args.debug, port = args.port)

mercurial