ui change to improve tag list load

This commit is contained in:
Bryan Van Deusen
2026-01-24 12:14:27 -05:00
parent 9ebeeed133
commit 5af1dcbd4f
5 changed files with 253 additions and 76 deletions
+66 -22
View File
@@ -423,27 +423,22 @@ def gallery_jump():
)
@main.route('/tags')
def tag_list():
def _get_tags_with_previews(kind=None, limit=35, offset=0, images_per_tag=3):
"""
Generic tag explorer:
/tags -> all tags
/tags?kind=user -> only user tags
/tags?kind=artist -> only artist tags
/tags?kind=archive -> only archive tags
/tags?kind=character -> only character tags
/tags?kind=series -> only series tags
/tags?kind=rating -> only rating tags
Shows a few preview images per tag.
Helper function to get tags with counts and preview images.
Returns (tag_data list, total_count, has_more).
Optimized to use 2 queries instead of N+1:
1. Get all tags with counts
2. Get preview images for all tags at once using window function
1. Get tags with counts (paginated)
2. Get preview images for those tags using window function
"""
images_per_tag = 3
kind = request.args.get('kind')
# Query for total count
count_q = db.session.query(func.count(Tag.id))
if kind:
count_q = count_q.filter(Tag.kind == kind)
total_count = count_q.scalar()
# Query 1: Get tags with image counts
# Query 1: Get tags with image counts (paginated)
q = db.session.query(
Tag,
func.count(image_tags.c.image_id).label('img_count')
@@ -452,7 +447,7 @@ def tag_list():
if kind:
q = q.filter(Tag.kind == kind)
tags_with_counts = q.order_by(Tag.name.asc()).all()
tags_with_counts = q.order_by(Tag.name.asc()).offset(offset).limit(limit).all()
# Build tag_id list and initialize tag_data dict
tag_ids = [t.id for t, _ in tags_with_counts]
@@ -469,9 +464,7 @@ def tag_list():
}
# Query 2: Get preview images for all tags at once using a subquery with row_number
# This fetches the top N images per tag in a single query
if tag_ids:
# Subquery to rank images within each tag
row_num = func.row_number().over(
partition_by=image_tags.c.tag_id,
order_by=desc(func.coalesce(ImageRecord.taken_at, ImageRecord.imported_at))
@@ -488,7 +481,6 @@ def tag_list():
.subquery()
)
# Get only the top N images per tag
preview_rows = (
db.session.query(subq.c.tag_id, ImageRecord)
.join(ImageRecord, ImageRecord.id == subq.c.image_id)
@@ -496,18 +488,70 @@ def tag_list():
.all()
)
# Group images by tag_id
for tag_id, img in preview_rows:
if tag_id in tag_map:
tag_map[tag_id]["images"].append(img)
# Convert to list maintaining original order
tag_data = [tag_map[t.id] for t, _ in tags_with_counts]
has_more = (offset + len(tag_data)) < total_count
return tag_data, total_count, has_more
@main.route('/tags')
def tag_list():
"""
Generic tag explorer with infinite scroll:
/tags -> all tags
/tags?kind=user -> only user tags
etc.
Shows a few preview images per tag.
Initially loads 35 tags, more loaded via API as user scrolls.
"""
kind = request.args.get('kind')
limit = 35
images_per_tag = 3
tag_data, total_count, has_more = _get_tags_with_previews(
kind=kind, limit=limit, offset=0, images_per_tag=images_per_tag
)
return render_template('tags_list.html',
tag_data=tag_data,
images_per_tag=images_per_tag,
active_kind=kind)
active_kind=kind,
total_count=total_count,
has_more=has_more,
page_size=limit)
@main.route('/api/tags/list')
def api_tags_list():
"""
API endpoint for loading more tags (infinite scroll).
Returns JSON with tag cards HTML and pagination info.
"""
kind = request.args.get('kind')
offset = request.args.get('offset', 0, type=int)
limit = request.args.get('limit', 35, type=int)
images_per_tag = 3
tag_data, total_count, has_more = _get_tags_with_previews(
kind=kind, limit=limit, offset=offset, images_per_tag=images_per_tag
)
# Render tag cards to HTML
cards_html = render_template('_tag_cards.html', tag_data=tag_data)
return jsonify(
ok=True,
html=cards_html,
count=len(tag_data),
total=total_count,
has_more=has_more,
offset=offset + len(tag_data)
)
@main.route('/artists')
def artist_list():