This is the tool originally asked for — DISTINCT from the Library Scan (where
SoulSync reads the server into video.db). Server Scan tells Plex/Jellyfin to
rescan its OWN folders so newly-downloaded files get indexed, then a Library Scan
pulls them in. It's the manual twin of the post-download 'Scan Video Server'
automation, and targets Movies / TV / both like the Library Scan.
- POST /api/video/scan/server {media_type} -> refresh_video_server_sections (trigger)
- GET /api/video/scan/server/status?media_type -> {scanning:true|false|null} (live poll)
- new Server Scan card on the video Tools page + video-server-scan.js controller,
mirroring the music live-status UX (phase + working bar); resumes if the page
opens mid-scan. Server scans have no % (Plex doesn't report one) so the bar is a
working indicator. Both backend functions already existed + are media-type aware.
Seam tests: trigger threads media_type (movie / default all), status reports the
scanning flag (True / null passthrough), and the blueprint exposes both routes.
61 lines
2.6 KiB
Python
61 lines
2.6 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")
|
|
# Which library to scan — movies and TV are independent libraries, so the
|
|
# UI can target one or both. The scanner normalizes/validates it.
|
|
media_type = body.get("media_type", "all")
|
|
scanner = get_video_scanner(get_video_db())
|
|
return jsonify(scanner.request_scan(get_active_video_source, mode, media_type))
|
|
|
|
@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())
|
|
|
|
# ── Server-side scan (distinct from the SoulSync-reads-server scan above) ──
|
|
# This tells the media server (Plex/Jellyfin) to rescan its OWN folders so
|
|
# newly-downloaded files get indexed — the manual twin of the post-download
|
|
# 'Scan Video Server' automation. media_type scopes it to Movies / TV / both.
|
|
@bp.route("/scan/server", methods=["POST"])
|
|
def video_scan_server():
|
|
from core.video.sources import refresh_video_server_sections
|
|
body = request.get_json(silent=True) or {}
|
|
media_type = body.get("media_type", "all")
|
|
return jsonify(refresh_video_server_sections(media_type))
|
|
|
|
@bp.route("/scan/server/status", methods=["GET"])
|
|
def video_scan_server_status():
|
|
# {scanning: true|false|null} — null when the adapter can't report state.
|
|
from core.video.sources import video_server_scan_in_progress
|
|
media_type = request.args.get("media_type", "all")
|
|
return jsonify({"scanning": video_server_scan_in_progress(media_type)})
|