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