soulsync/api/video/library.py
BoulderBadgeDad 3a8c803a54 Video: scope library reads to the active server (Plex/Jellyfin don't commingle)
Storage was already per-server (movies/shows UNIQUE(server_source, server_id),
episodes via per-server show_id, prune_missing scoped) — but reads returned
every server's rows, so a Jellyfin scan would show up alongside Plex.

Mirror the music standard: scope reads to the active video server
(resolve_video_server). query_library, calendar_upcoming, dashboard_stats and
library_id_for_tmdb take a server_source; the dashboard/library/calendar
endpoints pass it. server_source=None keeps "all servers" (enrichment processes
every server; tests unchanged). No schema change, no data migration — existing
Plex data is untouched and simply hidden while Jellyfin is the active server.

Regression tests: same title on both servers stays two rows; scoped reads only
return the active server's data; deep-scan prune never touches the other server.
2026-06-15 18:45:28 -07:00

34 lines
1.2 KiB
Python

"""Video library listing endpoint.
GET /api/video/library -> {"movies": [...], "shows": [...]}
Reads what the last scan mirrored from the media server into video.db.
"""
from __future__ import annotations
from flask import jsonify, request
from utils.logging_config import get_logger
logger = get_logger("video_api.library")
def register_routes(bp):
@bp.route("/library", methods=["GET"])
def video_library():
from . import get_video_db
from core.video.sources import resolve_video_server
try:
return jsonify(get_video_db().query_library(
request.args.get("kind", "movies"),
search=request.args.get("search") or None,
letter=request.args.get("letter") or None,
sort=request.args.get("sort", "title"),
status=request.args.get("status", "all"),
page=request.args.get("page", 1),
limit=request.args.get("limit", 75),
server_source=resolve_video_server(),
))
except Exception:
logger.exception("Failed to query video library")
return jsonify({"error": "Failed to load video library"}), 500