refactor: move game-specific import logic into profiles; unblock Tomie import

- Add app/games: GameProfile base, registry, ReaderHooks and renpy/naninovel/
  tomie profiles. pipeline, preflight, detect and mods dispatch via the registry
- Move tomie_* converter modules to app/games/tomie and split out reader hooks,
  import, mod validation and known defects
- Tolerate the 31 authoring defects of the pinned Tomie build as report
  warnings (exact list, per-script counts); any new defect still blocks import
- Frontend: runtime registry (runtimes.ts) with lazy Tomie launcher
- Add profile/registry tests and docs/GAME_PROFILES.md; update IMPORT.md

Full media export of the original Tomie build is not yet verified.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Sonnet 5.5 committed 2026-10-25 11:35:23 +03:00
1 parent bbbcc6a5d8
commit 12ec82c7e6
30 files changed
+700 -196

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
"""Profile lookup. Specific (build-pinned) profiles are tried before engine-wide ones."""
from __future__ import annotations
from pathlib import Path
from app.games.base import GameProfile
_PROFILES: list[GameProfile] = []
def register(profile: GameProfile) -> GameProfile:
if any(p.id == profile.id for p in _PROFILES):
raise ValueError(f"Профиль уже зарегистрирован: {profile.id}")
_PROFILES.append(profile)
return profile
def all_profiles() -> list[GameProfile]:
_load()
return list(_PROFILES)
def select(engine: str, root: Path) -> GameProfile | None:
"""The profile that imports the game at ``root`` for a detected ``engine``."""
_load()
candidates = [p for p in _PROFILES if p.engine == engine]
for profile in sorted(candidates, key=lambda p: not p.specific):
if profile.claims(root):
return profile
return None
def for_runtime(runtime: str | None) -> GameProfile | None:
_load()
return next((p for p in _PROFILES if runtime and p.runtime == runtime), None)
def for_id(profile_id: str | None) -> GameProfile | None:
_load()
return next((p for p in _PROFILES if p.id == profile_id), None)
def _load() -> None:
# Importing the package registers the built-in profiles.
import app.games # noqa: F401