Reads the active media server and mirrors it into video.db, adapting the music scan pattern (ask the server, upsert, prune what's gone) — isolated from music. - core/video/scanner.py: server-agnostic VideoLibraryScanner. Consumes a media source (duck-typed) yielding normalized dicts; upserts movies + show trees, prunes removed items, reports progress/state. Skips pruning when a scan returns nothing (transient-failure safety). Background thread + scan_sync. - core/video/sources.py: Plex + Jellyfin adapters that REUSE the shared connected clients (MediaServerEngine) but own all video-section logic; produce normalized dicts. (Validated against a live server by design; scanner itself is fully unit-tested with a fake source.) - api/video/scan.py: POST /api/video/scan/request, GET /api/video/scan/status. - .gitignore: video_library.db + sidecars (mirrors music); tests inject a tmp DB so none is ever created in the repo. Tests: scan populate/prune/empty-safety/no-source-error, isolation guard (core/video imports nothing from music), scan routes registered. 101 green.
32 lines
1.1 KiB
Python
32 lines
1.1 KiB
Python
"""Video library scan endpoints.
|
|
|
|
POST /api/video/scan/request -> start a background scan of the active server
|
|
GET /api/video/scan/status -> current scan progress/state
|
|
|
|
The scan READS the media server (source of truth) into video.db. Triggering the
|
|
server's own rescan (post-download) is wired separately into the download flow.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from flask import jsonify
|
|
|
|
from utils.logging_config import get_logger
|
|
|
|
logger = get_logger("video_api.scan")
|
|
|
|
|
|
def register_routes(bp):
|
|
@bp.route("/scan/request", methods=["POST"])
|
|
def video_scan_request():
|
|
from . import get_video_db
|
|
from core.video.scanner import get_video_scanner
|
|
from core.video.sources import get_active_video_source
|
|
scanner = get_video_scanner(get_video_db())
|
|
return jsonify(scanner.request_scan(get_active_video_source))
|
|
|
|
@bp.route("/scan/status", methods=["GET"])
|
|
def video_scan_status():
|
|
from . import get_video_db
|
|
from core.video.scanner import get_video_scanner
|
|
return jsonify(get_video_scanner(get_video_db()).get_status())
|