package main import ( "fmt" "io" "net/http" "time" ) const BaseURL = "https://www.nationalrail.co.uk/live-trains/departures/" // FetchStationDepartures fetches the HTML content for a station's departures func FetchStationDepartures(stationCode string) (string, error) { client := &http.Client{ Timeout: 30 * time.Second, } url := BaseURL + stationCode + "/" req, err := http.NewRequest("GET", url, nil) if err != nil { return "", fmt.Errorf("failed to create request: %w", err) } // Add headers to mimic a browser request req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36") req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") resp, err := client.Do(req) if err != nil { return "", fmt.Errorf("failed to fetch data: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return "", fmt.Errorf("unexpected status code: %d", resp.StatusCode) } body, err := io.ReadAll(resp.Body) if err != nil { return "", fmt.Errorf("failed to read response body: %w", err) } return string(body), nil } type StationData struct { Station Station `json:"station"` Departures []Departure `json:"departures"` LastUpdate time.Time `json:"last_update"` Error string `json:"error,omitempty"` } // FetchAllStationsData fetches departure data for all configured stations func FetchAllStationsData(stations []Station) []StationData { results := make([]StationData, len(stations)) for i, station := range stations { results[i] = StationData{ Station: station, LastUpdate: time.Now(), } htmlContent, err := FetchStationDepartures(station.Code) if err != nil { results[i].Error = err.Error() continue } departures, err := ParseDeparturesFromHTML(htmlContent) if err != nil { results[i].Error = err.Error() continue } results[i].Departures = departures } return results }