diff --git a/pytorrent/services/download_planner.py b/pytorrent/services/download_planner.py index fa36486..13ce3b5 100644 --- a/pytorrent/services/download_planner.py +++ b/pytorrent/services/download_planner.py @@ -443,11 +443,13 @@ def evaluate(profile: dict, settings: dict | None = None, now: datetime | None = } -def enforce(profile: dict, force: bool = False) -> dict: +def enforce(profile: dict, force: bool = False, user_id: int | None = None) -> dict: profile_id = int(profile.get("id") or 0) - settings = get_settings(profile_id) + user_id = user_id or int(profile.get("user_id") or default_user_id()) + # Note: Background planner runs without Flask session state, so settings are resolved with the profile owner. + settings = get_settings(profile_id, user_id) if not settings.get("enabled"): - return {"ok": True, "enabled": False, "profile_id": profile_id, "history": history(profile_id, 20), "history_total": history_count(profile_id), "preview": preview(profile)} + return {"ok": True, "enabled": False, "profile_id": profile_id, "history": history(profile_id, 20), "history_total": history_count(profile_id), "preview": preview(profile, user_id=user_id)} now = time.monotonic() interval = int(settings.get("check_interval_seconds") or 30) if not force and now - _LAST_RUN.get(profile_id, 0) < interval: @@ -497,13 +499,14 @@ def enforce(profile: dict, force: bool = False) -> dict: _append_history(profile_id, "resumed_torrents", {"count": len(hashes), "dry_run": dry_run}) result["history"] = history(profile_id, 20) result["history_total"] = history_count(profile_id) - result["preview"] = preview(profile) + result["preview"] = preview(profile, user_id=user_id) return result -def preview(profile: dict) -> dict: +def preview(profile: dict, user_id: int | None = None) -> dict: profile_id = int(profile.get("id") or 0) - settings = get_settings(profile_id) + user_id = user_id or int(profile.get("user_id") or default_user_id()) + settings = get_settings(profile_id, user_id) decision = evaluate(profile, settings) return { "profile_id": profile_id, diff --git a/pytorrent/services/websocket.py b/pytorrent/services/websocket.py index 373e29c..25396ef 100644 --- a/pytorrent/services/websocket.py +++ b/pytorrent/services/websocket.py @@ -64,7 +64,7 @@ def _run_slow_profile_tasks(socketio, profile: dict, profile_id: int) -> None: except Exception as exc: _emit_profile(socketio, "automation_update", {"ok": False, "profile_id": profile_id, "error": str(exc)}, profile_id) try: - plan_result = download_planner.enforce(profile, force=False) + plan_result = download_planner.enforce(profile, force=False, user_id=profile_user_id) if plan_result.get("enabled") and not plan_result.get("skipped"): _emit_profile(socketio, "download_plan_update", plan_result, profile_id) except Exception as exc: diff --git a/pytorrent/services/workers.py b/pytorrent/services/workers.py index 990731f..4e3778f 100644 --- a/pytorrent/services/workers.py +++ b/pytorrent/services/workers.py @@ -292,6 +292,8 @@ def _run(job_id: str): return sem = None ordered_lock = None + job = {} + payload = {} try: job = _job_row(job_id) if not job or job["status"] == "cancelled": @@ -330,6 +332,8 @@ def _run(job_id: str): _set_job(job_id, "done", result=result, finished=True) operation_logs.record_job_event(profile["id"], job["action"], "done", payload, result=result or {}, job_id=job_id, user_id=int(job.get("user_id") or 0)) _emit("operation_finished", {"job_id": job_id, "action": job["action"], "profile_id": profile["id"], "hashes": payload.get("hashes") or [], "hash_count": len(payload.get("hashes") or []), "bulk": len(payload.get("hashes") or []) > 1, "result": result, **event_meta}) + # Note: Completed jobs must publish a fresh torrent snapshot/patch so removed or moved torrents disappear without a page reload. + _emit_torrent_refresh(profile, str(job["action"] or "")) _emit("job_update", {"id": job_id, "profile_id": profile["id"], "status": "done", "result": result}) except Exception as exc: fresh = _job_row(job_id) or {}