mirror of
https://github.com/rommapp/romm.git
synced 2026-06-30 15:55:54 +00:00
1234 lines
30 KiB
Python
1234 lines
30 KiB
Python
import json
|
|
from typing import NotRequired, TypedDict
|
|
|
|
import httpx
|
|
from config import HASHEOUS_API_ENABLED
|
|
from fastapi import HTTPException, status
|
|
from logger.logger import log
|
|
from utils import get_version
|
|
from utils.context import ctx_httpx_client
|
|
|
|
from .base_hander import MetadataHandler
|
|
|
|
|
|
class HasheousMetadata(TypedDict):
|
|
tosec_match: bool
|
|
mame_arcade_match: bool
|
|
mame_mess_match: bool
|
|
nointro_match: bool
|
|
redump_match: bool
|
|
whdload_match: bool
|
|
ra_match: bool
|
|
fbneo_match: bool
|
|
|
|
|
|
class HasheousPlatform(TypedDict):
|
|
slug: str
|
|
hasheous_id: int | None
|
|
name: NotRequired[str]
|
|
igdb_id: NotRequired[str | None]
|
|
tgdb_id: NotRequired[int | None]
|
|
ra_id: NotRequired[int | None]
|
|
|
|
|
|
class HasheousRom(TypedDict):
|
|
hasheous_id: int | None
|
|
name: NotRequired[str]
|
|
url_cover: NotRequired[str]
|
|
igdb_id: NotRequired[int | None]
|
|
tgdb_id: NotRequired[int | None]
|
|
ra_id: NotRequired[int | None]
|
|
hasheous_metadata: NotRequired[HasheousMetadata]
|
|
|
|
|
|
class HasheousHandler(MetadataHandler):
|
|
def __init__(self) -> None:
|
|
self.BASE_URL = "https://hasheous.org/api/v1"
|
|
self.platform_endpoint = f"{self.BASE_URL}/Lookup/Platforms"
|
|
self.games_endpoint = f"{self.BASE_URL}/Lookup/ByHash"
|
|
# self.proxy_igdb_game_endpoint = f"{self.BASE_URL}/MetadataProxy/IGDB/Game"
|
|
# self.proxy_igdb_cover_endpoint = f"{self.BASE_URL}/MetadataProxy/IGDB/Cover"
|
|
# self.app_api_key = (
|
|
# "JNoFBA-jEh4HbxuxEHM6MVzydKoAXs9eCcp2dvcg5LRCnpp312voiWmjuaIssSzS"
|
|
# )
|
|
|
|
async def _request(
|
|
self,
|
|
url: str,
|
|
method: str = "POST",
|
|
params: dict | None = None,
|
|
data: dict | None = None,
|
|
) -> dict:
|
|
httpx_client = ctx_httpx_client.get()
|
|
|
|
# Normalize method to uppercase
|
|
method = method.upper()
|
|
if method not in ["GET", "POST"]:
|
|
raise ValueError(f"Unsupported HTTP method: {method}")
|
|
|
|
try:
|
|
log.debug(
|
|
"API request: Method=%s, URL=%s, Params=%s, Data=%s",
|
|
method,
|
|
url,
|
|
params,
|
|
data,
|
|
)
|
|
|
|
# Prepare request kwargs
|
|
request_kwargs = {
|
|
"url": url,
|
|
"params": params,
|
|
"headers": {
|
|
"Content-Type": "application/json-patch+json",
|
|
"User-Agent": f"RomM/{get_version()}",
|
|
# "X-Client-API-Key": self.app_api_key,
|
|
},
|
|
"timeout": 120,
|
|
}
|
|
|
|
# Add method-specific parameters
|
|
if method == "POST":
|
|
request_kwargs["json"] = data
|
|
|
|
# Make the request
|
|
res = await httpx_client.request(method, **request_kwargs)
|
|
|
|
res.raise_for_status()
|
|
return res.json()
|
|
except httpx.HTTPStatusError as exc:
|
|
# Check if its a 404 error
|
|
if exc.response.status_code == status.HTTP_404_NOT_FOUND:
|
|
log.warning("Hasheous API returned 404 Not Found")
|
|
return {}
|
|
|
|
log.error(
|
|
"Hasheous API returned an error: %s %s",
|
|
exc.response.status_code,
|
|
exc.response.text,
|
|
)
|
|
raise HTTPException(
|
|
status_code=exc.response.status_code,
|
|
detail=f"Hasheous API error: {exc.response.text}",
|
|
) from exc
|
|
except httpx.NetworkError as exc:
|
|
log.critical("Connection error: can't connect to Hasheous")
|
|
raise HTTPException(
|
|
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
detail="Can't connect to Hasheous, check your internet connection",
|
|
) from exc
|
|
except json.decoder.JSONDecodeError as exc:
|
|
# Log the error and return an empty dict if the response is not valid JSON
|
|
log.error(exc)
|
|
return {}
|
|
except httpx.TimeoutException:
|
|
pass
|
|
|
|
return {}
|
|
|
|
def get_platform(self, slug: str) -> HasheousPlatform:
|
|
platform = HASHEOUS_PLATFORM_LIST.get(slug, None)
|
|
|
|
if not platform:
|
|
return HasheousPlatform(hasheous_id=None, slug=slug)
|
|
|
|
return HasheousPlatform(
|
|
hasheous_id=platform["id"],
|
|
slug=slug,
|
|
name=platform["name"],
|
|
igdb_id=platform["igdb_id"],
|
|
tgdb_id=platform["tgdb_id"],
|
|
ra_id=platform["ra_id"],
|
|
)
|
|
|
|
async def get_rom(self, rom_attrs: dict) -> HasheousRom:
|
|
fallback_rom = HasheousRom(hasheous_id=None)
|
|
|
|
if not HASHEOUS_API_ENABLED:
|
|
return fallback_rom
|
|
|
|
md5_hash = rom_attrs.get("md5_hash")
|
|
sha1_hash = rom_attrs.get("sha1_hash")
|
|
crc_hash = rom_attrs.get("crc_hash")
|
|
|
|
if not (md5_hash or sha1_hash or crc_hash):
|
|
log.warning(
|
|
"No hashes provided for Hasheous lookup. "
|
|
"At least one of md5_hash, sha1_hash, or crc_hash is required."
|
|
)
|
|
return fallback_rom
|
|
|
|
data = {}
|
|
if md5_hash:
|
|
data["mD5"] = md5_hash
|
|
if sha1_hash:
|
|
data["shA1"] = sha1_hash
|
|
if crc_hash:
|
|
data["crc"] = crc_hash
|
|
|
|
hasheous_game = await self._request(
|
|
self.games_endpoint,
|
|
params={
|
|
"returnAllSources": "true",
|
|
"returnFields": "Signatures, Metadata, Attributes",
|
|
},
|
|
data=data,
|
|
)
|
|
|
|
if not hasheous_game:
|
|
return fallback_rom
|
|
|
|
metadata = hasheous_game.get("metadata", [])
|
|
attributes = hasheous_game.get("attributes", [])
|
|
signatures = hasheous_game.get("signatures", {}).keys()
|
|
|
|
igdb_id = None
|
|
tgdb_id = None
|
|
ra_id = None
|
|
|
|
for meta in metadata:
|
|
if meta["source"] == "IGDB":
|
|
igdb_id = meta["immutableId"]
|
|
elif meta["source"] == "TheGamesDB":
|
|
tgdb_id = meta["immutableId"]
|
|
elif meta["source"] == "RetroAchievements":
|
|
ra_id = meta["immutableId"]
|
|
|
|
url_cover = ""
|
|
for attr in attributes:
|
|
if attr["attributeName"] == "Logo":
|
|
url_cover = f"https://hasheous.org{attr['link']}"
|
|
break
|
|
|
|
return HasheousRom(
|
|
hasheous_id=hasheous_game["id"],
|
|
name=hasheous_game.get("name", ""),
|
|
igdb_id=int(igdb_id) if igdb_id else None,
|
|
tgdb_id=int(tgdb_id) if tgdb_id else None,
|
|
ra_id=int(ra_id) if ra_id else None,
|
|
url_cover=url_cover,
|
|
hasheous_metadata=HasheousMetadata(
|
|
tosec_match="TOSEC" in signatures,
|
|
mame_arcade_match="MAMEArcade" in signatures,
|
|
mame_mess_match="MAMEMess" in signatures,
|
|
nointro_match="NoIntros" in signatures,
|
|
redump_match="Redump" in signatures,
|
|
whdload_match="WHDLoad" in signatures,
|
|
ra_match="RetroAchievements" in signatures,
|
|
fbneo_match="FBNeo" in signatures,
|
|
),
|
|
)
|
|
|
|
# Not in use while fibble works on the proxy
|
|
# async def get_igdb_game(
|
|
# self, hasheous_rom: HasheousRom, igdb_id: int
|
|
# ) -> HasheousRom:
|
|
# fallback_rom = HasheousRom(
|
|
# hasheous_id=None,
|
|
# igdb_id=None,
|
|
# tgdb_id=None,
|
|
# ra_id=None,
|
|
# )
|
|
|
|
# if not HASHEOUS_API_ENABLED:
|
|
# return fallback_rom
|
|
|
|
# if not igdb_id:
|
|
# log.warning("No IGDB ID provided for Hasheous IGDB game lookup.")
|
|
# return fallback_rom
|
|
|
|
# igdb_game = await self._request(
|
|
# self.proxy_igdb_game_endpoint,
|
|
# params={"Id": igdb_id},
|
|
# method="GET",
|
|
# )
|
|
|
|
# if not igdb_game:
|
|
# log.warning(f"No Hasheous game found for IGDB ID {igdb_id}.")
|
|
# return fallback_rom
|
|
|
|
# return HasheousRom(
|
|
# {
|
|
# **hasheous_rom,
|
|
# "slug": igdb_game.get("slug", ""),
|
|
# "name": igdb_game.get("name", ""),
|
|
# "summary": igdb_game.get("summary", ""),
|
|
# "url_cover": self._normalize_cover_url(
|
|
# igdb_game.get("cover", {}).get("url", "")
|
|
# ).replace("t_thumb", "t_1080p"),
|
|
# "url_screenshots": [
|
|
# self._normalize_cover_url(s.get("url", "")).replace(
|
|
# "t_thumb", "t_720p"
|
|
# )
|
|
# for s in igdb_game.get("screenshots", [])
|
|
# ],
|
|
# "igdb_metadata": extract_metadata_from_igdb_rom(igdb_game),
|
|
# }
|
|
# )
|
|
|
|
|
|
class SlugToHasheousId(TypedDict):
|
|
id: int
|
|
name: str
|
|
igdb_id: str | None
|
|
tgdb_id: int | None
|
|
ra_id: int | None
|
|
|
|
|
|
HASHEOUS_PLATFORM_LIST: dict[str, SlugToHasheousId] = {
|
|
"3do": {
|
|
"id": 161825,
|
|
"name": "3DO Interactive Multiplayer",
|
|
"igdb_id": "3do",
|
|
"tgdb_id": None,
|
|
"ra_id": 43,
|
|
},
|
|
"3ds": {
|
|
"id": 62,
|
|
"name": "Nintendo 3DS",
|
|
"igdb_id": "3ds",
|
|
"tgdb_id": None,
|
|
"ra_id": 62,
|
|
},
|
|
"64dd": {
|
|
"id": 65,
|
|
"name": "Nintendo 64DD",
|
|
"igdb_id": "64dd",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"acorn-archimedes": {
|
|
"id": 24,
|
|
"name": "Acorn Archimedes",
|
|
"igdb_id": "acorn-archimedes",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"acorn-electron": {
|
|
"id": 25,
|
|
"name": "Acorn Electron",
|
|
"igdb_id": "acorn-electron",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"acpc": {
|
|
"id": 28,
|
|
"name": "Amstrad CPC",
|
|
"igdb_id": "acpc",
|
|
"tgdb_id": None,
|
|
"ra_id": 37,
|
|
},
|
|
"action-max": {
|
|
"id": 232983,
|
|
"name": "Action Max",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"adventure-vision": {
|
|
"id": 234388,
|
|
"name": "Entex Adventure Vision",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"altair-8800": {
|
|
"id": 234456,
|
|
"name": "MITS Altair 8800",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"amiga": {
|
|
"id": 3,
|
|
"name": "Commodore Amiga",
|
|
"igdb_id": "amiga",
|
|
"tgdb_id": None,
|
|
"ra_id": 35,
|
|
},
|
|
"amiga-cd32": {
|
|
"id": 161823,
|
|
"name": "Commodore CD32",
|
|
"igdb_id": "amiga-cd32",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"amstrad-gx4000": {
|
|
"id": 61540,
|
|
"name": "Amstrad GX4000",
|
|
"igdb_id": "amstrad-gx4000",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"amstrad-pcw": {
|
|
"id": 29,
|
|
"name": "Amstrad PCW",
|
|
"igdb_id": "amstrad-pcw",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"apf": {
|
|
"id": 61738,
|
|
"name": "APF Imagination Machine",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"apple": {
|
|
"id": 61885,
|
|
"name": "Apple I",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"apple-iigs": {
|
|
"id": 21,
|
|
"name": "Apple IIGS",
|
|
"igdb_id": "apple-iigs",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"apple-lisa": {
|
|
"id": 69659,
|
|
"name": "Apple Lisa",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"apple-pippin": {
|
|
"id": 22,
|
|
"name": "Apple Pippin",
|
|
"igdb_id": "apple-pippin",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"apple2": {
|
|
"id": 20,
|
|
"name": "Apple II",
|
|
"igdb_id": "appleii",
|
|
"tgdb_id": None,
|
|
"ra_id": 38,
|
|
},
|
|
"apple2gs": {
|
|
"id": 21,
|
|
"name": "Apple IIGS",
|
|
"igdb_id": "apple-iigs",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"apple3": {
|
|
"id": 63154,
|
|
"name": "Apple III",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"appleii": {
|
|
"id": 20,
|
|
"name": "Apple II",
|
|
"igdb_id": "appleii",
|
|
"tgdb_id": None,
|
|
"ra_id": 38,
|
|
},
|
|
"appleiii": {
|
|
"id": 63154,
|
|
"name": "Apple III",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"aquarius": {
|
|
"id": 51,
|
|
"name": "Mattel Aquarius",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"arcade": {
|
|
"id": 178,
|
|
"name": "Arcade",
|
|
"igdb_id": "arcade",
|
|
"tgdb_id": None,
|
|
"ra_id": 27,
|
|
},
|
|
"arduboy": {
|
|
"id": 244294,
|
|
"name": "Arduboy",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"astrocade": {
|
|
"id": 31,
|
|
"name": "Bally Astrocade",
|
|
"igdb_id": "astrocade",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"atari-st": {
|
|
"id": 15,
|
|
"name": "Atari ST/STE",
|
|
"igdb_id": "atari-st",
|
|
"tgdb_id": None,
|
|
"ra_id": 36,
|
|
},
|
|
"atari2600": {
|
|
"id": 12,
|
|
"name": "Atari 2600",
|
|
"igdb_id": "atari2600",
|
|
"tgdb_id": None,
|
|
"ra_id": 25,
|
|
},
|
|
"atari5200": {
|
|
"id": 17,
|
|
"name": "Atari 5200",
|
|
"igdb_id": "atari5200",
|
|
"tgdb_id": None,
|
|
"ra_id": 50,
|
|
},
|
|
"atari7800": {
|
|
"id": 16,
|
|
"name": "Atari 7800",
|
|
"igdb_id": "atari7800",
|
|
"tgdb_id": None,
|
|
"ra_id": 51,
|
|
},
|
|
"atari8bit": {
|
|
"id": 18,
|
|
"name": "Atari 8-bit",
|
|
"igdb_id": "atari8bit",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"atom": {
|
|
"id": 55099,
|
|
"name": "Acorn Atom",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"bbcmicro": {
|
|
"id": 26,
|
|
"name": "BBC Micro",
|
|
"igdb_id": "bbcmicro",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"beena": {
|
|
"id": 82,
|
|
"name": "Sega Advanced Pico Beena",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"bit-90": {
|
|
"id": 97614,
|
|
"name": "Bit Corporation BIT 90",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"c-plus-4": {
|
|
"id": 7,
|
|
"name": "Commodore Plus/4",
|
|
"igdb_id": "c-plus-4",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"c128": {
|
|
"id": 8,
|
|
"name": "Commodore 128",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"c16": {
|
|
"id": 6,
|
|
"name": "Commodore 16",
|
|
"igdb_id": "c16",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"c64": {
|
|
"id": 5,
|
|
"name": "Commodore MAX",
|
|
"igdb_id": "c64",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"camputers-lynx": {
|
|
"id": 97720,
|
|
"name": "Camputers Lynx",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"casio-cfx-9850": {
|
|
"id": 97839,
|
|
"name": "Casio CFX-9850",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"casio-fp-1000": {
|
|
"id": 98757,
|
|
"name": "Casio FP-1000 & FP-1100",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"casio-loopy": {
|
|
"id": 37,
|
|
"name": "Casio Loopy",
|
|
"igdb_id": "casio-loopy",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"casio-pb-1000": {
|
|
"id": 98771,
|
|
"name": "Casio PB-1000",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"casio-pv-1000": {
|
|
"id": 98793,
|
|
"name": "Casio PV-1000",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"casio-pv-2000": {
|
|
"id": 98811,
|
|
"name": "Casio PV-2000",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"colecovision": {
|
|
"id": 39,
|
|
"name": "ColecoVision",
|
|
"igdb_id": "colecovision",
|
|
"tgdb_id": None,
|
|
"ra_id": 44,
|
|
},
|
|
"commander-x16": {
|
|
"id": 54769,
|
|
"name": "8-Bit Productions Commander X16",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"commodore-cdtv": {
|
|
"id": 9,
|
|
"name": "Commodore CDTV",
|
|
"igdb_id": "commodore-cdtv",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"cpet": {
|
|
"id": 10,
|
|
"name": "Commodore PET",
|
|
"igdb_id": "cpet",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"dc": {
|
|
"id": 54694,
|
|
"name": "Sega Dreamcast",
|
|
"igdb_id": "dc",
|
|
"tgdb_id": None,
|
|
"ra_id": 40,
|
|
},
|
|
"dos": {
|
|
"id": 233075,
|
|
"name": "Microsoft DOS",
|
|
"igdb_id": "dos",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"excalibur-64": {
|
|
"id": 97612,
|
|
"name": "BGR Computers Excalibur 64",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"fairchild-channel-f": {
|
|
"id": 43,
|
|
"name": "Fairchild Channel F",
|
|
"igdb_id": "fairchild-channel-f",
|
|
"tgdb_id": None,
|
|
"ra_id": 57,
|
|
},
|
|
"fds": {
|
|
"id": 54692,
|
|
"name": "Nintendo Famicom Disk System",
|
|
"igdb_id": "fds",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"fm-towns": {
|
|
"id": 238902,
|
|
"name": "Fujitsu - FM Towns",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"gamate": {
|
|
"id": 97616,
|
|
"name": "Bit Corporation Gamate",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"gamegear": {
|
|
"id": 84,
|
|
"name": "Sega Game Gear",
|
|
"igdb_id": "gamegear",
|
|
"tgdb_id": None,
|
|
"ra_id": 15,
|
|
},
|
|
"gb": {
|
|
"id": 70,
|
|
"name": "Nintendo GameBoy",
|
|
"igdb_id": "gb",
|
|
"tgdb_id": None,
|
|
"ra_id": 4,
|
|
},
|
|
"gba": {
|
|
"id": 71,
|
|
"name": "Nintendo Game Boy Advance",
|
|
"igdb_id": "gba",
|
|
"tgdb_id": None,
|
|
"ra_id": 5,
|
|
},
|
|
"gbc": {
|
|
"id": 72,
|
|
"name": "Nintendo Game Boy Color",
|
|
"igdb_id": "gbc",
|
|
"tgdb_id": None,
|
|
"ra_id": 6,
|
|
},
|
|
"genesis-slash-megadrive": {
|
|
"id": 86,
|
|
"name": "Sega Mega Drive / Genesis",
|
|
"igdb_id": "genesis-slash-megadrive",
|
|
"tgdb_id": None,
|
|
"ra_id": 1,
|
|
},
|
|
"intellivision": {
|
|
"id": 52,
|
|
"name": "Mattel Intellivision",
|
|
"igdb_id": "intellivision",
|
|
"tgdb_id": None,
|
|
"ra_id": 45,
|
|
},
|
|
"jaguar": {
|
|
"id": 13,
|
|
"name": "Atari Jaguar",
|
|
"igdb_id": "jaguar",
|
|
"tgdb_id": None,
|
|
"ra_id": 17,
|
|
},
|
|
"linux": {
|
|
"id": 233076,
|
|
"name": "Linux",
|
|
"igdb_id": "linux",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"lynx": {
|
|
"id": 14,
|
|
"name": "Atari Lynx",
|
|
"igdb_id": "lynx",
|
|
"tgdb_id": None,
|
|
"ra_id": 13,
|
|
},
|
|
"mac": {
|
|
"id": 30,
|
|
"name": "Apple Mac",
|
|
"igdb_id": "mac",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"microbee": {
|
|
"id": 69714,
|
|
"name": "Applied Technology MicroBee",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"msx": {"id": 53, "name": "MSX", "igdb_id": "msx", "tgdb_id": None, "ra_id": 29},
|
|
"msx2": {
|
|
"id": 54,
|
|
"name": "MSX 2",
|
|
"igdb_id": "msx2",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"multivision": {
|
|
"id": 52922,
|
|
"name": "Tsukuda Original Othello Multivision",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"n64": {
|
|
"id": 64,
|
|
"name": "Nintendo 64",
|
|
"igdb_id": "n64",
|
|
"tgdb_id": None,
|
|
"ra_id": 2,
|
|
},
|
|
"nds": {
|
|
"id": 66,
|
|
"name": "Nintendo DS",
|
|
"igdb_id": "nds",
|
|
"tgdb_id": None,
|
|
"ra_id": 18,
|
|
},
|
|
"nec-pc-6000-series": {
|
|
"id": 58,
|
|
"name": "NEC PC-6000",
|
|
"igdb_id": "nec-pc-6000-series",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"neo-geo-cd": {
|
|
"id": 161829,
|
|
"name": "Neo Geo CD",
|
|
"igdb_id": "neo-geo-cd",
|
|
"tgdb_id": None,
|
|
"ra_id": 56,
|
|
},
|
|
"neo-geo-pocket": {
|
|
"id": 97,
|
|
"name": "Neo Geo Pocket",
|
|
"igdb_id": "neo-geo-pocket",
|
|
"tgdb_id": None,
|
|
"ra_id": 14,
|
|
},
|
|
"neo-geo-pocket-color": {
|
|
"id": 98,
|
|
"name": "Neo Geo Pocket Color",
|
|
"igdb_id": "neo-geo-pocket-color",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"neogeoaes": {
|
|
"id": 96,
|
|
"name": "Neo Geo",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"nes": {
|
|
"id": 68,
|
|
"name": "Nintendo Entertainment System",
|
|
"igdb_id": "nes",
|
|
"tgdb_id": None,
|
|
"ra_id": 7,
|
|
},
|
|
"new-nintendo-3ds": {
|
|
"id": 63,
|
|
"name": "Nintendo New 3DS",
|
|
"igdb_id": "new-nintendo-3ds",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"ngc": {
|
|
"id": 73,
|
|
"name": "Nintendo GameCube",
|
|
"igdb_id": "ngc",
|
|
"tgdb_id": None,
|
|
"ra_id": 16,
|
|
},
|
|
"nintendo-dsi": {
|
|
"id": 67,
|
|
"name": "Nintendo DSi",
|
|
"igdb_id": "nintendo-dsi",
|
|
"tgdb_id": None,
|
|
"ra_id": 78,
|
|
},
|
|
"odyssey--1": {
|
|
"id": 48,
|
|
"name": "Magnavox Odyssey",
|
|
"igdb_id": "odyssey--1",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"odyssey-2-slash-videopac-g7000": {
|
|
"id": 49,
|
|
"name": "Magnavox Odyssey 2",
|
|
"igdb_id": "odyssey-2-slash-videopac-g7000",
|
|
"tgdb_id": None,
|
|
"ra_id": 23,
|
|
},
|
|
"pc-8800-series": {
|
|
"id": 57,
|
|
"name": "NEC PC-8800",
|
|
"igdb_id": "pc-8800-series",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"pc-9800-series": {
|
|
"id": 59,
|
|
"name": "NEC PC-9000",
|
|
"igdb_id": "pc-9800-series",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"pc-jr": {
|
|
"id": 233269,
|
|
"name": "IBM PCjr",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"philips-cd-i": {
|
|
"id": 161827,
|
|
"name": "Philips CD-i",
|
|
"igdb_id": "philips-cd-i",
|
|
"tgdb_id": None,
|
|
"ra_id": 42,
|
|
},
|
|
"pocket-challenge-v2": {
|
|
"id": 97550,
|
|
"name": "Benesse Pocket Challenge V2",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"pocket-challenge-w": {
|
|
"id": 97577,
|
|
"name": "Benesse Pocket Challenge W",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"pocketstation": {
|
|
"id": 103,
|
|
"name": "Sony PocketStation",
|
|
"igdb_id": "pocketstation",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"pokemon-mini": {
|
|
"id": 244733,
|
|
"name": "Nintendo Pokemon Mini",
|
|
"igdb_id": "pokemon-mini",
|
|
"tgdb_id": None,
|
|
"ra_id": 24,
|
|
},
|
|
"ps": {
|
|
"id": 100,
|
|
"name": "Sony PlayStation",
|
|
"igdb_id": "ps",
|
|
"tgdb_id": None,
|
|
"ra_id": 12,
|
|
},
|
|
"ps2": {
|
|
"id": 101,
|
|
"name": "Sony PlayStation 2",
|
|
"igdb_id": "ps2",
|
|
"tgdb_id": None,
|
|
"ra_id": 21,
|
|
},
|
|
"ps3": {
|
|
"id": 161830,
|
|
"name": "Sony Playstation 3",
|
|
"igdb_id": "ps3",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"ps4--1": {
|
|
"id": 232986,
|
|
"name": "Sony Playstation 4",
|
|
"igdb_id": "ps4--1",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"ps5": {
|
|
"id": 232987,
|
|
"name": "Sony Playstation 5",
|
|
"igdb_id": "ps5",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"psp": {
|
|
"id": 161831,
|
|
"name": "Sony Playstation Portable",
|
|
"igdb_id": "psp",
|
|
"tgdb_id": None,
|
|
"ra_id": 41,
|
|
},
|
|
"psvita": {
|
|
"id": 102,
|
|
"name": "Sony PlayStation Vita",
|
|
"igdb_id": "psvita",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"rca-studio-ii": {
|
|
"id": 234745,
|
|
"name": "RCA Studio II",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"saturn": {
|
|
"id": 54695,
|
|
"name": "Sega Saturn",
|
|
"igdb_id": "saturn",
|
|
"tgdb_id": None,
|
|
"ra_id": 39,
|
|
},
|
|
"sc3000": {
|
|
"id": 52165,
|
|
"name": "Sega Computer 3000",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"sega-pico": {
|
|
"id": 81,
|
|
"name": "Sega Pico",
|
|
"igdb_id": "sega-pico",
|
|
"tgdb_id": None,
|
|
"ra_id": 68,
|
|
},
|
|
"sega32": {
|
|
"id": 80,
|
|
"name": "Sega 32X",
|
|
"igdb_id": "sega32",
|
|
"tgdb_id": None,
|
|
"ra_id": 10,
|
|
},
|
|
"segacd": {
|
|
"id": 161828,
|
|
"name": "Sega Mega CD / Sega CD",
|
|
"igdb_id": "segacd",
|
|
"tgdb_id": None,
|
|
"ra_id": 9,
|
|
},
|
|
"series-x-s": {
|
|
"id": 232984,
|
|
"name": "Microsoft Xbox Series X",
|
|
"igdb_id": "series-x-s",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"sfam": {
|
|
"id": 233081,
|
|
"name": "Super Famicom",
|
|
"igdb_id": "sfam",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"sg1000": {
|
|
"id": 244470,
|
|
"name": "SG-1000",
|
|
"igdb_id": "sg1000",
|
|
"tgdb_id": None,
|
|
"ra_id": 33,
|
|
},
|
|
"sharp-x68000": {
|
|
"id": 90,
|
|
"name": "Sharp X68000",
|
|
"igdb_id": "sharp-x68000",
|
|
"tgdb_id": None,
|
|
"ra_id": 52,
|
|
},
|
|
"sinclair-ql": {
|
|
"id": 92,
|
|
"name": "Sinclair QL",
|
|
"igdb_id": "sinclair-ql",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"sinclair-zx81": {
|
|
"id": 94,
|
|
"name": "Sinclair ZX81",
|
|
"igdb_id": "sinclair-zx81",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"sms": {
|
|
"id": 85,
|
|
"name": "Sega Master System",
|
|
"igdb_id": "sms",
|
|
"tgdb_id": None,
|
|
"ra_id": 11,
|
|
},
|
|
"snes": {
|
|
"id": 74,
|
|
"name": "Super Nintendo Entertainment System",
|
|
"igdb_id": "snes",
|
|
"tgdb_id": None,
|
|
"ra_id": 3,
|
|
},
|
|
"super-vision-8000": {
|
|
"id": 97267,
|
|
"name": "Bandai Super Vision 8000",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"switch": {
|
|
"id": 233067,
|
|
"name": "Nintendo Switch",
|
|
"igdb_id": "switch",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"ti-82": {
|
|
"id": 47973,
|
|
"name": "Texas Instruments TI-82",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"ti-83": {
|
|
"id": 243852,
|
|
"name": "Texas Instruments TI-83",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"trs-80": {
|
|
"id": 105,
|
|
"name": "Tandy/RadioShack TRS-80",
|
|
"igdb_id": "trs-80",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"trs-80-color-computer": {
|
|
"id": 106,
|
|
"name": "Tandy/RadioShack TRS-80 Color Computer",
|
|
"igdb_id": "trs-80-color-computer",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"turbografx-16-slash-pc-engine-cd": {
|
|
"id": 247350,
|
|
"name": "Turbografx-16/PC Engine CD",
|
|
"igdb_id": "turbografx-16-slash-pc-engine-cd",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"turbografx16--1": {
|
|
"id": 245372,
|
|
"name": "TurboGrafx-16/PC Engine",
|
|
"igdb_id": "turbografx16--1",
|
|
"tgdb_id": None,
|
|
"ra_id": 8,
|
|
},
|
|
"vectrex": {
|
|
"id": 45,
|
|
"name": "Vectrex",
|
|
"igdb_id": "vectrex",
|
|
"tgdb_id": None,
|
|
"ra_id": 46,
|
|
},
|
|
"vic-20": {
|
|
"id": 4,
|
|
"name": "Commodore VIC20",
|
|
"igdb_id": "vic-20",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"virtualboy": {
|
|
"id": 75,
|
|
"name": "Nintendo Virtual Boy",
|
|
"igdb_id": "virtualboy",
|
|
"tgdb_id": None,
|
|
"ra_id": 28,
|
|
},
|
|
"watara-slash-quickshot-supervision": {
|
|
"id": 244828,
|
|
"name": "Watara Supervision",
|
|
"igdb_id": "watara-slash-quickshot-supervision",
|
|
"tgdb_id": None,
|
|
"ra_id": 63,
|
|
},
|
|
"wii": {
|
|
"id": 76,
|
|
"name": "Nintendo Wii",
|
|
"igdb_id": "wii",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"wiiu": {
|
|
"id": 77,
|
|
"name": "Nintendo WiiU",
|
|
"igdb_id": "wiiu",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"win": {
|
|
"id": 233074,
|
|
"name": "Microsoft Windows",
|
|
"igdb_id": "win",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"wonderswan": {
|
|
"id": 34,
|
|
"name": "Bandai WonderSwan",
|
|
"igdb_id": "wonderswan",
|
|
"tgdb_id": None,
|
|
"ra_id": 53,
|
|
},
|
|
"wonderswan-color": {
|
|
"id": 35,
|
|
"name": "Bandai WonderSwan Color",
|
|
"igdb_id": "wonderswan-color",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"x1": {"id": 89, "name": "Sharp X1", "igdb_id": "x1", "tgdb_id": None, "ra_id": 64},
|
|
"xbox": {
|
|
"id": 54696,
|
|
"name": "Microsoft Xbox",
|
|
"igdb_id": "xbox",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"xbox360": {
|
|
"id": 54697,
|
|
"name": "Microsoft Xbox 360",
|
|
"igdb_id": "xbox360",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"xboxone": {
|
|
"id": 161824,
|
|
"name": "Microsoft Xbox One",
|
|
"igdb_id": "xboxone",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"z88": {
|
|
"id": 97718,
|
|
"name": "Cambridge Computer Z88",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"zx80": {
|
|
"id": 232985,
|
|
"name": "Sinclair ZX80",
|
|
"igdb_id": "",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
"zxs": {
|
|
"id": 93,
|
|
"name": "Sinclair ZX Spectrum",
|
|
"igdb_id": "zxs",
|
|
"tgdb_id": None,
|
|
"ra_id": None,
|
|
},
|
|
}
|