changes to series order system. add artist retagging tool

This commit is contained in:
Bryan Van Deusen
2026-01-23 08:38:07 -05:00
parent 82cf3b782b
commit d3e73b9533
5 changed files with 316 additions and 1 deletions
+126
View File
@@ -537,11 +537,13 @@ def search_tags():
- q: search query (matches tag name, case-insensitive)
- limit: max results (default 10)
- exclude_kind: comma-separated list of tag kinds to exclude (e.g., 'archive')
- kind: filter to only include tags of this kind (e.g., 'series')
"""
query = request.args.get('q', '').strip().lower()
limit = request.args.get('limit', 10, type=int)
exclude_kind = request.args.get('exclude_kind', '').strip()
exclude_kinds = [k.strip() for k in exclude_kind.split(',') if k.strip()]
include_kind = request.args.get('kind', '').strip()
if not query:
# Return most-used tags when no query
@@ -552,6 +554,8 @@ def search_tags():
)
if exclude_kinds:
base_query = base_query.filter(~Tag.kind.in_(exclude_kinds))
if include_kind:
base_query = base_query.filter(Tag.kind == include_kind)
tags = (
base_query
.order_by(func.count(image_tags.c.image_id).desc())
@@ -562,6 +566,8 @@ def search_tags():
base_query = Tag.query.filter(Tag.name.ilike(f'%{query}%'))
if exclude_kinds:
base_query = base_query.filter(~Tag.kind.in_(exclude_kinds))
if include_kind:
base_query = base_query.filter(Tag.kind == include_kind)
tags = (
base_query
.order_by(Tag.name)
@@ -1285,6 +1291,72 @@ def regenerate_missing_thumbnails_celery():
return jsonify({'ok': False, 'error': str(e)}), 500
@main.route('/api/reapply-artist-tags', methods=['POST'])
def reapply_artist_tags_from_paths():
"""
Re-apply artist tags to all images based on their file paths.
Artist is extracted from the first directory component after /images/
(e.g., /images/artist_name/file.jpg -> artist:artist_name)
"""
try:
images = ImageRecord.query.all()
updated = 0
skipped = 0
errors = []
for img in images:
if not img.filepath:
skipped += 1
continue
# Extract artist from path: /images/{artist}/...
# Handle both /images/artist/file.jpg and /images/artist/subdir/file.jpg
path_parts = img.filepath.split('/')
try:
# Find 'images' in path and get the next component
images_idx = path_parts.index('images')
if images_idx + 1 < len(path_parts):
artist_name = path_parts[images_idx + 1]
else:
skipped += 1
continue
except ValueError:
# 'images' not in path, try alternative format
# Maybe it's a Windows path or different structure
skipped += 1
continue
if not artist_name or artist_name == '':
skipped += 1
continue
# Create or get the artist tag
tag_name = f"artist:{artist_name}"
tag = Tag.query.filter_by(name=tag_name).first()
if not tag:
tag = Tag(name=tag_name, kind='artist')
db.session.add(tag)
db.session.flush()
# Add tag if not already present
if tag not in img.tags:
img.tags.append(tag)
updated += 1
db.session.commit()
return jsonify({
'ok': True,
'updated': updated,
'skipped': skipped,
'total': len(images),
'errors': errors if errors else None
})
except Exception as e:
db.session.rollback()
return jsonify({'ok': False, 'error': str(e)}), 500
@main.route('/api/celery/status')
def celery_cluster_status():
"""
@@ -1865,3 +1937,57 @@ def get_image_series_info(image_id):
'series_tag_id': sp.series_tag_id,
'series_name': sp.series_tag.name
})
@main.post('/api/image/<int:image_id>/add-to-series')
def add_image_to_series(image_id):
"""Add a single image to a series with a specific page number."""
from app.models import SeriesPage, Tag
data = request.get_json() or {}
series_tag_id = data.get('series_tag_id')
page_number = data.get('page_number')
if not series_tag_id:
return jsonify(ok=False, error="series_tag_id required"), 400
if not page_number:
return jsonify(ok=False, error="page_number required"), 400
# Verify the series tag exists and is a series
series_tag = Tag.query.get(series_tag_id)
if not series_tag:
return jsonify(ok=False, error="Series not found"), 404
if series_tag.kind != 'series':
return jsonify(ok=False, error="Tag is not a series"), 400
# Check if image is already in this series
existing = SeriesPage.query.filter_by(
series_tag_id=series_tag_id,
image_id=image_id
).first()
if existing:
return jsonify(ok=False, error="Image already in this series"), 409
# Check if page number is taken
page_taken = SeriesPage.query.filter_by(
series_tag_id=series_tag_id,
page_number=page_number
).first()
if page_taken:
return jsonify(ok=False, error=f"Page {page_number} already exists in this series"), 409
# Create the series page
sp = SeriesPage(
series_tag_id=series_tag_id,
image_id=image_id,
page_number=page_number
)
db.session.add(sp)
db.session.commit()
return jsonify(ok=True, series_page={
'id': sp.id,
'page_number': sp.page_number,
'series_tag_id': sp.series_tag_id,
'series_name': series_tag.name
})