"""FC-3a: plural /api/artists endpoints — POST (find-or-create) + autocomplete. FC-3f: GET /api/artists/directory (cursor-paginated browse grid). The slug-routed singular /api/artist/ blueprint stays separate and unmodified.""" from quart import Blueprint, jsonify, request from ..extensions import get_session from ..services.artist_directory_service import ArtistDirectoryService from ..services.artist_service import ArtistService from ..services.source_service import KNOWN_PLATFORMS artists_bp = Blueprint("artists", __name__, url_prefix="/api/artists") @artists_bp.route("", methods=["POST"]) async def create_or_get(): body = await request.get_json() if not isinstance(body, dict): return jsonify({"error": "invalid_body"}), 400 name = body.get("name", "") async with get_session() as session: svc = ArtistService(session) try: artist, created = await svc.find_or_create(name) except ValueError as exc: return jsonify({"error": "empty_name", "detail": str(exc)}), 400 return jsonify({ "id": artist.id, "name": artist.name, "slug": artist.slug, "created": created, }), 201 @artists_bp.route("/autocomplete", methods=["GET"]) async def autocomplete(): q = request.args.get("q") or "" try: limit = int(request.args.get("limit", "20")) except ValueError: return jsonify({"error": "invalid_limit"}), 400 if limit < 1 or limit > 100: return jsonify({"error": "invalid_limit"}), 400 async with get_session() as session: rows = await ArtistService(session).autocomplete(q, limit=limit) return jsonify([ {"id": a.id, "name": a.name, "slug": a.slug} for a in rows ]) @artists_bp.route("/directory", methods=["GET"]) async def directory(): """FC-3f: cursor-paginated artists directory. Mirrors /api/tags/directory shape: { cards: [...], next_cursor }. """ args = request.args cursor = args.get("cursor") or None q = args.get("q") or None platform = args.get("platform") or None limit_raw = args.get("limit", "60") try: limit = int(limit_raw) except ValueError: return jsonify({"error": "invalid_limit"}), 400 if limit < 1 or limit > 200: return jsonify({"error": "invalid_limit"}), 400 if platform is not None and platform not in KNOWN_PLATFORMS: return jsonify({"error": "unknown_platform"}), 400 async with get_session() as session: svc = ArtistDirectoryService(session) try: page = await svc.list_artists( q=q, platform=platform, cursor=cursor, limit=limit, ) except ValueError: # Service raises only on bad cursor (limit was validated above). return jsonify({"error": "invalid_cursor"}), 400 return jsonify({"cards": page.cards, "next_cursor": page.next_cursor})