Spaces:
Running
Running
| from dotenv import load_dotenv | |
| import os | |
| import requests | |
| from APIs.api_types import MetacriticType | |
| from difflib import SequenceMatcher | |
| from urllib.parse import quote | |
| class Metacritic: | |
| def __init__(self): | |
| load_dotenv() | |
| self.api_key = os.getenv("METACRITIC_API_KEY") | |
| def _score_ratio(self, score_obj: dict): | |
| score = score_obj.get("score", 0) | |
| num = 0 if score is None else score | |
| max = score_obj.get("max", 1) | |
| den = 1 if max is None else max | |
| return float(num) / float(den) | |
| def search(self, game_name: str, max_n: int = 1) -> list[MetacriticType]: | |
| """ | |
| Searches for games by name and retrieves details. | |
| Returns a list of MetacriticType objects. | |
| """ | |
| # Find name of the game in the Metacritic API | |
| find_url = f"https://backend.metacritic.com/finder/metacritic/search/{quote(game_name)}/web?apiKey={self.api_key}&limit={max_n+5}&offset=0" | |
| find_response = requests.get(find_url) | |
| find_response.raise_for_status() | |
| find_data = find_response.json() | |
| # No result found | |
| if not "data" in find_data: | |
| return [] | |
| # Start the return array | |
| metacritic_results = [] | |
| for item in find_data["data"]["items"]: | |
| if item["type"] == "game-title": | |
| # Match between names | |
| name_ratio = SequenceMatcher(None, item["title"], game_name).ratio() | |
| # Get game metadata | |
| game_slug = item["slug"] | |
| game_url = f"https://backend.metacritic.com/composer/metacritic/pages/games/{game_slug}/web?contentOnly=true" | |
| game_response = requests.get(game_url) | |
| game_response.raise_for_status() | |
| game_data = game_response.json() | |
| if not "components" in game_data or len(game_data["components"]) < 8: | |
| continue | |
| if not "data" in game_data["components"][0]: | |
| continue | |
| if not "data" in game_data["components"][6]: | |
| continue | |
| if not "data" in game_data["components"][8]: | |
| continue | |
| metadata = game_data["components"][0]["data"]["item"] | |
| critics_score = self._score_ratio(game_data["components"][6]["data"]["item"]) | |
| user_score = self._score_ratio(game_data["components"][8]["data"]["item"]) | |
| metacritic_obj = MetacriticType( | |
| name=metadata.get("title"), | |
| release=metadata.get("releaseDate", ""), | |
| developers=[company["name"] for company in metadata.get("production", {}).get("companies", []) if company["typeName"] == "Developer"], | |
| publishers=[company["name"] for company in metadata.get("production", {}).get("companies", []) if company["typeName"] == "Publisher"], | |
| genres=[genre["name"] for genre in metadata.get("genres", [])], | |
| platforms=[platform["name"] for platform in metadata.get("platforms", [])], | |
| metacritic_rating=critics_score, | |
| user_rating=user_score, | |
| ) | |
| metacritic_results.append((metacritic_obj, name_ratio)) | |
| # Sort by ratio of the name | |
| sorted_data = sorted(metacritic_results, key=lambda x: x[1], reverse=True) | |
| # Only return the max_n results | |
| return [obj for obj, ratio in sorted_data][:max_n] | |