removed TUI and others
This commit is contained in:
+120
-37
@@ -16,7 +16,7 @@ def add_startup_check(
|
||||
name: str,
|
||||
*,
|
||||
provider: str = "",
|
||||
store: str = "",
|
||||
instance: str = "",
|
||||
files: int | str | None = None,
|
||||
detail: str = "",
|
||||
) -> None:
|
||||
@@ -24,11 +24,82 @@ def add_startup_check(
|
||||
row.add_column("STATUS", upper_text(status))
|
||||
row.add_column("NAME", upper_text(name))
|
||||
row.add_column("PLUGIN", upper_text(provider or ""))
|
||||
row.add_column("STORE", upper_text(store or ""))
|
||||
row.add_column("INSTANCE", upper_text(instance or ""))
|
||||
row.add_column("FILES", "" if files is None else str(files))
|
||||
row.add_column("DETAIL", upper_text(detail or ""))
|
||||
|
||||
|
||||
def _provider_config_map(config: dict) -> dict[str, Any]:
|
||||
if not isinstance(config, dict):
|
||||
return {}
|
||||
|
||||
provider_cfg = config.get("plugin")
|
||||
if not isinstance(provider_cfg, dict):
|
||||
provider_cfg = config.get("provider")
|
||||
return provider_cfg if isinstance(provider_cfg, dict) else {}
|
||||
|
||||
|
||||
def _iter_registered_plugin_infos() -> tuple[Any, ...]:
|
||||
try:
|
||||
from ProviderCore.registry import REGISTRY
|
||||
|
||||
return tuple(
|
||||
sorted(
|
||||
REGISTRY.iter_plugins(),
|
||||
key=lambda info: str(
|
||||
getattr(info, "canonical_name", "") or ""
|
||||
).lower(),
|
||||
)
|
||||
)
|
||||
except Exception:
|
||||
return ()
|
||||
|
||||
|
||||
def _extract_configured_instance_names(raw_entry: Any) -> list[str]:
|
||||
if not isinstance(raw_entry, dict) or not raw_entry:
|
||||
return []
|
||||
if not all(isinstance(value, dict) for value in raw_entry.values()):
|
||||
return []
|
||||
|
||||
names: list[str] = []
|
||||
for key in raw_entry.keys():
|
||||
name = str(key or "").strip()
|
||||
if not name or name.lower() == "default":
|
||||
continue
|
||||
names.append(name)
|
||||
return names
|
||||
|
||||
|
||||
def _resolve_startup_instance_text(
|
||||
plugin: Any,
|
||||
summary: dict[str, Any],
|
||||
configured_entry: Any,
|
||||
) -> str:
|
||||
instance_text = str(summary.get("instance") or "").strip()
|
||||
if instance_text:
|
||||
return instance_text
|
||||
|
||||
raw_instances = summary.get("instances")
|
||||
if isinstance(raw_instances, (list, tuple, set)):
|
||||
values = [str(value).strip() for value in raw_instances if str(value).strip()]
|
||||
if values:
|
||||
return ", ".join(values)
|
||||
elif raw_instances is not None:
|
||||
instance_text = str(raw_instances).strip()
|
||||
if instance_text:
|
||||
return instance_text
|
||||
|
||||
try:
|
||||
configured_instances = plugin.configured_instances() if plugin is not None else []
|
||||
except Exception:
|
||||
configured_instances = []
|
||||
|
||||
if configured_instances:
|
||||
return ", ".join(str(value).strip() for value in configured_instances if str(value).strip())
|
||||
|
||||
return ", ".join(_extract_configured_instance_names(configured_entry))
|
||||
|
||||
|
||||
def has_store_subtype(cfg: dict, subtype: str) -> bool:
|
||||
store_cfg = cfg.get("store")
|
||||
if not isinstance(store_cfg, dict):
|
||||
@@ -113,61 +184,73 @@ def ping_first(urls: list[str]) -> tuple[bool, str]:
|
||||
|
||||
|
||||
def collect_plugin_startup_checks(config: dict) -> list[dict[str, Any]]:
|
||||
provider_cfg = None
|
||||
if isinstance(config, dict):
|
||||
provider_cfg = config.get("plugin")
|
||||
if not isinstance(provider_cfg, dict):
|
||||
provider_cfg = config.get("provider")
|
||||
if not isinstance(provider_cfg, dict) or not provider_cfg:
|
||||
return []
|
||||
|
||||
try:
|
||||
from ProviderCore.registry import get_plugin_class
|
||||
except Exception:
|
||||
return []
|
||||
provider_cfg = _provider_config_map(config)
|
||||
|
||||
checks: list[dict[str, Any]] = []
|
||||
for plugin_name in provider_cfg.keys():
|
||||
plugin_key = str(plugin_name or "").strip().lower()
|
||||
seen_plugin_keys: set[str] = set()
|
||||
|
||||
for info in _iter_registered_plugin_infos():
|
||||
plugin_key = str(getattr(info, "canonical_name", "") or "").strip().lower()
|
||||
if not plugin_key:
|
||||
continue
|
||||
seen_plugin_keys.add(plugin_key)
|
||||
|
||||
plugin_class = None
|
||||
try:
|
||||
plugin_class = get_plugin_class(plugin_key)
|
||||
except Exception:
|
||||
plugin_class = None
|
||||
|
||||
if plugin_class is None:
|
||||
checks.append(
|
||||
{
|
||||
"status": "UNKNOWN",
|
||||
"name": provider_display_name(plugin_key),
|
||||
"plugin": plugin_key,
|
||||
"detail": "Not registered",
|
||||
}
|
||||
)
|
||||
continue
|
||||
plugin = None
|
||||
summary: dict[str, Any]
|
||||
display_name = provider_display_name(plugin_key)
|
||||
configured_entry: Any = None
|
||||
|
||||
try:
|
||||
plugin = plugin_class(config)
|
||||
plugin = info.plugin_class(config)
|
||||
configured_entry = plugin.plugin_config_root()
|
||||
summary = plugin.status_summary()
|
||||
except Exception as exc:
|
||||
summary = {
|
||||
"status": "DISABLED",
|
||||
"name": provider_display_name(plugin_key),
|
||||
"name": display_name,
|
||||
"plugin": plugin_key,
|
||||
"detail": str(exc),
|
||||
}
|
||||
|
||||
status = str(summary.get("status") or "UNKNOWN").strip().upper() or "UNKNOWN"
|
||||
name = str(summary.get("name") or display_name)
|
||||
detail = str(summary.get("detail") or "").strip()
|
||||
if detail.lower() == "configured" and not configured_entry:
|
||||
detail = "Available"
|
||||
if not detail:
|
||||
if status == "ENABLED":
|
||||
detail = "Configured" if configured_entry else "Available"
|
||||
else:
|
||||
detail = "Not configured" if not configured_entry else "Unavailable"
|
||||
|
||||
checks.append(
|
||||
{
|
||||
"status": str(summary.get("status") or "UNKNOWN"),
|
||||
"name": str(summary.get("name") or provider_display_name(plugin_key)),
|
||||
"status": status,
|
||||
"name": name,
|
||||
"plugin": str(summary.get("plugin") or plugin_key),
|
||||
"detail": str(summary.get("detail") or ""),
|
||||
"instance": _resolve_startup_instance_text(
|
||||
plugin,
|
||||
summary,
|
||||
configured_entry if configured_entry else provider_cfg.get(plugin_key),
|
||||
),
|
||||
"detail": detail,
|
||||
"files": summary.get("files"),
|
||||
}
|
||||
)
|
||||
|
||||
for plugin_name, raw_entry in sorted(provider_cfg.items()):
|
||||
plugin_key = str(plugin_name or "").strip().lower()
|
||||
if not plugin_key or plugin_key in seen_plugin_keys:
|
||||
continue
|
||||
checks.append(
|
||||
{
|
||||
"status": "UNKNOWN",
|
||||
"name": provider_display_name(plugin_key),
|
||||
"plugin": plugin_key,
|
||||
"instance": ", ".join(_extract_configured_instance_names(raw_entry)),
|
||||
"detail": "Not registered",
|
||||
"files": None,
|
||||
}
|
||||
)
|
||||
|
||||
return checks
|
||||
+4
-40
@@ -291,47 +291,11 @@ def _run(piped_result: Any, args: List[str], config: Dict[str, Any]) -> int:
|
||||
return 1
|
||||
|
||||
if not args:
|
||||
# Check if we're in an interactive terminal and can launch a Textual modal
|
||||
if sys.stdin.isatty() and not piped_result:
|
||||
try:
|
||||
from textual.app import App
|
||||
from TUI.modalscreen.config_modal import ConfigModal
|
||||
|
||||
class ConfigApp(App):
|
||||
def on_mount(self) -> None:
|
||||
self.title = "Config Editor"
|
||||
# We push the modal screen. It will sit on top of the main (blank) screen.
|
||||
# Using a callback to exit the app when the modal is dismissed.
|
||||
self.push_screen(ConfigModal(), callback=self.exit_on_close)
|
||||
|
||||
def exit_on_close(self, result: Any = None) -> None:
|
||||
self.exit()
|
||||
|
||||
with ctx.suspend_live_progress():
|
||||
app = ConfigApp()
|
||||
app.run()
|
||||
|
||||
# After modal exits, show the new status table if possible
|
||||
try:
|
||||
from cmdlet._shared import SharedArgs
|
||||
from cmdnat.status import CMDLET as STATUS_CMDLET
|
||||
# We reload the config one more time because it might have changed on disk
|
||||
fresh_config = load_config()
|
||||
|
||||
# Force refresh of shared caches (especially stores)
|
||||
SharedArgs._refresh_store_choices_cache(fresh_config)
|
||||
# Update the global SharedArgs choices so cmdlets pick up new stores
|
||||
SharedArgs.STORE.choices = SharedArgs.get_store_choices(fresh_config, force=True)
|
||||
|
||||
return STATUS_CMDLET.exec(None, [], fresh_config)
|
||||
except Exception:
|
||||
pass
|
||||
return 0
|
||||
except Exception as exc:
|
||||
# Fall back to table display if Textual modal fails
|
||||
print(f"Note: Could not launch interactive editor ({exc}). Showing configuration table:")
|
||||
return _show_config_table(current_config)
|
||||
|
||||
print(
|
||||
"Interactive TUI config editor has been discontinued. "
|
||||
"Showing configuration table instead."
|
||||
)
|
||||
return _show_config_table(current_config)
|
||||
|
||||
key = args[0]
|
||||
|
||||
+3
-57
@@ -4,14 +4,12 @@ import shutil
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from SYS.cmdlet_spec import Cmdlet
|
||||
from SYS.config import resolve_cookies_path
|
||||
from SYS import pipeline as ctx
|
||||
from SYS.result_table import Table
|
||||
from SYS.logger import set_debug, debug
|
||||
from SYS.logger import set_debug
|
||||
from cmdnat._status_shared import (
|
||||
add_startup_check as _add_startup_check,
|
||||
collect_plugin_startup_checks as _collect_plugin_startup_checks,
|
||||
has_store_subtype as _has_store_subtype,
|
||||
)
|
||||
|
||||
CMDLET = Cmdlet(
|
||||
@@ -35,7 +33,6 @@ def _run(result: Any, args: List[str], config: Dict[str, Any]) -> int:
|
||||
set_debug(debug_enabled)
|
||||
except Exception:
|
||||
pass
|
||||
debug(f"Status check: debug_enabled={debug_enabled}")
|
||||
_add_startup_check(startup_table, "ENABLED" if debug_enabled else "DISABLED", "DEBUGGING")
|
||||
|
||||
try:
|
||||
@@ -45,51 +42,8 @@ def _run(result: Any, args: List[str], config: Dict[str, Any]) -> int:
|
||||
MPV()
|
||||
mpv_path = shutil.which("mpv")
|
||||
_add_startup_check(startup_table, "ENABLED", "MPV", detail=mpv_path or "Available")
|
||||
debug(f"MPV check OK: path={mpv_path or 'Available'}")
|
||||
except Exception as exc:
|
||||
_add_startup_check(startup_table, "DISABLED", "MPV", detail=str(exc))
|
||||
debug(f"MPV check failed: {exc}")
|
||||
|
||||
# Store Registry
|
||||
store_registry = None
|
||||
try:
|
||||
from Store import Store as StoreRegistry
|
||||
store_registry = StoreRegistry(config=config, suppress_debug=True)
|
||||
try:
|
||||
backends = store_registry.list_backends()
|
||||
except Exception:
|
||||
backends = []
|
||||
debug(f"StoreRegistry initialized. backends={backends}")
|
||||
except Exception as exc:
|
||||
debug(f"StoreRegistry initialization failed: {exc}")
|
||||
store_registry = None
|
||||
|
||||
# Hydrus
|
||||
if _has_store_subtype(config, "hydrusnetwork"):
|
||||
hcfg = config.get("store", {}).get("hydrusnetwork", {})
|
||||
for iname, icfg in hcfg.items():
|
||||
if not isinstance(icfg, dict): continue
|
||||
nkey = str(icfg.get("NAME") or iname)
|
||||
uval = str(icfg.get("URL") or "").strip()
|
||||
debug(f"Hydrus network check: name={nkey}, url={uval}")
|
||||
ok = bool(store_registry and store_registry.is_available(nkey))
|
||||
status = "ENABLED" if ok else "DISABLED"
|
||||
files = None
|
||||
detail = uval
|
||||
if ok and store_registry:
|
||||
try:
|
||||
backend = store_registry[nkey]
|
||||
files = getattr(backend, "total_count", None)
|
||||
if files is None and hasattr(backend, "get_total_count"):
|
||||
files = backend.get_total_count()
|
||||
debug(f"Hydrus backend '{nkey}' available: files={files}")
|
||||
except Exception as exc:
|
||||
debug(f"Hydrus backend '{nkey}' check failed: {exc}")
|
||||
else:
|
||||
err = store_registry.get_backend_error(iname) if store_registry else None
|
||||
debug(f"Hydrus backend '{nkey}' not available: {err}")
|
||||
detail = f"{uval} - {err or 'Unavailable'}"
|
||||
_add_startup_check(startup_table, status, nkey, store="hydrusnetwork", files=files, detail=detail)
|
||||
|
||||
for check in _collect_plugin_startup_checks(config):
|
||||
_add_startup_check(
|
||||
@@ -97,27 +51,19 @@ def _run(result: Any, args: List[str], config: Dict[str, Any]) -> int:
|
||||
str(check.get("status") or "UNKNOWN"),
|
||||
str(check.get("name") or "Plugin"),
|
||||
provider=str(check.get("plugin") or ""),
|
||||
instance=str(check.get("instance") or ""),
|
||||
files=check.get("files"),
|
||||
detail=str(check.get("detail") or ""),
|
||||
)
|
||||
|
||||
# Cookies
|
||||
try:
|
||||
cf = resolve_cookies_path(config)
|
||||
_add_startup_check(startup_table, "FOUND" if cf else "MISSING", "Cookies", detail=str(cf) if cf else "Not found")
|
||||
debug(f"Cookies: resolved cookiefile={cf}")
|
||||
except Exception as exc:
|
||||
debug(f"Cookies check failed: {exc}")
|
||||
|
||||
except Exception as exc:
|
||||
debug(f"Status check failed: {exc}")
|
||||
_add_startup_check(startup_table, "ERROR", "STATUS", detail=str(exc))
|
||||
|
||||
if startup_table.rows:
|
||||
# Mark as rendered to prevent CLI.py from auto-printing it to stdout
|
||||
# (avoiding duplication in TUI logs, while keeping it in TUI Results)
|
||||
setattr(startup_table, "_rendered_by_cmdlet", True)
|
||||
ctx.set_current_stage_table(startup_table)
|
||||
debug(f"Status check completed: {len(startup_table.rows)} checks recorded")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user