soulsync/api/video/scan.py
BoulderBadgeDad b5d0b76fe6 video Tools: match music Database Updater (stats, cancel, real progress)
The scan tool now behaves like music's, not just looks like it:
- Card matches: help '?' button, 'Last Scan' line, and the Movies/Shows/
  Episodes/Size stats grid (populated from /api/video/dashboard on show + after
  a scan). Same .tool-card-stats markup.
- Real progress bar: scanner fetches item totals up front (Plex section.
  totalSize / Jellyfin TotalRecordCount) and reports a true percent as it
  processes; the bar actually moves (movies → shows) instead of sitting at 100%.
- Cancel: the Scan button toggles to 'Cancel' mid-scan and POSTs
  /api/video/scan/stop; the scanner checks a cancel flag between items and ends
  in a 'cancelled' state. Mirrors music's stop affordance.
Tests: percent reported, cancel stops midway + saves only processed items, stop
route registered, tool-card structure. 117 video/integrity tests green.
2026-06-14 07:35:57 -07:00

40 lines
1.4 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, request
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
body = request.get_json(silent=True) or {}
mode = body.get("mode", "full")
scanner = get_video_scanner(get_video_db())
return jsonify(scanner.request_scan(get_active_video_source, mode))
@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())
@bp.route("/scan/stop", methods=["POST"])
def video_scan_stop():
from . import get_video_db
from core.video.scanner import get_video_scanner
return jsonify(get_video_scanner(get_video_db()).cancel())