Allow specifying state in weather location

This commit is contained in:
Svilen Markov
2024-05-02 19:54:20 +01:00
parent ad06146784
commit d8d6625478
4 changed files with 79 additions and 3 deletions

View File

@@ -6,6 +6,7 @@ import (
"net/http"
"net/url"
"slices"
"strings"
"time"
_ "time/tzdata"
@@ -17,6 +18,7 @@ type PlacesResponseJson struct {
type PlaceJson struct {
Name string
Area string `json:"admin1"`
Latitude float64
Longitude float64
Timezone string
@@ -48,8 +50,41 @@ type weatherColumn struct {
HasPrecipitation bool
}
var commonCountryAbbreviations = map[string]string{
"US": "United States",
"USA": "United States",
"UK": "United Kingdom",
}
func expandCountryAbbreviations(name string) string {
if expanded, ok := commonCountryAbbreviations[strings.TrimSpace(name)]; ok {
return expanded
}
return name
}
// Separates the location that Open Meteo accepts from the administrative area
// which can then be used to filter to the correct place after the list of places
// has been retrieved. Also expands abbreviations since Open Meteo does not accept
// country names like "US", "USA" and "UK"
func parsePlaceName(name string) (string, string) {
parts := strings.Split(name, ",")
if len(parts) == 1 {
return name, ""
}
if len(parts) == 2 {
return parts[0] + ", " + expandCountryAbbreviations(parts[1]), ""
}
return parts[0] + ", " + expandCountryAbbreviations(parts[2]), strings.TrimSpace(parts[1])
}
func FetchPlaceFromName(location string) (*PlaceJson, error) {
requestUrl := fmt.Sprintf("https://geocoding-api.open-meteo.com/v1/search?name=%s&count=1&language=en&format=json", url.QueryEscape(location))
location, area := parsePlaceName(location)
requestUrl := fmt.Sprintf("https://geocoding-api.open-meteo.com/v1/search?name=%s&count=10&language=en&format=json", url.QueryEscape(location))
request, _ := http.NewRequest("GET", requestUrl, nil)
responseJson, err := decodeJsonFromRequest[PlacesResponseJson](defaultClient, request)
@@ -61,7 +96,24 @@ func FetchPlaceFromName(location string) (*PlaceJson, error) {
return nil, fmt.Errorf("no places found for %s", location)
}
place := &responseJson.Results[0]
var place *PlaceJson
if area != "" {
area = strings.ToLower(area)
for i := range responseJson.Results {
if strings.ToLower(responseJson.Results[i].Area) == area {
place = &responseJson.Results[i]
break
}
}
if place == nil {
return nil, fmt.Errorf("no place found for %s in %s", location, area)
}
} else {
place = &responseJson.Results[0]
}
loc, err := time.LoadLocation(place.Timezone)