Revive giantbomb metadata handler

This commit is contained in:
Georges-Antoine Assi
2025-11-18 12:57:41 -05:00
parent c22e0db816
commit ce3e37c6cb
39 changed files with 2420 additions and 122 deletions

View File

@@ -15,7 +15,7 @@ PLATFORM_SLUG_TO_RETROACHIEVEMENTS_ID: dict[UPS, int] = {
UPS.ARCADE: 27,
UPS.ARCADIA_2001: 73,
UPS.ARDUBOY: 71,
UPS.ATARI_JAGUAR_CD: 77,
UPS.JAGUAR_CD: 77,
UPS.ATARI2600: 25,
UPS.ATARI7800: 51,
UPS.COLECOVISION: 44,

View File

@@ -0,0 +1,41 @@
"""empty message
Revision ID: 0057_add_giantbomb_metadata
Revises: 0056_gamelist_xml
Create Date: 2025-09-19 21:37:14.878761
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = "0057_add_giantbomb_metadata"
down_revision = "0056_gamelist_xml"
branch_labels = None
depends_on = None
def upgrade() -> None:
with op.batch_alter_table("platforms", schema=None) as batch_op:
batch_op.add_column(sa.Column("giantbomb_id", sa.Integer(), nullable=True))
with op.batch_alter_table("roms", schema=None) as batch_op:
batch_op.add_column(sa.Column("giantbomb_id", sa.Integer(), nullable=True))
batch_op.add_column(
sa.Column(
"giantbomb_metadata",
sa.JSON().with_variant(
postgresql.JSONB(astext_type=sa.Text()), "postgresql"
),
nullable=True,
)
)
batch_op.create_index("idx_roms_giantbomb_id", ["giantbomb_id"], unique=False)
def downgrade() -> None:
with op.batch_alter_table("roms", schema=None) as batch_op:
batch_op.drop_index("idx_roms_giantbomb_id")
batch_op.drop_column("giantbomb_metadata")
batch_op.drop_column("giantbomb_id")
with op.batch_alter_table("platforms", schema=None) as batch_op:
batch_op.drop_column("giantbomb_id")

View File

@@ -108,6 +108,9 @@ FLASHPOINT_API_ENABLED: Final[bool] = safe_str_to_bool(
# HOWLONGTOBEAT
HLTB_API_ENABLED: Final[bool] = safe_str_to_bool(_get_env("HLTB_API_ENABLED"))
# GIANTBOMB
GIANTBOMB_API_ENABLED: Final = safe_str_to_bool(_get_env("GIANTBOMB_API_ENABLED"))
# AUTH
ROMM_AUTH_SECRET_KEY: Final[str | None] = _get_env("ROMM_AUTH_SECRET_KEY")
if not ROMM_AUTH_SECRET_KEY:
@@ -153,7 +156,8 @@ ENABLE_RESCAN_ON_FILESYSTEM_CHANGE: Final[bool] = safe_str_to_bool(
_get_env("ENABLE_RESCAN_ON_FILESYSTEM_CHANGE")
)
RESCAN_ON_FILESYSTEM_CHANGE_DELAY: Final[int] = safe_int(
_get_env("RESCAN_ON_FILESYSTEM_CHANGE_DELAY"), 5 # 5 minutes
_get_env("RESCAN_ON_FILESYSTEM_CHANGE_DELAY"),
5, # 5 minutes
)
ENABLE_SCHEDULED_RESCAN: Final[bool] = safe_str_to_bool(
_get_env("ENABLE_SCHEDULED_RESCAN")

View File

@@ -24,6 +24,7 @@ from handler.filesystem import fs_platform_handler
from handler.metadata import (
meta_flashpoint_handler,
meta_gamelist_handler,
meta_giantbomb_handler,
meta_hasheous_handler,
meta_hltb_handler,
meta_igdb_handler,
@@ -62,6 +63,7 @@ async def heartbeat() -> HeartbeatResponse:
playmatch_enabled = meta_playmatch_handler.is_enabled()
hltb_enabled = meta_hltb_handler.is_enabled()
tgdb_enabled = meta_tgdb_handler.is_enabled()
giantbomb_enabled = meta_giantbomb_handler.is_enabled()
return {
"SYSTEM": {
@@ -80,6 +82,7 @@ async def heartbeat() -> HeartbeatResponse:
or tgdb_enabled
or flashpoint_enabled
or hltb_enabled
or giantbomb_enabled
),
"IGDB_API_ENABLED": igdb_enabled,
"SS_API_ENABLED": ss_enabled,
@@ -92,6 +95,7 @@ async def heartbeat() -> HeartbeatResponse:
"TGDB_API_ENABLED": tgdb_enabled,
"FLASHPOINT_API_ENABLED": flashpoint_enabled,
"HLTB_API_ENABLED": hltb_enabled,
"GIANTBOMB_API_ENABLED": giantbomb_enabled,
},
"FILESYSTEM": {
"FS_PLATFORMS": await fs_platform_handler.get_platforms(),
@@ -153,5 +157,7 @@ async def metadata_heartbeat(source: str) -> bool:
return await meta_hltb_handler.heartbeat()
case MetadataSource.GAMELIST:
return await meta_gamelist_handler.heartbeat()
case MetadataSource.GIANTBOMB:
return await meta_giantbomb_handler.heartbeat()
case _:
return False

View File

@@ -19,6 +19,7 @@ class MetadataSourcesDict(TypedDict):
TGDB_API_ENABLED: bool
FLASHPOINT_API_ENABLED: bool
HLTB_API_ENABLED: bool
GIANTBOMB_API_ENABLED: bool
class FilesystemDict(TypedDict):

View File

@@ -17,6 +17,7 @@ class PlatformSchema(BaseModel):
igdb_slug: str | None
moby_slug: str | None
hltb_slug: str | None
giantbomb_slug: str | None = None
custom_name: str | None = None
igdb_id: int | None = None
sgdb_id: int | None = None
@@ -27,6 +28,7 @@ class PlatformSchema(BaseModel):
hasheous_id: int | None = None
tgdb_id: int | None = None
flashpoint_id: int | None = None
giantbomb_id: int | None = None
category: str | None = None
generation: int | None = None
family_name: str | None = None

View File

@@ -10,6 +10,7 @@ from pydantic import Field, computed_field, field_validator
from endpoints.responses.assets import SaveSchema, ScreenshotSchema, StateSchema
from handler.metadata.flashpoint_handler import FlashpointMetadata
from handler.metadata.gamelist_handler import GamelistMetadata
from handler.metadata.giantbomb_handler import GiantBombMetadata
from handler.metadata.hasheous_handler import HasheousMetadata
from handler.metadata.hltb_handler import HLTBMetadata
from handler.metadata.igdb_handler import IGDBMetadata
@@ -69,6 +70,11 @@ RomGamelistMetadata = TypedDict( # type: ignore[misc]
{k: NotRequired[v] for k, v in get_type_hints(GamelistMetadata).items()}, # type: ignore[misc]
total=False,
)
RomGiantBombMetadata = TypedDict( # type: ignore[misc]
"RomGiantBombMetadata",
{k: NotRequired[v] for k, v in get_type_hints(GiantBombMetadata).items()}, # type: ignore[misc]
total=False,
)
def rom_user_schema_factory() -> RomUserSchema:
@@ -210,6 +216,7 @@ class RomSchema(BaseModel):
flashpoint_id: str | None
hltb_id: int | None
gamelist_id: str | None
giantbomb_id: int | None
platform_id: int
platform_slug: str
@@ -240,6 +247,7 @@ class RomSchema(BaseModel):
flashpoint_metadata: RomFlashpointMetadata | None
hltb_metadata: RomHLTBMetadata | None
gamelist_metadata: RomGamelistMetadata | None
giantbomb_metadata: RomGiantBombMetadata | None
path_cover_small: str | None
path_cover_large: str | None

View File

@@ -240,6 +240,7 @@ class DBRomsHandler(DBBaseHandler):
Rom.hasheous_id.isnot(None),
Rom.tgdb_id.isnot(None),
Rom.flashpoint_id.isnot(None),
Rom.giantbomb_id.isnot(None),
)
if not value:
predicate = not_(predicate)
@@ -465,6 +466,7 @@ class DBRomsHandler(DBBaseHandler):
base_subquery.c.launchbox_id,
base_subquery.c.tgdb_id,
base_subquery.c.flashpoint_id,
base_subquery.c.giantbomb_id,
)
.outerjoin(
RomUser,
@@ -516,6 +518,11 @@ class DBRomsHandler(DBBaseHandler):
base_subquery.c.flashpoint_id,
base_subquery.c.platform_id,
),
_create_metadata_id_case(
MetadataSource.GIANTBOMB,
base_subquery.c.giantbomb_id,
base_subquery.c.platform_id,
),
_create_metadata_id_case(
"romm",
base_subquery.c.id,

View File

@@ -1,5 +1,6 @@
from .flashpoint_handler import FlashpointHandler
from .gamelist_handler import GamelistHandler
from .giantbomb_handler import GiantBombHandler
from .hasheous_handler import HasheousHandler
from .hltb_handler import HLTBHandler
from .igdb_handler import IGDBHandler
@@ -23,3 +24,4 @@ meta_tgdb_handler = TGDBHandler()
meta_flashpoint_handler = FlashpointHandler()
meta_gamelist_handler = GamelistHandler()
meta_hltb_handler = HLTBHandler()
meta_giantbomb_handler = GiantBombHandler()

View File

@@ -304,7 +304,7 @@ class UniversalPlatformSlug(enum.StrEnum):
ARDUBOY = "arduboy"
ASTRAL_2000 = "astral-2000"
ASTROCADE = "astrocade"
ATARI_JAGUAR_CD = "atari-jaguar-cd"
JAGUAR_CD = "atari-jaguar-cd"
ATARI_ST = "atari-st"
ATARI_VCS = "atari-vcs"
ATARI_XEGS = "atari-xegs"
@@ -371,6 +371,7 @@ class UniversalPlatformSlug(enum.StrEnum):
DC = "dc"
DEDICATED_CONSOLE = "dedicated-console"
DEDICATED_HANDHELD = "dedicated-handheld"
DENSHI_MANGAJUKU = "denshi-mangajuku"
DIDJ = "didj"
DIGIBLAST = "digiblast"
DOJA = "doja"
@@ -406,6 +407,8 @@ class UniversalPlatformSlug(enum.StrEnum):
GAME_WAVE = "game-wave"
GAMEGEAR = "gamegear"
GAMESTICK = "gamestick"
GAMEKING = "gameking"
GAMEKINGIII = "gamekingiii"
GB = "gb"
GBA = "gba"
GBC = "gbc"
@@ -421,6 +424,7 @@ class UniversalPlatformSlug(enum.StrEnum):
GP32 = "gp32"
GT40 = "gt40"
GVM = "gvm"
HALCYON = "halcyon"
HANDHELD_ELECTRONIC_LCD = "handheld-electronic-lcd"
HARTUNG = "hartung"
HD_DVD_PLAYER = "hd-dvd-player"
@@ -472,6 +476,7 @@ class UniversalPlatformSlug(enum.StrEnum):
LYNX = "lynx"
MAC = "mac"
MAEMO = "maemo"
MAGIC_LEAP_ONE = "magic-leap-one"
MAINFRAME = "mainframe"
MATSUSHITAPANASONIC_JR = "matsushitapanasonic-jr"
MEEGO = "meego"
@@ -489,6 +494,7 @@ class UniversalPlatformSlug(enum.StrEnum):
MODEL1 = "model1"
MODEL2 = "model2"
MODEL3 = "model3"
MONON_COLOR = "monon-color"
MOPHUN = "mophun"
MOS_TECHNOLOGY_6502 = "mos-technology-6502"
MOTOROLA_6800 = "motorola-6800"
@@ -500,6 +506,7 @@ class UniversalPlatformSlug(enum.StrEnum):
MSX2PLUS = "msx2plus"
MTX512 = "mtx512"
MUGEN = "mugen"
MULTI_8 = "multi-8"
MULTIVISION = "multivision"
N3DS = "3ds"
N64 = "n64"
@@ -592,6 +599,7 @@ class UniversalPlatformSlug(enum.StrEnum):
RCA_STUDIO_II = "rca-studio-ii"
RESEARCH_MACHINES_380Z = "research-machines-380z"
ROKU = "roku"
RX_78 = "rx-78"
SAM_COUPE = "sam-coupe"
SATELLAVIEW = "satellaview"
SATURN = "saturn"
@@ -604,6 +612,7 @@ class UniversalPlatformSlug(enum.StrEnum):
SEGA32 = "sega32"
SEGACD = "segacd"
SEGACD32 = "segacd32"
SELECT_A_GAME = "select-a-game"
SERIES_X_S = "series-x-s"
SFAM = "sfam"
SG1000 = "sg1000"
@@ -615,6 +624,7 @@ class UniversalPlatformSlug(enum.StrEnum):
SIGNETICS_2650 = "signetics-2650"
SINCLAIR_QL = "sinclair-ql"
SK_VM = "sk-vm"
SMAKY = "smaky"
SMC_777 = "smc-777"
SMS = "sms"
SNES = "snes"
@@ -625,6 +635,7 @@ class UniversalPlatformSlug(enum.StrEnum):
SRI_5001000 = "sri-5001000"
STADIA = "stadia"
STEAM_VR = "steam-vr"
STREAMING = "streaming"
STV = "stv"
SUFAMI_TURBO = "sufami-turbo"
SUPER_ACAN = "super-acan"
@@ -673,6 +684,7 @@ class UniversalPlatformSlug(enum.StrEnum):
TRS_80_MC_10 = "trs-80-mc-10"
TRS_80_MODEL_100 = "trs-80-model-100"
TURBOGRAFX_CD = "turbografx-cd"
TVBOY = "tvboy"
TVOS = "tvos"
TYPE_X = "type-x"
UZEBOX = "uzebox"
@@ -685,6 +697,7 @@ class UniversalPlatformSlug(enum.StrEnum):
VIC_20 = "vic-20"
VIDEOBRAIN = "videobrain"
VIDEOPAC_G7400 = "videopac-g7400"
VIEW_MASTER = "view-master"
VIRTUALBOY = "virtualboy"
VIS = "vis"
VISIONOS = "visionos"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -558,7 +558,7 @@ HLTB_PLATFORM_LIST: dict[UPS, SlugToHLTBPlatform] = {
"count": 259,
},
UPS.JAGUAR: {"name": "Atari Jaguar", "slug": "atari-jaguar", "count": 64},
UPS.ATARI_JAGUAR_CD: {
UPS.JAGUAR_CD: {
"name": "Atari Jaguar CD",
"slug": "atari-jaguar-cd",
"count": 14,

View File

@@ -547,9 +547,9 @@ class IGDBHandler(MetadataHandler):
list(
map(
lambda rom: (
f'id={pydash.get(rom, "game.id", "")}'
f"id={pydash.get(rom, 'game.id', '')}"
if "game" in rom.keys()
else f'id={rom.get("id", "")}'
else f"id={rom.get('id', '')}"
),
alternative_matched_roms,
)
@@ -1216,7 +1216,7 @@ IGDB_PLATFORM_LIST: dict[UPS, SlugToIGDB] = {
"url": "https://www.igdb.com/platforms/astrocade",
"url_logo": "",
},
UPS.ATARI_JAGUAR_CD: {
UPS.JAGUAR_CD: {
"category": "Console",
"family_name": "Atari",
"family_slug": "atari",

View File

@@ -362,7 +362,7 @@ LAUNCHBOX_PLATFORM_LIST: dict[UPS, SlugToLaunchboxId] = {
UPS.ARCADE: {"id": 5, "name": "Arcade"},
UPS.ARCADIA_2001: {"id": 79, "name": "Emerson Arcadia 2001"},
UPS.ASTROCADE: {"id": 77, "name": "Bally Astrocade"},
UPS.ATARI_JAGUAR_CD: {"id": 10, "name": "Atari Jaguar CD"},
UPS.JAGUAR_CD: {"id": 10, "name": "Atari Jaguar CD"},
UPS.ATARI_ST: {"id": 76, "name": "Atari ST"},
UPS.ATARI_XEGS: {"id": 12, "name": "Atari XEGS"},
UPS.ATARI2600: {"id": 6, "name": "Atari 2600"},

View File

@@ -391,7 +391,7 @@ RA_PLATFORM_LIST: dict[UPS, SlugToRAId] = {
UPS.ARDUBOY: {"id": 71, "name": "Arduboy"},
UPS.ATARI2600: {"id": 25, "name": "Atari 2600"},
UPS.ATARI7800: {"id": 51, "name": "Atari 7800"},
UPS.ATARI_JAGUAR_CD: {"id": 77, "name": "Atari Jaguar CD"},
UPS.JAGUAR_CD: {"id": 77, "name": "Atari Jaguar CD"},
UPS.COLECOVISION: {"id": 44, "name": "ColecoVision"},
UPS.DC: {"id": 40, "name": "Dreamcast"},
UPS.ELEKTOR: {"id": 75, "name": "Elektor"},

View File

@@ -348,7 +348,7 @@ TGDB_PLATFORM_LIST: dict[UPS, SlugToTGDBId] = {
"summary": "The Atari Jaguar is a video game console that was released by Atari Corporation in 1993. It was the last to be marketed under the Atari brand until the release of the Atari Flashback in 2004. It was designed to surpass the Mega Drive/Genesis, Super Nintendo Entertainment System, and the Panasonic 3DO in processing power. Although launched one year earlier, it was eventually in competition with the Sega Saturn, the Sony PlayStation, and other consoles that made up the fifth generation of video game consoles. The console was first released in New York City and San Francisco on November 23, 1993, and the rest of the country in early 1994. Although it was promoted as the first 64-bit gaming system, the Jaguar proved to be a commercial failure and prompted Atari to leave the home video game console market. Despite its commercial failure, the Jaguar has a dedicated fan base that produces homebrew games for it.",
"url_logo": "https://cdn.thegamesdb.net/images/original/platform/boxart/28-2.jpg",
},
UPS.ATARI_JAGUAR_CD: {
UPS.JAGUAR_CD: {
"id": 29,
"name": "Atari Jaguar CD",
"manufacturer": "Atari",

View File

@@ -12,6 +12,7 @@ from handler.filesystem.roms_handler import FSRom
from handler.metadata import (
meta_flashpoint_handler,
meta_gamelist_handler,
meta_giantbomb_handler,
meta_hasheous_handler,
meta_hltb_handler,
meta_igdb_handler,
@@ -70,6 +71,7 @@ class MetadataSource(enum.StrEnum):
FLASHPOINT = "flashpoint" # Flashpoint Project
HLTB = "hltb" # HowLongToBeat
GAMELIST = "gamelist" # ES-DE gamelist.xml
GIANTBOMB = "giantbomb" # Giantbomb
def get_main_platform_igdb_id(platform: Platform):
@@ -178,6 +180,7 @@ async def scan_platform(
tgdb_platform = meta_tgdb_handler.get_platform(platform_attrs["slug"])
flashpoint_platform = meta_flashpoint_handler.get_platform(platform_attrs["slug"])
hltb_platform = meta_hltb_handler.get_platform(platform_attrs["slug"])
giantbomb_platform = meta_giantbomb_handler.get_platform(platform_attrs["slug"])
platform_attrs["name"] = platform_attrs["slug"].replace("-", " ").title()
platform_attrs.update(
@@ -198,6 +201,9 @@ async def scan_platform(
"tgdb_id": moby_platform.get("tgdb_id")
or hasheous_platform.get("tgdb_id")
or None,
"giantbomb_id": giantbomb_platform.get("giantbomb_id")
or hasheous_platform.get("giantbomb_id")
or None,
"name": igdb_platform.get("name")
or ss_platform.get("name")
or moby_platform.get("name")
@@ -207,9 +213,11 @@ async def scan_platform(
or tgdb_platform.get("name")
or flashpoint_platform.get("name")
or hltb_platform.get("name")
or giantbomb_platform.get("name")
or platform_attrs["slug"].replace("-", " ").title(),
"url_logo": igdb_platform.get("url_logo")
or tgdb_platform.get("url_logo")
or giantbomb_platform.get("url_logo")
or "",
}
)
@@ -447,7 +455,7 @@ async def scan_rom(
if playmatch_rom["igdb_id"] is not None:
log.debug(
f"{hl(rom_attrs['fs_name'])} identified by Playmatch as "
f"{hl(str(playmatch_rom["igdb_id"]), color=BLUE)} {emoji.EMOJI_ALIEN_MONSTER}",
f"{hl(str(playmatch_rom['igdb_id']), color=BLUE)} {emoji.EMOJI_ALIEN_MONSTER}",
extra=LOGGER_MODULE_NAME,
)

View File

@@ -1,5 +1,6 @@
from __future__ import annotations
from functools import cached_property
from typing import TYPE_CHECKING
from sqlalchemy import Integer, String, func, select
@@ -28,6 +29,7 @@ class Platform(BaseModel):
hasheous_id: Mapped[int | None] = mapped_column(Integer(), default=None)
tgdb_id: Mapped[int | None] = mapped_column(Integer(), default=None)
flashpoint_id: Mapped[int | None] = mapped_column(Integer(), default=None)
giantbomb_id: Mapped[int | None] = mapped_column(Integer(), default=None)
igdb_slug: Mapped[str | None] = mapped_column(String(length=100), default=None)
moby_slug: Mapped[str | None] = mapped_column(String(length=100), default=None)
hltb_slug: Mapped[str | None] = mapped_column(String(length=100), default=None)
@@ -80,11 +82,20 @@ class Platform(BaseModel):
and not self.launchbox_id
and not self.ra_id
and not self.hasheous_id
and not self.tgdb_id
and not self.giantbomb_id
)
@property
def is_identified(self) -> bool:
return not self.is_unidentified
@cached_property
def giantbomb_slug(self) -> str | None:
from handler.metadata import meta_giantbomb_handler
giantbomb_platform = meta_giantbomb_handler.get_platform(self.slug)
return giantbomb_platform.get("slug", None)
def __repr__(self) -> str:
return f"{self.name} ({self.slug}) ({self.id})"

View File

@@ -156,6 +156,7 @@ class Rom(BaseModel):
flashpoint_id: Mapped[str | None] = mapped_column(String(length=100), default=None)
hltb_id: Mapped[int | None] = mapped_column(Integer(), default=None)
gamelist_id: Mapped[str | None] = mapped_column(String(length=100), default=None)
giantbomb_id: Mapped[int | None] = mapped_column(Integer(), default=None)
__table_args__ = (
Index("idx_roms_igdb_id", "igdb_id"),
@@ -169,6 +170,7 @@ class Rom(BaseModel):
Index("idx_roms_flashpoint_id", "flashpoint_id"),
Index("idx_roms_hltb_id", "hltb_id"),
Index("idx_roms_gamelist_id", "gamelist_id"),
Index("idx_roms_giantbomb_id", "giantbomb_id"),
)
fs_name: Mapped[str] = mapped_column(String(length=FILE_NAME_MAX_LENGTH))
@@ -208,6 +210,9 @@ class Rom(BaseModel):
gamelist_metadata: Mapped[dict[str, Any] | None] = mapped_column(
CustomJSON(), default=dict
)
giantbomb_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="")
@@ -350,6 +355,7 @@ class Rom(BaseModel):
and not self.flashpoint_id
and not self.hltb_id
and not self.gamelist_id
and not self.giantbomb_id
)
@property

View File

@@ -5,6 +5,7 @@ from config import (
from endpoints.sockets.scan import ScanStats, scan_platforms
from handler.metadata import (
meta_flashpoint_handler,
meta_giantbomb_handler,
meta_hasheous_handler,
meta_hltb_handler,
meta_igdb_handler,
@@ -51,6 +52,7 @@ class ScanLibraryTask(PeriodicTask):
MetadataSource.FLASHPOINT: meta_flashpoint_handler.is_enabled(),
MetadataSource.HLTB: meta_hltb_handler.is_enabled(),
MetadataSource.TGDB: meta_tgdb_handler.is_enabled(),
MetadataSource.GIANTBOMB: meta_giantbomb_handler.is_enabled(),
}
metadata_sources = [source for source, flag in source_mapping.items() if flag]

View File

@@ -36,6 +36,8 @@ def test_heartbeat(client):
assert isinstance(metadata["HASHEOUS_API_ENABLED"], bool)
assert isinstance(metadata["TGDB_API_ENABLED"], bool)
assert isinstance(metadata["FLASHPOINT_API_ENABLED"], bool)
assert isinstance(metadata["HLTB_API_ENABLED"], bool)
assert isinstance(metadata["GIANTBOMB_API_ENABLED"], bool)
assert "FILESYSTEM" in heartbeat
filesystem = heartbeat["FILESYSTEM"]

View File

@@ -3,6 +3,7 @@ from typing import TypedDict
from handler.metadata import (
meta_flashpoint_handler,
meta_giantbomb_handler,
meta_hasheous_handler,
meta_hltb_handler,
meta_igdb_handler,
@@ -25,6 +26,7 @@ class SupportedPlatform(TypedDict):
ra_id: int | None
flashpoint_id: int | None
hltb_slug: str | None
giantbomb_url: str | None
if __name__ == "__main__":
@@ -41,6 +43,7 @@ if __name__ == "__main__":
ra_platform = meta_ra_handler.get_platform(slug_lower)
flashpoint_platform = meta_flashpoint_handler.get_platform(slug_lower)
hltb_platform = meta_hltb_handler.get_platform(slug_lower)
giantbomb_platform = meta_giantbomb_handler.get_platform(slug_lower)
supported_platforms[slug_lower] = {
"name": igdb_platform.get("name", None)
@@ -51,6 +54,7 @@ if __name__ == "__main__":
or ra_platform.get("name", None)
or flashpoint_platform.get("name", None)
or hltb_platform.get("name", None)
or giantbomb_platform.get("name", None)
or slug_lower.replace("-", " ").title(),
"folder": slug_lower,
"igdb_slug": igdb_platform.get("igdb_slug", None),
@@ -61,6 +65,7 @@ if __name__ == "__main__":
"ra_id": ra_platform["ra_id"],
"flashpoint_id": flashpoint_platform["flashpoint_id"],
"hltb_slug": hltb_platform.get("hltb_slug", None),
"giantbomb_url": giantbomb_platform.get("url_logo", None),
}
# Sort platforms by name field
@@ -75,8 +80,8 @@ if __name__ == "__main__":
for platform in supported_platforms.values():
print(
f'| {platform["name"]} |',
f'`{platform["folder"]}` |',
f"| {platform['name']} |",
f"`{platform['folder']}` |",
(
f'<a href="https://www.igdb.com/platforms/{platform["igdb_slug"]}" target="_blank" rel="noopener noreferrer"><img alt="igdb logo" src="../../resources/metadata_providers/igdb.png" height="24px" width="24px"></a>'
if platform["igdb_slug"]
@@ -117,5 +122,10 @@ if __name__ == "__main__":
if platform["hltb_slug"]
else ""
),
(
f'<a href="{platform["giantbomb_url"]}" target="_blank" rel="noopener noreferrer"><img alt="giantbomb logo" src="../../resources/metadata_providers/giantbomb.png" height="24px" width="24px"></a>'
if platform["giantbomb_url"]
else ""
),
" |",
)

View File

@@ -37,6 +37,9 @@ HLTB_API_ENABLED=
# TheGamesDB
TGDB_API_ENABLED=
# GiantBomb
GIANTBOMB_API_ENABLED=
# Database config
DB_HOST=127.0.0.1
DB_PORT=3306

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

View File

@@ -61,6 +61,7 @@ export type { RomFileCategory } from './models/RomFileCategory';
export type { RomFileSchema } from './models/RomFileSchema';
export type { RomFlashpointMetadata } from './models/RomFlashpointMetadata';
export type { RomGamelistMetadata } from './models/RomGamelistMetadata';
export type { RomGiantBombMetadata } from './models/RomGiantBombMetadata';
export type { RomHasheousMetadata } from './models/RomHasheousMetadata';
export type { RomHLTBMetadata } from './models/RomHLTBMetadata';
export type { RomIGDBMetadata } from './models/RomIGDBMetadata';

View File

@@ -5,6 +5,7 @@
import type { RomFileSchema } from './RomFileSchema';
import type { RomFlashpointMetadata } from './RomFlashpointMetadata';
import type { RomGamelistMetadata } from './RomGamelistMetadata';
import type { RomGiantBombMetadata } from './RomGiantBombMetadata';
import type { RomHasheousMetadata } from './RomHasheousMetadata';
import type { RomHLTBMetadata } from './RomHLTBMetadata';
import type { RomIGDBMetadata } from './RomIGDBMetadata';
@@ -33,6 +34,7 @@ export type DetailedRomSchema = {
flashpoint_id: (string | null);
hltb_id: (number | null);
gamelist_id: (string | null);
giantbomb_id: (number | null);
platform_id: number;
platform_slug: string;
platform_fs_slug: string;
@@ -58,6 +60,7 @@ export type DetailedRomSchema = {
flashpoint_metadata: (RomFlashpointMetadata | null);
hltb_metadata: (RomHLTBMetadata | null);
gamelist_metadata: (RomGamelistMetadata | null);
giantbomb_metadata: (RomGiantBombMetadata | null);
path_cover_small: (string | null);
path_cover_large: (string | null);
url_cover: (string | null);

View File

@@ -15,5 +15,6 @@ export type MetadataSourcesDict = {
TGDB_API_ENABLED: boolean;
FLASHPOINT_API_ENABLED: boolean;
HLTB_API_ENABLED: boolean;
GIANTBOMB_API_ENABLED: boolean;
};

View File

@@ -12,6 +12,7 @@ export type PlatformSchema = {
igdb_slug: (string | null);
moby_slug: (string | null);
hltb_slug: (string | null);
giantbomb_slug?: (string | null);
custom_name?: (string | null);
igdb_id?: (number | null);
sgdb_id?: (number | null);
@@ -22,6 +23,7 @@ export type PlatformSchema = {
hasheous_id?: (number | null);
tgdb_id?: (number | null);
flashpoint_id?: (number | null);
giantbomb_id?: (number | null);
category?: (string | null);
generation?: (number | null);
family_name?: (string | null);

View File

@@ -0,0 +1,15 @@
/* generated using openapi-typescript-codegen -- do not edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type RomGiantBombMetadata = {
guid?: string;
alternative_names?: Array<string>;
deck?: string;
description?: string;
first_release_date?: string;
image?: Record<string, any>;
age_ratings?: Array<string>;
site_url?: string;
};

View File

@@ -5,6 +5,7 @@
import type { RomFileSchema } from './RomFileSchema';
import type { RomFlashpointMetadata } from './RomFlashpointMetadata';
import type { RomGamelistMetadata } from './RomGamelistMetadata';
import type { RomGiantBombMetadata } from './RomGiantBombMetadata';
import type { RomHasheousMetadata } from './RomHasheousMetadata';
import type { RomHLTBMetadata } from './RomHLTBMetadata';
import type { RomIGDBMetadata } from './RomIGDBMetadata';
@@ -27,6 +28,7 @@ export type SimpleRomSchema = {
flashpoint_id: (string | null);
hltb_id: (number | null);
gamelist_id: (string | null);
giantbomb_id: (number | null);
platform_id: number;
platform_slug: string;
platform_fs_slug: string;
@@ -52,6 +54,7 @@ export type SimpleRomSchema = {
flashpoint_metadata: (RomFlashpointMetadata | null);
hltb_metadata: (RomHLTBMetadata | null);
gamelist_metadata: (RomGamelistMetadata | null);
giantbomb_metadata: (RomGiantBombMetadata | null);
path_cover_small: (string | null);
path_cover_large: (string | null);
url_cover: (string | null);

View File

@@ -77,6 +77,11 @@ const dataSources = computed(() => {
condition: props.rom.hltb_id,
url: `https://howlongtobeat.com/game/${props.rom.hltb_id}`,
},
{
name: "Giant Bomb",
condition: props.rom.giantbomb_id,
url: props.rom.giantbomb_metadata?.site_url,
},
].filter((source) => source.condition);
});
@@ -108,6 +113,7 @@ const coverImageSource = computed(() => {
if (hostname === "hasheous.org") return "Hasheous";
if (hostname === "infinity.unstable.life") return "Flashpoint";
if (hostname === "howlongtobeat.com") return "HowLongToBeat";
if (hostname === "giantbomb") return "Giantbomb";
return null;
} catch {

View File

@@ -333,6 +333,20 @@ const hashMatches = computed(() => {
<span>{{ rom.sgdb_id }}</span>
</v-chip>
</a>
<a
v-if="rom.giantbomb_id"
style="text-decoration: none; color: inherit"
:href="rom.giantbomb_metadata?.site_url"
target="_blank"
class="mr-1"
>
<v-chip class="pl-0 mt-1" size="small" title="Giant Bomb ID">
<v-avatar variant="text" class="mr-2" size="30" rounded="0">
<v-img src="/assets/scrappers/giantbomb.png" />
</v-avatar>
<span>{{ rom.giantbomb_id }}</span>
</v-chip>
</a>
</v-col>
</v-row>
<v-row

View File

@@ -439,6 +439,20 @@ watch(
<v-img src="/assets/scrappers/hltb.png" />
</v-avatar>
</v-chip>
<a
v-if="currentPlatform.giantbomb_id"
style="text-decoration: none; color: inherit"
:href="`https://www.giantbomb.com/${currentPlatform.giantbomb_slug}/3045-${currentPlatform.giantbomb_id}`"
target="_blank"
class="ml-1"
>
<v-chip class="pl-0 mt-1" size="small" @click.stop>
<v-avatar variant="text" class="mr-2" size="30" rounded="0">
<v-img src="/assets/scrappers/giantbomb.png" />
</v-avatar>
<span>{{ currentPlatform.giantbomb_id }}</span>
</v-chip>
</a>
</v-col>
</v-row>
<v-row

View File

@@ -281,6 +281,16 @@ function updateOptions({ sortBy }: { sortBy: SortBy }) {
<v-img src="/assets/scrappers/esde.png" />
</v-avatar>
</v-chip>
<v-chip
v-if="item.giantbomb_id"
class="mr-1 pa-0 item-chip"
size="x-small"
title="Giant Bomb match"
>
<v-avatar variant="text" size="20" rounded>
<v-img src="/assets/scrappers/giantbomb.png" />
</v-avatar>
</v-chip>
<v-chip
v-if="item.siblings.length > 0 && showSiblings"
class="translucent text-white mr-1 px-1 item-chip"

View File

@@ -285,6 +285,7 @@ async function updateRom({
formData.append("hasheous_id", rom.hasheous_id?.toString() || "");
formData.append("tgdb_id", rom.tgdb_id?.toString() || "");
formData.append("hltb_id", rom.hltb_id?.toString() || "");
formData.append("giantbomb_id", rom.giantbomb_id?.toString() || "");
if (rom.raw_metadata?.igdb_metadata) {
formData.append("raw_igdb_metadata", rom.raw_metadata.igdb_metadata);

View File

@@ -30,6 +30,7 @@ const defaultHeartbeat: Heartbeat = {
TGDB_API_ENABLED: false,
FLASHPOINT_API_ENABLED: false,
HLTB_API_ENABLED: false,
GIANTBOMB_API_ENABLED: false,
},
FILESYSTEM: {
FS_PLATFORMS: [],
@@ -168,6 +169,14 @@ export default defineStore("heartbeat", {
logo_path: "/assets/scrappers/esde.png",
disabled: "",
},
{
name: "Giant Bomb",
value: "giantbomb",
logo_path: "/assets/scrappers/giantbomb.png",
disabled: !this.value.METADATA_SOURCES?.GIANTBOMB_API_ENABLED
? i18n.global.t("scan.api-key-missing")
: "",
},
];
},
getEnabledMetadataOptions(): MetadataOption[] {

View File

@@ -73,6 +73,12 @@ const metadataOptions = computed(() => [
logo_path: "/assets/scrappers/sgdb.png",
disabled: !heartbeat.value.METADATA_SOURCES?.STEAMGRIDDB_API_ENABLED,
},
{
name: "Giant Bomb",
value: "giantbomb",
logo_path: "/assets/scrappers/giantbomb.png",
disabled: !heartbeat.value.METADATA_SOURCES?.GIANTBOMB_API_ENABLED,
},
]);
const defaultAdminUser = ref({
username: "",

View File

@@ -257,6 +257,16 @@ async function stopScan() {
>
<v-img src="/assets/scrappers/hltb.png" />
</v-avatar>
<v-avatar
v-if="item.raw.giantbomb_id"
class="bg-surface"
variant="text"
size="25"
rounded
>
<v-img src="/assets/scrappers/giantbomb.png" />
</v-avatar>
</v-col>
</v-row>
<v-row