mirror of
https://github.com/ldericher/fftcgtool
synced 2025-01-15 15:02:59 +00:00
fallback for nonexistent images, verbosity, logging output
This commit is contained in:
parent
ba58a99690
commit
0f6c7be504
5 changed files with 60 additions and 21 deletions
|
@ -19,11 +19,11 @@ class Book:
|
|||
|
||||
# all card face URLs
|
||||
urls = [
|
||||
f"https://fftcg.cdn.sewest.net/images/cards/full/{card.code}_{language.image_suffix}.jpg"
|
||||
("https://fftcg.cdn.sewest.net/images/cards/full/{}_{}.jpg", str(card.code), language.image_suffix)
|
||||
for card in cards
|
||||
]
|
||||
# card back URL
|
||||
urls.append(CARD_BACK_URL)
|
||||
urls.append((CARD_BACK_URL, "", ""))
|
||||
|
||||
# multi-threaded download
|
||||
images = ImageLoader.load(urls, num_threads)
|
||||
|
|
|
@ -1,33 +1,46 @@
|
|||
import io
|
||||
import logging
|
||||
import multiprocessing
|
||||
|
||||
import requests
|
||||
from PIL import Image
|
||||
|
||||
from .language import Language
|
||||
from .utils import RESOLUTION
|
||||
|
||||
# constants
|
||||
FALLBACK_LANGUAGE = Language("en")
|
||||
|
||||
|
||||
class ImageLoader:
|
||||
@classmethod
|
||||
def _load(cls, url: str) -> Image.Image:
|
||||
def _load_inner(cls, url_parts: tuple[str, str, str]) -> Image.Image:
|
||||
logger = logging.getLogger(__name__)
|
||||
base_url, code, lang_suffix = url_parts
|
||||
|
||||
# put together image url
|
||||
url = base_url.format(code, lang_suffix)
|
||||
logger.info(f"trying image {url}")
|
||||
|
||||
# fetch image (retry on fail)
|
||||
while True:
|
||||
logger.info(f"downloading image {url}")
|
||||
try:
|
||||
res = requests.get(url)
|
||||
image = Image.open(io.BytesIO(res.content))
|
||||
res = requests.get(url, stream=True)
|
||||
break
|
||||
|
||||
# unify images
|
||||
image.convert(mode="RGB")
|
||||
return image.resize(RESOLUTION, Image.BICUBIC)
|
||||
|
||||
except requests.exceptions.RequestException:
|
||||
except requests.RequestException:
|
||||
pass
|
||||
|
||||
# if rejected, substitute the english version
|
||||
if not res.status_code == 200:
|
||||
logger.warning(f"falling back to english version of {url}")
|
||||
return cls._load_inner((base_url, code, FALLBACK_LANGUAGE.image_suffix))
|
||||
|
||||
# unify images
|
||||
image = Image.open(res.raw)
|
||||
image.convert(mode="RGB")
|
||||
return image.resize(RESOLUTION, Image.BICUBIC)
|
||||
|
||||
@classmethod
|
||||
def load(cls, urls: list[str], num_threads: int) -> list[Image.Image]:
|
||||
def load(cls, urls_parts: list[tuple[str, str, str]], num_threads: int) -> list[Image.Image]:
|
||||
with multiprocessing.Pool(num_threads) as p:
|
||||
return p.map(ImageLoader._load, urls)
|
||||
return p.map(cls._load_inner, urls_parts)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
|
||||
class Language:
|
||||
def __init__(self, language: str):
|
||||
language = language.lower()
|
||||
|
@ -15,6 +18,12 @@ class Language:
|
|||
def __str__(self):
|
||||
return self.__short
|
||||
|
||||
def __hash__(self) -> hash:
|
||||
return hash(str(self))
|
||||
|
||||
def __eq__(self, other: Language):
|
||||
return str(self) == str(other)
|
||||
|
||||
@property
|
||||
def image_suffix(self):
|
||||
# supported languages for face URLs
|
||||
|
@ -32,4 +41,3 @@ class Language:
|
|||
return ""
|
||||
else:
|
||||
return "_EN"
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ from .ttsdeck import TTSDeck
|
|||
|
||||
|
||||
class Opus(Cards):
|
||||
__SQUARE_API_URL = "https://fftcg.square-enix-games.com/de/get-cards"
|
||||
__SQUARE_API_URL = "https://fftcg.square-enix-games.com/en/get-cards"
|
||||
|
||||
def __init__(self, opus_id: str, language: Language):
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -64,7 +64,7 @@ class Opus(Cards):
|
|||
self.sort(key=lambda x: x.code.opus)
|
||||
|
||||
for card in self:
|
||||
logger.info(f"imported card {card}")
|
||||
logger.debug(f"imported card {card}")
|
||||
|
||||
@property
|
||||
def number(self) -> str:
|
||||
|
|
26
main.py
26
main.py
|
@ -47,6 +47,12 @@ def main() -> None:
|
|||
description="Imports FFTCG cards for TT-Sim.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-v", "--verbose",
|
||||
help="increase output verbosity",
|
||||
action="count",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-l", "--language",
|
||||
type=fftcg.Language,
|
||||
|
@ -105,12 +111,25 @@ def main() -> None:
|
|||
help="the Deck to import",
|
||||
)
|
||||
|
||||
# parse arguments
|
||||
args = parser.parse_args()
|
||||
|
||||
# set up logging
|
||||
if args.verbose is None:
|
||||
args.verbose = logging.WARN
|
||||
elif args.verbose == 1:
|
||||
args.verbose = logging.INFO
|
||||
else:
|
||||
args.verbose = logging.DEBUG
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
level=args.verbose,
|
||||
format="%(levelname)s: %(processName)s %(message)s",
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.debug(f"{args = }")
|
||||
|
||||
# output directory
|
||||
if not os.path.exists(OUT_DIR_NAME):
|
||||
os.mkdir(OUT_DIR_NAME)
|
||||
|
@ -118,13 +137,12 @@ def main() -> None:
|
|||
os.chdir(OUT_DIR_NAME)
|
||||
|
||||
# call function based on args
|
||||
args = parser.parse_args()
|
||||
for deck in args.func(args):
|
||||
deck.save()
|
||||
|
||||
# bye
|
||||
logging.info("Done. Put the generated JSON files in your 'Saved Objects' Folder.")
|
||||
logging.info("Thanks for using fftcgtool!")
|
||||
print("Done. Put the generated JSON files in your 'Saved Objects' Folder.")
|
||||
print("Thanks for using fftcgtool!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
Loading…
Reference in a new issue