mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 10:18:01 +00:00
239 lines
8.7 KiB
Python
239 lines
8.7 KiB
Python
#!/usr/bin/env python3
|
||
|
||
# This python script is designed to handle individual cards located in /res/cardsfolder/*
|
||
# Insert and update Oracle text into data files from scryfall oracle_cards bulk data
|
||
# Also rename script filename if the name is incorrect
|
||
|
||
import json
|
||
import fnmatch
|
||
import os
|
||
import re
|
||
import urllib.request
|
||
import unidecode
|
||
|
||
|
||
NAME_STR = 'Name:'
|
||
ORACLE_STR = 'Oracle:'
|
||
ALTERNATE_STR = 'AlternateMode:'
|
||
ALTERNATE_MARK = 'ALTERNATE'
|
||
ALTERNATE_SEPARATER = ' // '
|
||
tools_folder = os.path.dirname(os.path.realpath(__file__))
|
||
|
||
|
||
def download_oracle_cards():
|
||
'''Request Scryfall API to download oracle_cards json file'''
|
||
request = urllib.request.urlopen('https://api.scryfall.com/bulk-data')
|
||
data = json.load(request)['data']
|
||
scryfalldburl = [x for x in data if x['type'] == 'oracle_cards'][0]['download_uri']
|
||
urllib.request.urlretrieve(scryfalldburl, os.path.join(tools_folder, 'oracle_cards.json'))
|
||
|
||
|
||
def load_oracle_cards():
|
||
'''Load oracle card data from oracle_cards json file and build oracle cards dict'''
|
||
with open(os.path.join(tools_folder, 'oracle_cards.json'), 'r', encoding='utf8') as oracle_file:
|
||
oracle_json = json.load(oracle_file)
|
||
oracle_cards = {}
|
||
for card in oracle_json:
|
||
if (card['layout'] == 'token' and card['type_line'] != 'Dungeon'):
|
||
continue
|
||
name = unidecode.unidecode(card['name'])
|
||
oracle_cards[name] = card
|
||
return oracle_cards
|
||
|
||
|
||
def formalize_name(names):
|
||
name = '_'.join(names)
|
||
name = unidecode.unidecode(name)
|
||
name = name.lower()
|
||
name = name.replace('& ', '')
|
||
name = name.replace(' ', '_')
|
||
name = name.replace('-', '_')
|
||
name = name.replace(',', '')
|
||
name = name.replace('.', '')
|
||
name = name.replace(':', '')
|
||
name = name.replace("'", '')
|
||
name = name.replace('"', '')
|
||
name = name.replace('?', '')
|
||
name = name.replace('!', '')
|
||
name = name.replace('(', '')
|
||
name = name.replace(')', '')
|
||
return name
|
||
|
||
|
||
def read_card_script(cardfile):
|
||
names = []
|
||
oracle_texts = []
|
||
lines = []
|
||
line_num = 0
|
||
alternate_line = 0
|
||
alternate_mode = ''
|
||
for line in cardfile.readlines():
|
||
line = line.strip()
|
||
if line.startswith(NAME_STR):
|
||
names.append(line[len(NAME_STR):])
|
||
elif line.startswith(ALTERNATE_STR):
|
||
alternate_mode = line[len(ALTERNATE_STR):]
|
||
elif line.startswith(ALTERNATE_MARK):
|
||
alternate_line = line_num
|
||
elif line.startswith(ORACLE_STR):
|
||
oracle_texts.append([line_num, line[len(ORACLE_STR):]])
|
||
lines.append('')
|
||
line_num += 1
|
||
continue
|
||
lines.append(line + '\n')
|
||
line_num += 1
|
||
cardfile.close()
|
||
return names, lines, oracle_texts, alternate_mode, alternate_line
|
||
|
||
|
||
def write_card_script(cardfile, lines, oracle_texts):
|
||
line_num = 0
|
||
oracle_index = 0
|
||
for line in lines:
|
||
if oracle_index < len(oracle_texts) and line_num == oracle_texts[oracle_index][0]:
|
||
cardfile.write(ORACLE_STR + oracle_texts[oracle_index][1] + '\n')
|
||
oracle_index += 1
|
||
else:
|
||
cardfile.write(line)
|
||
line_num += 1
|
||
cardfile.close()
|
||
|
||
|
||
def update_oracle(name, lines, oracle_text, new_oracle, type_line, alternate_line):
|
||
updated = False
|
||
# Update type line first
|
||
type_line = type_line.replace('Summon', 'Creature')
|
||
type_line = type_line.replace('’', "'")
|
||
for i, line in enumerate(lines):
|
||
if i <= alternate_line:
|
||
continue
|
||
if line.startswith('Types:'):
|
||
if line[6:].rstrip() != type_line:
|
||
lines[i] = 'Types:' + type_line + '\n'
|
||
updated = True
|
||
break
|
||
|
||
is_planeswalker = type_line.find('Planeswalker') != -1
|
||
if is_planeswalker:
|
||
new_oracle = re.sub(r'([\+−]?[0-9X]+):', r'[\1]:', new_oracle)
|
||
new_oracle = new_oracle.replace('\n', '\\n')
|
||
if oracle_text[1] == new_oracle:
|
||
return updated
|
||
|
||
oracle_lines = oracle_text[1].split('\\n')
|
||
new_lines = new_oracle.split('\\n')
|
||
nickname = name.split(', ')[0]
|
||
oracle_text[1] = new_oracle
|
||
updated = True
|
||
|
||
if len(oracle_lines) != len(new_lines):
|
||
return updated
|
||
|
||
# Also replace descriptions
|
||
for org_line, new_line in zip(oracle_lines, new_lines):
|
||
org_line = org_line.replace(name, 'CARDNAME')
|
||
org_line = org_line.replace(nickname, 'NICKNAME')
|
||
org_line = org_line.replace('|', 'VERT')
|
||
if org_line.find(':') != -1:
|
||
if org_line.find('"') == -1 or org_line.find('"') > org_line.find(':'):
|
||
org_line = org_line[org_line.find(':') + 1:].lstrip()
|
||
if org_line.find('• ') != -1:
|
||
org_line = org_line[org_line.find('• ') + 2:].lstrip()
|
||
if len(org_line) == 0:
|
||
continue
|
||
new_line = new_line.replace(name, 'CARDNAME')
|
||
new_line = new_line.replace(nickname, 'NICKNAME')
|
||
new_line = new_line.replace('|', 'VERT')
|
||
if new_line.find(':') != -1:
|
||
if new_line.find('"') == -1 or new_line.find('"') > new_line.find(':'):
|
||
new_line = new_line[new_line.find(':') + 1:].lstrip()
|
||
if new_line.find('• ') != -1:
|
||
new_line = new_line[new_line.find('• ') + 2:].lstrip()
|
||
for i, line in enumerate(lines):
|
||
if line.startswith('K:'):
|
||
continue
|
||
if line.find(org_line) != -1:
|
||
lines[i] = line.replace(org_line, new_line)
|
||
|
||
return updated
|
||
|
||
def update_card_script(dirname, filename, oracle_cards, logfile):
|
||
file = open(os.path.join(dirname, filename), 'r', encoding='utf8')
|
||
clean_name = filename.replace('.txt', '')
|
||
|
||
names, lines, oracle_texts, alternate_mode, alternate_line = read_card_script(file)
|
||
formal_name = formalize_name(names)
|
||
if clean_name != formal_name:
|
||
logfile.write(f'Rename "{clean_name}" => "{formal_name}"\n')
|
||
print(f'Rename "{clean_name}" => "{formal_name}"')
|
||
full_org_filename = os.path.join(dirname, filename)
|
||
full_new_filename = os.path.join(dirname, formal_name + '.txt')
|
||
filename = formal_name + '.txt'
|
||
os.system(f'git mv "{full_org_filename}" "{full_new_filename}"')
|
||
|
||
oracle_updated = False
|
||
if alternate_mode == 'Meld':
|
||
cardname = names[0]
|
||
else:
|
||
cardname = ALTERNATE_SEPARATER.join(names)
|
||
if cardname not in oracle_cards:
|
||
logfile.write(f'Skipped unknown card {formal_name}\n')
|
||
print(f'Skipped unknown card {formal_name}')
|
||
return
|
||
|
||
card = oracle_cards[cardname]
|
||
if len(names) == 1:
|
||
type_line = card['type_line'].replace(' — ', ' ')
|
||
is_vanguard = card['type_line'].find('Vanguard') != -1
|
||
new_oracle = card['oracle_text']
|
||
if is_vanguard:
|
||
new_oracle = 'Hand {0}, life {1}\n'.format(card['hand_modifier'], card['life_modifier']) + new_oracle
|
||
oracle_updated = update_oracle(names[0], lines, oracle_texts[0], new_oracle, type_line, 0)
|
||
elif len(names) == 2:
|
||
if alternate_mode == 'Meld':
|
||
type_line = card['type_line'].replace(' — ', ' ')
|
||
new_oracle = card['oracle_text']
|
||
oracle_updated = update_oracle(names[0], lines, oracle_texts[0], new_oracle, type_line, 0)
|
||
card = oracle_cards[names[1]]
|
||
type_line = card['type_line'].replace(' — ', ' ')
|
||
new_oracle = card['oracle_text']
|
||
oracle_updated = oracle_updated | update_oracle(names[1], lines, oracle_texts[1], new_oracle, type_line, alternate_line)
|
||
else:
|
||
for i, face in enumerate(card['card_faces']):
|
||
type_line = face['type_line'].replace(' — ', ' ')
|
||
new_oracle = face['oracle_text']
|
||
if i == 0:
|
||
oracle_updated = oracle_updated | update_oracle(names[i], lines, oracle_texts[i], new_oracle, type_line, 0)
|
||
else:
|
||
oracle_updated = oracle_updated | update_oracle(names[i], lines, oracle_texts[i], new_oracle, type_line, alternate_line)
|
||
|
||
|
||
if not oracle_updated:
|
||
return
|
||
|
||
logfile.write(f'Updated {formal_name}\n')
|
||
print(f'Updated {formal_name}')
|
||
file = open(os.path.join(dirname, filename), 'w', encoding='utf8')
|
||
write_card_script(file, lines, oracle_texts)
|
||
full_filename = os.path.join(dirname, filename)
|
||
os.system(f'git add {full_filename}')
|
||
|
||
|
||
def main():
|
||
# download_oracle_cards()
|
||
oracle_cards = load_oracle_cards()
|
||
|
||
folder = os.path.join(tools_folder, '..', 'res', 'cardsfolder')
|
||
logfile = open(os.path.join(tools_folder, 'oracleScript.log'), 'w')
|
||
|
||
for root, dirnames, filenames in os.walk(folder):
|
||
for filename in fnmatch.filter(filenames, '*.txt'):
|
||
if filename.startswith('.'):
|
||
continue
|
||
update_card_script(root, filename, oracle_cards, logfile)
|
||
|
||
logfile.close()
|
||
|
||
if __name__ == '__main__':
|
||
main()
|