Search any movie / show / person (TMDB multi-search) entirely in-app. Results that you already own link straight to the library detail; the rest open a TMDB-backed 'preview' detail that reuses the exact same Netflix billboard UI (direct image URLs, nothing owned/enriched). Everything resolves back into SoulSync — no external links on un-owned titles. - Search page (video-search.js): debounced /api/video/search, grouped movies/shows/people cards (reuses .library-artist-card) with owned/preview ribbons. People open the person page. - Source-agnostic detail (video-detail.js): loads from /api/video/detail (library) or /api/video/tmdb (preview); art helpers pick proxy vs direct URLs; tmdb shows lazy-load episodes per season; owned-via-tmdb-url auto-redirects to the library detail. - 'More Like This' now drills in-app (tmdb detail, redirects if owned); cast/crew link to a new in-app person page (bio + filmography, each credit owned/preview). Library credits now carry tmdb_id so owned-item cast is clickable too. - Backend: TMDBClient.search/full_detail/person (+ shared _parse_extras); engine.search/tmdb_detail/tmdb_season/person_detail; db.library_id_for_tmdb; routes /search, /tmdb/<kind>/<id>, /tmdb/show/<id>/season/<n>, /person/<id>. Isolated (one-way): video-only files, no music imports, music shell untouched. Seam tests: search/full_detail parsing, tmdb_detail assemble+redirect, search + person library annotation, library_id_for_tmdb, route registration, shell/JS isolation. 234 video-suite tests pass.
33 lines
1.1 KiB
Python
33 lines
1.1 KiB
Python
"""Video search API (in-app, isolated).
|
|
|
|
GET /api/video/search?q=... → TMDB multi-search (movies / shows / people),
|
|
movie/show results annotated with library_id
|
|
if already owned.
|
|
|
|
Everything resolves back into SoulSync — results link to the library detail
|
|
(owned) or the TMDB-backed detail (not owned); people open the in-app person
|
|
page. Reads only the video engine + video.db.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from flask import jsonify, request
|
|
|
|
from utils.logging_config import get_logger
|
|
|
|
logger = get_logger("video_api.search")
|
|
|
|
|
|
def register_routes(bp):
|
|
@bp.route("/search", methods=["GET"])
|
|
def video_search():
|
|
q = (request.args.get("q") or "").strip()
|
|
if not q:
|
|
return jsonify({"results": [], "query": ""})
|
|
try:
|
|
from core.video.enrichment.engine import get_video_enrichment_engine
|
|
results = get_video_enrichment_engine().search(q)
|
|
except Exception:
|
|
logger.exception("video search failed for %r", q)
|
|
results = []
|
|
return jsonify({"results": results, "query": q})
|