mirror of
https://github.com/ldericher/fftcgtool
synced 2025-01-15 15:02:59 +00:00
inverted book.yml; card text formatting
This commit is contained in:
parent
eed07e4bb0
commit
2946bc81e4
5 changed files with 140 additions and 61 deletions
|
@ -4,6 +4,7 @@ import yaml
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from .cards import Cards
|
from .cards import Cards
|
||||||
|
from .code import Code
|
||||||
from .grid import Grid
|
from .grid import Grid
|
||||||
from .imageloader import ImageLoader
|
from .imageloader import ImageLoader
|
||||||
|
|
||||||
|
@ -55,24 +56,39 @@ class Book:
|
||||||
return self.__pages[index]["image"]
|
return self.__pages[index]["image"]
|
||||||
|
|
||||||
def save(self, filename: str) -> None:
|
def save(self, filename: str) -> None:
|
||||||
pages: dict[str, dict[str, any]]
|
book: dict[str, dict[str, any]]
|
||||||
|
|
||||||
# load pages.yml file
|
# load book.yml file
|
||||||
try:
|
try:
|
||||||
with open("pages.yml", "r") as file:
|
with open("book.yml", "r") as file:
|
||||||
pages = yaml.load(file, Loader=yaml.Loader)
|
book = yaml.load(file, Loader=yaml.Loader)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pages = {}
|
book = {}
|
||||||
|
|
||||||
# save book
|
# save book
|
||||||
for i, page in enumerate(self.__pages):
|
for i, page in enumerate(self.__pages):
|
||||||
fn = f"{filename}_{i}.jpg"
|
fn = f"{filename}_{i}.jpg"
|
||||||
# save page image
|
# save page image
|
||||||
page["image"].save(fn)
|
page["image"].save(fn)
|
||||||
# add contents of image
|
# add contents of that image
|
||||||
pages[fn] = {}
|
book[fn] = {"cards": page["cards"]}
|
||||||
pages[fn]["cards"] = page["cards"]
|
|
||||||
|
|
||||||
# update pages.yml file
|
# update book.yml file
|
||||||
with open("pages.yml", "w") as file:
|
with open("book.yml", "w") as file:
|
||||||
yaml.dump(pages, file, Dumper=yaml.Dumper)
|
yaml.dump(book, file, Dumper=yaml.Dumper)
|
||||||
|
|
||||||
|
# invert book
|
||||||
|
inverse_book: dict[Code, dict[str, any]] = {}
|
||||||
|
|
||||||
|
for fn, content in book.items():
|
||||||
|
inverse_book |= {
|
||||||
|
str(card.code): {
|
||||||
|
"card": card,
|
||||||
|
"file": fn,
|
||||||
|
"index": i
|
||||||
|
} for i, card in enumerate(content["cards"])
|
||||||
|
}
|
||||||
|
|
||||||
|
# write inverse_book.yml file
|
||||||
|
with open("inverse_book.yml", "w") as file:
|
||||||
|
yaml.dump(inverse_book, file, Dumper=yaml.Dumper)
|
||||||
|
|
|
@ -3,6 +3,32 @@ import re
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from .code import Code
|
||||||
|
|
||||||
|
|
||||||
|
def encircle_symbol(symbol: str, negative: bool):
|
||||||
|
symbol = symbol[0].upper()
|
||||||
|
|
||||||
|
base_symbols: tuple[str, str] = "", ""
|
||||||
|
if symbol.isalpha():
|
||||||
|
if negative:
|
||||||
|
base_symbols = "A", "🅐"
|
||||||
|
else:
|
||||||
|
base_symbols = "A", "Ⓐ"
|
||||||
|
elif symbol == "0":
|
||||||
|
if negative:
|
||||||
|
base_symbols = "0", "🄌"
|
||||||
|
else:
|
||||||
|
base_symbols = "0", "⓪"
|
||||||
|
elif symbol.isnumeric():
|
||||||
|
if negative:
|
||||||
|
base_symbols = "1", "➊"
|
||||||
|
else:
|
||||||
|
base_symbols = "1", "①"
|
||||||
|
|
||||||
|
symbol_num = ord(symbol) - ord(base_symbols[0])
|
||||||
|
return chr(ord(base_symbols[1]) + symbol_num)
|
||||||
|
|
||||||
|
|
||||||
class Card(yaml.YAMLObject):
|
class Card(yaml.YAMLObject):
|
||||||
yaml_tag = u'!Card'
|
yaml_tag = u'!Card'
|
||||||
|
@ -18,10 +44,10 @@ class Card(yaml.YAMLObject):
|
||||||
"闇": "Darkness"
|
"闇": "Darkness"
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, opus, serial, rarity, elements, name, text):
|
__ELEMENTS = "".join(__ELEMENTS_MAP.keys())
|
||||||
self.__opus = opus
|
|
||||||
self.__serial = serial
|
def __init__(self, code, elements, name, text):
|
||||||
self.__rarity = rarity
|
self.__code = code
|
||||||
self.__elements = elements
|
self.__elements = elements
|
||||||
self.__name = name
|
self.__name = name
|
||||||
self.__text = text
|
self.__text = text
|
||||||
|
@ -30,44 +56,41 @@ class Card(yaml.YAMLObject):
|
||||||
def from_data(cls, data: dict[str, any], language: str):
|
def from_data(cls, data: dict[str, any], language: str):
|
||||||
if not data:
|
if not data:
|
||||||
return cls(
|
return cls(
|
||||||
opus="0",
|
code=Code(""),
|
||||||
serial="000",
|
|
||||||
rarity="X",
|
|
||||||
elements=[],
|
elements=[],
|
||||||
name=None,
|
name=None,
|
||||||
text=None,
|
text=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if str(data["Code"])[0].isnumeric():
|
def sub_encircle(match: re.Match):
|
||||||
# card code starts with a number
|
return encircle_symbol(match.group(1), True)
|
||||||
opus, serial, rarity = \
|
|
||||||
re.match(r"([0-9]+)-([0-9]+)([CRHLS])", data["Code"]).groups()
|
|
||||||
|
|
||||||
elif str(data["Code"]).startswith("PR"):
|
def sub_elements(match: re.Match):
|
||||||
# card code starts with "PR"
|
return encircle_symbol(Card.__ELEMENTS_MAP[match.group(1)], True)
|
||||||
opus, serial = \
|
|
||||||
re.match(r"(PR)-([0-9]+)", data["Code"]).groups()
|
|
||||||
rarity = ""
|
|
||||||
|
|
||||||
elif str(data["Code"]).startswith("B"):
|
# load text
|
||||||
# card code starts with "B"
|
text = str(data[f"Text_{language}"])
|
||||||
opus, serial = \
|
# place "S" symbols
|
||||||
re.match(r"(B)-([0-9]+)", data["Code"]).groups()
|
text = text.replace("《S》", encircle_symbol("S", False))
|
||||||
rarity = ""
|
# place other letter and numerical cost symbols
|
||||||
|
text = re.sub(r"《([a-z0-9])》", sub_encircle, text, flags=re.IGNORECASE)
|
||||||
else:
|
# place elemental cost symbols
|
||||||
# card code not recognized
|
text = re.sub(rf"《([{Card.__ELEMENTS}])》", sub_elements, text, flags=re.IGNORECASE)
|
||||||
opus, serial, rarity = \
|
# place dull symbols
|
||||||
"?", "???", "?"
|
text = text.replace("《ダル》", "[⤵]")
|
||||||
|
# replace formatting hints with brackets
|
||||||
|
text = re.sub(r"\[\[[a-z]\]\]([^\[]*?)\s*\[\[/\]\]\s*", r"[\1] ", text, flags=re.IGNORECASE)
|
||||||
|
# place EX-BURST markers
|
||||||
|
text = re.sub(r"\[\[ex\]\]\s*EX BURST\s*\[\[/\]\]\s*", r"[EX BURST] ", text, flags=re.IGNORECASE)
|
||||||
|
# place line breaks
|
||||||
|
text = re.sub(r"\s*\[\[br\]\]\s*", "\n\n", text, flags=re.IGNORECASE)
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
opus=opus,
|
code=Code(data["Code"]),
|
||||||
serial=serial,
|
|
||||||
rarity=rarity,
|
|
||||||
elements=[Card.__ELEMENTS_MAP[element] for element in data["Element"].split("/")],
|
elements=[Card.__ELEMENTS_MAP[element] for element in data["Element"].split("/")],
|
||||||
name=data[f"Name_{language}"],
|
name=data[f"Name_{language}"],
|
||||||
text=data[f"Text_{language}"],
|
text=text,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
|
@ -78,20 +101,8 @@ class Card(yaml.YAMLObject):
|
||||||
|
|
||||||
# 6-048C
|
# 6-048C
|
||||||
@property
|
@property
|
||||||
def code(self) -> str:
|
def code(self) -> Code:
|
||||||
return f"{self.__opus}-{self.__serial}{self.__rarity}"
|
return self.__code
|
||||||
|
|
||||||
@property
|
|
||||||
def opus(self) -> str:
|
|
||||||
return self.__opus
|
|
||||||
|
|
||||||
@property
|
|
||||||
def serial(self) -> int:
|
|
||||||
return int(self.__serial)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def rarity(self) -> str:
|
|
||||||
return self.__rarity
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
|
|
|
@ -6,7 +6,7 @@ from .card import Card
|
||||||
class Cards(list[Card]):
|
class Cards(list[Card]):
|
||||||
__API_URL = "https://fftcg.square-enix-games.com/de/get-cards"
|
__API_URL = "https://fftcg.square-enix-games.com/de/get-cards"
|
||||||
|
|
||||||
def __init__(self, params: dict[str, any]):
|
def _load(self, params: dict[str, any]):
|
||||||
# required params:
|
# required params:
|
||||||
# text
|
# text
|
||||||
# supported params:
|
# supported params:
|
||||||
|
@ -18,7 +18,8 @@ class Cards(list[Card]):
|
||||||
params["text"] = ""
|
params["text"] = ""
|
||||||
|
|
||||||
req = requests.post(Cards.__API_URL, json=params)
|
req = requests.post(Cards.__API_URL, json=params)
|
||||||
super().__init__([Card.from_data(card_data, "EN") for card_data in req.json()["cards"]])
|
self.clear()
|
||||||
|
self.extend([Card.from_data(card_data, "EN") for card_data in req.json()["cards"]])
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return "\n".join(str(card) for card in self)
|
return "\n".join(str(card) for card in self)
|
||||||
|
|
49
fftcg/code.py
Normal file
49
fftcg/code.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
class Code(yaml.YAMLObject):
|
||||||
|
yaml_tag = u'!Code'
|
||||||
|
|
||||||
|
__RE_NUM = re.compile(r"([0-9]+)-([0-9]+)([CRHLS])")
|
||||||
|
__RE_PROMO = re.compile(r"(PR)-([0-9]+)")
|
||||||
|
__RE_BOSS = re.compile(r"(B)-([0-9]+)")
|
||||||
|
|
||||||
|
def __init__(self, code: str):
|
||||||
|
if code[0].isnumeric():
|
||||||
|
# card code starts with a number
|
||||||
|
self.__opus, self.__serial, self.__rarity = \
|
||||||
|
Code.__RE_NUM.match(code).groups()
|
||||||
|
|
||||||
|
elif code.startswith("PR"):
|
||||||
|
# card code starts with "PR"
|
||||||
|
self.__opus, self.__serial = \
|
||||||
|
Code.__RE_PROMO.match(code).groups()
|
||||||
|
self.__rarity = ""
|
||||||
|
|
||||||
|
elif code.startswith("B"):
|
||||||
|
# card code starts with "B"
|
||||||
|
self.__opus, self.__serial = \
|
||||||
|
Code.__RE_BOSS.match(code).groups()
|
||||||
|
self.__rarity = ""
|
||||||
|
|
||||||
|
else:
|
||||||
|
# card code not recognized
|
||||||
|
self.__opus, self.__serial, self.__rarity = \
|
||||||
|
"?", "???", "?"
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"{self.__opus}-{self.__serial}{self.__rarity}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def opus(self) -> str:
|
||||||
|
return self.__opus
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serial(self) -> int:
|
||||||
|
return int(self.__serial)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rarity(self) -> str:
|
||||||
|
return self.__rarity
|
|
@ -7,6 +7,8 @@ from .cards import Cards
|
||||||
|
|
||||||
class Opus(Cards):
|
class Opus(Cards):
|
||||||
def __init__(self, opus_id: str):
|
def __init__(self, opus_id: str):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
if opus_id.isnumeric():
|
if opus_id.isnumeric():
|
||||||
|
@ -33,16 +35,16 @@ class Opus(Cards):
|
||||||
self.__filename = "?"
|
self.__filename = "?"
|
||||||
params = {"set": "?"}
|
params = {"set": "?"}
|
||||||
|
|
||||||
super().__init__(params)
|
self._load(params)
|
||||||
|
|
||||||
# remove reprints
|
# remove reprints
|
||||||
for card in self:
|
for card in self:
|
||||||
if not card.code.startswith(self.__number + "-"):
|
if not card.code.opus == self.__number:
|
||||||
self.remove(card)
|
self.remove(card)
|
||||||
|
|
||||||
# sort cards by opus, then serial
|
# sort cards by opus, then serial
|
||||||
self.sort(key=lambda x: x.serial)
|
self.sort(key=lambda x: x.code.serial)
|
||||||
self.sort(key=lambda x: x.opus)
|
self.sort(key=lambda x: x.code.opus)
|
||||||
|
|
||||||
for card in self:
|
for card in self:
|
||||||
logger.info(f"imported card {card}")
|
logger.info(f"imported card {card}")
|
||||||
|
|
Loading…
Reference in a new issue