Backend: Improve location hashing and categories
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
f3cf300590
commit
1e7c0c2435
25 changed files with 451 additions and 1346 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -15,6 +15,7 @@
|
|||
/assets/backups
|
||||
/assets/resources/nasnet
|
||||
/assets/resources/nsfw
|
||||
/package-lock.json
|
||||
*.log
|
||||
|
||||
# Binaries for programs and plugins
|
||||
|
|
|
@ -4,14 +4,13 @@
|
|||
"presets": [
|
||||
"@babel/preset-env"
|
||||
],
|
||||
"plugins": [ ["istanbul", {
|
||||
"exclude": [
|
||||
"**/*_test.js"
|
||||
]
|
||||
}] ]
|
||||
"plugins": [
|
||||
["@babel/plugin-transform-runtime"],
|
||||
["istanbul", {"exclude": ["**/*_test.js"]}]
|
||||
]
|
||||
}
|
||||
},
|
||||
"presets": [
|
||||
"@babel/preset-env"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,9 @@ module.exports = (config) => {
|
|||
},
|
||||
|
||||
files: [
|
||||
{pattern: "tests/unit/**/*_test.js", watched: false},
|
||||
"node_modules/@babel/polyfill/dist/polyfill.js",
|
||||
"node_modules/regenerator-runtime/runtime/runtime.js",
|
||||
{pattern: "tests/unit/**/*_test.js", watched: false},
|
||||
],
|
||||
|
||||
// Preprocess through webpack
|
||||
|
|
1458
frontend/package-lock.json
generated
1458
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -17,12 +17,13 @@
|
|||
"gettext-compile": "gettext-compile --output src/resources/translations.json src/resources/*.po"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/cli": "^7.7.5",
|
||||
"@babel/core": "^7.7.5",
|
||||
"@babel/cli": "^7.7.7",
|
||||
"@babel/core": "^7.7.7",
|
||||
"@babel/plugin-transform-runtime": "^7.7.6",
|
||||
"@babel/polyfill": "^7.7.0",
|
||||
"@babel/preset-env": "^7.7.6",
|
||||
"@babel/register": "^7.7.4",
|
||||
"@babel/preset-env": "^7.7.7",
|
||||
"@babel/register": "^7.7.7",
|
||||
"@babel/runtime": "^7.7.7",
|
||||
"@fortawesome/fontawesome-free": "^5.12.0",
|
||||
"@types/leaflet": "^1.5.7",
|
||||
"acorn": "^6.4.0",
|
||||
|
@ -41,13 +42,13 @@
|
|||
"clean-webpack-plugin": "^3.0.0",
|
||||
"connect-history-api-fallback": "^1.3.0",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"core-js": "^3.5.0",
|
||||
"core-js": "^3.6.0",
|
||||
"cross-env": "^5.2.1",
|
||||
"crypto-random-string": "^3.0.1",
|
||||
"css-loader": "^2.1.1",
|
||||
"cssnano": "^4.1.10",
|
||||
"easygettext": "^2.9.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-standard": "^13.0.1",
|
||||
"eslint-formatter-pretty": "^2.1.1",
|
||||
"eslint-friendly-formatter": "^4.0.1",
|
||||
|
@ -62,6 +63,7 @@
|
|||
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"http-proxy-middleware": "^0.19.1",
|
||||
"i18n-iso-countries": "^4.3.1",
|
||||
"inject-loader": "^4.0.1",
|
||||
"karma": "^4.4.1",
|
||||
"karma-chrome-launcher": "^3.1.0",
|
||||
|
@ -110,10 +112,10 @@
|
|||
"vue-style-loader": "^4.1.2",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vue2-filters": "^0.6.1",
|
||||
"vue2-leaflet": "^2.3.2",
|
||||
"vue2-leaflet": "^2.4.1",
|
||||
"vuelidate": "^0.7.4",
|
||||
"vuetify": "^1.5.21",
|
||||
"webpack": "^4.41.3",
|
||||
"webpack": "^4.41.4",
|
||||
"webpack-bundle-analyzer": "^3.6.0",
|
||||
"webpack-cli": "^3.3.10",
|
||||
"webpack-hot-middleware": "^2.25.0",
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
{text: '', value: '', align: 'center', sortable: false, class: 'p-col-select'},
|
||||
{text: this.$gettext('Title'), value: 'PhotoTitle'},
|
||||
{text: this.$gettext('Taken At'), value: 'TakenAt'},
|
||||
{text: this.$gettext('Location'), value: 'LocRegion'},
|
||||
{text: this.$gettext('Location'), value: 'LocDescription'},
|
||||
{text: this.$gettext('Camera'), value: 'CameraModel'},
|
||||
{text: this.$gettext('Favorite'), value: 'PhotoFavorite', align: 'left'},
|
||||
],
|
||||
|
|
|
@ -105,10 +105,8 @@ class Photo extends Abstract {
|
|||
}
|
||||
|
||||
getLocation() {
|
||||
if (this.LocRegion) {
|
||||
return this.LocRegion
|
||||
} else if (this.CountryName) {
|
||||
return this.CountryName;
|
||||
if (this.LocDescription) {
|
||||
return this.LocDescription
|
||||
}
|
||||
|
||||
return "Unknown"
|
||||
|
|
|
@ -119,8 +119,6 @@
|
|||
this.$router.push({name: "places", query: {lat: String(photo.PhotoLat), lng: String(photo.PhotoLng)}});
|
||||
} else if (photo.LocCity) {
|
||||
this.$router.push({name: "places", query: {q: photo.LocCity}});
|
||||
} else {
|
||||
this.$router.push({name: "places", query: {q: photo.CountryName}});
|
||||
}
|
||||
},
|
||||
openPhoto(index) {
|
||||
|
|
|
@ -109,8 +109,6 @@
|
|||
this.$router.push({name: "places", query: {lat: String(photo.PhotoLat), lng: String(photo.PhotoLng)}});
|
||||
} else if (photo.LocCity) {
|
||||
this.$router.push({name: "places", query: {q: photo.LocCity}});
|
||||
} else {
|
||||
this.$router.push({name: "places", query: {q: photo.CountryName}});
|
||||
}
|
||||
},
|
||||
openPhoto(index) {
|
||||
|
|
|
@ -135,14 +135,14 @@ describe("model/photo", () => {
|
|||
});
|
||||
|
||||
it("should get location", () => {
|
||||
const values = {ID: 5, PhotoTitle: "Crazy Cat", LocationID: 6, LocType: "viewpoint", LocRegion: "Cape Point, South Africa", LocCountry: "South Africa"};
|
||||
const values = {ID: 5, PhotoTitle: "Crazy Cat", LocationID: 6, LocType: "viewpoint", LocDescription: "Cape Point, South Africa", LocCountry: "South Africa"};
|
||||
const photo = new Photo(values);
|
||||
const result = photo.getLocation();
|
||||
assert.equal(result, "Cape Point, South Africa");
|
||||
});
|
||||
|
||||
it("should get location", () => {
|
||||
const values = {ID: 5, PhotoTitle: "Crazy Cat", LocationID: 6, LocType: "viewpoint", LocRegion: "Cape Point, State, South Africa", LocCountry: "South Africa", LocCity: "Cape Town", LocCounty: "County", LocState: "State"};
|
||||
const values = {ID: 5, PhotoTitle: "Crazy Cat", LocationID: 6, LocType: "viewpoint", LocDescription: "Cape Point, State, South Africa", LocCountry: "South Africa", LocCity: "Cape Town", LocCounty: "County", LocState: "State"};
|
||||
const photo = new Photo(values);
|
||||
const result = photo.getLocation();
|
||||
assert.equal(result, "Cape Point, State, South Africa");
|
||||
|
@ -159,7 +159,7 @@ describe("model/photo", () => {
|
|||
const values = {ID: 5, PhotoTitle: "Crazy Cat", CountryName: "Africa", LocCity: "Cape Town"};
|
||||
const photo = new Photo(values);
|
||||
const result = photo.getLocation();
|
||||
assert.equal(result, "Africa");
|
||||
assert.equal(result, "Unknown");
|
||||
});
|
||||
|
||||
it("should get camera", () => {
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
olc "github.com/google/open-location-code/go"
|
||||
"github.com/jinzhu/gorm"
|
||||
"github.com/photoprism/photoprism/internal/maps"
|
||||
"github.com/photoprism/photoprism/internal/util"
|
||||
|
@ -13,7 +12,6 @@ import (
|
|||
// Photo location
|
||||
type Location struct {
|
||||
maps.Location
|
||||
LocDescription string `gorm:"type:text;"`
|
||||
LocNotes string `gorm:"type:text;"`
|
||||
LocFavorite bool
|
||||
CreatedAt time.Time
|
||||
|
@ -23,19 +21,19 @@ type Location struct {
|
|||
func NewLocation(lat, lng float64) *Location {
|
||||
result := &Location{}
|
||||
|
||||
result.ID = olc.Encode(lat, lng, 11)
|
||||
result.ID = maps.OlcEncode(lat, lng)
|
||||
result.LocLat = lat
|
||||
result.LocLng = lng
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *Location) Label() string {
|
||||
return m.LocLabel
|
||||
func (m *Location) Category() string {
|
||||
return m.LocCategory
|
||||
}
|
||||
|
||||
func (m *Location) Find(db *gorm.DB) error {
|
||||
if err := db.First(m, "id = ?", m.ID).Error; err == nil {
|
||||
if err := db.First(m, "id LIKE ?", m.ID + "%").Error; err == nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -57,7 +55,7 @@ func (m *Location) Keywords() []string {
|
|||
strings.ToLower(m.LocSuburb),
|
||||
strings.ToLower(m.LocState),
|
||||
strings.ToLower(m.CountryName()),
|
||||
strings.ToLower(m.LocLabel),
|
||||
strings.ToLower(m.LocCategory),
|
||||
}
|
||||
|
||||
result = append(result, util.Keywords(m.LocTitle)...)
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
|
||||
func TestLocation_Label(t *testing.T) {
|
||||
l := NewLocation(1,1)
|
||||
l.LocLabel = "restaurant"
|
||||
result := l.Label()
|
||||
l.LocCategory = "restaurant"
|
||||
result := l.Category()
|
||||
|
||||
assert.Equal(t, "restaurant", result)
|
||||
}
|
||||
|
|
|
@ -17,24 +17,24 @@ import (
|
|||
type PhotoSearch struct {
|
||||
Query string `form:"q"`
|
||||
|
||||
Title string `form:"title"`
|
||||
Description string `form:"description"`
|
||||
Notes string `form:"notes"`
|
||||
Artist string `form:"artist"`
|
||||
Hash string `form:"hash"`
|
||||
Duplicate bool `form:"duplicate"`
|
||||
Lat float64 `form:"lat"`
|
||||
Lng float64 `form:"lng"`
|
||||
Dist uint `form:"dist"`
|
||||
Fmin float64 `form:"fmin"`
|
||||
Fmax float64 `form:"fmax"`
|
||||
Chroma uint `form:"chroma"`
|
||||
Mono bool `form:"mono"`
|
||||
Portrait bool `form:"portrait"`
|
||||
Location bool `form:"location"`
|
||||
Album string `form:"album"`
|
||||
Label string `form:"label"`
|
||||
Country string `form:"country"`
|
||||
Title string `form:"title"`
|
||||
Description string `form:"description"`
|
||||
Notes string `form:"notes"`
|
||||
Artist string `form:"artist"`
|
||||
Hash string `form:"hash"`
|
||||
Duplicate bool `form:"duplicate"`
|
||||
Lat float64 `form:"lat"`
|
||||
Lng float64 `form:"lng"`
|
||||
Dist uint `form:"dist"`
|
||||
Fmin float64 `form:"fmin"`
|
||||
Fmax float64 `form:"fmax"`
|
||||
Chroma uint `form:"chroma"`
|
||||
Mono bool `form:"mono"`
|
||||
Portrait bool `form:"portrait"`
|
||||
Location bool `form:"location"`
|
||||
Album string `form:"album"`
|
||||
Label string `form:"label"`
|
||||
Country string `form:"country"`
|
||||
Color string `form:"color"`
|
||||
Camera int `form:"camera"`
|
||||
Before time.Time `form:"before" time_format:"2006-01-02"`
|
||||
|
@ -43,6 +43,7 @@ type PhotoSearch struct {
|
|||
Public bool `form:"public"`
|
||||
Story bool `form:"story"`
|
||||
Safe bool `form:"safe"`
|
||||
NSFW bool `form:"nsfw"`
|
||||
|
||||
Count int `form:"count" binding:"required"`
|
||||
Offset int `form:"offset"`
|
||||
|
|
|
@ -4,39 +4,38 @@ import (
|
|||
"errors"
|
||||
"strings"
|
||||
|
||||
olc "github.com/google/open-location-code/go"
|
||||
"github.com/photoprism/photoprism/internal/maps/osm"
|
||||
)
|
||||
|
||||
// Photo location
|
||||
type Location struct {
|
||||
ID string `gorm:"primary_key"`
|
||||
CountryID string
|
||||
LocLat float64
|
||||
LocLng float64
|
||||
LocCategory string
|
||||
LocTitle string
|
||||
LocRegion string
|
||||
LocDescription string
|
||||
LocCity string
|
||||
LocSuburb string
|
||||
LocState string
|
||||
LocCountryCode string
|
||||
LocLabel string
|
||||
LocSource string
|
||||
}
|
||||
|
||||
type LocationSource interface {
|
||||
CountryCode() string
|
||||
Latitude() float64
|
||||
Longitude() float64
|
||||
Category() string
|
||||
Title() string
|
||||
City() string
|
||||
Suburb() string
|
||||
State() string
|
||||
CountryCode() string
|
||||
Label() string
|
||||
Source() string
|
||||
}
|
||||
|
||||
func NewLocation (lat, lng float64) *Location {
|
||||
id := olc.Encode(lat, lng, 11)
|
||||
id := OlcEncode(lat, lng)
|
||||
|
||||
result := &Location{
|
||||
ID: id,
|
||||
|
@ -64,19 +63,19 @@ func (l *Location) Assign(s LocationSource) error {
|
|||
if l.LocLng == 0 { l.LocLng = s.Longitude() }
|
||||
|
||||
if l.Unknown() {
|
||||
l.LocLabel = "unknown"
|
||||
l.LocCategory = "unknown"
|
||||
return errors.New("maps: unknown location")
|
||||
}
|
||||
|
||||
if l.ID == "" { l.ID = olc.Encode(l.LocLat, l.LocLng, 11) }
|
||||
if l.ID == "" { l.ID = OlcEncode(l.LocLat, l.LocLng) }
|
||||
|
||||
l.LocTitle = s.Title()
|
||||
l.LocCity = s.City()
|
||||
l.LocSuburb = s.Suburb()
|
||||
l.LocState = s.State()
|
||||
l.LocCountryCode = s.CountryCode()
|
||||
l.LocLabel = s.Label()
|
||||
l.LocRegion = l.region()
|
||||
l.CountryID = s.CountryCode()
|
||||
l.LocCategory = s.Category()
|
||||
l.LocDescription = l.description()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -89,7 +88,7 @@ func (l *Location) Unknown() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (l *Location) region() string {
|
||||
func (l *Location) description() string {
|
||||
if l.Unknown() {
|
||||
return "Unknown"
|
||||
}
|
||||
|
@ -139,8 +138,8 @@ func (l Location) State() string {
|
|||
return l.LocState
|
||||
}
|
||||
|
||||
func (l Location) Label() string {
|
||||
return l.LocLabel
|
||||
func (l Location) Category() string {
|
||||
return l.LocCategory
|
||||
}
|
||||
|
||||
func (l Location) Source() string {
|
||||
|
@ -148,13 +147,13 @@ func (l Location) Source() string {
|
|||
}
|
||||
|
||||
func (l Location) Region() string {
|
||||
return l.LocRegion
|
||||
return l.LocDescription
|
||||
}
|
||||
|
||||
func (l Location) CountryCode() string {
|
||||
return l.LocCountryCode
|
||||
return l.CountryID
|
||||
}
|
||||
|
||||
func (l Location) CountryName() string {
|
||||
return CountryNames[l.LocCountryCode]
|
||||
return CountryNames[l.CountryID]
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ func TestLocation_Query(t *testing.T) {
|
|||
}
|
||||
|
||||
assert.Equal(t, "Fernsehturm Berlin", l.LocTitle)
|
||||
assert.Equal(t, "Berlin, Germany", l.LocRegion)
|
||||
assert.Equal(t, "Berlin, Germany", l.LocDescription)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
}
|
||||
|
||||
assert.Equal(t, 189675302, o.PlaceID)
|
||||
assert.Equal(t, "Fernsehturm Berlin", o.Name)
|
||||
assert.Equal(t, "Fernsehturm Berlin", o.LocTitle)
|
||||
assert.Equal(t, "10178", o.Address.Postcode)
|
||||
assert.Equal(t, "Berlin", o.Address.State)
|
||||
assert.Equal(t, "de", o.Address.CountryCode)
|
||||
|
@ -48,7 +48,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
}
|
||||
|
||||
assert.Equal(t, "Fernsehturm Berlin", l.LocTitle)
|
||||
assert.Equal(t, "Berlin, Germany", l.LocRegion)
|
||||
assert.Equal(t, "Berlin, Germany", l.LocDescription)
|
||||
})
|
||||
|
||||
t.Run("SantaMonica", func(t *testing.T) {
|
||||
|
@ -63,7 +63,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
|
||||
assert.False(t, o.Cached)
|
||||
assert.Equal(t, 79854991, o.PlaceID)
|
||||
assert.Equal(t, "Santa Monica Pier", o.Name)
|
||||
assert.Equal(t, "Santa Monica Pier", o.LocTitle)
|
||||
assert.Equal(t, "90401", o.Address.Postcode)
|
||||
assert.Equal(t, "California", o.Address.State)
|
||||
assert.Equal(t, "us", o.Address.CountryCode)
|
||||
|
@ -76,7 +76,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
}
|
||||
|
||||
assert.Equal(t, "Santa Monica Pier", l.LocTitle)
|
||||
assert.Equal(t, "Santa Monica, California, USA", l.LocRegion)
|
||||
assert.Equal(t, "Santa Monica, California, USA", l.LocDescription)
|
||||
})
|
||||
|
||||
t.Run("AirportZurich", func(t *testing.T) {
|
||||
|
@ -92,7 +92,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
assert.False(t, o.Cached)
|
||||
|
||||
assert.Equal(t, 115198412, o.PlaceID)
|
||||
assert.Equal(t, "Dock A", o.Name)
|
||||
assert.Equal(t, "Dock A", o.LocTitle)
|
||||
assert.Equal(t, "8302", o.Address.Postcode)
|
||||
assert.Equal(t, "Zurich", o.Address.State)
|
||||
assert.Equal(t, "ch", o.Address.CountryCode)
|
||||
|
@ -105,7 +105,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
}
|
||||
|
||||
assert.Equal(t, "Airport", l.LocTitle)
|
||||
assert.Equal(t, "Kloten, Zurich, Switzerland", l.LocRegion)
|
||||
assert.Equal(t, "Kloten, Zurich, Switzerland", l.LocDescription)
|
||||
})
|
||||
|
||||
t.Run("AirportTegel", func(t *testing.T) {
|
||||
|
@ -121,7 +121,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
assert.False(t, o.Cached)
|
||||
|
||||
assert.Equal(t, 25410613, o.PlaceID)
|
||||
assert.Equal(t, "TGL", o.Name)
|
||||
assert.Equal(t, "TGL", o.LocTitle)
|
||||
assert.Equal(t, "13405", o.Address.Postcode)
|
||||
assert.Equal(t, "Berlin", o.Address.State)
|
||||
assert.Equal(t, "de", o.Address.CountryCode)
|
||||
|
@ -134,7 +134,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
}
|
||||
|
||||
assert.Equal(t, "Airport", l.LocTitle)
|
||||
assert.Equal(t, "Berlin, Germany", l.LocRegion)
|
||||
assert.Equal(t, "Berlin, Germany", l.LocDescription)
|
||||
})
|
||||
|
||||
t.Run("PinkBeach", func(t *testing.T) {
|
||||
|
@ -150,7 +150,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
assert.False(t, o.Cached)
|
||||
|
||||
assert.Equal(t, 119616937, o.PlaceID)
|
||||
assert.Equal(t, "Pink Beach", o.Name)
|
||||
assert.Equal(t, "Pink Beach", o.LocTitle)
|
||||
assert.Equal(t, "", o.Address.Postcode)
|
||||
assert.Equal(t, "Crete", o.Address.State)
|
||||
assert.Equal(t, "gr", o.Address.CountryCode)
|
||||
|
@ -162,9 +162,9 @@ func TestLocation_Assign(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, "8G757G9P+R5C", l.ID)
|
||||
assert.Equal(t, "8G757G9P+", l.ID)
|
||||
assert.Equal(t, "Pink Beach", l.LocTitle)
|
||||
assert.Equal(t, "Crete, Greece", l.LocRegion)
|
||||
assert.Equal(t, "Crete, Greece", l.LocDescription)
|
||||
})
|
||||
|
||||
t.Run("NewJersey", func(t *testing.T) {
|
||||
|
@ -180,7 +180,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
assert.False(t, o.Cached)
|
||||
|
||||
assert.Equal(t, 164551421, o.PlaceID)
|
||||
assert.Equal(t, "", o.Name)
|
||||
assert.Equal(t, "", o.LocTitle)
|
||||
assert.Equal(t, "07307", o.Address.Postcode)
|
||||
assert.Equal(t, "New Jersey", o.Address.State)
|
||||
assert.Equal(t, "us", o.Address.CountryCode)
|
||||
|
@ -192,9 +192,9 @@ func TestLocation_Assign(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, "87G7PXV2+4G9", l.ID)
|
||||
assert.Equal(t, "87G7PXV2+", l.ID)
|
||||
assert.Equal(t, "", l.LocTitle)
|
||||
assert.Equal(t, "Jersey City, New Jersey, USA", l.LocRegion)
|
||||
assert.Equal(t, "Jersey City, New Jersey, USA", l.LocDescription)
|
||||
})
|
||||
|
||||
t.Run("SouthAfrica", func(t *testing.T) {
|
||||
|
@ -210,7 +210,7 @@ func TestLocation_Assign(t *testing.T) {
|
|||
assert.False(t, o.Cached)
|
||||
|
||||
assert.Equal(t, 98820569, o.PlaceID)
|
||||
assert.Equal(t, "R411", o.Name)
|
||||
assert.Equal(t, "R411", o.LocTitle)
|
||||
assert.Equal(t, "", o.Address.Postcode)
|
||||
assert.Equal(t, "Eastern Cape", o.Address.State)
|
||||
assert.Equal(t, "za", o.Address.CountryCode)
|
||||
|
@ -222,8 +222,8 @@ func TestLocation_Assign(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, "4GWF24FX+F5H", l.ID)
|
||||
assert.Equal(t, "4GWF24FX+", l.ID)
|
||||
assert.Equal(t, "R411", l.LocTitle)
|
||||
assert.Equal(t, "Eastern Cape, South Africa", l.LocRegion)
|
||||
assert.Equal(t, "Eastern Cape, South Africa", l.LocDescription)
|
||||
})
|
||||
}
|
||||
|
|
19
internal/maps/olc.go
Normal file
19
internal/maps/olc.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package maps
|
||||
|
||||
import olc "github.com/google/open-location-code/go"
|
||||
|
||||
var OlcLength = 8
|
||||
|
||||
func OlcEncode (lat, lng float64) string {
|
||||
if lat < -90 || lat > 90 {
|
||||
log.Warnf("olc: latitude out of range (%f)", lat)
|
||||
return ""
|
||||
}
|
||||
|
||||
if lng < -180 || lng > 180 {
|
||||
log.Warnf("olc: longitude out of range (%f)", lat)
|
||||
return ""
|
||||
}
|
||||
|
||||
return olc.Encode(lat, lng, OlcLength)
|
||||
}
|
30
internal/maps/olc_test.go
Normal file
30
internal/maps/olc_test.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package maps
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestOlcEncode(t *testing.T) {
|
||||
t.Run("Wildgehege", func(t *testing.T) {
|
||||
plusCode := OlcEncode(48.56344833333333, 8.996878333333333)
|
||||
expected := "8FWCHX7W+"
|
||||
|
||||
assert.Equal(t, expected, plusCode)
|
||||
})
|
||||
|
||||
t.Run("LatOverflow", func(t *testing.T) {
|
||||
plusCode := OlcEncode(548.56344833333333, 8.996878333333333)
|
||||
expected := ""
|
||||
|
||||
assert.Equal(t, expected, plusCode)
|
||||
})
|
||||
|
||||
t.Run("LongOverflow", func(t *testing.T) {
|
||||
plusCode := OlcEncode(48.56344833333333, 258.996878333333333)
|
||||
expected := ""
|
||||
|
||||
assert.Equal(t, expected, plusCode)
|
||||
})
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
package osm
|
||||
|
||||
import "fmt"
|
||||
|
||||
var locationLabels = map[string]string{
|
||||
var osmCategories = map[string]string{
|
||||
"aeroway=*": "airport",
|
||||
"natural=bay": "bay",
|
||||
"natural=peninsula": "peninsula",
|
||||
|
@ -159,21 +157,3 @@ var locationLabels = map[string]string{
|
|||
"*=water_park": "water park",
|
||||
"*=wildlife_hide": "wildlife",
|
||||
}
|
||||
|
||||
func (o Location) Label() (result string) {
|
||||
key := fmt.Sprintf("%s=%s", o.Category, o.Type)
|
||||
catKey := fmt.Sprintf("%s=*", o.Category)
|
||||
typeKey := fmt.Sprintf("*=%s", o.Type)
|
||||
|
||||
if result, ok := locationLabels[key]; ok {
|
||||
return result
|
||||
} else if result, ok := locationLabels[catKey]; ok {
|
||||
return result
|
||||
} else if result, ok := locationLabels[typeKey]; ok {
|
||||
return result
|
||||
}
|
||||
|
||||
log.Debugf("osm: no label found for %s", key)
|
||||
|
||||
return ""
|
||||
}
|
21
internal/maps/osm/category.go
Normal file
21
internal/maps/osm/category.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package osm
|
||||
|
||||
import "fmt"
|
||||
|
||||
func (o Location) Category() (result string) {
|
||||
key := fmt.Sprintf("%s=%s", o.LocCategory, o.LocType)
|
||||
catKey := fmt.Sprintf("%s=*", o.LocCategory)
|
||||
typeKey := fmt.Sprintf("*=%s", o.LocType)
|
||||
|
||||
if result, ok := osmCategories[key]; ok {
|
||||
return result
|
||||
} else if result, ok := osmCategories[catKey]; ok {
|
||||
return result
|
||||
} else if result, ok := osmCategories[typeKey]; ok {
|
||||
return result
|
||||
}
|
||||
|
||||
// log.Debugf("osm: no label found for %s", key)
|
||||
|
||||
return ""
|
||||
}
|
|
@ -13,15 +13,15 @@ import (
|
|||
)
|
||||
|
||||
type Location struct {
|
||||
PlaceID int `json:"place_id"`
|
||||
Lat string `json:"lat"`
|
||||
Lon string `json:"lon"`
|
||||
Name string `json:"name"`
|
||||
Category string `json:"category"`
|
||||
Type string `json:"type"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Address Address `json:"address"`
|
||||
Cached bool
|
||||
PlaceID int `json:"place_id"`
|
||||
LocLat string `json:"lat"`
|
||||
LocLng string `json:"lon"`
|
||||
LocTitle 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"
|
||||
|
@ -99,7 +99,7 @@ func (o Location) CountryCode() (result string) {
|
|||
}
|
||||
|
||||
func (o Location) Latitude() (result float64) {
|
||||
result, err := strconv.ParseFloat(o.Lat, 64)
|
||||
result, err := strconv.ParseFloat(o.LocLat, 64)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("osm: %s", err.Error())
|
||||
|
@ -109,7 +109,7 @@ func (o Location) Latitude() (result float64) {
|
|||
}
|
||||
|
||||
func (o Location) Longitude() (result float64) {
|
||||
result, err := strconv.ParseFloat(o.Lon, 64)
|
||||
result, err := strconv.ParseFloat(o.LocLng, 64)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("osm: %s", err.Error())
|
||||
|
@ -119,7 +119,7 @@ func (o Location) Longitude() (result float64) {
|
|||
}
|
||||
|
||||
func (o Location) Keywords() (result []string) {
|
||||
return util.Keywords(o.DisplayName)
|
||||
return util.Keywords(o.LocDisplayName)
|
||||
}
|
||||
|
||||
func (o Location) Source() string {
|
||||
|
|
|
@ -19,7 +19,7 @@ func TestFindLocation(t *testing.T) {
|
|||
|
||||
assert.False(t, l.Cached)
|
||||
assert.Equal(t, 189675302, l.PlaceID)
|
||||
assert.Equal(t, "Fernsehturm Berlin", l.Name)
|
||||
assert.Equal(t, "Fernsehturm Berlin", l.LocTitle)
|
||||
assert.Equal(t, "10178", l.Address.Postcode)
|
||||
assert.Equal(t, "Berlin", l.Address.State)
|
||||
assert.Equal(t, "de", l.Address.CountryCode)
|
||||
|
@ -37,7 +37,7 @@ func TestFindLocation(t *testing.T) {
|
|||
|
||||
assert.True(t, cached.Cached)
|
||||
assert.Equal(t, 189675302, cached.PlaceID)
|
||||
assert.Equal(t, l.Name, cached.Name)
|
||||
assert.Equal(t, l.LocTitle, cached.LocTitle)
|
||||
assert.Equal(t, l.Address.Postcode, cached.Address.Postcode)
|
||||
assert.Equal(t, l.Address.State, cached.Address.State)
|
||||
assert.Equal(t, l.Address.CountryCode, cached.Address.CountryCode)
|
||||
|
@ -56,7 +56,7 @@ func TestFindLocation(t *testing.T) {
|
|||
|
||||
assert.False(t, l.Cached)
|
||||
assert.Equal(t, 48287001, l.PlaceID)
|
||||
assert.Equal(t, "Menschen Museum", l.Name)
|
||||
assert.Equal(t, "Menschen Museum", l.LocTitle)
|
||||
assert.Equal(t, "10178", l.Address.Postcode)
|
||||
assert.Equal(t, "Berlin", l.Address.State)
|
||||
assert.Equal(t, "de", l.Address.CountryCode)
|
||||
|
|
|
@ -12,15 +12,15 @@ var labelTitles = map[string]string{
|
|||
}
|
||||
|
||||
func (o Location) Title() (result string) {
|
||||
result = o.Label()
|
||||
result = o.Category()
|
||||
|
||||
if title, ok := labelTitles[result]; ok {
|
||||
title = strings.Replace(title, "%name%", o.Name, 1)
|
||||
title = strings.Replace(title, "%name%", o.LocTitle, 1)
|
||||
return title
|
||||
}
|
||||
|
||||
if o.Name != "" {
|
||||
result = o.Name
|
||||
if o.LocTitle != "" {
|
||||
result = o.LocTitle
|
||||
}
|
||||
|
||||
result = strings.Replace(result, "_", " ", -1)
|
||||
|
|
|
@ -388,14 +388,14 @@ func (i *Indexer) indexLocation(mediaFile *MediaFile, photo *entity.Photo, label
|
|||
}
|
||||
|
||||
countryName := photo.Country.CountryName
|
||||
locLabel := location.Label()
|
||||
locCategory := location.Category()
|
||||
|
||||
keywords = append(keywords, location.Keywords()...)
|
||||
|
||||
// Append label from OpenStreetMap
|
||||
if locLabel != "" {
|
||||
keywords = append(keywords, locLabel)
|
||||
labels = append(labels, NewLocationLabel(locLabel, 0, -1))
|
||||
// Append category from reverse location lookup
|
||||
if locCategory != "" {
|
||||
keywords = append(keywords, locCategory)
|
||||
labels = append(labels, NewLocationLabel(locCategory, 0, -1))
|
||||
}
|
||||
|
||||
if (fileChanged || o.UpdateTitle) && photo.PhotoTitleChanged == false {
|
||||
|
|
|
@ -30,9 +30,9 @@ func TestMediaFile_Location(t *testing.T) {
|
|||
assert.Equal(t, "Himeji", location.City())
|
||||
assert.Equal(t, "Kinki Region", location.State())
|
||||
assert.Equal(t, "Japan", location.CountryName())
|
||||
assert.Equal(t, "", location.Label())
|
||||
assert.Equal(t, "", location.Category())
|
||||
assert.Equal(t, 34.79745, location.Latitude())
|
||||
assert.Equal(t, "8Q6PQQW7+XVJ", location.ID)
|
||||
assert.Equal(t, "8Q6PQQW7+", location.ID)
|
||||
location2, err := mediaFile.Location()
|
||||
|
||||
if err != nil {
|
||||
|
@ -68,7 +68,7 @@ func TestMediaFile_Location(t *testing.T) {
|
|||
assert.Equal(t, "de", location.CountryCode())
|
||||
assert.Equal(t, "Germany", location.CountryName())
|
||||
assert.Equal(t, 48.53870833333333, location.Latitude())
|
||||
assert.Equal(t, "8FWFG2Q6+FVM", location.ID)
|
||||
assert.Equal(t, "8FWFG2Q6+", location.ID)
|
||||
})
|
||||
t.Run("/dog_orange.jpg", func(t *testing.T) {
|
||||
conf := config.TestConfig()
|
||||
|
|
|
@ -54,17 +54,15 @@ type PhotoResult struct {
|
|||
|
||||
// Country
|
||||
CountryID string
|
||||
CountryName string
|
||||
|
||||
// Location
|
||||
LocationID string
|
||||
LocTitle string
|
||||
LocDescription string
|
||||
LocCity string
|
||||
LocSuburb string
|
||||
LocState string
|
||||
LocCountryCode string
|
||||
LocRegion string
|
||||
LocLabel string
|
||||
LocCategory string
|
||||
LocSource string
|
||||
LocationChanged bool
|
||||
LocationEstimated bool
|
||||
|
@ -120,13 +118,11 @@ func (s *Repo) Photos(f form.PhotoSearch) (results []PhotoResult, err error) {
|
|||
files.file_orientation, files.file_main_color, files.file_colors, files.file_luminance, files.file_chroma,
|
||||
cameras.camera_make, cameras.camera_model,
|
||||
lenses.lens_make, lenses.lens_model,
|
||||
countries.country_name,
|
||||
locations.loc_title, locations.loc_city, locations.loc_suburb, locations.loc_state, locations.loc_country_code,
|
||||
locations.loc_region, locations.loc_label, locations.loc_source`).
|
||||
locations.loc_title, locations.loc_description, locations.loc_city, locations.loc_suburb, locations.loc_state,
|
||||
locations.loc_category, locations.loc_source`).
|
||||
Joins("JOIN files ON files.photo_id = photos.id AND files.file_primary AND files.deleted_at IS NULL").
|
||||
Joins("JOIN cameras ON cameras.id = photos.camera_id").
|
||||
Joins("JOIN lenses ON lenses.id = photos.lens_id").
|
||||
Joins("LEFT JOIN countries ON countries.id = photos.country_id").
|
||||
Joins("LEFT JOIN locations ON locations.id = photos.location_id").
|
||||
Joins("LEFT JOIN photos_labels ON photos_labels.photo_id = photos.id").
|
||||
Where("photos.deleted_at IS NULL AND files.file_missing = 0").
|
||||
|
@ -215,12 +211,16 @@ func (s *Repo) Photos(f form.PhotoSearch) (results []PhotoResult, err error) {
|
|||
q = q.Where("photos.photo_nsfw = 0")
|
||||
}
|
||||
|
||||
if f.NSFW {
|
||||
q = q.Where("photos.photo_nsfw = 1")
|
||||
}
|
||||
|
||||
if f.Story {
|
||||
q = q.Where("photos.photo_story = 1")
|
||||
}
|
||||
|
||||
if f.Country != "" {
|
||||
q = q.Where("locations.loc_country_code = ?", f.Country)
|
||||
q = q.Where("photos.country_id = ?", f.Country)
|
||||
}
|
||||
|
||||
if f.Title != "" {
|
||||
|
|
Loading…
Reference in a new issue