photoprism/internal/maps/osm/location.go
Michael Mayer f8a45b14d9 Backend: Move reusable packages to pkg/
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
2020-01-12 14:00:56 +01:00

131 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"
"github.com/photoprism/photoprism/pkg/txt"
)
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 txt.Keywords(l.LocDisplayName)
}
func (l Location) Source() string {
return "osm"
}