Experimental filters for category and country (photo search)
This commit is contained in:
parent
39ab854672
commit
d3ef7abb54
9 changed files with 74 additions and 47 deletions
|
@ -18,7 +18,8 @@
|
|||
appName: "{{ .title }}",
|
||||
appVersion: "1.0.0",
|
||||
debug: {{ .debug }},
|
||||
cameras: {{ .cameras }}
|
||||
cameras: {{ .cameras }},
|
||||
countries: {{ .countries }}
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
|
|
|
@ -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"
|
||||
|
@ -203,7 +206,11 @@
|
|||
const cat = query['cat'] ? query['cat'] : '';
|
||||
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 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'},
|
||||
|
@ -302,7 +307,7 @@
|
|||
this.refreshList();
|
||||
},
|
||||
loadMore() {
|
||||
if(this.loadMoreDisabled) return;
|
||||
if (this.loadMoreDisabled) return;
|
||||
|
||||
this.loadMoreDisabled = true;
|
||||
|
||||
|
@ -321,7 +326,7 @@
|
|||
|
||||
this.loadMoreDisabled = (response.models.length < this.pageSize);
|
||||
|
||||
if(this.loadMoreDisabled) {
|
||||
if (this.loadMoreDisabled) {
|
||||
this.$alert.info('All ' + this.results.length + ' photos loaded');
|
||||
}
|
||||
});
|
||||
|
@ -351,7 +356,7 @@
|
|||
|
||||
this.loadMoreDisabled = (response.models.length < this.pageSize);
|
||||
|
||||
if(this.loadMoreDisabled) {
|
||||
if (this.loadMoreDisabled) {
|
||||
this.$alert.info(this.results.length + ' photos found');
|
||||
} else {
|
||||
this.$alert.info('More than 50 photos found');
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
Loading…
Reference in a new issue