bristol-eurostar/app.py
2026-03-30 19:34:46 +01:00

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)