Experimental filters for category and country (photo search)

This commit is contained in:
Michael Mayer 2018-09-19 00:53:39 +02:00
parent 39ab854672
commit d3ef7abb54
9 changed files with 74 additions and 47 deletions

View file

@ -18,7 +18,8 @@
appName: "{{ .title }}",
appVersion: "1.0.0",
debug: {{ .debug }},
cameras: {{ .cameras }}
cameras: {{ .cameras }},
countries: {{ .countries }}
};
</script>
</head>

View file

@ -40,6 +40,8 @@
label="Country"
flat solo
color="blue-grey"
item-value="LocCountryCode"
item-text="LocCountry"
v-model="query.country"
:items="options.countries">
</v-select>
@ -77,6 +79,7 @@
direction="top"
open-on-hover
transition="slide-y-reverse-transition"
style="right: 8px; bottom: 8px;"
>
<v-btn
slot="activator"
@ -204,6 +207,10 @@
const country = query['country'] ? query['country'] : '';
const view = query['view'] ? query['view'] : 'tile';
const cameras = [{ID: 0, CameraModel: 'All Cameras'}].concat(this.$config.getValue('cameras'));
const countries = [{
LocCountryCode: '',
LocCountry: 'All Countries'
}].concat(this.$config.getValue('countries'));
return {
'snackbarVisible': false,
@ -220,16 +227,14 @@
'options': {
'categories': [
{value: '', text: 'All Categories'},
{value: 'junction', text: 'Junction'},
{value: 'tourism', text: 'Tourism'},
{value: 'airport', text: 'Airport'},
{value: 'amenity', text: 'Amenity'},
{value: 'building', text: 'Building'},
{value: 'historic', text: 'Historic'},
{value: 'shop', text: 'Shop'},
{value: 'tourism', text: 'Tourism'},
],
'countries': [
{value: '', text: 'All Countries'},
{value: 'de', text: 'Germany'},
{value: 'ca', text: 'Canada'},
{value: 'us', text: 'United States'}
],
'countries': countries,
'cameras': cameras,
'sorting': [
{value: 'newest', text: 'Newest first'},

View file

@ -7,7 +7,7 @@ import (
type PhotoSearchForm struct {
Query string `form:"q"`
Tags string `form:"tags"`
Category string `form:"cat"`
Cat string `form:"cat"`
Country string `form:"country"`
CameraID int `form:"camera"`
Order string `form:"order"`

View file

@ -231,7 +231,15 @@ func (c *Config) GetClientConfig() ConfigValues {
db := c.GetDb()
var cameras []*Camera
// var countries map[string]string
type country struct {
LocCountry string
LocCountryCode string
}
var countries []country
db.Model(&Location{}).Select("DISTINCT loc_country_code, loc_country").Scan(&countries)
db.Where("deleted_at IS NULL").Limit(1000).Order("camera_model").Find(&cameras)
@ -242,6 +250,7 @@ func (c *Config) GetClientConfig() ConfigValues {
"title": "PhotoPrism",
"debug": c.Debug,
"cameras": cameras,
"countries": countries,
"jsHash": jsHash,
"cssHash": cssHash,
}

View file

@ -39,7 +39,7 @@ func (m *MediaFile) GetExifData() (*ExifData, error) {
file, err := m.openFile()
if err != nil {
return m.exifData, err
return nil, err
}
defer file.Close()
@ -49,7 +49,7 @@ func (m *MediaFile) GetExifData() (*ExifData, error) {
x, err := exif.Decode(file)
if err != nil {
return m.exifData, err
return nil, err
}
if artist, err := x.Get(exif.Artist); err == nil {

View file

@ -77,7 +77,7 @@ func NewSearch(originalsPath string, db *gorm.DB) *Search {
return instance
}
func (s *Search) Photos(form PhotoSearchForm) ([]PhotoSearchResult, int, error) {
func (s *Search) Photos(form PhotoSearchForm) ([]PhotoSearchResult, error) {
q := s.db.NewScope(nil).DB()
q = q.Table("photos").
Select(`SQL_CALC_FOUND_ROWS photos.*,
@ -98,7 +98,39 @@ func (s *Search) Photos(form PhotoSearchForm) ([]PhotoSearchResult, int, error)
}
if form.CameraID > 0 {
q = q.Where("camera_id = ?", form.CameraID)
q = q.Where("photos.camera_id = ?", form.CameraID)
}
if form.Country != "" {
q = q.Where("locations.loc_country_code = ?", form.Country)
}
switch form.Cat {
case "amenity":
q = q.Where("locations.loc_category = 'amenity'")
case "bank":
q = q.Where("locations.loc_type = 'bank'")
case "building":
q = q.Where("locations.loc_category = 'building'")
case "school":
q = q.Where("locations.loc_type = 'school'")
case "supermarket":
q = q.Where("locations.loc_type = 'supermarket'")
case "shop":
q = q.Where("locations.loc_category = 'shop'")
case "hotel":
q = q.Where("locations.loc_type = 'hotel'")
case "bar":
q = q.Where("locations.loc_type = 'bar'")
case "parking":
q = q.Where("locations.loc_type = 'parking'")
case "airport":
q = q.Where("locations.loc_category = 'aeroway'")
case "historic":
q = q.Where("locations.loc_category = 'historic'")
case "tourism":
q = q.Where("locations.loc_category = 'tourism'")
default:
}
switch form.Order {
@ -118,28 +150,13 @@ func (s *Search) Photos(form PhotoSearchForm) ([]PhotoSearchResult, int, error)
q = q.Limit(100).Offset(0)
}
results := make([]PhotoSearchResult, 0, form.Count)
var results []PhotoSearchResult
rows, err := q.Rows()
if err != nil {
return results, 0, err
if result := q.Scan(&results); result.Error != nil {
return results, result.Error
}
defer rows.Close()
for rows.Next() {
var result PhotoSearchResult
s.db.ScanRows(rows, &result)
results = append(results, result)
}
// TODO: Check if this works properly with concurrent requests and caching
count := &SearchCount{}
s.db.Raw("SELECT FOUND_ROWS() AS total").Scan(&count)
total := count.Total
return results, total, nil
return results, nil
}
func (s *Search) FindFiles(count int, offset int) (files []File) {

View file

@ -20,23 +20,21 @@ func TestSearch_Photos_Query(t *testing.T) {
form.Count = 3
form.Offset = 0
photos, total, err := search.Photos(form)
photos, err := search.Photos(form)
if err != nil {
t.Fatal(err)
}
t.Log(photos)
t.Logf("Total Count: %d", total)
photos, total, err = search.Photos(form)
photos, err = search.Photos(form)
if err != nil {
t.Fatal(err)
}
t.Log(photos)
t.Logf("Total Count: %d", total)
}
@ -56,12 +54,11 @@ func TestSearch_Photos_Camera(t *testing.T) {
form.Count = 3
form.Offset = 0
photos, total, err := search.Photos(form)
photos, err := search.Photos(form)
if err != nil {
t.Fatal(err)
}
t.Log(photos)
t.Logf("Total Count: %d", total)
}

View file

@ -25,7 +25,6 @@ func CreateThumbnailsFromOriginals(originalsPath string, thumbnailsPath string,
if thumbnail, err := mediaFile.GetSquareThumbnail(thumbnailsPath, size); err != nil {
log.Printf("Could not create thumbnail: %s", err.Error())
} else {
thumbnail.GetHeight()
log.Printf("Created %dx%d px thumbnail for \"%s\"", thumbnail.GetWidth(), thumbnail.GetHeight(), mediaFile.GetRelativeFilename(originalsPath))
}
} else {

View file

@ -28,13 +28,12 @@ func ConfigureRoutes(app *gin.Engine, conf *photoprism.Config) {
c.MustBindWith(&form, binding.Form)
result, total, err := search.Photos(form)
result, err := search.Photos(form)
if err != nil {
c.AbortWithStatusJSON(400, gin.H{"error": err.Error()})
}
c.Header("x-result-total", strconv.Itoa(total))
c.Header("x-result-count", strconv.Itoa(form.Count))
c.Header("x-result-offset", strconv.Itoa(form.Offset))