mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-08-13 23:33:43 +02:00
98 lines
2.9 KiB
Python
98 lines
2.9 KiB
Python
"""NXM session state: remembers which modlist to route downloads to.
|
|
|
|
Clears when the process exits. Not persisted to disk.
|
|
"""
|
|
|
|
import logging
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Optional, List, Dict
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_remembered_modlist: Optional[str] = None
|
|
|
|
|
|
def get_remembered_modlist() -> Optional[str]:
|
|
return _remembered_modlist
|
|
|
|
|
|
def set_remembered_modlist(name: str) -> None:
|
|
global _remembered_modlist
|
|
_remembered_modlist = name
|
|
|
|
|
|
def clear_remembered_modlist() -> None:
|
|
global _remembered_modlist
|
|
_remembered_modlist = None
|
|
|
|
|
|
def detect_active_mo2_modlist(modlists: List[Dict]) -> Optional[Dict]:
|
|
"""Return the modlist whose MO2 instance is currently running, or None.
|
|
|
|
Scans live processes for ModOrganizer.exe and matches the install path
|
|
against the provided modlist list.
|
|
"""
|
|
try:
|
|
import psutil
|
|
except ImportError:
|
|
logger.debug("psutil not available, skipping MO2 process detection")
|
|
return None
|
|
|
|
mo2_dirs: List[Path] = []
|
|
try:
|
|
for proc in psutil.process_iter(["cmdline"]):
|
|
try:
|
|
cmdline = proc.info.get("cmdline") or []
|
|
for arg in cmdline:
|
|
arg_str = str(arg)
|
|
if "ModOrganizer.exe" in arg_str:
|
|
resolved = _resolve_mo2_path(arg_str)
|
|
if resolved:
|
|
mo2_dirs.append(resolved)
|
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
|
continue
|
|
except Exception as e:
|
|
logger.debug("MO2 process scan failed: %s", e)
|
|
return None
|
|
|
|
if not mo2_dirs:
|
|
return None
|
|
|
|
matches = []
|
|
for modlist in modlists:
|
|
ml_dir = Path(modlist.get("modlist_dir", "")).resolve()
|
|
for mo2_dir in mo2_dirs:
|
|
try:
|
|
if mo2_dir.resolve() == ml_dir:
|
|
matches.append(modlist)
|
|
break
|
|
except Exception:
|
|
continue
|
|
|
|
if len(matches) == 1:
|
|
logger.debug("Active MO2 instance matched modlist: %s", matches[0].get("name"))
|
|
return matches[0]
|
|
|
|
if len(matches) > 1:
|
|
logger.debug("Multiple active MO2 instances found, falling back to picker")
|
|
else:
|
|
logger.debug("MO2 process found but no modlist match for dirs: %s", mo2_dirs)
|
|
return None
|
|
|
|
|
|
def _resolve_mo2_path(arg: str) -> Optional[Path]:
|
|
"""Extract and resolve the modlist directory from a ModOrganizer.exe cmdline arg."""
|
|
# Wine path: Z:\path\to\modlist\ModOrganizer.exe
|
|
m = re.match(r"(?i)z:([\\/].+?)[\\/]ModOrganizer\.exe", arg)
|
|
if m:
|
|
linux_path = m.group(1).replace("\\", "/")
|
|
return Path(linux_path)
|
|
|
|
# Raw Linux path: /path/to/modlist/ModOrganizer.exe
|
|
m = re.match(r"(/.+?)/ModOrganizer\.exe", arg)
|
|
if m:
|
|
return Path(m.group(1))
|
|
|
|
return None
|