fix: match mod folder by steam_id when folder name diverges from modlist name
_find_folder in mods.py now has a fourth fallback: reads publishedid from meta.cpp inside each candidate folder and matches against mod["steam_id"]. Fixes mods appearing as "not downloaded" when the folder name on disk differs from the name in the modlist but the mod content (meta.cpp) is correct. Also adds 8 tests covering all four match strategies and edge cases.
This commit is contained in:
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Optional
|
||||
|
||||
import customtkinter as ctk
|
||||
|
||||
from arma_modlist_tools.fetcher import _normalize_name
|
||||
from arma_modlist_tools.fetcher import _normalize_name, _parse_meta_cpp
|
||||
from gui._constants import COLOR_OK, COLOR_ERROR, COLOR_WARN, COLOR_RUNNING
|
||||
from gui.locales import t
|
||||
from gui.views.base import BaseView
|
||||
@@ -16,13 +16,14 @@ if TYPE_CHECKING:
|
||||
from gui.app import ArmaModManagerApp
|
||||
|
||||
|
||||
def _find_folder(group_dir: Path, mod_name: str) -> Optional[Path]:
|
||||
def _find_folder(group_dir: Path, mod_name: str, steam_id: str | None = None) -> Optional[Path]:
|
||||
"""Return the local mod folder path, or None if not downloaded.
|
||||
|
||||
Matches in priority order:
|
||||
1. Exact folder name ``@{mod_name}``
|
||||
2. Case-insensitive name (handles ``@CBA_A3`` vs ``CBA_A3``)
|
||||
3. Normalized name — strips non-alphanumeric (handles ``@cba_a3`` vs ``CBA A3``)
|
||||
4. Steam ID match via ``meta.cpp`` ``publishedid`` field (folder name differs from modlist name)
|
||||
"""
|
||||
if not group_dir.is_dir():
|
||||
return None
|
||||
@@ -38,6 +39,18 @@ def _find_folder(group_dir: Path, mod_name: str) -> Optional[Path]:
|
||||
return p
|
||||
if _normalize_name(p.name) == target_norm:
|
||||
return p
|
||||
# Fallback: match by steam_id via meta.cpp when folder name diverges from modlist name
|
||||
if steam_id:
|
||||
for p in group_dir.iterdir():
|
||||
if not p.is_dir():
|
||||
continue
|
||||
meta = p / "meta.cpp"
|
||||
try:
|
||||
sid = _parse_meta_cpp(meta.read_text(encoding="utf-8", errors="replace"))
|
||||
if sid == steam_id:
|
||||
return p
|
||||
except OSError:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
@@ -215,7 +228,7 @@ class ModsView(BaseView):
|
||||
link_map: dict[str, bool],
|
||||
) -> None:
|
||||
for i, mod in enumerate(sorted(mods, key=lambda m: m["name"].lower())):
|
||||
folder_path = _find_folder(cfg.downloads / group, mod["name"])
|
||||
folder_path = _find_folder(cfg.downloads / group, mod["name"], mod.get("steam_id"))
|
||||
downloaded = folder_path is not None
|
||||
linked = (link_map.get(folder_path.name.lower(), False)
|
||||
if folder_path else False)
|
||||
|
||||
Reference in New Issue
Block a user