96 lines
2.9 KiB
Python
96 lines
2.9 KiB
Python
import asyncio
|
|
from flask import Flask, render_template, redirect, url_for, request
|
|
from datetime import date, timedelta
|
|
|
|
from cache import get_cached, set_cached
|
|
import scraper.eurostar as eurostar_scraper
|
|
import scraper.realtime_trains as rtt_scraper
|
|
from trip_planner import combine_trips
|
|
|
|
app = Flask(__name__)
|
|
|
|
DESTINATIONS = {
|
|
'paris': 'Paris Gare du Nord',
|
|
'brussels': 'Brussels Midi',
|
|
'lille': 'Lille Europe',
|
|
'amsterdam': 'Amsterdam Centraal',
|
|
}
|
|
|
|
|
|
async def _fetch_both(destination: str, travel_date: str, user_agent: str):
|
|
"""Fetch GWR trains and Eurostar times simultaneously."""
|
|
gwr, es = await asyncio.gather(
|
|
rtt_scraper.fetch(travel_date, user_agent),
|
|
eurostar_scraper.fetch(destination, travel_date, user_agent),
|
|
return_exceptions=True,
|
|
)
|
|
return gwr, es
|
|
|
|
|
|
@app.route('/')
|
|
def index():
|
|
today = date.today().isoformat()
|
|
return render_template('index.html', destinations=DESTINATIONS, today=today)
|
|
|
|
|
|
@app.route('/results/<slug>/<travel_date>')
|
|
def results(slug, travel_date):
|
|
destination = DESTINATIONS.get(slug)
|
|
if not destination or not travel_date:
|
|
return redirect(url_for('index'))
|
|
|
|
user_agent = request.headers.get('User-Agent', rtt_scraper.DEFAULT_UA)
|
|
|
|
cache_key = f"{travel_date}_{destination}"
|
|
cached = get_cached(cache_key)
|
|
|
|
error = None
|
|
if cached:
|
|
gwr_trains = cached['gwr']
|
|
eurostar_trains = cached['eurostar']
|
|
from_cache = True
|
|
else:
|
|
from_cache = False
|
|
gwr_result, es_result = asyncio.run(_fetch_both(destination, travel_date, user_agent))
|
|
|
|
if isinstance(gwr_result, Exception):
|
|
gwr_trains = []
|
|
error = f"Could not fetch GWR trains: {gwr_result}"
|
|
else:
|
|
gwr_trains = gwr_result
|
|
|
|
if isinstance(es_result, Exception):
|
|
eurostar_trains = []
|
|
msg = f"Could not fetch Eurostar times: {es_result}"
|
|
error = f"{error}; {msg}" if error else msg
|
|
else:
|
|
eurostar_trains = es_result
|
|
|
|
if gwr_trains or eurostar_trains:
|
|
set_cached(cache_key, {'gwr': gwr_trains, 'eurostar': eurostar_trains})
|
|
|
|
trips = combine_trips(gwr_trains, eurostar_trains, travel_date)
|
|
|
|
dt = date.fromisoformat(travel_date)
|
|
prev_date = (dt - timedelta(days=1)).isoformat()
|
|
next_date = (dt + timedelta(days=1)).isoformat()
|
|
travel_date_display = dt.strftime('%A %-d %B %Y')
|
|
|
|
return render_template(
|
|
'results.html',
|
|
trips=trips,
|
|
destination=destination,
|
|
travel_date=travel_date,
|
|
slug=slug,
|
|
prev_date=prev_date,
|
|
next_date=next_date,
|
|
travel_date_display=travel_date_display,
|
|
gwr_count=len(gwr_trains),
|
|
eurostar_count=len(eurostar_trains),
|
|
from_cache=from_cache,
|
|
error=error,
|
|
)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
app.run(debug=True)
|