Source code for pyKirara.client

# coding: utf-8

import requests
import json
import re
from functools import lru_cache

from .idol import Idol
from .card import Card
from .infos import Event, Gacha, Info
from .enums import enum, rarities
from .errors import CategoryNotFound, NotFound, NotValid

class KiraraException(Exception):
    def __init__(self, http_status, code, msg):
        self.http_status = http_status
        self.code = code
        self.msg = msg

    def __str__(self):
        return f"http status: {self.http_status} {self.code} - {self.msg}"

[docs]class Kirara(object): """A class that connects to the kirara api """ max_retries = 10 def __init__(self, requests_session=True, request_timeout=10): self.prefix = 'https://starlight.kirara.ca/api/v1/' self.request_timeout = request_timeout if isinstance(requests_session, requests.Session): self._session = requests_session else: if requests_session: self._session = requests.Session() else: from requests import api self._session = api def internal_call(self, method, url, payload, params): """Makes HTTP requests Parameters ---------- method : str method of making HTTP requests ('GET', 'POST', etc.) url : str The url to make HTTP requests to payload : str Any additional parameters to pass params : dict Parameters to pass to a dict Returns ---------- dict The result of the request in dict format """ args = dict(params=params) args["timeout"] = self.request_timeout if not url.startswith('http'): url = self.prefix + url if payload: args["data"] = json.dumps(payload) r = self._session.request(method, url, **args) try: r.raise_for_status() finally: r.connection.close() if r.text and len(r.text) > 0 and r.text != 'null': results = r.json() return results else: return None @lru_cache(maxsize=None) def get(self, url, args=None, payload=None, **kwargs): """Make GET requests Parameters ---------- url : str The url to the api (excluding the prefix url) args : dict Pass additional args payload : str Pass any additional parameters to request Returns ---------- dict The result of the GET request """ if args: kwargs.update(args) reconnect = self.max_retries while reconnect > 0: try: return self.internal_call('GET', url, payload, kwargs) except Exception as e: raise print('exception', str(e)) def post(self, url, args=None, payload=None, **kwargs): """Make POST requests Parameters ---------- url : str The url to the api (excluding the prefix url) args : dict Pass additional args payload : str Pass any additional parameters to request Returns ---------- dict The result of the POST request """ if args: kwargs.update(args) reconnect = self.max_retries while reconnect > 0: try: return self.internal_call('POST', url, payload, kwargs) except Exception as e: raise print('exception', str(e)) def translate(self, translations: tuple): """Translate a tuple of Japanese strings to English Parameters ---------- translate : tuple A tuple of eligible stings Returns --------- dict A dict of the translated text (JP:EN mapping) """ results = self.post('read_tl', payload=translations) return results
[docs] def get_idol(self, idol_id: int): """Retrieve an idol's info Parameters ---------- idol_id : int An Idol's ID to use from Returns ---------- Idol An Idol object, which contains the idol's info """ data = self.get("char_t/{0}".format(idol_id)) if data['result'][0] is not None: return Idol(data['result'][0]) else: raise NotFound("Idol ID can not be found in the Database. Is the ID correct?")
def get_idols(self, idol_ids: list): """Retrieve a list of Idols using a list IDs Parameters ---------- idol_ids : list A list of ints that represent idol IDs Returns ---------- list A list of idol objects """ idol_ids = str(idol_ids).replace('[', '').replace(']', '') idol_list = [] data = self.get('char_t/{0}'.format(idol_ids)) for idol in data['result']: idol_list.append(Idol(idol)) return idol_list
[docs] def get_card(self, card_id: int, en_translate=False): """Retrieve a card's data Parameters ---------- card_id : int A Card's ID to use from en_translate : bool Whether to translate the title, skill name, and lead skill to english Returns ---------- Card A Card object, which contains the card's info """ data = self.get("card_t/{0}".format(card_id)) if data['result'][0] is not None: card = Card(data['result'][0]) if en_translate: translations = [] translations.append(card.title) if card.skill is not None: translations.append(card.skill.name) if card.lead_skill is not None: translations.append(card.lead_skill.name) result = self.translate(tuple(translations)) for strings, translated in result.items(): if translated is None: translated = strings card.title = card.title if result.get(card.title) is None else result.get(card.title) if card.skill is not None: card.skill.name = card.skill.name if result.get( card.skill.name) is None else result.get(card.skill.name) if card.lead_skill is not None: card.lead_skill.name = card.title if result.get( card.lead_skill.name) is None else result.get(card.lead_skill.name) return card else: return card else: raise NotFound("Card ID can not be found in the Database. Is the ID correct?")
def get_cards(self, card_ids: list, en_translate=False): """Retrieve multiple cards using a list of card Ids Parameters ---------- card_ids : list A list of ints representing card ids en_translate : bool Whether to translate the card's JP text to EN Returns ---------- list A list of card objects """ card_ids = str(card_ids).replace('[', '').replace(']', '') card_list = [] data = self.get("card_t/{0}".format(card_ids)) for card_data in data['result']: card_list.append(Card(card_data)) if en_translate: translations = [] for string in card_list: translations.append(string.title) if string.skill is not None: translations.append(string.skill.name) if string.lead_skill is not None: translations.append(string.lead_skill.name) result = self.translate(tuple(translations)) for strings, translated in result.items(): if translated is None: translated = strings for card in card_list: card.title = card.title if result.get( card.title) is None else result.get(card.title) if card.skill is not None: card.skill.name = card.skill.name if result.get( card.skill.name) is None else result.get(card.skill.name) if card.lead_skill is not None: card.lead_skill.name = card.lead_skill.name if result.get( card.lead_skill.name) is None else result.get( card.lead_skill.name) return card_list
[docs] def get_version(self): """Retrieve the client's version Returns ---------- Info An Info object, which contains version info """ data = self.get('info') return Info(data)
[docs] def get_image(self, card: 'Card', category='card'): """Retrieve a Card's image data Parameters ---------- card : Card A card object to use catergory : str What type of image to use (Default value is 'card') Returns ---------- bytes The image bytes """ if type(card) is Card: categories = { 'card': card.image, 'icon': card.icon, 'spread': card.spread, 'sprite': card.sprite } if category in categories: image = categories.get(category) response = self._session.get(image) return response else: raise CategoryNotFound("Defined Category not valid, use 'card', 'icon', 'spread', or 'sprite'") else: raise NotValid("The passed object for card is not a Card object")
[docs] def get_now(self, category, en_translate=False): """Retrieve a list of occasions happenning in the game Parameters ---------- category : str What type of event to iterate from en_translate : bool Whether to translate the event's name Returns -------- list A list of gachas or events """ categories = { 'events': self.get("happening/now")['events'], 'gachas': self.get("happening/now")['gachas'] } happening_list = [] if category in categories: stuff = categories.get(category) for event in stuff: if category == 'events': happening_list.append(Event(event)) else: for event in stuff: # I don't know why you have to iterate again, maybe Im dumb happening_list.append(Gacha(event)) if en_translate: for thing in happening_list: translations = self.translate((thing.name,)) # Tuples are weird thing.name = translations.get(thing.name) return happening_list else: return happening_list
[docs] def get_id(self, category, name, card_rarity=None, position=None): """Find a specific id based on parameters given Parameters ---------- category : str Which category to search from ('card_t, or 'char_t') name : str An idol's name, full or just one part of a name card_rarity : str A rarity of card to look from (ranges from n to ssr, or n+ to ssr+) position : int Which card to get, based on release order Returns ---------- list A list of cards matching the parameters int An ID of a specfic idol, or card""" cat_list = self.get('list/{0}'.format(category))['result'] rarity = enum(rarities, card_rarity) card_list= [] for index, v in enumerate(cat_list): cat_name = cat_list[index]['conventional'].lower() match = bool(re.search(r"\b{0}\b".format(name), cat_name)) if category == 'char_t': if match: return int(cat_list[index]['chara_id']) elif category == 'card_t': if match: if card_rarity: if int(rarity) == cat_list[index]['rarity_dep']['rarity']: card_list.append(int(cat_list[index]['id'])) else: card_list.append(int(cat_list[index]['id'])) else: raise CategoryNotFound("Category not found: Use 'card_t',or 'char_t'") if position: return card_list[position-1] else: return card_list