mirror of
https://github.com/rommapp/romm.git
synced 2026-04-23 06:54:40 +00:00
208 lines
6.8 KiB
Python
208 lines
6.8 KiB
Python
import re
|
|
|
|
from config import LAUNCHBOX_API_ENABLED
|
|
from handler.filesystem import fs_rom_handler
|
|
from handler.redis_handler import async_cache
|
|
from logger.logger import log
|
|
from utils.database import safe_int
|
|
|
|
from ..base_handler import MetadataHandler
|
|
from ..base_handler import UniversalPlatformSlug as UPS
|
|
from .local_source import LocalSource
|
|
from .media import build_rom, local_media_req, remote_media_req
|
|
from .platforms import get_platform
|
|
from .remote_source import RemoteSource
|
|
from .types import (
|
|
DASH_COLON_REGEX,
|
|
LAUNCHBOX_METADATA_NAME_KEY,
|
|
LAUNCHBOX_PLATFORMS_DIR,
|
|
LAUNCHBOX_TAG_REGEX,
|
|
LaunchboxPlatform,
|
|
LaunchboxRom,
|
|
)
|
|
|
|
|
|
class LaunchboxHandler(MetadataHandler):
|
|
def __init__(self) -> None:
|
|
self._local = LocalSource()
|
|
self._remote = RemoteSource()
|
|
|
|
@classmethod
|
|
def is_cloud_enabled(cls) -> bool:
|
|
return LAUNCHBOX_API_ENABLED
|
|
|
|
@classmethod
|
|
def is_local_enabled(cls) -> bool:
|
|
return LAUNCHBOX_PLATFORMS_DIR.exists()
|
|
|
|
@classmethod
|
|
def is_enabled(cls) -> bool:
|
|
return cls.is_cloud_enabled() or cls.is_local_enabled()
|
|
|
|
async def heartbeat(self) -> bool:
|
|
return self.is_enabled()
|
|
|
|
def get_platform(self, slug: str) -> LaunchboxPlatform:
|
|
return get_platform(slug)
|
|
|
|
async def get_rom(
|
|
self,
|
|
fs_name: str,
|
|
platform_slug: str,
|
|
keep_tags: bool = False,
|
|
*,
|
|
remote_enabled: bool = True,
|
|
) -> LaunchboxRom:
|
|
fallback_rom = LaunchboxRom(launchbox_id=None)
|
|
|
|
if not self.is_enabled():
|
|
return fallback_rom
|
|
|
|
local = await self._local.get_rom(fs_name, platform_slug)
|
|
|
|
remote_available = remote_enabled and bool(
|
|
await async_cache.exists(LAUNCHBOX_METADATA_NAME_KEY)
|
|
)
|
|
|
|
if local is not None:
|
|
launchbox_id_local = safe_int(local.get("DatabaseID"))
|
|
remote: dict | None = None
|
|
if remote_available:
|
|
if launchbox_id_local:
|
|
remote = await self._remote.get_by_id(launchbox_id_local)
|
|
|
|
if remote is None:
|
|
local_title = (local.get("Title") or "").strip()
|
|
if local_title:
|
|
remote = await self._remote.get_rom(
|
|
local_title,
|
|
platform_slug,
|
|
assume_cache_present=True,
|
|
)
|
|
platform_name = get_platform(platform_slug).get("name")
|
|
remote_images = await self._remote.fetch_images(
|
|
remote=remote, remote_enabled=remote_available
|
|
)
|
|
media_req = local_media_req(
|
|
platform_name=platform_name,
|
|
fs_name=fs_name,
|
|
local=local,
|
|
remote=remote,
|
|
remote_images=remote_images,
|
|
remote_enabled=remote_available,
|
|
)
|
|
return build_rom(
|
|
local=local,
|
|
remote=remote,
|
|
launchbox_id=launchbox_id_local
|
|
or (remote.get("DatabaseID") if remote else None),
|
|
media_req=media_req,
|
|
)
|
|
|
|
match = LAUNCHBOX_TAG_REGEX.search(fs_name)
|
|
launchbox_id_from_tag = int(match.group(1)) if match else None
|
|
|
|
if launchbox_id_from_tag is not None:
|
|
log.debug(f"Found LaunchBox ID tag in filename: {launchbox_id_from_tag}")
|
|
rom_by_id = await self.get_rom_by_id(
|
|
launchbox_id_from_tag, remote_enabled=remote_enabled
|
|
)
|
|
if rom_by_id["launchbox_id"]:
|
|
log.debug(
|
|
f"Successfully matched ROM by LaunchBox ID tag: {fs_name} -> {launchbox_id_from_tag}"
|
|
)
|
|
return rom_by_id
|
|
else:
|
|
log.warning(
|
|
f"LaunchBox ID {launchbox_id_from_tag} from filename tag not found in LaunchBox"
|
|
)
|
|
|
|
if not remote_available:
|
|
return fallback_rom
|
|
|
|
# `keep_tags` prevents stripping content that is considered a tag, e.g., anything between `()` or `[]`.
|
|
# By default, tags are still stripped to keep scan behavior consistent with previous versions.
|
|
# If `keep_tags` is True, the full `fs_name` is used for searching.
|
|
if not keep_tags:
|
|
search_term = fs_rom_handler.get_file_name_with_no_tags(fs_name)
|
|
else:
|
|
search_term = fs_name
|
|
|
|
# We replace " - "/"- " with ": " to match Launchbox's naming convention
|
|
search_term = re.sub(DASH_COLON_REGEX, ": ", search_term).lower()
|
|
|
|
# Check if game is scummvm shortname
|
|
if platform_slug == UPS.SCUMMVM:
|
|
search_term = await self._scummvm_format(search_term)
|
|
fallback_rom = LaunchboxRom(launchbox_id=None, name=search_term)
|
|
|
|
index_entry = await self._remote.get_rom(
|
|
search_term,
|
|
platform_slug,
|
|
assume_cache_present=True,
|
|
)
|
|
|
|
if not index_entry:
|
|
return fallback_rom
|
|
|
|
remote_images = await self._remote.fetch_images(
|
|
remote=index_entry, remote_enabled=remote_available
|
|
)
|
|
media_req = remote_media_req(
|
|
remote=index_entry,
|
|
remote_images=remote_images,
|
|
remote_enabled=remote_available,
|
|
)
|
|
|
|
return build_rom(
|
|
local=None,
|
|
remote=index_entry,
|
|
launchbox_id=index_entry["DatabaseID"],
|
|
media_req=media_req,
|
|
)
|
|
|
|
async def get_rom_by_id(
|
|
self, database_id: int, *, remote_enabled: bool = True
|
|
) -> LaunchboxRom:
|
|
if not self.is_enabled():
|
|
return LaunchboxRom(launchbox_id=None)
|
|
|
|
if not remote_enabled:
|
|
return LaunchboxRom(launchbox_id=None)
|
|
|
|
remote = await self._remote.get_by_id(database_id)
|
|
if not remote:
|
|
return LaunchboxRom(launchbox_id=None)
|
|
|
|
remote_images = await self._remote.fetch_images(
|
|
remote=remote, remote_enabled=remote_enabled
|
|
)
|
|
media_req = remote_media_req(
|
|
remote=remote,
|
|
remote_images=remote_images,
|
|
remote_enabled=remote_enabled,
|
|
)
|
|
|
|
return build_rom(
|
|
local=None,
|
|
remote=remote,
|
|
launchbox_id=database_id,
|
|
media_req=media_req,
|
|
)
|
|
|
|
async def get_matched_roms_by_name(
|
|
self, search_term: str, platform_slug: str
|
|
) -> list[LaunchboxRom]:
|
|
if not self.is_enabled():
|
|
return []
|
|
|
|
rom = await self.get_rom(search_term, platform_slug, keep_tags=True)
|
|
return [rom]
|
|
|
|
async def get_matched_rom_by_id(self, database_id: int) -> LaunchboxRom | None:
|
|
if not self.is_enabled():
|
|
return None
|
|
|
|
rom = await self.get_rom_by_id(database_id)
|
|
return rom if rom.get("launchbox_id") else None
|