Source code for somerandomapi.clients.client

from __future__ import annotations

from typing import TYPE_CHECKING, Literal, Self, overload
import logging

import aiohttp

from .. import utils as _utils
from ..enums import WelcomeBackground, WelcomeTextColor, WelcomeType
from ..internals.endpoints import (
    Base as BaseEndpoint,
    CanvasMisc as CanvasMiscEndpoint,
    _Endpoint,
)
from ..internals.http import HTTPClient
from ..models.encoding import EncodeResult
from ..models.lyrics import Lyrics
from ..models.rgb import RGB
from ..models.welcome.free import WelcomeFree
from .abc import BaseClient
from .chatbot import Chatbot

if TYPE_CHECKING:
    from .animal import AnimalClient
    from .animu import AnimuClient
    from .canvas import CanvasClient
    from .pokemon import PokemonClient
    from .premium import PremiumClient


__all__ = ("Client",)

_log: logging.Logger = logging.getLogger(__name__)


[docs] class Client(BaseClient): """Client for interacting with the Some Random API. This class provides access to all endpoints of the Some Random API, including both free and premium features. Parameters ---------- session: :class:`aiohttp.ClientSession` An aiohttp session to use for HTTP requests. If not provided, the client will create and manage its own session. .. versionchanged:: 0.1.0 - If a session is provided, it will not be closed by the client. Otherwise, the client manages its own session. - This parameter can no longer be ``None``. Either pass a session or omit it entirely. token: str | None The token to use for endpoints that require it. .. versionadded:: 0.1.0 """ __slots__: tuple[str, ...] = (*(BaseClient.__slots__), "__chatbot") def __init__( self, token: str | None = None, *, session: aiohttp.ClientSession = _utils.NOVALUE, ) -> None: http = HTTPClient(token, session) super().__init__(http) self.__chatbot: Chatbot | None = None async def __aenter__(self) -> Self: return self async def __aexit__(self, *_: object) -> None: await self.close() @property def animu(self) -> AnimuClient: """:class:`.AnimuClient`: The Animu endpoint.""" return self._http._animu @property def animal(self) -> AnimalClient: """:class:`.AnimalClient`: The Animal endpoint.""" return self._http._animal @property def canvas(self) -> CanvasClient: """:class:`.CanvasClient`: The Canvas endpoint.""" return self._http._canvas @property def pokemon(self) -> PokemonClient: """:class:`.PokemonClient`: The Pokemon endpoint.""" return self._http._pokemon @property def premium(self) -> PremiumClient: """:class:`.PremiumClient`: The Premium endpoint.""" return self._http._premium
[docs] def chatbot(self, message: str | None = None) -> Chatbot: """Chatbot endpoint. Parameters ---------- message: Optional[:class:`str`] The message to send to the chatbot. If not provided, the Chatbot object will be returned instead which has a send method and supports ``async with`` else :class:`.ChatbotResult` will be returned. ``.response`` on that is the response from the chatbot. Example -------- .. code-block:: python async with client.chatbot() as bot: await bot.send("Hello!") print(bot.response) # or res = await client.chatbot("Hello!") print(res.response) Returns ------- Union[:class:`.Chatbot`, :class:`.ChatbotResult`] The Chatbot object or the ChatbotResult object. ``ChatbotResult`` is returned if ``message`` is provided and ``await`` is used else ``Chatbot``. """ if self.__chatbot: self.__chatbot.message = message return self.__chatbot self.__chatbot = Chatbot( message=message, client=self, ) return self.__chatbot
async def _handle_encode_decode( self, what: Literal["ENCODE", "DECODE"], name: Literal["base64", "binary"], _input: str ) -> EncodeResult: type_to_endpoint = {"base64": BaseEndpoint.BASE64, "binary": BaseEndpoint.BINARY} res = await self._http.request(type_to_endpoint[name], **{what.lower(): _input}) return EncodeResult.from_dict( _input=_input, _type=what.upper(), # pyright: ignore[reportArgumentType]] text=res[f"{what.lower()}d"], name=name.upper(), # pyright: ignore[reportArgumentType]] )
[docs] async def encode_base64(self, _input: str, /) -> EncodeResult: """Encode a string to base64. Parameters ---------- input: :class:`str` The string to encode. Returns ------- :class:`.EncodeResult` Object representing the result of the encoding. """ return await self._handle_encode_decode("ENCODE", "base64", _input)
[docs] async def decode_base64(self, _input: str, /) -> EncodeResult: """Decode a base64 string. Parameters ---------- input: :class:`str` The base64 string to decode. Returns ------- :class:`.EncodeResult` Object representing the result of the decoding. """ return await self._handle_encode_decode("DECODE", "base64", _input)
[docs] async def encode_binary(self, _input: str, /) -> EncodeResult: """Encode a string to binary. Parameters ---------- input: :class:`str` The string to encode. Returns ------- :class:`.EncodeResult` Object representing the result of the encoding. """ return await self._handle_encode_decode("ENCODE", "binary", _input)
[docs] async def decode_binary(self, _input: str) -> EncodeResult: """Decode a binary string. Parameters ---------- input: :class:`str` The binary string to decode. Returns ------- :class:`.EncodeResult` Object representing the result of the decoding. """ return await self._handle_encode_decode("DECODE", "binary", _input)
[docs] async def generate_bot_token(self) -> str: """:class:`str`: Generate a very realistic bot token""" res = await self._http.request( BaseEndpoint.BOTTOKEN, ) return res["token"]
[docs] async def lyrics(self, song_title: str) -> Lyrics: """Get the lyrics of a song. Parameters ---------- song_title: :class:`str` The title of the song to get the lyrics of. Returns ------- :class:`.Lyrics` Object representing the lyrics result. """ res = await self._http.request(BaseEndpoint.LYRICS, title=song_title) return Lyrics.from_dict(res)
[docs] async def random_joke(self) -> str: """Get a random joke. Returns ------- :class:`str` The joke. """ res = await self._http.request(BaseEndpoint.JOKE) return res["joke"]
@overload async def _handle_rgb_or_hex(self, endpoint: Literal[_Endpoint.CANVAS_RGB,], _input: str) -> RGB: ... @overload async def _handle_rgb_or_hex(self, endpoint: Literal[_Endpoint.CANVAS_HEX], _input: str) -> str: ... @overload async def _handle_rgb_or_hex(self, endpoint: Literal[_Endpoint.CANVAS_RGB], _input: str) -> RGB: ... async def _handle_rgb_or_hex( self, endpoint: Literal[_Endpoint.CANVAS_RGB, _Endpoint.CANVAS_HEX], _input: str ) -> RGB | str: endpoint_to_arg = {CanvasMiscEndpoint.RGB: "hex", CanvasMiscEndpoint.HEX: "rgb"} kwarga = {endpoint_to_arg[endpoint.value]: _input.strip("#")} res = await self._http.request(endpoint, **kwarga) if endpoint is _Endpoint.CANVAS_HEX: return res["hex"] return RGB.from_dict(res) # @_utils.endpoint(CanvasMiscEndpoint.HEX, to_call=_handle_rgb_or_hex)
[docs] async def rgb_to_hex(self, rgb: str) -> str: """Converts an RGB value to a hex value. Parameters ---------- rgb: :class:`str` The RGB value to convert. Must be in the format ``r,g,b``. Returns ------- :class:`str` The hex value. """ return await self._handle_rgb_or_hex(_Endpoint.CANVAS_HEX, rgb)
# @_utils.endpoint(CanvasMiscEndpoint.RGB, to_call=_handle_rgb_or_hex)
[docs] async def hex_to_rgb(self, _hex: str, /) -> RGB: """Converts a hex value to an RGB value. Parameters ---------- hex: :class:`str` The hex value to convert. Must be in the format ``123456`` or ``#123456``. Returns ------- :class:`.RGB` Object containing the RGB values. Use ``.as_tuple`` to get a tuple with the RGB values (``(r, g, b)``). """ return await self._handle_rgb_or_hex(_Endpoint.CANVAS_RGB, _hex)
@overload async def welcome_image( self, obj: WelcomeFree, ) -> WelcomeFree: ... @overload async def welcome_image( self, *, template: Literal[1, 2, 3, 4, 5, 6, 7], type: WelcomeType, background: WelcomeBackground, avatar_url: str, username: str, server_name: str, member_count: int, text_color: WelcomeTextColor, discriminator: int | None = ..., key: str | None = ..., font: Literal[0, 1, 2, 3, 4, 5, 6, 7] | None = ..., ) -> WelcomeFree: ...
[docs] async def welcome_image( self, obj: WelcomeFree = _utils.NOVALUE, *, template: Literal[1, 2, 3, 4, 5, 6, 7] = _utils.NOVALUE, type: WelcomeType = _utils.NOVALUE, # noqa: A002 background: WelcomeBackground = _utils.NOVALUE, avatar_url: str = _utils.NOVALUE, username: str = _utils.NOVALUE, server_name: str = _utils.NOVALUE, member_count: int = _utils.NOVALUE, text_color: WelcomeTextColor = _utils.NOVALUE, discriminator: int | None = _utils.NOVALUE, key: str | None = _utils.NOVALUE, font: Literal[0, 1, 2, 3, 4, 5, 6, 7] | None = _utils.NOVALUE, ) -> WelcomeFree: """Generate a welcome image. Parameters ---------- obj: :class:`.WelcomeFree` The object to use. If not passed, the other parameters will be used and a new object will be created. template: Literal[1, 2, 3, 4, 5, 6, 7, 8] The template to use. Required if ``obj`` is not passed. type: :class:`.WelcomeType` The type of welcome image to generate. Required if ``obj`` is not passed. background: :class:`.WelcomeBackground` The background to use. Required if ``obj`` is not passed. avatar_url: :class:`str` The avatar URL to use. Required if ``obj`` is not passed. username: :class:`str` The username to use. Required if ``obj`` is not passed. discriminator: :class:`int` The discriminator to use. server_name: :class:`str` The server name to use. Required if ``obj`` is not passed. member_count: :class:`int` The member count to use. Required if ``obj`` is not passed. text_color: :class:`.WelcomeTextColor` The text color to use. Required if ``obj`` is not passed. key: :class:`str` The key to use. Required if a key was not passed when creating the client. font: :class:`int` The font from a predefined list. Choose a number between 0 and 7. .. versionchanged:: 0.1.0 Now takes a range of 1-7 instead of 1-8. """ values = ( ("template", template, True), ("type", type, True), ("background", background, True), ("avatar_url", avatar_url, True), ("username", username, True), ("server_name", server_name, True), ("member_count", member_count, True), ("text_color", text_color, True), ("discriminator", discriminator, False), ("key", key, False), ("font", font, False), ) endpoint = BaseEndpoint.WELCOME obj = _utils._handle_obj_or_args(WelcomeFree, obj, values).copy() res = await self._http.request(endpoint, **obj.to_dict()) new = obj.copy() new._set_image(res) return new
[docs] async def close(self) -> None: """Close the client session.""" await self._http.close() if self.__chatbot: await self.__chatbot.close()