Skip to content

Commit

Permalink
Search: Add live and raw search filters, improve faces filter #22
Browse files Browse the repository at this point in the history
  • Loading branch information
lastzero committed Oct 13, 2021
1 parent aaa344d commit 25a954d
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 65 deletions.
2 changes: 2 additions & 0 deletions internal/form/photo_search.go
Expand Up @@ -23,6 +23,8 @@ type PhotoSearch struct {
Stackable bool `form:"stackable"`
Video bool `form:"video"`
Photo bool `form:"photo"`
Raw bool `form:"raw"`
Live bool `form:"live"`
Scan bool `form:"scan"`
Panorama bool `form:"panorama"`
Error bool `form:"error"`
Expand Down
4 changes: 4 additions & 0 deletions internal/form/photo_search_geo.go
Expand Up @@ -15,6 +15,10 @@ type PhotoSearchGeo struct {
Favorite bool `form:"favorite"`
Video bool `form:"video"`
Photo bool `form:"photo"`
Raw bool `form:"raw"`
Live bool `form:"live"`
Scan bool `form:"scan"`
Panorama bool `form:"panorama"`
Archived bool `form:"archived"`
Public bool `form:"public"`
Private bool `form:"private"`
Expand Down
5 changes: 1 addition & 4 deletions internal/search/like.go
Expand Up @@ -16,10 +16,7 @@ func LikeAny(col, s string, keywords, exact bool) (wheres []string) {
return wheres
}

s = strings.ReplaceAll(s, txt.Or, " ")
s = strings.ReplaceAll(s, txt.OrEn, " ")
s = strings.ReplaceAll(s, txt.AndEn, txt.And)
s = strings.ReplaceAll(s, txt.Plus, txt.And)
s = txt.StripOr(txt.NormalizeQuery(s))

var wildcardThreshold int

Expand Down
56 changes: 34 additions & 22 deletions internal/search/photos.go
Expand Up @@ -135,7 +135,7 @@ func Photos(f form.PhotoSearch) (results PhotoResults, count int, err error) {
}
}

// Clip to reasonable size and normalize operators.
// Clip and normalize search query.
f.Query = txt.NormalizeQuery(f.Query)

// Set search filters based on search terms.
Expand All @@ -158,12 +158,12 @@ func Photos(f form.PhotoSearch) (results PhotoResults, count int, err error) {
case terms["video"]:
f.Query = strings.ReplaceAll(f.Query, "video", "")
f.Video = true
case terms["photos"]:
f.Query = strings.ReplaceAll(f.Query, "photos", "")
f.Photo = true
case terms["photo"]:
f.Query = strings.ReplaceAll(f.Query, "photo", "")
f.Photo = true
case terms["live"]:
f.Query = strings.ReplaceAll(f.Query, "live", "")
f.Live = true
case terms["raws"]:
f.Query = strings.ReplaceAll(f.Query, "raws", "")
f.Raw = true
case terms["favorites"]:
f.Query = strings.ReplaceAll(f.Query, "favorites", "")
f.Favorite = true
Expand Down Expand Up @@ -230,15 +230,16 @@ func Photos(f form.PhotoSearch) (results PhotoResults, count int, err error) {
}
}

// Filter by number of faces.
// Filter by number of faces?
if txt.IsUInt(f.Faces) {
s = s.Where("photos.photo_faces >= ?", txt.Int(f.Faces))
} else if txt.New(f.Faces) && f.Face == "" {
f.Face = f.Faces
f.Faces = ""
} else if txt.Yes(f.Faces) {
s = s.Where("photos.photo_faces > 0")
} else if txt.No(f.Faces) {
s = s.Where("photos.photo_faces = 0")
} else if txt.New(f.Faces) && f.Face == "" {
f.Face = f.Faces
}

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

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

// Find favorites only?
if f.Favorite {
s = s.Where("photos.photo_favorite = 1")
}

// Find scans only?
if f.Scan {
s = s.Where("photos.photo_scan = 1")
}

// Find panoramas only?
if f.Panorama {
s = s.Where("photos.photo_panorama = 1")
}

// Find portraits only?
if f.Portrait {
s = s.Where("files.file_portrait = 1")
}

if f.Stackable {
s = s.Where("photos.photo_stack > -1")
} else if f.Unstacked {
s = s.Where("photos.photo_stack = -1")
}

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

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

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

// Filter by media type.
// Filter by media type?
if f.Type != "" {
s = s.Where("photos.photo_type IN (?)", strings.Split(strings.ToLower(f.Type), txt.Or))
}

if f.Video {
} else if f.Video {
s = s.Where("photos.photo_type = 'video'")
} else if f.Photo {
s = s.Where("photos.photo_type IN ('image','raw','live')")
} else if f.Raw {
s = s.Where("photos.photo_type = 'raw'")
} else if f.Live {
s = s.Where("photos.photo_type = 'live'")
}

// Filter by storage path?
if f.Path != "" {
p := f.Path

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

// Filter by complete file names.
// Filter by complete file names?
if f.Filename != "" {
where, values := OrLike("files.file_name", f.Filename)
s = s.Where(where, values...)
}

// Filter by original file name.
// Filter by original file name?
if f.Original != "" {
where, values := OrLike("photos.original_name", f.Original)
s = s.Where(where, values...)
}

// Filter by photo title.
// Filter by photo title?
if f.Title != "" {
where, values := OrLike("photos.photo_title", f.Title)
s = s.Where(where, values...)
}

// Filter by file hash.
// Filter by file hash?
if f.Hash != "" {
s = s.Where("files.file_hash IN (?)", strings.Split(strings.ToLower(f.Hash), txt.Or))
}

if f.Portrait {
s = s.Where("files.file_portrait = 1")
}

if f.Mono {
s = s.Where("files.file_chroma = 0 OR file_colors = '111111111'")
} else if f.Chroma > 9 {
Expand Down
66 changes: 44 additions & 22 deletions internal/search/photos_geo.go
Expand Up @@ -39,7 +39,7 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
Where("photos.deleted_at IS NULL").
Where("photos.photo_lat <> 0")

// Clip to reasonable size and normalize operators.
// Clip and normalize search query.
f.Query = txt.NormalizeQuery(f.Query)

// Set search filters based on search terms.
Expand All @@ -62,19 +62,25 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
case terms["video"]:
f.Query = strings.ReplaceAll(f.Query, "video", "")
f.Video = true
case terms["photos"]:
f.Query = strings.ReplaceAll(f.Query, "photos", "")
f.Photo = true
case terms["photo"]:
f.Query = strings.ReplaceAll(f.Query, "photo", "")
f.Photo = true
case terms["live"]:
f.Query = strings.ReplaceAll(f.Query, "live", "")
f.Live = true
case terms["raws"]:
f.Query = strings.ReplaceAll(f.Query, "raws", "")
f.Raw = true
case terms["favorites"]:
f.Query = strings.ReplaceAll(f.Query, "favorites", "")
f.Favorite = true
case terms["panoramas"]:
f.Query = strings.ReplaceAll(f.Query, "panoramas", "")
f.Panorama = true
case terms["scans"]:
f.Query = strings.ReplaceAll(f.Query, "scans", "")
f.Scan = true
}
}

// Filter by label, label category and keywords.
// Filter by label, label category, and keywords?
if f.Query != "" {
var categories []entity.Category
var labels []entity.Label
Expand Down Expand Up @@ -117,15 +123,16 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
}
}

// Filter by number of faces.
// Filter by number of faces?
if txt.IsUInt(f.Faces) {
s = s.Where("photos.photo_faces >= ?", txt.Int(f.Faces))
} else if txt.New(f.Faces) && f.Face == "" {
f.Face = f.Faces
f.Faces = ""
} else if txt.Yes(f.Faces) {
s = s.Where("photos.photo_faces > 0")
} else if txt.No(f.Faces) {
s = s.Where("photos.photo_faces = 0")
} else if txt.New(f.Faces) && f.Face == "" {
f.Face = f.Faces
}

// Filter for specific face clusters? Example: PLJ7A3G4MBGZJRMVDIUCBLC46IAP4N7O
Expand All @@ -134,6 +141,9 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
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 (?))",
entity.Marker{}.TableName()), strings.Split(f, txt.Or))
}
} else if txt.New(f.Face) {
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 = '')",
entity.Marker{}.TableName()), entity.MarkerFace)
} else if txt.No(f.Face) {
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 = '')",
entity.Marker{}.TableName()), entity.MarkerFace)
Expand Down Expand Up @@ -199,29 +209,45 @@ func PhotosGeo(f form.PhotoSearchGeo) (results GeoResults, err error) {
s = s.Where(AnyInt("photos.photo_day", f.Day, txt.Or, entity.UnknownDay, txt.DayMax))
}

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

// Find favorites only?
if f.Favorite {
s = s.Where("photos.photo_favorite = 1")
}

// Find scans only?
if f.Scan {
s = s.Where("photos.photo_scan = 1")
}

// Find panoramas only?
if f.Panorama {
s = s.Where("photos.photo_panorama = 1")
}

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

// Filter by media type.
// Filter by media type?
if f.Type != "" {
s = s.Where("photos.photo_type IN (?)", strings.Split(strings.ToLower(f.Type), txt.Or))
}

if f.Video {
} else if f.Video {
s = s.Where("photos.photo_type = 'video'")
} else if f.Photo {
s = s.Where("photos.photo_type IN ('image','raw','live')")
} else if f.Raw {
s = s.Where("photos.photo_type = 'raw'")
} else if f.Live {
s = s.Where("photos.photo_type = 'live'")
}

// Filter by storage path?
if f.Path != "" {
p := f.Path

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

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

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

// Filter by photo title.
// Filter by photo title?
if f.Title != "" {
where, values := OrLike("photos.photo_title", f.Title)
s = s.Where(where, values...)
}

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

if f.Favorite {
s = s.Where("photos.photo_favorite = 1")
}

if f.S2 != "" {
s2Min, s2Max := s2.PrefixedRange(f.S2, 7)
s = s.Where("photos.cell_id BETWEEN ? AND ?", s2Min, s2Max)
Expand Down
10 changes: 10 additions & 0 deletions pkg/txt/en.go
@@ -0,0 +1,10 @@
package txt

const (
EnOr = "or"
EnAnd = "and"
EnWith = "with"
EnIn = "in"
EnAt = "at"
EnNew = "new"
)

0 comments on commit 25a954d

Please sign in to comment.