116 lines
3.7 KiB
Python
116 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
По имени папки (игры) возвращает Steam App ID из локального steam_library_with_sizes.json.
|
||
Совпадение по нормализованному имени (регистр, пунктуация не учитываются).
|
||
Использование: resolve_steam_appid.py [PATH_TO_JSON] "Имя папки"
|
||
Выход: один appid или пусто при ненайденном.
|
||
"""
|
||
|
||
import json
|
||
import re
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||
DEFAULT_JSON = SCRIPT_DIR / "steam_library_with_sizes.json"
|
||
|
||
# Ручное сопоставление: имя папки на диске -> appId (если нет в JSON или совпадение неверное)
|
||
MANUAL_MAP = {
|
||
"CM3": "351920", # Crazy Machines 3
|
||
"Darksiders 3": "606280", # Darksiders III
|
||
"DOOMEternal": "782330", # DOOM Eternal (папка без пробела)
|
||
"FarCry5": "552520", # Far Cry 5
|
||
"Gears5": "1097840", # Gears 5
|
||
"GodOfWar": "1593500", # God of War
|
||
"HITMAN 3": "1659040", # HITMAN World of Assassination
|
||
"ItTakesTwo": "1426210", # It Takes Two
|
||
"hotline_miami": "219150", # Hotline Miami
|
||
"Jaded": "1932570", # Jaded
|
||
}
|
||
|
||
|
||
def normalize(name: str) -> str:
|
||
s = (name or "").lower().strip()
|
||
s = re.sub(r"[^\w\s]", " ", s)
|
||
s = re.sub(r"\s+", " ", s)
|
||
return s.strip()
|
||
|
||
|
||
def load_library(path: Path) -> list[dict]:
|
||
with open(path, encoding="utf-8") as f:
|
||
return json.load(f)
|
||
|
||
|
||
def find_best_appid(query: str, library: list[dict]) -> str:
|
||
if not query:
|
||
return ""
|
||
qnorm = normalize(query)
|
||
if not qnorm:
|
||
return ""
|
||
qwords = set(qnorm.split())
|
||
best_appid = ""
|
||
best_score = -1
|
||
for entry in library:
|
||
name = entry.get("name") or ""
|
||
appid = entry.get("appid")
|
||
if appid is None:
|
||
continue
|
||
nnorm = normalize(name)
|
||
if not nnorm:
|
||
continue
|
||
# Точное совпадение
|
||
if nnorm == qnorm:
|
||
return str(appid)
|
||
# Оба содержат друг друга
|
||
if qnorm in nnorm or nnorm in qnorm:
|
||
score = len(qwords & set(nnorm.split()))
|
||
if score > best_score:
|
||
best_score = score
|
||
best_appid = str(appid)
|
||
# Пересечение по словам
|
||
nwords = set(nnorm.split())
|
||
overlap = len(qwords & nwords)
|
||
if overlap > 0 and overlap >= min(2, len(qwords), len(nwords)):
|
||
if overlap > best_score:
|
||
best_score = overlap
|
||
best_appid = str(appid)
|
||
return best_appid
|
||
|
||
|
||
def main() -> int:
|
||
args = [a for a in sys.argv[1:] if a.strip()]
|
||
if not args:
|
||
print("", end="")
|
||
return 0
|
||
# Путь к JSON: первый аргумент, если это путь к существующему файлу
|
||
json_path = Path(args[0])
|
||
if json_path.exists() and json_path.is_file():
|
||
path = json_path
|
||
name = " ".join(args[1:]).strip()
|
||
else:
|
||
path = DEFAULT_JSON
|
||
name = " ".join(args).strip()
|
||
if not name:
|
||
print("", end="")
|
||
return 0
|
||
if not path.exists():
|
||
sys.stderr.write(f"resolve_steam_appid: file not found: {path}\n")
|
||
print("", end="")
|
||
return 1
|
||
if name in MANUAL_MAP:
|
||
print(MANUAL_MAP[name], end="")
|
||
return 0
|
||
try:
|
||
library = load_library(path)
|
||
except Exception as e:
|
||
sys.stderr.write(f"resolve_steam_appid: {e}\n")
|
||
print("", end="")
|
||
return 1
|
||
appid = find_best_appid(name, library)
|
||
print(appid, end="")
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|