Skip to content

Commit 25a954d

Browse files
committed
Search: Add live and raw search filters, improve faces filter #22
1 parent aaa344d commit 25a954d

File tree

10 files changed

+155
-65
lines changed

10 files changed

+155
-65
lines changed

internal/form/photo_search.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ type PhotoSearch struct {
2323
Stackable bool `form:"stackable"`
2424
Video bool `form:"video"`
2525
Photo bool `form:"photo"`
26+
Raw bool `form:"raw"`
27+
Live bool `form:"live"`
2628
Scan bool `form:"scan"`
2729
Panorama bool `form:"panorama"`
2830
Error bool `form:"error"`

internal/form/photo_search_geo.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ type PhotoSearchGeo struct {
1515
Favorite bool `form:"favorite"`
1616
Video bool `form:"video"`
1717
Photo bool `form:"photo"`
18+
Raw bool `form:"raw"`
19+
Live bool `form:"live"`
20+
Scan bool `form:"scan"`
21+
Panorama bool `form:"panorama"`
1822
Archived bool `form:"archived"`
1923
Public bool `form:"public"`
2024
Private bool `form:"private"`

internal/search/like.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ func LikeAny(col, s string, keywords, exact bool) (wheres []string) {
1616
return wheres
1717
}
1818

19-
s = strings.ReplaceAll(s, txt.Or, " ")
20-
s = strings.ReplaceAll(s, txt.OrEn, " ")
21-
s = strings.ReplaceAll(s, txt.AndEn, txt.And)
22-
s = strings.ReplaceAll(s, txt.Plus, txt.And)
19+
s = txt.StripOr(txt.NormalizeQuery(s))
2320

2421
var wildcardThreshold int
2522

internal/search/photos.go

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ func Photos(f form.PhotoSearch) (results PhotoResults, count int, err error) {
135135
}
136136
}
137137

138-
// Clip to reasonable size and normalize operators.
138+
// Clip and normalize search query.
139139
f.Query = txt.NormalizeQuery(f.Query)
140140

141141
// Set search filters based on search terms.
@@ -158,12 +158,12 @@ func Photos(f form.PhotoSearch) (results PhotoResults, count int, err error) {
158158
case terms["video"]:
159159
f.Query = strings.ReplaceAll(f.Query, "video", "")
160160
f.Video = true
161-
case terms["photos"]:
162-
f.Query = strings.ReplaceAll(f.Query, "photos", "")
163-
f.Photo = true
164-
case terms["photo"]:
165-
f.Query = strings.ReplaceAll(f.Query, "photo", "")
166-
f.Photo = true
161+
case terms["live"]:
162+
f.Query = strings.ReplaceAll(f.Query, "live", "")
163+
f.Live = true
164+
case terms["raws"]:
165+
f.Query = strings.ReplaceAll(f.Query, "raws", "")
166+
f.Raw = true
167167
case terms["favorites"]:
168168
f.Query = strings.ReplaceAll(f.Query, "favorites", "")
169169
f.Favorite = true
@@ -230,15 +230,16 @@ func Photos(f form.PhotoSearch) (results PhotoResults, count int, err error) {
230230
}
231231
}
232232

233-
// Filter by number of faces.
233+
// Filter by number of faces?
234234
if txt.IsUInt(f.Faces) {
235235
s = s.Where("photos.photo_faces >= ?", txt.Int(f.Faces))
236+
} else if txt.New(f.Faces) && f.Face == "" {
237+
f.Face = f.Faces
238+
f.Faces = ""
236239
} else if txt.Yes(f.Faces) {
237240
s = s.Where("photos.photo_faces > 0")
238241
} else if txt.No(f.Faces) {
239242
s = s.Where("photos.photo_faces = 0")
240-
} else if txt.New(f.Faces) && f.Face == "" {
241-
f.Face = f.Faces
242243
}
243244

244245
// Filter for specific face clusters? Example: PLJ7A3G4MBGZJRMVDIUCBLC46IAP4N7O
@@ -324,52 +325,67 @@ func Photos(f form.PhotoSearch) (results PhotoResults, count int, err error) {
324325
s = s.Where(AnyInt("photos.photo_day", f.Day, txt.Or, entity.UnknownDay, txt.DayMax))
325326
}
326327

328+
// Filter by main color?
327329
if f.Color != "" {
328330
s = s.Where("files.file_main_color IN (?)", strings.Split(strings.ToLower(f.Color), txt.Or))
329331
}
330332

333+
// Find favorites only?
331334
if f.Favorite {
332335
s = s.Where("photos.photo_favorite = 1")
333336
}
334337

338+
// Find scans only?
335339
if f.Scan {
336340
s = s.Where("photos.photo_scan = 1")
337341
}
338342

343+
// Find panoramas only?
339344
if f.Panorama {
340345
s = s.Where("photos.photo_panorama = 1")
341346
}
342347

348+
// Find portraits only?
349+
if f.Portrait {
350+
s = s.Where("files.file_portrait = 1")
351+
}
352+
343353
if f.Stackable {
344354
s = s.Where("photos.photo_stack > -1")
345355
} else if f.Unstacked {
346356
s = s.Where("photos.photo_stack = -1")
347357
}
348358

359+
// Filter by location country?
349360
if f.Country != "" {
350361
s = s.Where("photos.photo_country IN (?)", strings.Split(strings.ToLower(f.Country), txt.Or))
351362
}
352363

364+
// Filter by location state?
353365
if f.State != "" {
354366
s = s.Where("places.place_state IN (?)", strings.Split(f.State, txt.Or))
355367
}
356368

369+
// Filter by location category?
357370
if f.Category != "" {
358371
s = s.Joins("JOIN cells ON photos.cell_id = cells.id").
359372
Where("cells.cell_category IN (?)", strings.Split(strings.ToLower(f.Category), txt.Or))
360373
}
361374

362-
// Filter by media type.
375+
// Filter by media type?
363376
if f.Type != "" {
364377
s = s.Where("photos.photo_type IN (?)", strings.Split(strings.ToLower(f.Type), txt.Or))
365-
}
366-
367-
if f.Video {
378+
} else if f.Video {
368379
s = s.Where("photos.photo_type = 'video'")
369380
} else if f.Photo {
370381
s = s.Where("photos.photo_type IN ('image','raw','live')")
382+
} else if f.Raw {
383+
s = s.Where("photos.photo_type = 'raw'")
384+
} else if f.Live {
385+
s = s.Where("photos.photo_type = 'live'")
371386
}
372387

388+
// Filter by storage path?
373389
if f.Path != "" {
374390
p := f.Path
375391

@@ -397,33 +413,29 @@ func Photos(f form.PhotoSearch) (results PhotoResults, count int, err error) {
397413
s = s.Where(where, names...)
398414
}
399415

400-
// Filter by complete file names.
416+
// Filter by complete file names?
401417
if f.Filename != "" {
402418
where, values := OrLike("files.file_name", f.Filename)
403419
s = s.Where(where, values...)
404420
}
405421

406-
// Filter by original file name.
422+
// Filter by original file name?
407423
if f.Original != "" {
408424
where, values := OrLike("photos.original_name", f.Original)
409425
s = s.Where(where, values...)
410426
}
411427

412-
// Filter by photo title.
428+
// Filter by photo title?
413429
if f.Title != "" {
414430
where, values := OrLike("photos.photo_title", f.Title)
415431
s = s.Where(where, values...)
416432
}
417433

418-
// Filter by file hash.
434+
// Filter by file hash?
419435
if f.Hash != "" {
420436
s = s.Where("files.file_hash IN (?)", strings.Split(strings.ToLower(f.Hash), txt.Or))
421437
}
422438

423-
if f.Portrait {
424-
s = s.Where("files.file_portrait = 1")
425-
}
426-
427439
if f.Mono {
428440
s = s.Where("files.file_chroma = 0 OR file_colors = '111111111'")
429441
} else if f.Chroma > 9 {

internal/search/photos_geo.go

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
3939
Where("photos.deleted_at IS NULL").
4040
Where("photos.photo_lat <> 0")
4141

42-
// Clip to reasonable size and normalize operators.
42+
// Clip and normalize search query.
4343
f.Query = txt.NormalizeQuery(f.Query)
4444

4545
// Set search filters based on search terms.
@@ -62,19 +62,25 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
6262
case terms["video"]:
6363
f.Query = strings.ReplaceAll(f.Query, "video", "")
6464
f.Video = true
65-
case terms["photos"]:
66-
f.Query = strings.ReplaceAll(f.Query, "photos", "")
67-
f.Photo = true
68-
case terms["photo"]:
69-
f.Query = strings.ReplaceAll(f.Query, "photo", "")
70-
f.Photo = true
65+
case terms["live"]:
66+
f.Query = strings.ReplaceAll(f.Query, "live", "")
67+
f.Live = true
68+
case terms["raws"]:
69+
f.Query = strings.ReplaceAll(f.Query, "raws", "")
70+
f.Raw = true
7171
case terms["favorites"]:
7272
f.Query = strings.ReplaceAll(f.Query, "favorites", "")
7373
f.Favorite = true
74+
case terms["panoramas"]:
75+
f.Query = strings.ReplaceAll(f.Query, "panoramas", "")
76+
f.Panorama = true
77+
case terms["scans"]:
78+
f.Query = strings.ReplaceAll(f.Query, "scans", "")
79+
f.Scan = true
7480
}
7581
}
7682

77-
// Filter by label, label category and keywords.
83+
// Filter by label, label category, and keywords?
7884
if f.Query != "" {
7985
var categories []entity.Category
8086
var labels []entity.Label
@@ -117,15 +123,16 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
117123
}
118124
}
119125

120-
// Filter by number of faces.
126+
// Filter by number of faces?
121127
if txt.IsUInt(f.Faces) {
122128
s = s.Where("photos.photo_faces >= ?", txt.Int(f.Faces))
129+
} else if txt.New(f.Faces) && f.Face == "" {
130+
f.Face = f.Faces
131+
f.Faces = ""
123132
} else if txt.Yes(f.Faces) {
124133
s = s.Where("photos.photo_faces > 0")
125134
} else if txt.No(f.Faces) {
126135
s = s.Where("photos.photo_faces = 0")
127-
} else if txt.New(f.Faces) && f.Face == "" {
128-
f.Face = f.Faces
129136
}
130137

131138
// Filter for specific face clusters? Example: PLJ7A3G4MBGZJRMVDIUCBLC46IAP4N7O
@@ -134,6 +141,9 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
134141
s = s.Where(fmt.Sprintf("photos.id IN (SELECT photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid AND m.marker_invalid = 0 WHERE face_id IN (?))",
135142
entity.Marker{}.TableName()), strings.Split(f, txt.Or))
136143
}
144+
} else if txt.New(f.Face) {
145+
s = s.Where(fmt.Sprintf("photos.id IN (SELECT photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid AND m.marker_invalid = 0 AND m.marker_type = ? WHERE subj_uid IS NULL OR subj_uid = '')",
146+
entity.Marker{}.TableName()), entity.MarkerFace)
137147
} else if txt.No(f.Face) {
138148
s = s.Where(fmt.Sprintf("photos.id IN (SELECT photo_id FROM files f JOIN %s m ON f.file_uid = m.file_uid AND m.marker_invalid = 0 AND m.marker_type = ? WHERE face_id IS NULL OR face_id = '')",
139149
entity.Marker{}.TableName()), entity.MarkerFace)
@@ -199,29 +209,45 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
199209
s = s.Where(AnyInt("photos.photo_day", f.Day, txt.Or, entity.UnknownDay, txt.DayMax))
200210
}
201211

212+
// Filter by main color?
202213
if f.Color != "" {
203214
s = s.Where("files.file_main_color IN (?)", strings.Split(strings.ToLower(f.Color), txt.Or))
204215
}
205216

217+
// Find favorites only?
206218
if f.Favorite {
207219
s = s.Where("photos.photo_favorite = 1")
208220
}
209221

222+
// Find scans only?
223+
if f.Scan {
224+
s = s.Where("photos.photo_scan = 1")
225+
}
226+
227+
// Find panoramas only?
228+
if f.Panorama {
229+
s = s.Where("photos.photo_panorama = 1")
230+
}
231+
232+
// Filter by location country?
210233
if f.Country != "" {
211234
s = s.Where("photos.photo_country IN (?)", strings.Split(strings.ToLower(f.Country), txt.Or))
212235
}
213236

214-
// Filter by media type.
237+
// Filter by media type?
215238
if f.Type != "" {
216239
s = s.Where("photos.photo_type IN (?)", strings.Split(strings.ToLower(f.Type), txt.Or))
217-
}
218-
219-
if f.Video {
240+
} else if f.Video {
220241
s = s.Where("photos.photo_type = 'video'")
221242
} else if f.Photo {
222243
s = s.Where("photos.photo_type IN ('image','raw','live')")
244+
} else if f.Raw {
245+
s = s.Where("photos.photo_type = 'raw'")
246+
} else if f.Live {
247+
s = s.Where("photos.photo_type = 'live'")
223248
}
224249

250+
// Filter by storage path?
225251
if f.Path != "" {
226252
p := f.Path
227253

@@ -237,7 +263,7 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
237263
}
238264
}
239265

240-
// Filter by primary file name without path and extension.
266+
// Filter by primary file name without path and extension?
241267
if f.Name != "" {
242268
where, names := OrLike("photos.photo_name", f.Name)
243269

@@ -249,13 +275,13 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
249275
s = s.Where(where, names...)
250276
}
251277

252-
// Filter by photo title.
278+
// Filter by photo title?
253279
if f.Title != "" {
254280
where, values := OrLike("photos.photo_title", f.Title)
255281
s = s.Where(where, values...)
256282
}
257283

258-
// Filter by status.
284+
// Filter by status?
259285
if f.Archived {
260286
s = s.Where("photos.photo_quality > -1")
261287
s = s.Where("photos.deleted_at IS NOT NULL")
@@ -275,10 +301,6 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
275301
}
276302
}
277303

278-
if f.Favorite {
279-
s = s.Where("photos.photo_favorite = 1")
280-
}
281-
282304
if f.S2 != "" {
283305
s2Min, s2Max := s2.PrefixedRange(f.S2, 7)
284306
s = s.Where("photos.cell_id BETWEEN ? AND ?", s2Min, s2Max)

pkg/txt/en.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package txt
2+
3+
const (
4+
EnOr = "or"
5+
EnAnd = "and"
6+
EnWith = "with"
7+
EnIn = "in"
8+
EnAt = "at"
9+
EnNew = "new"
10+
)

0 commit comments

Comments
 (0)