Added ability to parse JSON files exported from Foundry.

This commit is contained in:
Mark Wolfman
2021-05-21 09:47:40 -05:00
parent 9b1a33bfa2
commit 90e362055a
9 changed files with 3599 additions and 171 deletions
+57 -104
View File
@@ -21,105 +21,25 @@ from dungeonsheets.fill_pdf_template import (
)
from dungeonsheets.character import Character
"""Program to take character definitions and build a PDF of the
character sheet."""
PDFTK_CMD = "pdftk"
log = logging.getLogger(__name__)
ORDINALS = {
1: "1st",
2: "2nd",
3: "3rd",
4: "4th",
5: "5th",
6: "6th",
7: "7th",
2: "2nd",
3: "3rd",
4: "4th",
5: "5th",
6: "6th",
7: "7th",
8: "8th",
9: "9th"
9: "9th",
}
"""Program to take character definitions and build a PDF of the
character sheet."""
bold_re = re.compile(r"\*\*([^*]+)\*\*")
it_re = re.compile(r"\*([^*]+)\*")
verb_re = re.compile(r"``([^`]+)``")
heading_re = re.compile(r"^[ \t\r\f\v]*(.+)\n\s*([-=\^]+)$", flags=re.MULTILINE)
# What defines a list in reST:
# - a blank line
# - one or more of the following
# - "- [a-z]"
# - an additional line of text (if multi-line bullets)
# - a blank line
# - a blank line
# - a non-list line or end of file
# list_re = re.compile('^[ \t\r\f\v]*\n((?:\s*[-*+]\s+[^\n]*\n)+)', flags=re.MULTILINE)
list_re = re.compile(
r"^[ \t\r\f\v]*\n" # A blank line
r"((?:\s*[-*+]\s+[^\n]*\n)+)" # The first line of each list item
"",
flags=re.MULTILINE,
)
# What defines a list item in reST:
# - a line starting with "- " then some text
# - zero or more lines starting with anything other than "- "
list_item_re = re.compile(r"^\s*[-*+]\s+", flags=re.MULTILINE)
def _parse_rst_lists(rst):
"""Read lists in reST and iterate.
Yields
======
list_rst : str
The matching reST list found in the input text
list_items : list
A python list of the items found in the reST list.
"""
for match in list_re.finditer(rst):
list_rst = match.group(0)
# Separate the list items
list_items = list_item_re.split(match.group(1))
# Clean up separated list items
list_items = list_items[1:] # First item is an empty string
list_items = [item.replace("\n", " ").strip() for item in list_items]
yield list_rst, list_items
def _parse_rst_headings(rst):
"""Read headings in reST and iterate.
Yields
======
heading_rst : str
The matching reST heading found in the input text.
heading : str
The text of the heading with underlining removed.
level : int
How deep the heading is: 0 is top-level, 1 is next level down,
etc.
"""
heading_levels = {
"=": 0,
"-": 1,
"^": 2,
}
for match in heading_re.finditer(rst):
heading_rst = match.group(0)
heading, underline = match.groups()
# Check for valid heading
if len(underline) < len(heading):
log.debug("Skipping malformed reST heading: '%s\n%s'", heading, underline)
continue
if len(set(underline)) > 1:
log.debug("Skipping malformed reST heading: '%s\n%s'", heading, underline)
continue
# Valid heading, so determine how many levels deep it is
level = heading_levels[underline[0]]
yield heading_rst, heading, level
jinja_env = Environment(
loader=PackageLoader("dungeonsheets", "forms"),
block_start_string="[%",
@@ -141,6 +61,7 @@ def create_subclasses_tex(
template = jinja_env.get_template("subclasses_template.tex")
return template.render(character=character, use_dnd_decorations=use_dnd_decorations)
def create_features_tex(
character: Character,
use_dnd_decorations: bool = False,
@@ -148,6 +69,7 @@ def create_features_tex(
template = jinja_env.get_template("features_template.tex")
return template.render(character=character, use_dnd_decorations=use_dnd_decorations)
def create_magic_items_tex(
character: Character,
use_dnd_decorations: bool = False,
@@ -155,12 +77,16 @@ def create_magic_items_tex(
template = jinja_env.get_template("magic_items_template.tex")
return template.render(character=character, use_dnd_decorations=use_dnd_decorations)
def create_spellbook_tex(
character: Character,
use_dnd_decorations: bool = False,
) -> str:
template = jinja_env.get_template("spellbook_template.tex")
return template.render(character=character, ordinals=ORDINALS, use_dnd_decorations=use_dnd_decorations)
return template.render(
character=character, ordinals=ORDINALS, use_dnd_decorations=use_dnd_decorations
)
def create_infusions_tex(
character: Character,
@@ -169,6 +95,7 @@ def create_infusions_tex(
template = jinja_env.get_template("infusions_template.tex")
return template.render(character=character, use_dnd_decorations=use_dnd_decorations)
def create_druid_shapes_tex(
character: Character,
use_dnd_decorations: bool = False,
@@ -211,7 +138,11 @@ def make_sheet(
char_base = os.path.splitext(character_file)[0] + "_char"
sheets = [char_base + ".pdf"]
pages = []
tex = [jinja_env.get_template("preamble.tex").render(use_dnd_decorations=fancy_decorations)]
tex = [
jinja_env.get_template("preamble.tex").render(
use_dnd_decorations=fancy_decorations
)
]
# Start of PDF gen
char_pdf = create_character_pdf_template(
@@ -230,33 +161,54 @@ def make_sheet(
features_base = "{:s}_features".format(os.path.splitext(character_file)[0])
# Create a list of subcasses
if character.subclasses:
tex.append(create_subclasses_tex(character, use_dnd_decorations=fancy_decorations))
tex.append(
create_subclasses_tex(character, use_dnd_decorations=fancy_decorations)
)
# Create a list of features
if character.features:
tex.append(create_features_tex(character, use_dnd_decorations=fancy_decorations))
tex.append(
create_features_tex(character, use_dnd_decorations=fancy_decorations)
)
if character.magic_items:
tex.append(create_magic_items_tex(character, use_dnd_decorations=fancy_decorations))
tex.append(
create_magic_items_tex(character, use_dnd_decorations=fancy_decorations)
)
# Create a list of spells
if character.is_spellcaster:
tex.append(create_spellbook_tex(character, use_dnd_decorations=fancy_decorations))
tex.append(
create_spellbook_tex(character, use_dnd_decorations=fancy_decorations)
)
# Create a list of Artificer infusions
if getattr(character, "infusions", []):
tex.append(create_infusions_tex(character, use_dnd_decorations=fancy_decorations))
tex.append(
create_infusions_tex(character, use_dnd_decorations=fancy_decorations)
)
# Create a list of Druid wild_shapes
if getattr(character, "wild_shapes", []):
tex.append(create_druid_shapes_tex(character, use_dnd_decorations=fancy_decorations))
tex.append(jinja_env.get_template("postamble.tex").render(use_dnd_decorations=fancy_decorations))
tex.append(
create_druid_shapes_tex(character, use_dnd_decorations=fancy_decorations)
)
tex.append(
jinja_env.get_template("postamble.tex").render(
use_dnd_decorations=fancy_decorations
)
)
# Typeset combined LaTeX file
try:
if len(tex) > 2:
latex.create_latex_pdf("".join(tex), features_base, keep_temp_files=debug, use_dnd_decorations=fancy_decorations)
latex.create_latex_pdf(
"".join(tex),
features_base,
keep_temp_files=debug,
use_dnd_decorations=fancy_decorations,
)
sheets.append(features_base + ".pdf")
final_pdf = os.path.splitext(character_file)[0] + ".pdf"
merge_pdfs(sheets, final_pdf, clean_up=True)
@@ -293,7 +245,8 @@ def merge_pdfs(src_filenames, dest_filename, clean_up=False):
os.remove(sheet)
load_character_file = readers.read_character_file
# # Deprecated:
# load_character_file = readers.read_character_file
def _build(filename, args) -> int: