mirror of
https://github.com/ldericher/fftcgtool
synced 2025-01-15 15:02:59 +00:00
multilanguage support (breaks upload prompt)
This commit is contained in:
parent
77bc884eb6
commit
6ae0e00c2c
7 changed files with 81 additions and 70 deletions
|
@ -1,5 +1,6 @@
|
|||
import logging
|
||||
import os
|
||||
from dataclasses import replace
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
@ -14,8 +15,8 @@ class Book:
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
# sort cards by element, then alphabetically
|
||||
cards.sort(key=lambda x: x.name)
|
||||
cards.sort(key=lambda x: "Multi" if len(x.elements) > 1 else x.elements[0])
|
||||
# cards.sort(key=lambda x: x[""].name)
|
||||
# cards.sort(key=lambda x: "Multi" if len(x.elements) > 1 else x.elements[0])
|
||||
|
||||
# all card face URLs
|
||||
urls = [
|
||||
|
@ -35,6 +36,8 @@ class Book:
|
|||
for page_num, (page_images, page_cards) in enumerate(zip(
|
||||
chunks(GRID.capacity, images), chunks(GRID.capacity, cards)
|
||||
)):
|
||||
file_name = f"{cards.file_name}_{page_num}.jpg"
|
||||
|
||||
# create book page Image
|
||||
page_image = Image.new("RGB", GRID * RESOLUTION)
|
||||
logger.info(f"New image: {page_image.size[0]}x{page_image.size[1]}")
|
||||
|
@ -49,10 +52,11 @@ class Book:
|
|||
# set card indices
|
||||
for i, card in enumerate(page_cards):
|
||||
card.index = i
|
||||
card[language] = replace(card[language], face=file_name)
|
||||
|
||||
# save page
|
||||
self.__pages.append({
|
||||
"file_name": f"{cards.file_name}_{page_num}.jpg",
|
||||
"file_name": file_name,
|
||||
"image": page_image,
|
||||
"cards": page_cards,
|
||||
})
|
||||
|
@ -65,13 +69,3 @@ class Book:
|
|||
for page in self.__pages:
|
||||
page["file_name"] = os.path.join(IMAGES_DIR_NAME, page["file_name"])
|
||||
page["image"].save(page["file_name"])
|
||||
|
||||
# ask for upload
|
||||
for page in self.__pages:
|
||||
face_url = input(f"Upload '{page['file_name']}' and paste URL: ")
|
||||
|
||||
if not face_url:
|
||||
face_url = f"file://{os.path.abspath(page['file_name'])}"
|
||||
|
||||
for card in page["cards"]:
|
||||
card.face_url = face_url
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
|
||||
from .code import Code
|
||||
from .language import Language
|
||||
from .utils import encircle_symbol
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CardContent:
|
||||
name: str
|
||||
text: str
|
||||
face: str
|
||||
|
||||
|
||||
class Card:
|
||||
__ELEMENTS_JAP = [
|
||||
"火", "氷", "風", "土", "雷", "水", "光", "闇"
|
||||
|
@ -21,23 +29,19 @@ class Card:
|
|||
for elem_j, elem_e in zip(__ELEMENTS_JAP, __ELEMENTS_ENG)
|
||||
}
|
||||
|
||||
def __init__(self, code: Code, elements: list[str], name: str, text: str, face_url: str = "", index: int = 0):
|
||||
self.__code = code
|
||||
self.__elements = elements
|
||||
self.__name = name
|
||||
self.__text = text
|
||||
|
||||
self.__face_url = face_url
|
||||
def __init__(self, code: Code, elements: list[str], content: dict[Language, CardContent], index: int = 0):
|
||||
self.__code: Code = code
|
||||
self.__elements: list[str] = elements
|
||||
self.__content: dict[Language, CardContent] = content
|
||||
self.__index = index
|
||||
|
||||
@classmethod
|
||||
def from_square_api_data(cls, data: dict[str, any], language: Language) -> Card:
|
||||
def from_square_api_data(cls, data: dict[str, any]) -> Card:
|
||||
if not data:
|
||||
return cls(
|
||||
code=Code(""),
|
||||
elements=[],
|
||||
name="",
|
||||
text="",
|
||||
content={},
|
||||
)
|
||||
|
||||
else:
|
||||
|
@ -69,47 +73,48 @@ class Card:
|
|||
# place line breaks
|
||||
return re.sub(r"\s*\[\[br]]\s*", "\n\n", text, flags=re.IGNORECASE | re.UNICODE)
|
||||
|
||||
content = {
|
||||
language: CardContent(load_name(language), load_text(language), "")
|
||||
for language in Language.all_api_langs()
|
||||
}
|
||||
|
||||
return cls(
|
||||
code=Code(data["Code"]),
|
||||
elements=[
|
||||
Card.__ELEMENTS_MAP[element]
|
||||
for element in data["Element"].split("/")
|
||||
],
|
||||
name=load_name(language),
|
||||
text=load_text(language),
|
||||
content=content,
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Card(code={self.code!r}, name={self.name!r}, face_url={self.face_url!r})"
|
||||
return f"Card(code={self.code!r}, content={self.__content!r})"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"'{self.__name}' ({'/'.join(self.__elements)}, {self.code})"
|
||||
if self.__content:
|
||||
return f"'{self[''].name}' ({'/'.join(self.__elements)}, {self.code})"
|
||||
|
||||
def __getitem__(self, item: Language | str) -> CardContent:
|
||||
if isinstance(item, Language):
|
||||
return self.__content[item]
|
||||
else:
|
||||
return self.__content[Language(item)]
|
||||
|
||||
def __setitem__(self, key: Language | str, value: CardContent) -> None:
|
||||
if isinstance(key, Language):
|
||||
self.__content[key] = value
|
||||
else:
|
||||
self.__content[Language(key)] = value
|
||||
|
||||
# 6-048C
|
||||
@property
|
||||
def code(self) -> Code:
|
||||
return self.__code
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return self.__name
|
||||
|
||||
@property
|
||||
def text(self) -> str:
|
||||
return self.__text
|
||||
|
||||
@property
|
||||
def elements(self) -> list[str]:
|
||||
return self.__elements
|
||||
|
||||
@property
|
||||
def face_url(self) -> str:
|
||||
return self.__face_url
|
||||
|
||||
@face_url.setter
|
||||
def face_url(self, face_url: str) -> None:
|
||||
self.__face_url = face_url
|
||||
|
||||
@property
|
||||
def index(self) -> int:
|
||||
return self.__index
|
||||
|
|
|
@ -30,6 +30,9 @@ class Code:
|
|||
object.__setattr__(self, "serial", serial)
|
||||
object.__setattr__(self, "rarity", rarity)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.long
|
||||
|
||||
@property
|
||||
def short(self) -> str:
|
||||
return f"{self.opus}-{self.serial:03}"
|
||||
|
|
|
@ -35,3 +35,10 @@ class Language:
|
|||
return ""
|
||||
else:
|
||||
return "_EN"
|
||||
|
||||
@classmethod
|
||||
def all_api_langs(cls) -> set[Language]:
|
||||
return set([
|
||||
cls(short)
|
||||
for short in ["de", "en", "es", "fr", "it", "ja"]
|
||||
])
|
||||
|
|
|
@ -49,15 +49,17 @@ class Opus(Cards):
|
|||
|
||||
# get cards from square api
|
||||
req = requests.post(Opus.__SQUARE_API_URL, json=params)
|
||||
super().__init__(name, [
|
||||
Card.from_square_api_data(card_data, language)
|
||||
cards = [
|
||||
Card.from_square_api_data(card_data)
|
||||
for card_data in req.json()["cards"]
|
||||
])
|
||||
]
|
||||
|
||||
# remove reprints
|
||||
for card in self:
|
||||
if not card.code.opus == self.__number:
|
||||
self.remove(card)
|
||||
super().__init__(name, [
|
||||
card
|
||||
for card in cards
|
||||
if card.code.opus == self.__number
|
||||
])
|
||||
|
||||
# sort cards by opus, then serial
|
||||
self.sort(key=lambda x: x.code.serial)
|
||||
|
|
|
@ -8,6 +8,7 @@ import requests
|
|||
from .carddb import CardDB
|
||||
from .cards import Cards
|
||||
from .code import Code
|
||||
from .language import Language
|
||||
from .utils import CARD_BACK_URL, DECKS_DIR_NAME
|
||||
|
||||
|
||||
|
@ -23,18 +24,6 @@ class TTSDeck(Cards):
|
|||
for code in codes
|
||||
])
|
||||
|
||||
# unique face urls used
|
||||
unique_face_urls = set([
|
||||
card.face_url
|
||||
for card in self
|
||||
])
|
||||
|
||||
# lookup for indices of urls
|
||||
self.__url_indices = {
|
||||
url: i + 1
|
||||
for i, url in enumerate(unique_face_urls)
|
||||
}
|
||||
|
||||
__FFDECKS_API_URL = "https://ffdecks.com/api/deck"
|
||||
|
||||
@classmethod
|
||||
|
@ -49,8 +38,19 @@ class TTSDeck(Cards):
|
|||
|
||||
return cls(codes, name, description)
|
||||
|
||||
@property
|
||||
def tts_object(self) -> dict[str, any]:
|
||||
def tts_object(self, language: Language) -> dict[str, any]:
|
||||
# unique face urls used
|
||||
unique_faces = set([
|
||||
card[language].face
|
||||
for card in self
|
||||
])
|
||||
|
||||
# lookup for indices of urls
|
||||
url_indices = {
|
||||
url: i + 1
|
||||
for i, url in enumerate(unique_faces)
|
||||
}
|
||||
|
||||
# build the "CustomDeck" dictionary
|
||||
custom_deck = {
|
||||
str(i): {
|
||||
|
@ -58,7 +58,7 @@ class TTSDeck(Cards):
|
|||
"NumHeight": "7",
|
||||
"FaceURL": url,
|
||||
"BackURL": CARD_BACK_URL,
|
||||
} for url, i in self.__url_indices.items()
|
||||
} for url, i in url_indices.items()
|
||||
}
|
||||
|
||||
# values both in main deck and each contained card
|
||||
|
@ -81,9 +81,9 @@ class TTSDeck(Cards):
|
|||
# cards contained in deck
|
||||
contained_objects = [
|
||||
{
|
||||
"Nickname": card.name,
|
||||
"Description": card.text,
|
||||
"CardID": 100 * self.__url_indices[card.face_url] + card.index,
|
||||
"Nickname": card[language].name,
|
||||
"Description": card[language].text,
|
||||
"CardID": 100 * url_indices[card[language].face] + card.index,
|
||||
|
||||
"Name": "Card",
|
||||
"Hands": True,
|
||||
|
@ -112,11 +112,11 @@ class TTSDeck(Cards):
|
|||
} | common_dict
|
||||
]}
|
||||
|
||||
def save(self) -> None:
|
||||
def save(self, language: Language) -> None:
|
||||
# only save if the deck contains cards
|
||||
if self:
|
||||
if not os.path.exists(DECKS_DIR_NAME):
|
||||
os.mkdir(DECKS_DIR_NAME)
|
||||
|
||||
with open(os.path.join(DECKS_DIR_NAME, f"{self.file_name}.json"), "w") as file:
|
||||
json.dump(self.tts_object, file, indent=2)
|
||||
json.dump(self.tts_object(language), file, indent=2)
|
||||
|
|
2
main.py
2
main.py
|
@ -143,7 +143,7 @@ def main() -> None:
|
|||
|
||||
# call function based on args
|
||||
for deck in args.func(args):
|
||||
deck.save()
|
||||
deck.save(args.language)
|
||||
|
||||
# bye
|
||||
print("Done. Put the generated JSON files in your 'Saved Objects' Folder.")
|
||||
|
|
Loading…
Reference in a new issue