bridge: upgrade_resolve_candidates + evento upgrade:candidates_needed
start_upgrade accetta 'archive_dir' nel payload e lo inoltra a upgrade_folder. Il worker passa un resolve_callback che emette 'upgrade:candidates_needed' e blocca su una queue.Queue(1) attendendo la scelta utente dal modal (timeout 10 min → skip). Il metodo upgrade_resolve_candidates(choice) è chiamato dalla UI e deposita la scelta nella queue. stop_upgrade sblocca eventuale attesa inviando un 'skip' automatico. Log dedicati per gli status nuovi (local_copy, local_upgraded, skipped_by_user, resolve_wait, scan_archive).
This commit is contained in:
1 parent
d8723f9408
commit
4e1af7b8f6
1 file changed
+71
-3
+71
-3
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import queue
|
||||||
import re
|
import re
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
@@ -110,6 +111,9 @@ class Api:
|
|||||||
self._download_thread: Optional[threading.Thread] = None
|
self._download_thread: Optional[threading.Thread] = None
|
||||||
self._upgrade_thread: Optional[threading.Thread] = None
|
self._upgrade_thread: Optional[threading.Thread] = None
|
||||||
self._video_thread: Optional[threading.Thread] = None
|
self._video_thread: Optional[threading.Thread] = None
|
||||||
|
# Coda usata dal resolve_callback per attendere la scelta utente
|
||||||
|
# sul modal "match locali multipli" della tab Upgrade.
|
||||||
|
self._upgrade_resolve_q: "queue.Queue[dict]" = queue.Queue(1)
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# Helpers
|
# Helpers
|
||||||
@@ -882,6 +886,7 @@ class Api:
|
|||||||
return {"ok": False, "error": "Upgrade gia in corso"}
|
return {"ok": False, "error": "Upgrade gia in corso"}
|
||||||
|
|
||||||
directory = (payload.get("directory") or "").strip()
|
directory = (payload.get("directory") or "").strip()
|
||||||
|
archive_dir = (payload.get("archive_dir") or "").strip() or None
|
||||||
recursive = bool(payload.get("recursive", False))
|
recursive = bool(payload.get("recursive", False))
|
||||||
try:
|
try:
|
||||||
threshold = int(payload.get("threshold", 310))
|
threshold = int(payload.get("threshold", 310))
|
||||||
@@ -898,9 +903,16 @@ class Api:
|
|||||||
cfg = load_config()
|
cfg = load_config()
|
||||||
cookies_path = cfg.get("cookies_path", "")
|
cookies_path = cfg.get("cookies_path", "")
|
||||||
|
|
||||||
|
# Drain la queue di risoluzione da eventuali run precedenti (safety)
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
self._upgrade_resolve_q.get_nowait()
|
||||||
|
except queue.Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
self._upgrade_thread = threading.Thread(
|
self._upgrade_thread = threading.Thread(
|
||||||
target=self._upgrade_worker,
|
target=self._upgrade_worker,
|
||||||
args=(directory, threshold, cookies_path, recursive),
|
args=(directory, threshold, cookies_path, recursive, archive_dir),
|
||||||
daemon=True,
|
daemon=True,
|
||||||
)
|
)
|
||||||
self._upgrade_thread.start()
|
self._upgrade_thread.start()
|
||||||
@@ -908,10 +920,36 @@ class Api:
|
|||||||
|
|
||||||
def stop_upgrade(self) -> dict:
|
def stop_upgrade(self) -> dict:
|
||||||
request_upgrade_stop()
|
request_upgrade_stop()
|
||||||
|
# Sblocca eventuale resolve_callback in attesa: inviamo scelta 'skip'
|
||||||
|
# cosi il worker esce pulito invece di restare bloccato in q.get().
|
||||||
|
try:
|
||||||
|
self._upgrade_resolve_q.put_nowait({"action": "skip"})
|
||||||
|
except queue.Full:
|
||||||
|
pass
|
||||||
self._log("upgrade", "[INFO] Interruzione richiesta...")
|
self._log("upgrade", "[INFO] Interruzione richiesta...")
|
||||||
return {"ok": True}
|
return {"ok": True}
|
||||||
|
|
||||||
def _upgrade_worker(self, directory, threshold, cookies_path, recursive):
|
def upgrade_resolve_candidates(self, choice: dict) -> dict:
|
||||||
|
"""Riceve la scelta utente dal modal 'match locali multipli' e la
|
||||||
|
deposita nella queue attesa dal resolve_callback del worker.
|
||||||
|
|
||||||
|
`choice`: {'action': 'use_local'|'use_youtube'|'skip', 'path': str?}
|
||||||
|
"""
|
||||||
|
if not isinstance(choice, dict):
|
||||||
|
choice = {"action": "skip"}
|
||||||
|
try:
|
||||||
|
# Drain (nel caso rarissimo di doppio put) e poi metti la nuova
|
||||||
|
try:
|
||||||
|
self._upgrade_resolve_q.get_nowait()
|
||||||
|
except queue.Empty:
|
||||||
|
pass
|
||||||
|
self._upgrade_resolve_q.put_nowait(choice)
|
||||||
|
return {"ok": True}
|
||||||
|
except Exception as e:
|
||||||
|
return {"ok": False, "error": str(e)}
|
||||||
|
|
||||||
|
def _upgrade_worker(self, directory, threshold, cookies_path, recursive,
|
||||||
|
archive_dir: Optional[str] = None):
|
||||||
view = "upgrade"
|
view = "upgrade"
|
||||||
|
|
||||||
def progress_cb(idx, total, filename, status, old_kbps, new_kbps):
|
def progress_cb(idx, total, filename, status, old_kbps, new_kbps):
|
||||||
@@ -938,6 +976,19 @@ class Api:
|
|||||||
diff = new_kbps - old_kbps
|
diff = new_kbps - old_kbps
|
||||||
diff_str = f" (+{diff}kbps)" if diff > 0 else ""
|
diff_str = f" (+{diff}kbps)" if diff > 0 else ""
|
||||||
self._log(view, f"[UPGRADE] {filename}: {old_kbps} -> {new_kbps}kbps{diff_str}")
|
self._log(view, f"[UPGRADE] {filename}: {old_kbps} -> {new_kbps}kbps{diff_str}")
|
||||||
|
elif status == "local_copy":
|
||||||
|
self._log(view, f"[LOCALE] {filename}: uso match dall'archivio")
|
||||||
|
elif status == "local_upgraded":
|
||||||
|
diff = new_kbps - old_kbps
|
||||||
|
diff_str = f" (+{diff}kbps)" if diff > 0 else ""
|
||||||
|
self._log(view, f"[LOCALE OK] {filename}: {old_kbps} -> {new_kbps}kbps{diff_str}")
|
||||||
|
elif status == "skipped_by_user":
|
||||||
|
self._log(view, f"[SKIP] {filename} (saltato manualmente)")
|
||||||
|
elif status == "resolve_wait":
|
||||||
|
self._log(view, f"[SCELTA] {filename}: match multipli, in attesa scelta utente")
|
||||||
|
elif status == "scan_archive":
|
||||||
|
# `new_kbps` in questo caso trasporta il count delle chiavi
|
||||||
|
self._log(view, f"[ARCHIVIO] Indicizzati {new_kbps} gruppi audio")
|
||||||
elif status == "download_error":
|
elif status == "download_error":
|
||||||
self._log(view, f"[ERRORE] {filename}: download fallito")
|
self._log(view, f"[ERRORE] {filename}: download fallito")
|
||||||
elif status == "stopped":
|
elif status == "stopped":
|
||||||
@@ -948,7 +999,24 @@ class Api:
|
|||||||
|
|
||||||
self._emit("upgrade:progress", payload_evt)
|
self._emit("upgrade:progress", payload_evt)
|
||||||
|
|
||||||
upgrade_folder(directory, threshold, cookies_path, recursive, progress_cb)
|
def resolve_cb(filename: str, candidates: list) -> dict:
|
||||||
|
"""Bloccante: emette evento e attende scelta utente via queue."""
|
||||||
|
self._emit("upgrade:candidates_needed", {
|
||||||
|
"file": filename,
|
||||||
|
"candidates": candidates,
|
||||||
|
})
|
||||||
|
try:
|
||||||
|
# Timeout 10 min — se l'utente sparisce, salta il brano
|
||||||
|
choice = self._upgrade_resolve_q.get(timeout=600)
|
||||||
|
except queue.Empty:
|
||||||
|
choice = {"action": "skip"}
|
||||||
|
return choice
|
||||||
|
|
||||||
|
upgrade_folder(
|
||||||
|
directory, threshold, cookies_path, recursive, progress_cb,
|
||||||
|
archive_dir=archive_dir,
|
||||||
|
resolve_callback=resolve_cb,
|
||||||
|
)
|
||||||
self._emit("upgrade:done", {"ok": True})
|
self._emit("upgrade:done", {"ok": True})
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
|
|||||||
Reference in new issue
Block a user