Add search filter has_albums.

Sometimes it's nice to search just for the free spirits.
master
voussoir 2022-09-28 19:49:01 -07:00
parent 353b9eadaf
commit 3767558c66
No known key found for this signature in database
GPG Key ID: 5F7554F8C26DACCB
6 changed files with 43 additions and 9 deletions

View File

@ -426,6 +426,7 @@ class PDBPhotoMixin:
extension=None,
extension_not=None,
filename=None,
has_albums=None,
has_tags=None,
has_thumbnail=None,
is_searchhidden=False,
@ -475,6 +476,11 @@ class PDBPhotoMixin:
'.pdf AND (programming OR "survival guide")'
'.pdf programming python' (implicitly AND each term)
has_albums:
If True, require that the Photo belongs to >=1 album.
If False, require that the Photo belongs to no albums.
If None, either is okay.
has_tags:
If True, require that the Photo has >=1 tag.
If False, require that the Photo has no tags.
@ -569,6 +575,7 @@ class PDBPhotoMixin:
extension = searchhelpers.normalize_extension(extension)
extension_not = searchhelpers.normalize_extension(extension_not)
filename = searchhelpers.normalize_filename(filename)
has_albums = searchhelpers.normalize_has_tags(has_albums)
has_tags = searchhelpers.normalize_has_tags(has_tags)
has_thumbnail = searchhelpers.normalize_has_thumbnail(has_thumbnail)
is_searchhidden = searchhelpers.normalize_is_searchhidden(is_searchhidden)
@ -660,6 +667,7 @@ class PDBPhotoMixin:
'extension': list(extension) or None,
'extension_not': list(extension_not) or None,
'filename': filename or None,
'has_albums': has_albums,
'has_tags': has_tags,
'has_thumbnail': has_thumbnail,
'mimetype': list(mimetype) or None,
@ -731,9 +739,14 @@ class PDBPhotoMixin:
wheres.append(clauses)
bindings.extend(patterns)
if has_albums is True:
wheres.append('EXISTS (SELECT 1 FROM album_photo_rel WHERE photoid == photos.id)')
elif has_albums is False:
wheres.append('NOT EXISTS (SELECT 1 FROM album_photo_rel WHERE photoid == photos.id)')
if has_tags is True:
wheres.append('EXISTS (SELECT 1 FROM photo_tag_rel WHERE photoid == photos.id)')
if has_tags is False:
elif has_tags is False:
wheres.append('NOT EXISTS (SELECT 1 FROM photo_tag_rel WHERE photoid == photos.id)')
if yield_albums and not yield_photos:

View File

@ -192,6 +192,12 @@ def normalize_filename(filename_terms):
return filename_terms
def normalize_has_albums(has_albums):
'''
See voussoirkit.stringtools.truthystring.
'''
return stringtools.truthystring(has_albums, None)
def normalize_has_tags(has_tags):
'''
See voussoirkit.stringtools.truthystring.

View File

@ -140,6 +140,7 @@ def search_by_argparse(args, yield_albums=False, yield_photos=False):
extension=args.extension,
extension_not=args.extension_not,
filename=args.filename,
has_albums=args.has_albums,
has_tags=args.has_tags,
has_thumbnail=args.has_thumbnail,
is_searchhidden=args.is_searchhidden,
@ -1417,6 +1418,16 @@ def main(argv):
Search for strings within Photos' filenames.
''',
)
p_search.add_argument(
'--has_albums',
'--has-albums',
default=None,
help='''
If "yes", Photo must belong to at least one album.
If "no", Photo must not belong to any albums.
If "null", doesn't matter.
''',
)
p_search.add_argument(
'--has_tags',
'--has-tags',

View File

@ -205,14 +205,10 @@ def get_all_album_names():
response = {'albums': all_albums}
return flasktools.json_response(response)
def get_albums_core():
albums = list(common.P.get_root_albums())
albums.sort(key=lambda x: x.display_name.lower())
return albums
@site.route('/albums')
def get_albums_html():
albums = get_albums_core()
albums = list(common.P.get_root_albums())
albums.sort(key=lambda x: x.display_name.lower())
response = common.render_template(
request,
'album.html',
@ -223,8 +219,9 @@ def get_albums_html():
@site.route('/albums.json')
def get_albums_json():
albums = get_albums_core()
albums = [album.jsonify(minimal=True) for album in albums]
albums = list(common.P.get_albums())
albums.sort(key=lambda x: x.display_name.lower())
albums = [album.jsonify(include_photos=False) for album in albums]
return flasktools.json_response(albums)
# Album create and delete ##########################################################################

View File

@ -401,6 +401,7 @@ def get_search_core():
height = request.args.get('height')
aspectratio = request.args.get('aspectratio')
bytes = request.args.get('bytes')
has_albums = request.args.get('has_albums')
has_thumbnail = request.args.get('has_thumbnail')
duration = request.args.get('duration')
bitrate = request.args.get('bitrate')
@ -421,6 +422,7 @@ def get_search_core():
'extension': extension,
'extension_not': extension_not,
'filename': filename_terms,
'has_albums': has_albums,
'has_tags': has_tags,
'has_thumbnail': has_thumbnail,
'is_searchhidden': is_searchhidden,

View File

@ -296,6 +296,11 @@
</option>
{% endfor %}
</select>
<select name="has_albums" class="basic_param">
<option value="" {{"selected" if search_kwargs['has_albums']==None else ""}}>Album or no album</option>
<option value="yes" {{"selected" if search_kwargs['has_albums']==True else ""}}>Photos contained in albums</option>
<option value="no" {{"selected" if search_kwargs['has_albums']==False else ""}}>Photos not in albums</option>
</select>
<select name="has_tags" class="basic_param">
<option value="" {{"selected" if search_kwargs['has_tags']==None else ""}}>Tagged or untagged</option>
<option value="yes" {{"selected" if search_kwargs['has_tags']==True else ""}}>Tagged only</option>