Files
website/tools/content/games.py
T

106 lines
3.6 KiB
Python

import igdb
import library_api
STATUSES = ["played", "playing", "planning", "replayable"]
STATUS_ORDER = {"playing": 0, "replayable": 1, "played": 2, "planning": 3}
PROFILE_FLAGS = {"favorite": "favorite", "liked": "liked"}
SUGGESTED_TAGS = ["Casual", "Competitive", "Love it", "Open to play", "Looking to discuss"]
def check_rating(rating: int | None) -> int | None:
if rating is not None and not 0 <= rating <= 10:
raise ValueError("Rating must be between 0 and 10")
return rating
def check_status(status: str) -> str:
if status not in STATUSES:
raise ValueError(f"Status must be one of {', '.join(STATUSES)}")
return status
def list_games() -> list[dict]:
games = library_api.fetch_library()["games"]
rating = lambda game: game["rating"] if game.get("rating") is not None else -1
return sorted(games, key=lambda game: (STATUS_ORDER[game["status"]], -rating(game), game["name"].lower()))
def lookup(link: str | None, name: str | None) -> dict:
return igdb.details(igdb.find_game(link or None, name or None))
def add_game(link: str | None, name: str | None, status: str = "played", rating: int | None = None, image: str | None = None) -> dict:
if not link and not name:
raise ValueError("Enter a store link, an IGDB link or a name")
check_status(status)
check_rating(rating)
found = lookup(link, name)
identifier = found.pop("igdbId")
if any(game["igdbId"] == identifier for game in list_games()):
raise ValueError(f"{found['name']} is already listed")
is_store_link = bool(link) and not igdb.IGDB_SLUG_PATTERN.search(link)
fields = {
**found,
"name": name or found["name"],
"url": link if is_store_link else None,
"status": status,
"rating": rating,
}
if image:
fields["imageSource"] = image
return library_api.save_game(identifier, fields)
def update_game(identifier: str, fields: dict) -> dict:
return library_api.save_game(identifier, fields)
def rate_game(identifier: str, rating: int | None) -> dict:
return update_game(identifier, {"rating": check_rating(rating)})
def set_status(identifier: str, status: str) -> dict:
return update_game(identifier, {"status": check_status(status)})
def set_dates(identifier: str, started: str | None, finished: str | None) -> dict:
return update_game(identifier, {"started": started, "finished": finished})
def set_links(identifier: str, url: str | None, image: str | None) -> dict:
fields = {"url": url}
if image:
fields["imageSource"] = image
return update_game(identifier, fields)
def toggle_flag(game: dict, flag: str) -> dict:
if flag not in PROFILE_FLAGS:
raise ValueError(f"{flag} is not one of {', '.join(PROFILE_FLAGS)}")
return update_game(game["igdbId"], {flag: not game.get(flag, False)})
def set_tags(identifier: str, tags_text: str | None, note: str | None) -> dict:
tags = [tag.strip() for tag in (tags_text or "").split(",") if tag.strip()]
return update_game(identifier, {"tags": tags, "note": note or None})
def profile_text(game: dict) -> str:
return ", ".join(label for flag, label in PROFILE_FLAGS.items() if game.get(flag)) or "-"
def remove_game(identifier: str) -> None:
library_api.delete_game(identifier)
def refresh_game(game: dict) -> dict:
result = igdb.game_by_id(game["igdbId"])
if not result:
raise ValueError(f"{game['name']} is no longer on IGDB")
found = igdb.details(result)
found.pop("igdbId", None)
found.pop("name", None)
if game.get("image"):
found.pop("imageSource", None)
return update_game(game["igdbId"], found)