From 3df591112318bd58d4b589b84e6434dcc613941c Mon Sep 17 00:00:00 2001 From: LDericher <40151420+ldericher@users.noreply.github.com> Date: Wed, 4 Aug 2021 03:39:19 +0200 Subject: [PATCH] image loader --- fftcg/book.py | 27 ++++++++++++++++++++ fftcg/card.py | 40 +++++++++++++++++++++++------ fftcg/cards.py | 27 ++++++++++++-------- fftcg/imageloader.py | 61 ++++++++++++++++++++++++++++++++++++++++++++ fftcg/opus.py | 9 +++++-- main.py | 4 +++ 6 files changed, 148 insertions(+), 20 deletions(-) create mode 100644 fftcg/book.py create mode 100644 fftcg/imageloader.py diff --git a/fftcg/book.py b/fftcg/book.py new file mode 100644 index 0000000..bb6133d --- /dev/null +++ b/fftcg/book.py @@ -0,0 +1,27 @@ +import queue + +from .imageloader import ImageLoader + + +class Book: + def __init__(self, cards): + self.__cards = cards + + def __get_pages(self, grid): + # cards per sheet + r, c = grid + capacity = r*c - 1 + # flat copy + cards = self.__cards + + # while there are cards + while cards: + # get a chunk + yield cards[:capacity] + # remove that chunk + cards = cards[capacity:] + + def populate(self, grid, resolution, threadnum=16): + card_queue = queue.Queue() + for i, card in enumerate(self.__cards): + card_queue.put((i, card)) diff --git a/fftcg/card.py b/fftcg/card.py index 1a0f8f2..4f43d18 100644 --- a/fftcg/card.py +++ b/fftcg/card.py @@ -2,40 +2,64 @@ import re class Card: - def __init__(self, data): + __ELEMENTS_MAP = { + '火': "Fire", + '氷': "Ice", + '風': "Wind", + '土': "Earth", + '雷': "Lightning", + '水': "Water", + '光': "Light", + '闇': "Darkness" + } + + def __init__(self, data, language="EN"): if not data: self.__opus = "0" self.__serial = "000" self.__rarity = "X" - self.__element = None - self.__description = None + self.__elements = None + self.__text = None else: if str(data["Code"])[0].isnumeric(): + # card code starts with a number self.__opus, self.__serial, self.__rarity = \ re.match(r'([0-9]+)-([0-9]+)([CRHLS])', data["Code"]).groups() elif str(data["Code"]).startswith("PR"): + # card code starts with "PR" self.__opus, self.__serial = \ re.match(r'(PR)-([0-9]+)', data["Code"]).groups() self.__rarity = "" elif str(data["Code"]).startswith("B"): + # card code starts with "B" self.__opus, self.__serial = \ re.match(r'(B)-([0-9]+)', data["Code"]).groups() self.__rarity = "" else: + # card code not recognized self.__opus, self.__serial, self.__rarity = \ "?", "???", "?" - self.__name = data["Name_EN"] - self.__element = data["Element"].split("/") - self.__description = data["Text_EN"] + self.__elements = [Card.__ELEMENTS_MAP[element] for element in data["Element"].split("/")] + self.__name = data[f"Name_{language}"] + self.__text = data[f"Text_{language}"] def __str__(self): - return f"'{self.__name}' ({self.__element}, {self.get_id()})" + return f"'{self.__name}' ({'/'.join(self.__elements)}, {self.get_code()})" # 6-048C - def get_id(self): + def get_code(self): return f"{self.__opus}-{self.__serial}{self.__rarity}" + + def get_name(self): + return self.__name + + def get_text(self): + return self.__text + + def get_elements(self): + return self.__elements diff --git a/fftcg/cards.py b/fftcg/cards.py index f027fc1..a775ac8 100644 --- a/fftcg/cards.py +++ b/fftcg/cards.py @@ -2,19 +2,26 @@ import requests from .card import Card -APIURL = "https://fftcg.square-enix-games.com/de/get-cards" +class Cards(list): + __API_URL = "https://fftcg.square-enix-games.com/de/get-cards" -class Cards: def __init__(self, params): - # supported params: - # [str] text (required) - # [array] type, element, cost, rarity, power, category_1, set - # [str] language, code, multicard="○"|"", ex_burst="○"|"", special="《S》"|"" - # [int] exactmatch=0|1 + list.__init__(self) - req = requests.post(APIURL, json=params) - self.__content = [Card(card_data) for card_data in req.json()["cards"]] + if isinstance(params, dict): + # required params: + # text + # supported params: + # [str] text, language, code, multicard="○"|"", ex_burst="○"|"", special="《S》"|"" + # [array] type, element, cost, rarity, power, category_1, set + # [int] exactmatch=0|1 + + req = requests.post(Cards.__API_URL, json=params) + self.extend([Card(card_data) for card_data in req.json()["cards"]]) + + elif isinstance(params, list): + self.extend(params) def __str__(self): - return "\n".join(str(card) for card in self.__content) + return "\n".join(str(card) for card in self) diff --git a/fftcg/imageloader.py b/fftcg/imageloader.py new file mode 100644 index 0000000..90c115d --- /dev/null +++ b/fftcg/imageloader.py @@ -0,0 +1,61 @@ +import io +import logging +import threading +import queue + +from PIL import Image +import requests + + +class ImageLoader(threading.Thread): + # Card faces by Square API + __FACE_URL = "https://fftcg.cdn.sewest.net/images/cards/full/{}_{}.jpg" + + # Card back image by Aurik + __BACK_URL = "http://cloud-3.steamusercontent.com/ugc/948455238665576576/85063172B8C340602E8D6C783A457122F53F7843/" + + def __init__(self, card_queue, resolution, language): + threading.Thread.__init__(self) + + self.__queue = card_queue + self.__resolution = resolution + self.__language = language + self.__images = {} + + def run(self) -> None: + logger = logging.getLogger(__name__) + while not self.__queue.empty(): + # take next card + i, card = self.__queue.get() + + # fetch card image (retry on fail) + while True: + logger.info("get image for card {}".format(card)) + try: + res = requests.get(ImageLoader.__FACE_URL.format(card.get_code(), self.__language)) + image = Image.open(io.BytesIO(res.content)) + image.convert("RGB") + image = image.resize(self.__resolution, Image.BICUBIC) + break + except: + pass + + # put image in correct position + self.__images[i] = image + + # image is processed + self.__queue.task_done() + + @classmethod + def spawn(cls, cards, resolution, language="eg", num_threads=16): + card_queue = queue.Queue() + for i, card in enumerate(cards): + card_queue.put((i, card)) + + for _ in range(num_threads): + cls(card_queue, resolution, language).start() + + return card_queue + + def get_images(self): + return self.__images diff --git a/fftcg/opus.py b/fftcg/opus.py index 39f0af0..3fc9aee 100644 --- a/fftcg/opus.py +++ b/fftcg/opus.py @@ -1,4 +1,4 @@ -from roman import toRoman +import roman from .cards import Cards @@ -6,7 +6,7 @@ from .cards import Cards class Opus(Cards): def __init__(self, number): if isinstance(number, int): - number = f"Opus {toRoman(number)}" + number = f"Opus {roman.toRoman(number)}" params = { "text": "", @@ -15,3 +15,8 @@ class Opus(Cards): } Cards.__init__(self, params) + + # sort every element alphabetically + self.sort(key=lambda x: x.get_code()) + self.sort(key=lambda x: x.get_name()) + self.sort(key=lambda x: "Multi" if len(x.get_elements()) > 1 else x.get_elements()[0]) diff --git a/main.py b/main.py index fa6da43..0c6d217 100755 --- a/main.py +++ b/main.py @@ -1,12 +1,16 @@ #!/usr/bin/env python3 from fftcg.opus import Opus +from fftcg.imageloader import ImageLoader def main(): opus = Opus(14) print(opus) + queue = ImageLoader.spawn(opus, (429, 600)) + queue.join() + if __name__ == '__main__': main()