diff --git a/app.py b/app.py index eff2f76..2ad3fce 100644 --- a/app.py +++ b/app.py @@ -16,6 +16,12 @@ RTT_PADDINGTON_URL = ( "?stp=WVS&show=pax-calls&order=wtt" ) +RTT_BRISTOL_URL = ( + "https://www.realtimetrains.co.uk/search/detailed/" + "gb-nr:BRI/to/gb-nr:PAD/{date}/0000-2359" + "?stp=WVS&show=pax-calls&order=wtt" +) + app = Flask(__name__) DESTINATIONS = { @@ -154,8 +160,9 @@ def results(slug, travel_date): next_date = (dt + timedelta(days=1)).isoformat() travel_date_display = dt.strftime('%A %-d %B %Y') - eurostar_url = eurostar_scraper.timetable_url(destination) + f"?date={travel_date}" + eurostar_url = eurostar_scraper.search_url(destination, travel_date) rtt_url = RTT_PADDINGTON_URL.format(date=travel_date) + rtt_bristol_url = RTT_BRISTOL_URL.format(date=travel_date) return render_template( 'results.html', @@ -175,6 +182,7 @@ def results(slug, travel_date): error=error, eurostar_url=eurostar_url, rtt_url=rtt_url, + rtt_bristol_url=rtt_bristol_url, min_connection=min_connection, max_connection=max_connection, valid_min_connections=sorted(VALID_MIN_CONNECTIONS), diff --git a/scraper/eurostar.py b/scraper/eurostar.py index 8ae5129..4bbdfd9 100644 --- a/scraper/eurostar.py +++ b/scraper/eurostar.py @@ -48,6 +48,14 @@ def _slugify_station_name(name: str) -> str: return re.sub(r'[^a-z0-9]+', '-', name.lower()).strip('-') +def search_url(destination: str, travel_date: str) -> str: + dest_id = DESTINATION_STATION_IDS[destination] + return ( + f'https://www.eurostar.com/search/uk-en' + f'?adult=1&origin={ORIGIN_STATION_ID}&destination={dest_id}&outbound={travel_date}' + ) + + def timetable_url(destination: str) -> str: dest_id = DESTINATION_STATION_IDS[destination] dest_slug = _slugify_station_name(destination) diff --git a/templates/results.html b/templates/results.html index cce67cd..a9a244d 100644 --- a/templates/results.html +++ b/templates/results.html @@ -83,7 +83,7 @@ {% if unreachable_morning_services %}  ·  - {{ unreachable_morning_services | length }} morning service{{ 's' if unreachable_morning_services | length != 1 }} unavailable from Bristol + {{ unreachable_morning_services | length }} Eurostar service{{ 's' if unreachable_morning_services | length != 1 }} unavailable from Bristol {% endif %} {% if from_cache %} @@ -209,6 +209,8 @@ Eurostar Standard prices are for 1 adult in GBP; always check eurostar.com to book.  ·  + Bristol departures on RTT +  ·  Paddington arrivals on RTT

diff --git a/tests/test_app.py b/tests/test_app.py index cd21232..937432f 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -211,11 +211,10 @@ def test_results_shows_unreachable_morning_eurostar_services(monkeypatch): html = resp.get_data(as_text=True) assert resp.status_code == 200 - assert '1 morning service unavailable from Bristol' in html + assert '2 Eurostar services unavailable from Bristol' in html assert '09:30' in html assert 'ES 9001' in html assert 'Unavailable from Bristol' in html - assert 'Morning means Eurostar departures before 12:00 from St Pancras.' in html assert html.index('09:30') < html.index('10:15') @@ -267,6 +266,6 @@ def test_results_can_show_only_unreachable_morning_services(monkeypatch): assert resp.status_code == 200 assert 'No valid journeys found.' not in html - assert '1 morning service unavailable from Bristol' in html + assert '1 Eurostar service unavailable from Bristol' in html assert '09:30' in html assert 'Unavailable from Bristol' in html diff --git a/tests/test_trip_planner.py b/tests/test_trip_planner.py index 5e1c93c..a04d8d8 100644 --- a/tests/test_trip_planner.py +++ b/tests/test_trip_planner.py @@ -131,7 +131,9 @@ def test_connection_duration_in_trip(): assert trips[0]['connection_duration'] == '1h 16m' -def test_unreachable_morning_eurostars_lists_only_unreachable_morning_services(): +def test_find_unreachable_eurostars_excludes_connectable_services(): + # GWR arrives 08:45; default min=50/max=110 → viable window 09:35–10:35. + # 09:30 too early, 10:15 connectable, 12:30 beyond max connection. gwr = [ {'depart_bristol': '07:00', 'arrive_paddington': '08:45'}, ] @@ -143,7 +145,7 @@ def test_unreachable_morning_eurostars_lists_only_unreachable_morning_services() unreachable = find_unreachable_morning_eurostars(gwr, eurostar, DATE) - assert [service['depart_st_pancras'] for service in unreachable] == ['09:30'] + assert [s['depart_st_pancras'] for s in unreachable] == ['09:30', '12:30'] # --------------------------------------------------------------------------- @@ -205,7 +207,7 @@ def test_combine_trips_includes_ticket_fields(): assert 'ticket_code' in t -def test_unreachable_morning_eurostars_returns_empty_when_morning_service_is_reachable(): +def test_find_unreachable_eurostars_returns_empty_when_all_connectable(): gwr = [ {'depart_bristol': '07:00', 'arrive_paddington': '08:45'}, ]