soulsync/api/video/detail.py
BoulderBadgeDad 9b607b3d1b video: detail-page data layer (show tree + movie) + backdrop proxy
Backend for the upcoming TV/movie detail pages, isolated to video.db:
- show_detail(id): show + seasons->episodes tree with owned/total roll-ups
  (season 0 -> 'Specials', missing-season-row episodes still grouped).
- movie_detail(id): movie + owned flag + best media-file (resolution/quality).
- get_art_ref generalizes the poster ref to poster|backdrop; new
  /api/video/backdrop/<kind>/<id> streams the hero art server-side (Jellyfin
  Backdrop vs Primary handled).
- /api/video/detail/{show,movie}/<id> endpoints.

Seam tests for the tree roll-ups, owned/file, art ref, and both endpoints.
2026-06-14 15:52:22 -07:00

33 lines
1,008 B
Python

"""Video detail payloads (drill-in pages).
GET /api/video/detail/show/<id> → show + seasons→episodes tree (owned roll-ups)
GET /api/video/detail/movie/<id> → movie + owned/file info
Reads only video.db; isolated from the music API.
"""
from __future__ import annotations
from flask import jsonify
from utils.logging_config import get_logger
logger = get_logger("video_api.detail")
def register_routes(bp):
@bp.route("/detail/show/<int:show_id>", methods=["GET"])
def video_show_detail(show_id):
from . import get_video_db
data = get_video_db().show_detail(show_id)
if not data:
return jsonify({"error": "not found"}), 404
return jsonify(data)
@bp.route("/detail/movie/<int:movie_id>", methods=["GET"])
def video_movie_detail(movie_id):
from . import get_video_db
data = get_video_db().movie_detail(movie_id)
if not data:
return jsonify({"error": "not found"}), 404
return jsonify(data)