diff options
-rwxr-xr-x | planner_generator.py | 214 | ||||
-rwxr-xr-x | weekly_planner_generator.py | 102 |
2 files changed, 214 insertions, 102 deletions
diff --git a/planner_generator.py b/planner_generator.py new file mode 100755 index 0000000..b86ce68 --- /dev/null +++ b/planner_generator.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python3 + +import argparse +import calendar +import datetime +import locale +import logging +import os +import shutil +import subprocess +import sys + +from typing import Optional + +try: + from lesana.command import _get_first_docstring_line # type: ignore +except ImportError: + def _get_first_docstring_line(obj): + return "" + +try: + import argcomplete # type: ignore +except ImportError: + argcomplete = False + +import jinja2 + + +locale.setlocale(locale.LC_ALL, '') + + +class Generator: + """ + """ + default_template = "planner-A6" + + def __init__( + self, + year: Optional[int] = None, + template: Optional[str] = None, + out_file: Optional[str] = None, + build_dir: Optional[str] = "build", + ): + self.year = year or ( + datetime.date.today() + datetime.timedelta(days=334) + ).year + + self.out_file = out_file or self.default_template + ".pdf" + + env = jinja2.Environment() + self.templates_dir = "templates" + loader = jinja2.FileSystemLoader(self.templates_dir) + if not template: + template = self.default_template + self.template_recto = loader.load(env, template + "-r.svg") + self.template_verso = loader.load(env, template + "-v.svg") + self.template_cover = loader.load(env, "cover-A6-r.svg") + self.build_dir = build_dir + self.page_fname = os.path.join( + self.build_dir, + template + "-{year}-{page:03}.svg" + ) + + def render_page(self, page: int, **kw): + # page counts starts with 0 + if page == 0: + template = self.template_cover + elif page % 2 == 0: + template = self.template_recto + else: + template = self.template_verso + with open(self.page_fname.format( + year=self.year, page=page + ), "w") as fp: + fp.write(template.render(**kw)) + + def run(self): + self.clean_build_dir() + self.generate_cover_page() + self.generate_pages() + self.convert_pages_to_svg() + self.join_pages() + + def clean_build_dir(self): + try: + shutil.rmtree(self.build_dir) + except FileNotFoundError: + pass + os.makedirs(self.build_dir) + + def generate_cover_page(self): + self.render_page(page=0, year=self.year) + + def generate_pages(self): + pass + + def convert_pages_to_svg(self): + inkscape_commands = ";\n".join([ + ( + "file-open:{build_dir}/{svg};" + + " export-type: pdf;" + + " export-filename:build/{pdf};" + + " export-text-to-path;" + + " export-do" + ).format( + build_dir=self.build_dir, + svg=s, + pdf=os.path.splitext(s)[0] + ".pdf", + ) + for s in os.listdir(self.build_dir) + ]) + try: + subprocess.run( + ["inkscape", "--shell"], + input=inkscape_commands, + text=True, + ) + except FileNotFoundError: + logging.warning("Inkscape is not installed, can't convert to pdf") + logging.warning("Stopping here, you can use the svgs as you like") + sys.exit(1) + + def get_pdf_pages(self): + pdf_pages = sorted([ + os.path.join(self.build_dir, p) + for p in os.listdir(self.build_dir) + if p.endswith(".pdf") + ]) + return pdf_pages + + def join_pages(self): + pdf_pages = self.get_pdf_pages() + try: + subprocess.run([ + "pdfjam", + "--outfile", self.out_file, + *pdf_pages + ]) + except FileNotFoundError: + logging.warning("pdfjam is not installed") + logging.warning("you will have to join the pdf pages yourself") + sys.exit(1) + + +class WeeklyGenerator(Generator): + default_template = "week_on_two_pages-A6" + + def generate_pages(self): + cal = calendar.Calendar() + weeks = sum( + [r[0] for r in cal.yeardatescalendar(self.year, width=1)], + [] + ) + + last_monday = None + page = 1 + for week in weeks: + # yeardatescalendar will have the same week twice at the + # margin of a month, but we want to skip one of those + if week[0] == last_monday: + continue + last_monday = week[0] + + self.render_page(page=page, week=week) + page += 1 + + self.render_page(page=page, week=week) + page += 1 + + +class Command: + """ + Generate a planner + """ + def get_parser(self): + desc = _get_first_docstring_line(self) + parser = argparse.ArgumentParser(description=desc) + parser.add_argument( + "--year", '-y', + default=None, + help="Default is next year, or this year in January." + ) + parser.add_argument( + "--template", '-t', + default=None, + help="Base name of the template (without -[rv].svg)", + ) + parser.add_argument( + "command", + ) + return parser + + def main(self): + self.parser = self.get_parser() + if argcomplete: + argcomplete.autocomplete(self.parser) + self.args = self.parser.parse_args() + + generator = getattr( + sys.modules[__name__], + self.args.command.capitalize() + "Generator", + None + ) + if generator: + generator( + year=self.args.year, + template=self.args.template, + ).run() + else: + print("command not supported: {}".format(self.args.command)) + + +if __name__ == "__main__": + Command().main() diff --git a/weekly_planner_generator.py b/weekly_planner_generator.py deleted file mode 100755 index 4ba491e..0000000 --- a/weekly_planner_generator.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import calendar -import locale -import logging -import os -import subprocess -import sys - -import jinja2 - - -locale.setlocale(locale.LC_ALL, '') - - -def main(): - env = jinja2.Environment() - loader = jinja2.FileSystemLoader('templates') - template_verso = loader.load(env, 'week_on_two_pages-A6-v.svg') - template_recto = loader.load(env, 'week_on_two_pages-A6-r.svg') - - os.makedirs("build", exist_ok=True) - - year = 2022 - - template_cover = loader.load(env, 'cover-A6-r.svg') - with open("build/week_on_two_pages-A6-{year}-{page:03}.svg".format( - year=year, - page=0, - ), 'w') as fp: - fp.write(template_cover.render(year=year)) - - cal = calendar.Calendar() - weeks = sum([r[0] for r in cal.yeardatescalendar(2022, width=1)], []) - - last_monday = None - page = 1 - for week in weeks: - # yeardatescalendar will have the same week twice at the margin - # of a month, but we want to skip one of those - if week[0] == last_monday: - continue - last_monday = week[0] - - with open("build/week_on_two_pages-A6-{year}-{page:03}.svg".format( - year=year, - page=page, - ), 'w') as fp: - fp.write(template_verso.render(week=week)) - page += 1 - - with open("build/week_on_two_pages-A6-{year}-{page:03}.svg".format( - year=year, - page=page, - ), 'w') as fp: - fp.write(template_recto.render(week=week)) - page += 1 - - inkscape_commands = ";\n".join([ - ( - "file-open:build/{svg};" - + " export-type: pdf;" - + " export-filename:build/{pdf};" - + " export-text-to-path;" - + " export-do" - ).format( - svg = s, - pdf = os.path.splitext(s)[0] + ".pdf", - ) - for s in os.listdir("build") - ]) - try: - subprocess.run( - ["inkscape", "--shell" ], - input=inkscape_commands, - text=True, - ) - except FileNotFoundError: - logging.warning("Inkscape is not installed, can't convert to pdf") - logging.warning("Stopping here, you can use the svgs as you like") - sys.exit(1) - - pdf_pages = sorted([ - os.path.join("build", p) - for p in os.listdir("build") - if p.endswith(".pdf") - ]) - try: - subprocess.run([ - "pdfjam", - "--outfile", "weekly_planner_A6.pdf", - *pdf_pages - ]) - except FileNotFoundError: - logging.warning("pdfjam is not installed") - logging.warning("you will have to join the pdf pages yourself") - sys.exit(1) - - -if __name__ == '__main__': - main() |