refactor(main): gallery routes use ?tag_id=int
Drops the ?tag=<name> lookup. URLs become unambiguous (distinct same-name characters each have their own id-keyed URL). Eager-loads Tag.fandom for the active-tag header rendering. Applied to all four gallery routes: /gallery, /api/gallery/scroll, /api/gallery/timeline, /api/gallery/jump — they all shared the same name-keyed filter pattern. (Plan named only the first two; extended to all four for behavioral consistency so partial JS migration to tag_id doesn't silently drop filter on the sub-APIs.) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+18
-18
@@ -113,17 +113,17 @@ def gallery():
|
|||||||
from app.models import PostMetadata
|
from app.models import PostMetadata
|
||||||
|
|
||||||
initial_limit = 30
|
initial_limit = 30
|
||||||
tag_name = request.args.get('tag')
|
tag_id = request.args.get('tag_id', type=int)
|
||||||
|
active_tag_obj = (
|
||||||
|
Tag.query.options(joinedload(Tag.fandom)).get(tag_id)
|
||||||
|
if tag_id else None
|
||||||
|
)
|
||||||
|
|
||||||
# Base query + eager-load tags
|
# Base query + eager-load tags
|
||||||
q = ImageRecord.query.options(joinedload(ImageRecord.tags))
|
q = ImageRecord.query.options(joinedload(ImageRecord.tags))
|
||||||
|
|
||||||
# Optional tag filter
|
if active_tag_obj:
|
||||||
active_tag_obj = None
|
q = q.join(ImageRecord.tags).filter(Tag.id == active_tag_obj.id)
|
||||||
if tag_name:
|
|
||||||
active_tag_obj = Tag.query.filter_by(name=tag_name).first()
|
|
||||||
if active_tag_obj:
|
|
||||||
q = q.join(ImageRecord.tags).filter(Tag.name == tag_name)
|
|
||||||
|
|
||||||
# Fetch initial batch ordered by date descending
|
# Fetch initial batch ordered by date descending
|
||||||
images = q.order_by(
|
images = q.order_by(
|
||||||
@@ -169,14 +169,14 @@ def gallery():
|
|||||||
page_count = SeriesPage.query.filter_by(series_tag_id=active_tag_obj.id).count()
|
page_count = SeriesPage.query.filter_by(series_tag_id=active_tag_obj.id).count()
|
||||||
series_info = {
|
series_info = {
|
||||||
'tag_id': active_tag_obj.id,
|
'tag_id': active_tag_obj.id,
|
||||||
'name': active_tag_obj.name.split(':', 1)[1] if ':' in active_tag_obj.name else active_tag_obj.name,
|
'name': active_tag_obj.name,
|
||||||
'page_count': page_count,
|
'page_count': page_count,
|
||||||
}
|
}
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'gallery.html',
|
'gallery.html',
|
||||||
grouped_images=grouped_images,
|
grouped_images=grouped_images,
|
||||||
active_tag=tag_name,
|
active_tag=active_tag_obj.display_name if active_tag_obj else None,
|
||||||
active_tag_obj=active_tag_obj,
|
active_tag_obj=active_tag_obj,
|
||||||
initial_cursor=initial_cursor,
|
initial_cursor=initial_cursor,
|
||||||
has_more=has_more,
|
has_more=has_more,
|
||||||
@@ -264,14 +264,14 @@ def gallery_scroll():
|
|||||||
"""
|
"""
|
||||||
cursor_str = request.args.get('cursor')
|
cursor_str = request.args.get('cursor')
|
||||||
limit = request.args.get('limit', 30, type=int)
|
limit = request.args.get('limit', 30, type=int)
|
||||||
tag_name = request.args.get('tag')
|
tag_id = request.args.get('tag_id', type=int)
|
||||||
|
|
||||||
# Build base query
|
# Build base query
|
||||||
q = ImageRecord.query.options(joinedload(ImageRecord.tags))
|
q = ImageRecord.query.options(joinedload(ImageRecord.tags))
|
||||||
|
|
||||||
# Optional tag filter
|
# Optional tag filter
|
||||||
if tag_name:
|
if tag_id:
|
||||||
q = q.join(ImageRecord.tags).filter(Tag.name == tag_name)
|
q = q.join(ImageRecord.tags).filter(Tag.id == tag_id)
|
||||||
|
|
||||||
# Apply cursor filter (fetch images older than cursor)
|
# Apply cursor filter (fetch images older than cursor)
|
||||||
if cursor_str:
|
if cursor_str:
|
||||||
@@ -330,7 +330,7 @@ def gallery_timeline():
|
|||||||
|
|
||||||
Returns list of {key, label, count, year} ordered newest to oldest.
|
Returns list of {key, label, count, year} ordered newest to oldest.
|
||||||
"""
|
"""
|
||||||
tag_name = request.args.get('tag')
|
tag_id = request.args.get('tag_id', type=int)
|
||||||
|
|
||||||
# Use SQL to aggregate by year-month
|
# Use SQL to aggregate by year-month
|
||||||
date_expr = func.coalesce(ImageRecord.taken_at, ImageRecord.imported_at)
|
date_expr = func.coalesce(ImageRecord.taken_at, ImageRecord.imported_at)
|
||||||
@@ -341,8 +341,8 @@ def gallery_timeline():
|
|||||||
func.count(ImageRecord.id).label('count')
|
func.count(ImageRecord.id).label('count')
|
||||||
)
|
)
|
||||||
|
|
||||||
if tag_name:
|
if tag_id:
|
||||||
q = q.join(ImageRecord.tags).filter(Tag.name == tag_name)
|
q = q.join(ImageRecord.tags).filter(Tag.id == tag_id)
|
||||||
|
|
||||||
q = q.group_by(
|
q = q.group_by(
|
||||||
extract('year', date_expr),
|
extract('year', date_expr),
|
||||||
@@ -391,7 +391,7 @@ def gallery_jump():
|
|||||||
"""
|
"""
|
||||||
year_month = request.args.get('year_month', '')
|
year_month = request.args.get('year_month', '')
|
||||||
limit = request.args.get('limit', 30, type=int)
|
limit = request.args.get('limit', 30, type=int)
|
||||||
tag_name = request.args.get('tag')
|
tag_id = request.args.get('tag_id', type=int)
|
||||||
|
|
||||||
if not year_month:
|
if not year_month:
|
||||||
return jsonify(error='year_month is required'), 400
|
return jsonify(error='year_month is required'), 400
|
||||||
@@ -410,8 +410,8 @@ def gallery_jump():
|
|||||||
# Build query for images in that month and earlier
|
# Build query for images in that month and earlier
|
||||||
q = ImageRecord.query.options(joinedload(ImageRecord.tags))
|
q = ImageRecord.query.options(joinedload(ImageRecord.tags))
|
||||||
|
|
||||||
if tag_name:
|
if tag_id:
|
||||||
q = q.join(ImageRecord.tags).filter(Tag.name == tag_name)
|
q = q.join(ImageRecord.tags).filter(Tag.id == tag_id)
|
||||||
|
|
||||||
# Get images from start of target month onwards (but ordered descending)
|
# Get images from start of target month onwards (but ordered descending)
|
||||||
date_expr = func.coalesce(ImageRecord.taken_at, ImageRecord.imported_at)
|
date_expr = func.coalesce(ImageRecord.taken_at, ImageRecord.imported_at)
|
||||||
|
|||||||
Reference in New Issue
Block a user