96098913ff
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
130 lines
2.7 KiB
Go
130 lines
2.7 KiB
Go
package osm
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/melihmucuk/geocache"
|
|
"github.com/photoprism/photoprism/pkg/s2"
|
|
)
|
|
|
|
type Location struct {
|
|
ID string `json:"-"`
|
|
PlaceID int `json:"place_id"`
|
|
LocName string `json:"name"`
|
|
LocCategory string `json:"category"`
|
|
LocType string `json:"type"`
|
|
LocDisplayName string `json:"display_name"`
|
|
Address Address `json:"address"`
|
|
Cached bool
|
|
}
|
|
|
|
var ReverseLookupURL = "https://nominatim.openstreetmap.org/reverse?lat=%f&lon=%f&format=jsonv2&accept-language=en&zoom=18"
|
|
|
|
// API docs see https://wiki.openstreetmap.org/wiki/Nominatim#Reverse_Geocoding
|
|
func FindLocation(id string) (result Location, err error) {
|
|
if len(id) > 16 || len(id) == 0 {
|
|
return result, errors.New("osm: invalid location id")
|
|
}
|
|
|
|
lat, lng := s2.LatLng(id)
|
|
|
|
if lat == 0.0 || lng == 0.0 {
|
|
return result, fmt.Errorf("osm: skipping lat %f, lng %f", lat, lng)
|
|
}
|
|
|
|
point := geocache.GeoPoint{Latitude: lat, Longitude: lng}
|
|
|
|
if hit, ok := geoCache.Get(point); ok {
|
|
log.Debugf("osm: cache hit for lat %f, lng %f", lat, lng)
|
|
result = hit.(Location)
|
|
result.Cached = true
|
|
return result, nil
|
|
}
|
|
|
|
url := fmt.Sprintf(ReverseLookupURL, lat, lng)
|
|
|
|
log.Debugf("osm: query %s", url)
|
|
|
|
r, err := http.Get(url)
|
|
|
|
if err != nil {
|
|
log.Errorf("osm: %s", err.Error())
|
|
return result, err
|
|
}
|
|
|
|
err = json.NewDecoder(r.Body).Decode(&result)
|
|
|
|
if err != nil {
|
|
log.Errorf("osm: %s", err.Error())
|
|
return result, err
|
|
}
|
|
|
|
if result.PlaceID == 0 {
|
|
result.ID = ""
|
|
|
|
return result, fmt.Errorf("osm: no result for %s", id)
|
|
}
|
|
|
|
result.ID = id
|
|
|
|
geoCache.Set(point, result, time.Hour)
|
|
|
|
result.Cached = false
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (l Location) CellID() (result string) {
|
|
return l.ID
|
|
}
|
|
|
|
func (l Location) State() (result string) {
|
|
result = l.Address.State
|
|
|
|
return strings.TrimSpace(result)
|
|
}
|
|
|
|
func (l Location) City() (result string) {
|
|
if l.Address.City != "" {
|
|
result = l.Address.City
|
|
} else if l.Address.Town != "" {
|
|
result = l.Address.Town
|
|
} else if l.Address.Village != "" {
|
|
result = l.Address.Village
|
|
} else if l.Address.County != "" {
|
|
result = l.Address.County
|
|
} else if l.Address.State != "" {
|
|
result = l.Address.State
|
|
}
|
|
|
|
if len([]rune(result)) > 19 {
|
|
result = ""
|
|
}
|
|
|
|
return strings.TrimSpace(result)
|
|
}
|
|
|
|
func (l Location) Suburb() (result string) {
|
|
result = l.Address.Suburb
|
|
|
|
return strings.TrimSpace(result)
|
|
}
|
|
|
|
func (l Location) CountryCode() (result string) {
|
|
result = l.Address.CountryCode
|
|
|
|
return strings.ToLower(strings.TrimSpace(result))
|
|
}
|
|
|
|
func (l Location) Keywords() (result []string) {
|
|
return result
|
|
}
|
|
|
|
func (l Location) Source() string {
|
|
return "osm"
|
|
}
|