Cache reads now accept an optional ttl (seconds). get_cached checks the
file mtime and returns None if the entry is older than the TTL, triggering
a fresh fetch. Eurostar prices use a 24-hour TTL; timetable caches remain
indefinite (date-scoped keys become irrelevant once the date passes).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fetches prices via the site-api.eurostar.com GraphQL gateway
(NewBookingSearch operation, discovered with Playwright). Adds
fetch_prices() to scraper/eurostar.py using requests, caches results,
annotates each trip with eurostar_price and total_price, and shows an
ES Std column plus total cost (duration + price) in the results table.
The Transfer column is hidden on small screens for mobile usability.
Closes#4
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add cheapest_gwr_ticket() to trip_planner.py encoding the SSS/SVS/SDS
walk-on single restrictions for Bristol Temple Meads → Paddington: on
weekdays, Super Off-Peak (£45) is valid before 05:05 or from 09:58,
Off-Peak (£63.60) from 08:26, and Anytime (£138.70) covers the gap.
Weekends have no restrictions. The fare is included in each trip dict
and displayed in a new GWR Fare column on the results page.
Also wire up find_unreachable_morning_eurostars() into the results view
so early Eurostar services unreachable from Bristol appear in the table,
with tests covering both features.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>