Add Jellyfin handoff progress job
This commit is contained in:
@@ -66,7 +66,7 @@ from app_support import (
|
||||
write_json,
|
||||
)
|
||||
from http_handler import HandlerContext, build_handler_class, server_host, server_port
|
||||
from queue_jobs import DownloadQueue, WatchlistAutoRefreshScheduler, WatchlistRefreshJobs
|
||||
from queue_jobs import DownloadQueue, JellyfinSyncJobs, WatchlistAutoRefreshScheduler, WatchlistRefreshJobs
|
||||
from title_matching import (
|
||||
base_title_variants,
|
||||
normalize_title_key,
|
||||
@@ -92,6 +92,7 @@ WATCHLIST = None
|
||||
DOWNLOAD_QUEUE = None
|
||||
WATCHLIST_REFRESH = None
|
||||
WATCHLIST_AUTO_REFRESH = None
|
||||
WATCHLIST_JELLYFIN_SYNC = None
|
||||
|
||||
|
||||
def graph_request(query, variables, timeout=25):
|
||||
@@ -1042,15 +1043,28 @@ def watchlist_item_download_complete(item, mode=""):
|
||||
return True, "ready"
|
||||
|
||||
|
||||
def _move_tree_contents(source_dir, target_dir):
|
||||
def _move_tree_contents(source_dir, target_dir, progress_fn=None):
|
||||
moved = []
|
||||
for source_path in sorted(source_dir.rglob("*"), key=lambda path: (len(path.parts), str(path))):
|
||||
if source_path.is_dir():
|
||||
continue
|
||||
file_paths = [
|
||||
source_path
|
||||
for source_path in sorted(source_dir.rglob("*"), key=lambda path: (len(path.parts), str(path)))
|
||||
if source_path.is_file()
|
||||
]
|
||||
total_files = len(file_paths)
|
||||
for index, source_path in enumerate(file_paths, start=1):
|
||||
relative = source_path.relative_to(source_dir)
|
||||
destination = target_dir / relative
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
final_destination = app_support.unique_destination(destination)
|
||||
if progress_fn is not None:
|
||||
progress_fn(
|
||||
{
|
||||
"file_index": index,
|
||||
"file_total": total_files,
|
||||
"source": str(source_path),
|
||||
"current_file": str(final_destination),
|
||||
}
|
||||
)
|
||||
shutil.move(str(source_path), str(final_destination))
|
||||
moved.append(str(final_destination))
|
||||
for path in sorted(source_dir.rglob("*"), key=lambda path: len(path.parts), reverse=True):
|
||||
@@ -1085,7 +1099,7 @@ def jellyfin_target_looks_complete(item, target_dir):
|
||||
return len(files) >= expected_count
|
||||
|
||||
|
||||
def move_watchlist_item_to_jellyfin(item, config):
|
||||
def move_watchlist_item_to_jellyfin(item, config, progress_fn=None):
|
||||
source_dir = watchlist_source_library_dir(item, config)
|
||||
target_dir = jellyfin_target_library_dir(item, config)
|
||||
if target_dir is None:
|
||||
@@ -1101,11 +1115,8 @@ def move_watchlist_item_to_jellyfin(item, config):
|
||||
return {"moved": False, "reason": reason, "item": item, "source": str(source_dir), "target": str(target_dir)}
|
||||
return {"moved": False, "reason": "source_missing", "item": item, "source": str(source_dir), "target": str(target_dir)}
|
||||
target_dir.parent.mkdir(parents=True, exist_ok=True)
|
||||
if not target_dir.exists():
|
||||
shutil.move(str(source_dir), str(target_dir))
|
||||
moved_files = [str(path) for path in target_dir.rglob("*") if path.is_file()]
|
||||
else:
|
||||
moved_files = _move_tree_contents(source_dir, target_dir)
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
moved_files = _move_tree_contents(source_dir, target_dir, progress_fn=progress_fn)
|
||||
return {
|
||||
"moved": True,
|
||||
"reason": "moved",
|
||||
@@ -2558,7 +2569,7 @@ def queue_watchlist_auto_download(item, refresh_source="manual"):
|
||||
return {"queued": True, "mode": mode, "quality": quality, "episodes": specs, "jobs": jobs}
|
||||
|
||||
|
||||
def trigger_jellyfin_sync_for_item(item, automatic=False, config=None):
|
||||
def trigger_jellyfin_sync_for_item(item, automatic=False, config=None, progress_fn=None):
|
||||
active_config = normalize_config(config or get_config_snapshot())
|
||||
if automatic and not bool(active_config.get("jellyfin_sync_enabled")):
|
||||
return {"moved": False, "reason": "disabled", "item": item}
|
||||
@@ -2575,7 +2586,7 @@ def trigger_jellyfin_sync_for_item(item, automatic=False, config=None):
|
||||
debug_log("discord_webhook.jellyfin_sync_failed", show_id=item.get("show_id"), reason=result.get("reason"), error=exc)
|
||||
return result
|
||||
try:
|
||||
result = move_watchlist_item_to_jellyfin(item, active_config)
|
||||
result = move_watchlist_item_to_jellyfin(item, active_config, progress_fn=progress_fn)
|
||||
except Exception as exc:
|
||||
result = {
|
||||
"moved": False,
|
||||
@@ -2632,6 +2643,16 @@ def run_jellyfin_sync(config=None):
|
||||
}
|
||||
|
||||
|
||||
def start_jellyfin_sync(config=None):
|
||||
ensure_runtime()
|
||||
return WATCHLIST_JELLYFIN_SYNC.start(config=config)
|
||||
|
||||
|
||||
def get_jellyfin_sync_status():
|
||||
ensure_runtime()
|
||||
return WATCHLIST_JELLYFIN_SYNC.status()
|
||||
|
||||
|
||||
def update_watchlist_category(show_id, category):
|
||||
ensure_runtime()
|
||||
item = WATCHLIST.update_category(show_id, category)
|
||||
@@ -2778,6 +2799,7 @@ def runtime_state():
|
||||
"download_queue": DOWNLOAD_QUEUE,
|
||||
"watchlist_refresh": WATCHLIST_REFRESH,
|
||||
"watchlist_auto_refresh": WATCHLIST_AUTO_REFRESH,
|
||||
"watchlist_jellyfin_sync": WATCHLIST_JELLYFIN_SYNC,
|
||||
}
|
||||
|
||||
|
||||
@@ -2800,6 +2822,12 @@ def build_runtime(start_workers=None):
|
||||
config_getter=lambda: get_config_snapshot(config),
|
||||
start_worker=worker_state,
|
||||
)
|
||||
watchlist_jellyfin_sync = JellyfinSyncJobs(
|
||||
watchlist,
|
||||
sync_fn=trigger_jellyfin_sync_for_item,
|
||||
config_getter=lambda: get_config_snapshot(config),
|
||||
start_worker=worker_state,
|
||||
)
|
||||
watchlist_auto_refresh = WatchlistAutoRefreshScheduler(
|
||||
config_getter=lambda: get_config_snapshot(config),
|
||||
refresh_start_fn=watchlist_refresh.start,
|
||||
@@ -2811,11 +2839,12 @@ def build_runtime(start_workers=None):
|
||||
"download_queue": download_queue,
|
||||
"watchlist_refresh": watchlist_refresh,
|
||||
"watchlist_auto_refresh": watchlist_auto_refresh,
|
||||
"watchlist_jellyfin_sync": watchlist_jellyfin_sync,
|
||||
}
|
||||
|
||||
|
||||
def initialize_runtime(start_workers=None):
|
||||
global CONFIG, WATCHLIST, DOWNLOAD_QUEUE, WATCHLIST_REFRESH, WATCHLIST_AUTO_REFRESH
|
||||
global CONFIG, WATCHLIST, DOWNLOAD_QUEUE, WATCHLIST_REFRESH, WATCHLIST_AUTO_REFRESH, WATCHLIST_JELLYFIN_SYNC
|
||||
with RUNTIME_LOCK:
|
||||
workers_allowed = background_workers_enabled()
|
||||
if (
|
||||
@@ -2824,6 +2853,7 @@ def initialize_runtime(start_workers=None):
|
||||
and DOWNLOAD_QUEUE is not None
|
||||
and WATCHLIST_REFRESH is not None
|
||||
and WATCHLIST_AUTO_REFRESH is not None
|
||||
and WATCHLIST_JELLYFIN_SYNC is not None
|
||||
):
|
||||
if start_workers and workers_allowed:
|
||||
WATCHLIST.worker_enabled = True
|
||||
@@ -2831,6 +2861,7 @@ def initialize_runtime(start_workers=None):
|
||||
DOWNLOAD_QUEUE.ensure_worker()
|
||||
WATCHLIST_REFRESH.ensure_worker()
|
||||
WATCHLIST_AUTO_REFRESH.ensure_worker()
|
||||
WATCHLIST_JELLYFIN_SYNC.ensure_worker()
|
||||
return runtime_state()
|
||||
runtime = build_runtime(start_workers=start_workers)
|
||||
CONFIG = runtime["config"]
|
||||
@@ -2838,6 +2869,7 @@ def initialize_runtime(start_workers=None):
|
||||
DOWNLOAD_QUEUE = runtime["download_queue"]
|
||||
WATCHLIST_REFRESH = runtime["watchlist_refresh"]
|
||||
WATCHLIST_AUTO_REFRESH = runtime["watchlist_auto_refresh"]
|
||||
WATCHLIST_JELLYFIN_SYNC = runtime["watchlist_jellyfin_sync"]
|
||||
return runtime
|
||||
|
||||
|
||||
@@ -2848,6 +2880,7 @@ def ensure_runtime(start_workers=False):
|
||||
or DOWNLOAD_QUEUE is None
|
||||
or WATCHLIST_REFRESH is None
|
||||
or WATCHLIST_AUTO_REFRESH is None
|
||||
or WATCHLIST_JELLYFIN_SYNC is None
|
||||
):
|
||||
return initialize_runtime(start_workers=start_workers)
|
||||
if start_workers:
|
||||
@@ -2864,10 +2897,11 @@ def shutdown_runtime(wait=False, cancel_active_downloads=None):
|
||||
and DOWNLOAD_QUEUE is None
|
||||
and WATCHLIST_REFRESH is None
|
||||
and WATCHLIST_AUTO_REFRESH is None
|
||||
and WATCHLIST_JELLYFIN_SYNC is None
|
||||
):
|
||||
return False
|
||||
services = (WATCHLIST, DOWNLOAD_QUEUE, WATCHLIST_REFRESH, WATCHLIST_AUTO_REFRESH)
|
||||
watchlist, download_queue, watchlist_refresh, watchlist_auto_refresh = services
|
||||
services = (WATCHLIST, DOWNLOAD_QUEUE, WATCHLIST_REFRESH, WATCHLIST_AUTO_REFRESH, WATCHLIST_JELLYFIN_SYNC)
|
||||
watchlist, download_queue, watchlist_refresh, watchlist_auto_refresh, watchlist_jellyfin_sync = services
|
||||
should_cancel_downloads = bool(wait) if cancel_active_downloads is None else bool(cancel_active_downloads)
|
||||
stopped = True
|
||||
if watchlist is not None:
|
||||
@@ -2878,11 +2912,13 @@ def shutdown_runtime(wait=False, cancel_active_downloads=None):
|
||||
stopped = watchlist_refresh.shutdown(wait=wait) and stopped
|
||||
if watchlist_auto_refresh is not None:
|
||||
stopped = watchlist_auto_refresh.shutdown(wait=wait) and stopped
|
||||
if watchlist_jellyfin_sync is not None:
|
||||
stopped = watchlist_jellyfin_sync.shutdown(wait=wait) and stopped
|
||||
return stopped
|
||||
|
||||
|
||||
def reset_runtime(wait=False, cancel_active_downloads=None):
|
||||
global CONFIG, WATCHLIST, DOWNLOAD_QUEUE, WATCHLIST_REFRESH, WATCHLIST_AUTO_REFRESH
|
||||
global CONFIG, WATCHLIST, DOWNLOAD_QUEUE, WATCHLIST_REFRESH, WATCHLIST_AUTO_REFRESH, WATCHLIST_JELLYFIN_SYNC
|
||||
stopped = shutdown_runtime(wait=wait, cancel_active_downloads=cancel_active_downloads)
|
||||
if not stopped:
|
||||
if wait:
|
||||
@@ -2894,6 +2930,7 @@ def reset_runtime(wait=False, cancel_active_downloads=None):
|
||||
DOWNLOAD_QUEUE = None
|
||||
WATCHLIST_REFRESH = None
|
||||
WATCHLIST_AUTO_REFRESH = None
|
||||
WATCHLIST_JELLYFIN_SYNC = None
|
||||
return True
|
||||
|
||||
|
||||
@@ -2906,6 +2943,7 @@ Handler = build_handler_class(
|
||||
episode_list=episode_list,
|
||||
get_config_snapshot=get_config_snapshot,
|
||||
get_watchlist_homepage_summary=get_watchlist_homepage_summary,
|
||||
get_jellyfin_sync_status=get_jellyfin_sync_status,
|
||||
get_watchlist=get_watchlist,
|
||||
get_watchlist_refresh_status=get_watchlist_refresh_status,
|
||||
http_error=HttpError,
|
||||
@@ -2919,6 +2957,7 @@ Handler = build_handler_class(
|
||||
resolve_search_thumbnail=resolve_search_thumbnail,
|
||||
test_discord_webhook_config=test_discord_webhook_config,
|
||||
thumbnail_file_path=thumbnail_file_path,
|
||||
start_jellyfin_sync=start_jellyfin_sync,
|
||||
update_all_watchlist_statuses=update_all_watchlist_statuses,
|
||||
update_watchlist_auto_download=update_watchlist_auto_download,
|
||||
update_watchlist_category=update_watchlist_category,
|
||||
|
||||
Reference in New Issue
Block a user