First batch of work for hasheous

This commit is contained in:
Georges-Antoine Assi
2025-06-15 21:52:36 -04:00
parent a7ba71770c
commit 88130a60f8
14 changed files with 1424 additions and 3 deletions

View File

@@ -0,0 +1,39 @@
"""empty message
Revision ID: 0044_hasheous_id
Revises: 0043_launchbox_id
Create Date: 2025-06-16 03:15:42.692551
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = "0044_hasheous_id"
down_revision = "0043_launchbox_id"
branch_labels = None
depends_on = None
def upgrade() -> None:
with op.batch_alter_table("roms", schema=None) as batch_op:
batch_op.add_column(sa.Column("hasheous_id", sa.Integer(), nullable=True))
batch_op.add_column(
sa.Column(
"hasheous_metadata",
sa.JSON().with_variant(
postgresql.JSONB(astext_type=sa.Text()), "postgresql"
),
nullable=True,
)
)
batch_op.create_index("idx_roms_hasheous_id", ["hasheous_id"], unique=False)
def downgrade() -> None:
with op.batch_alter_table("roms", schema=None) as batch_op:
batch_op.drop_index("idx_roms_hasheous_id")
batch_op.drop_column("hasheous_metadata")
batch_op.drop_column("hasheous_id")

View File

@@ -85,6 +85,11 @@ PLAYMATCH_API_ENABLED: Final = str_to_bool(
os.environ.get("PLAYMATCH_API_ENABLED", "false")
)
# HASHEOUS
HASHEOUS_API_ENABLED: Final = str_to_bool(
os.environ.get("HASHEOUS_API_ENABLED", "false")
)
# AUTH
ROMM_AUTH_SECRET_KEY: Final = os.environ.get(
"ROMM_AUTH_SECRET_KEY", secrets.token_hex(32)

View File

@@ -6,6 +6,7 @@ from config import (
ENABLE_SCHEDULED_RESCAN,
ENABLE_SCHEDULED_UPDATE_LAUNCHBOX_METADATA,
ENABLE_SCHEDULED_UPDATE_SWITCH_TITLEDB,
HASHEOUS_API_ENABLED,
LAUNCHBOX_API_ENABLED,
OIDC_ENABLED,
OIDC_PROVIDER,
@@ -51,13 +52,15 @@ def heartbeat() -> HeartbeatResponse:
or MOBY_API_ENABLED
or RA_API_ENABLED
or LAUNCHBOX_API_ENABLED
or PLAYMATCH_API_ENABLED,
or PLAYMATCH_API_ENABLED
or HASHEOUS_API_ENABLED,
"IGDB_API_ENABLED": IGDB_API_ENABLED,
"SS_API_ENABLED": SS_API_ENABLED,
"MOBY_API_ENABLED": MOBY_API_ENABLED,
"STEAMGRIDDB_API_ENABLED": STEAMGRIDDB_API_ENABLED,
"RA_API_ENABLED": RA_API_ENABLED,
"LAUNCHBOX_API_ENABLED": LAUNCHBOX_API_ENABLED,
"HASHEOUS_API_ENABLED": HASHEOUS_API_ENABLED,
# Platmatch requires use of the IGDB API
"PLAYMATCH_API_ENABLED": PLAYMATCH_API_ENABLED and IGDB_API_ENABLED,
},

View File

@@ -31,6 +31,7 @@ class MetadataSourcesDict(TypedDict):
RA_API_ENABLED: bool
LAUNCHBOX_API_ENABLED: bool
PLAYMATCH_API_ENABLED: bool
HASHEOUS_API_ENABLED: bool
class FilesystemDict(TypedDict):

View File

@@ -1,3 +1,4 @@
from .hasheous_handler import HasheousHandler
from .igdb_handler import IGDBHandler
from .launchbox_handler import LaunchboxHandler
from .moby_handler import MobyGamesHandler
@@ -13,3 +14,4 @@ meta_sgdb_handler = SGDBBaseHandler()
meta_ra_handler = RAHandler()
meta_pm_handler = PlaymatchHandler()
meta_launchbox_handler = LaunchboxHandler()
meta_hasheous_handler = HasheousHandler()

File diff suppressed because it is too large Load Diff

View File

@@ -819,7 +819,13 @@ SEARCH_FIELDS = ("game.id", "name")
# name: a.innerText
# }))
IGDB_PLATFORM_LIST = (
class SlugToIGDB(TypedDict):
slug: str
name: str
IGDB_PLATFORM_LIST: list[SlugToIGDB] = [
{"slug": "visionos", "name": "visionOS"},
{"slug": "meta-quest-3", "name": "Meta Quest 3"},
{"slug": "atari2600", "name": "Atari 2600"},
@@ -1036,7 +1042,11 @@ IGDB_PLATFORM_LIST = (
{"slug": "onlive-game-system", "name": "OnLive Game System"},
{"slug": "vc", "name": "Virtual Console"},
{"slug": "airconsole", "name": "AirConsole"},
)
]
IGDB_PLATFORMS_BY_SLUG: dict[str, SlugToIGDB] = {
platform["slug"]: platform for platform in IGDB_PLATFORM_LIST
}
IGDB_PLATFORM_CATEGORIES: dict[int, str] = {
0: "Unknown",

View File

@@ -8,6 +8,7 @@ from handler.database import db_platform_handler
from handler.filesystem import fs_asset_handler, fs_firmware_handler, fs_rom_handler
from handler.filesystem.roms_handler import FSRom
from handler.metadata import (
meta_hasheous_handler,
meta_igdb_handler,
meta_launchbox_handler,
meta_moby_handler,
@@ -15,6 +16,7 @@ from handler.metadata import (
meta_ra_handler,
meta_ss_handler,
)
from handler.metadata.hasheous_handler import HasheousRom
from handler.metadata.igdb_handler import IGDBPlatform, IGDBRom
from handler.metadata.launchbox_handler import LaunchboxPlatform, LaunchboxRom
from handler.metadata.moby_handler import MobyGamesPlatform, MobyGamesRom
@@ -49,6 +51,7 @@ class MetadataSource:
RA = "ra" # RetroAchivements
LB = "lb" # Launchbox
PM = "pm" # Playmatch
HASHEOUS = "hasheous" # Hasheous
async def _get_main_platform_igdb_id(platform: Platform):
@@ -150,6 +153,8 @@ async def scan_platform(
else LaunchboxPlatform(launchbox_id=None, slug=platform_attrs["slug"])
)
await meta_hasheous_handler.get_platforms()
platform_attrs["name"] = platform_attrs["slug"].replace("-", " ").title()
platform_attrs.update(
{
@@ -423,6 +428,21 @@ async def scan_rom(
return IGDBRom(igdb_id=None)
async def fetch_hasheous_rom() -> HasheousRom:
if (
MetadataSource.HASHEOUS in metadata_sources
and platform.fs_slug
and (
newly_added
or scan_type == ScanType.COMPLETE
or (scan_type == ScanType.PARTIAL and not rom.hasheous_id)
or (scan_type == ScanType.UNIDENTIFIED and not rom.hasheous_id)
)
):
return await meta_hasheous_handler.get_rom(rom_attrs)
return HasheousRom(igdb_id=None)
# Run both metadata fetches concurrently
(
igdb_handler_rom,
@@ -431,6 +451,7 @@ async def scan_rom(
ra_handler_rom,
launchbox_handler_rom,
playmatch_handler_rom,
hasheous_handler_rom,
) = await asyncio.gather(
fetch_igdb_rom(),
fetch_moby_rom(),
@@ -438,6 +459,7 @@ async def scan_rom(
fetch_ra_rom(),
fetch_launchbox_rom(platform.slug),
fetch_playmatch_rom(),
fetch_hasheous_rom(),
)
# Only update fields if match is found

View File

@@ -120,6 +120,7 @@ class Rom(BaseModel):
ss_id: Mapped[int | None]
ra_id: Mapped[int | None]
launchbox_id: Mapped[int | None]
hasheous_id: Mapped[int | None]
__table_args__ = (
Index("idx_roms_igdb_id", "igdb_id"),
@@ -128,6 +129,7 @@ class Rom(BaseModel):
Index("idx_roms_ra_id", "ra_id"),
Index("idx_roms_sgdb_id", "sgdb_id"),
Index("idx_roms_launchbox_id", "launchbox_id"),
Index("idx_roms_hasheous_id", "hasheous_id"),
)
fs_name: Mapped[str] = mapped_column(String(length=450))
@@ -154,6 +156,9 @@ class Rom(BaseModel):
launchbox_metadata: Mapped[dict[str, Any] | None] = mapped_column(
CustomJSON(), default=dict
)
hasheous_metadata: Mapped[dict[str, Any] | None] = mapped_column(
CustomJSON(), default=dict
)
path_cover_s: Mapped[str | None] = mapped_column(Text, default="")
path_cover_l: Mapped[str | None] = mapped_column(Text, default="")

View File

@@ -30,6 +30,9 @@ PLAYMATCH_API_ENABLED=
# LaunchBox
LAUNCHBOX_API_ENABLED=
# Hasheous
HASHEOUS_API_ENABLED=
# Database config
DB_HOST=127.0.0.1
DB_PORT=3306

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 KiB

View File

@@ -11,5 +11,6 @@ export type MetadataSourcesDict = {
RA_API_ENABLED: boolean;
LAUNCHBOX_API_ENABLED: boolean;
PLAYMATCH_API_ENABLED: boolean;
HASHEOUS_API_ENABLED: boolean;
};

View File

@@ -43,6 +43,7 @@ const defaultHeartbeat: Heartbeat = {
STEAMGRIDDB_API_ENABLED: false,
LAUNCHBOX_API_ENABLED: false,
PLAYMATCH_API_ENABLED: false,
HASHEOUS_API_ENABLED: false,
},
FILESYSTEM: {
FS_PLATFORMS: [],

View File

@@ -63,6 +63,14 @@ const metadataOptions = computed(() => [
? t("scan.disabled-by-admin")
: "",
},
{
name: "Hasheous",
value: "hasheous",
logo_path: "/assets/scrappers/hasheous.png",
disabled: !heartbeat.value.METADATA_SOURCES?.HASHEOUS_API_ENABLED
? t("scan.disabled-by-admin")
: "",
},
{
name: "Playmatch",
value: "pm",