Source code for psnawp_api.models.game_title

"""Provides GameTitle class for retrieving Game details and trophies."""

from __future__ import annotations

import hashlib
import hmac
from typing import TYPE_CHECKING, Any, ClassVar

from typing_extensions import Self

from psnawp_api.core.psnawp_exceptions import PSNAWPIllegalArgumentError
from psnawp_api.models.listing import PaginationArguments
from psnawp_api.models.trophies import PlatformType, TrophyIterator, TrophyTitleIterator
from psnawp_api.models.trophies.trophy_group import (
    TrophyGroupsSummary,
    TrophyGroupsSummaryBuilder,
)
from psnawp_api.utils import API_PATH, BASE_PATH

if TYPE_CHECKING:
    from psnawp_api.core import Authenticator
    from psnawp_api.models.trophies import (
        TrophyGroupsSummary,
        TrophyGroupSummary,
    )


[docs] class GameTitle: """The GameTitle class provides the information and methods for retrieving Game details and trophies. Used for fetching game details and trophies for title that client doesn't own. :var Authenticator authenticator: An instance of :py:class:`~psnawp_api.core.authenticator.Authenticator` used to authenticate and make HTTPS requests. :var str title_id: Unique identifier for the game, used across PSN services except for trophy data, which requires the np_communication_id. However, the title_id is used to fetch the np_communication_id. :var PlatformType platform: The platform this title belongs to. :var str np_communication_id: Unique identifier associated with a game's trophy set, essential for accessing trophy data. .. note:: This class is intended to be used via PSNAWP. See :py:meth:`psnawp_api.psnawp.PSNAWP.game_title`. """ HMAC_SHA1_KEY: ClassVar[bytes] = bytes.fromhex( "F5DE66D2680E255B2DF79E74F890EBF349262F618BCAE2A9ACCDEE5156CE8DF2CDF2D48C71173CDC2594465B87405D197CF1AED3B7E9671EEB56CA6753C2E6B0" )
[docs] def __init__( self, authenticator: Authenticator, title_id: str, platform: PlatformType, np_communication_id: str, ) -> None: """The GameTitle class constructor. :param authenticator: The Authenticator instance used for making authenticated requests to the API. :param title_id: unique id of game. :param platform: The platform this title belongs to. :param np_communication_id: Unique ID of a game title used to request trophy information. """ self.authenticator = authenticator self.title_id = title_id self.platform = platform self.np_communication_id = np_communication_id
[docs] @classmethod def with_np_communication_id( cls, authenticator: Authenticator, title_id: str, platform: PlatformType, np_communication_id: str, ) -> Self: """Initialize instance of GameTitle class with ``np_communication_id`` provided. :param authenticator: The Authenticator instance used for making authenticated requests to the API. :param title_id: unique id of game. :param platform: The platform this title belongs to. :param np_communication_id: Unique ID of a game title used to request trophy information. :returns: Instance of :py:class:`GameTitle` """ return cls(authenticator, title_id, platform, np_communication_id)
[docs] @classmethod def from_title_id( cls, authenticator: Authenticator, title_id: str, platform: PlatformType, account_id: str, ) -> Self: """Initialize instance of GameTitle class from just the title_id. During the construction of the object, an additional call is made to get the ``np_communication_id``. This ID is important for getting trophy data. You can avoid this additional HTTP request by using the :py:meth:`with_np_communication_id` class method. :param authenticator: The Authenticator instance used for making authenticated requests to the API. :param title_id: unique id of game. :param platform: The platform this title belongs to. :returns: Instance of :py:class:`GameTitle` :raises PSNAWPNotFoundError: If the user does not have any trophies for that game or the game doesn't exist. """ np_communication_id = TrophyTitleIterator.get_np_communication_id( authenticator, title_id, account_id, ) return cls(authenticator, title_id, platform, np_communication_id)
[docs] def get_details(self, country: str | None = None, language: str | None = None) -> list[dict[str, Any]]: """Get game details such as full name, description, genre, promotional videos/images, etc... If `country` or `language` is not provided, defaults will be used from the authenticator headers. :param country: The country code used to retrieve localized content, in ISO 3166-1 alpha-2 format (e.g., "US", "JP"). :param language: The language code used to retrieve localized content, using the IETF BCP 47 format (e.g., "en-US", "fr-FR"). :returns: A list of dicts containing info similar to what is shown below (Not all values are shown because of space limitations): .. literalinclude:: ../examples/game_title/get_details.json :language: json """ country = country or self.authenticator.common_headers.get("Country", "US") language = language or self.authenticator.common_headers.get("Accept-Language", "en-US") param: dict[str, int | str] = {"age": 99, "country": country, "language": language} response: list[dict[str, Any]] = self.authenticator.get( url=f"{BASE_PATH['game_titles']}{API_PATH['title_concept'].format(title_id=self.title_id)}", params=param, ).json() return response
[docs] def trophies( self, trophy_group_id: str = "default", limit: int | None = None, offset: int = 0, page_size: int = 200, ) -> TrophyIterator: """Retrieves the individual trophy detail of a single - or all - trophy groups for a title. :param trophy_group_id: ID for the trophy group. Each game expansion is represented by a separate ID. all to return all trophies for the title, default for the game itself, and additional groups starting from 001 and so on return expansions trophies. :param limit: Limit of trophies returned, None means to return all trophy titles. :param offset: The starting point within the collection of trophies. :param page_size: The number of trophies to return per page. :returns: Returns the Trophy Generator object with all the information :raises PSNAWPNotFoundError: If you don't have any trophies for that game. """ pg_args = PaginationArguments( total_limit=limit, offset=offset, page_size=page_size, ) return TrophyIterator.from_endpoint( authenticator=self.authenticator, pagination_args=pg_args, np_communication_id=self.np_communication_id, platform=self.platform, trophy_group_id=trophy_group_id, )
[docs] def trophy_groups_summary( self, ) -> TrophyGroupsSummary[TrophyGroupSummary]: """Retrieves the trophy groups for a title and their respective trophy count. This is most commonly seen in games which have expansions where additional trophies are added. :returns: TrophyGroupSummary object containing title and title groups trophy information. :raises PSNAWPNotFoundError: If you don't have any trophies for that game. """ return TrophyGroupsSummaryBuilder( authenticator=self.authenticator, np_communication_id=self.np_communication_id, ).game_title_trophy_groups_summary(platform=self.platform)
[docs] def get_title_icon_url(self) -> str: """Generate/retrieve the title icon URL for a PlayStation 3/4 title. :returns: the title icon URL :raises PSNAWPIllegalArgumentError: If the platform is not supported. """ digest = hmac.new(type(self).HMAC_SHA1_KEY, self.title_id.encode(), hashlib.sha1).hexdigest().upper() if self.platform is PlatformType.PS3: return f"https://tmdb.np.dl.playstation.net/tmdb/{self.title_id}_{digest}/ICON0.PNG" if self.platform is PlatformType.PS4: json_url = f"https://tmdb.np.dl.playstation.net/tmdb2/{self.title_id}_{digest}/{self.title_id}.json" info: dict[str, Any] = self.authenticator.get(url=json_url).json() icon_url: str = info["icons"][0]["icon"] return icon_url raise PSNAWPIllegalArgumentError(f"Unsupported or unknown platform: {self.platform}")