From 055fc9a0e04269325060058e7f15b34a3cb9ddf6 Mon Sep 17 00:00:00 2001 From: chrisfinazzo Date: Sun, 2 Mar 2025 19:44:47 -0500 Subject: [PATCH 1/2] Add an optional Mastodon link to the output files --- README.md | 3 +- keynote_export/export.py | 96 +++-------------------- keynote_export/resources/presentation.css | 7 ++ keynote_export/resources/share.jinja | 13 +++ pypi-readme.md | 3 +- 5 files changed, 36 insertions(+), 86 deletions(-) diff --git a/README.md b/README.md index ca18771..1ffdfeb 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,8 @@ keynote-export \ --keynote= \ --outdir= \ --title= \ - --bluesky-handle= + --bluesky-handle= \ + --mastodon-handle= ``` The output path gets both a PDF file and a self-contained website that you can easily host with (for example) [GitHub pages](https://pages.github.com/). diff --git a/keynote_export/export.py b/keynote_export/export.py index 46834fc..893bd0b 100755 --- a/keynote_export/export.py +++ b/keynote_export/export.py @@ -26,7 +26,7 @@ class Options(object): def __init__( - self, outdir, pagesize, font_size, title, bsky_handle, skip_builds + self, outdir, pagesize, font_size, title, bsky_handle, mastodon_handle, skip_builds ): self.outdir = os.path.abspath(outdir) self.pagesize = pagesize @@ -36,6 +36,7 @@ def __init__( self.font = "SanFrancisco" self.title = title self.bsky_handle = bsky_handle + self.mastodon_handle = mastodon_handle self.skip_builds = skip_builds @property @@ -48,88 +49,6 @@ def note_width(self): return w - self.notepadding * 2 -def slides_and_notes(opts, notes): - return zip(sorted(glob("%s/*jpeg" % opts.slidesdir)), notes) - - -def make_dirs(opts): - for d in ( - opts.outdir, - opts.slidesdir, - ): - if not os.path.isdir(d): - os.mkdir(d) - - -def generate_pdf(opts, notes): - outfile = os.path.join(opts.outdir, "out.pdf") - - tallest_note = -1 - for n in notes: - lines = simpleSplit(n, opts.font, opts.font_size, opts.note_width) - tallest_note = max(tallest_note, len(lines)) - - note_height = ((tallest_note + 1) * opts.leading) + (opts.notepadding * 2) - - s = ParagraphStyle("note") - s.fontName = opts.font - s.textColor = "black" - s.alignment = TA_LEFT - s.fontSize = opts.font_size - s.leading = opts.leading - - img_w, img_h = opts.pagesize - pagesize = (img_w, img_h + note_height) - - c = canvas.Canvas(outfile, pagesize=pagesize) - c.setStrokeColorRGB(0, 0, 0) - - for slide, note in slides_and_notes(opts, notes): - c.setFillColor(HexColor("#ffffff")) - c.rect(0, 0, img_w, img_h + note_height, fill=1) - - c.drawImage( - slide, 0, note_height, img_w, img_h, preserveAspectRatio=True - ) - c.line(0, note_height, img_w, note_height) - - if note: - p = Paragraph(note.replace("\n", "
"), s) - p.wrapOn(c, opts.note_width, note_height) - p.breakLines(opts.note_width) - p.drawOn(c, opts.notepadding, note_height - opts.notepadding) - c.showPage() - c.save() - - -def export_keynote(filename, opts): - filename = os.path.abspath(filename) - - keynote = appscript.app("Keynote") - outpath = appscript.mactypes.File(opts.slidesdir) - k = appscript.k - keynote_file = appscript.mactypes.File(filename) - - with closing(keynote.open(keynote_file)) as doc: - notes = doc.slides.presenter_notes() - skipped = doc.slides.skipped() - notes = list(itertools.compress(notes, [not s for s in skipped])) - - doc.export( - as_=k.slide_images, - to=outpath, - with_properties={ - k.export_style: k.IndividualSlides, - k.compression_factor: 0.9, - k.image_format: k.JPEG, - k.all_stages: not opts.skip_builds, - k.skipped_slides: False, - }, - ) - - return notes - - def generate_html(opts, notes): def imgpath(s): return s.replace(opts.outdir + "/", "") @@ -144,6 +63,7 @@ def imgpath(s): ], title=opts.title, bsky_handle=opts.bsky_handle, + mastodon_handle=opts.mastodon_handle, ) outfile = os.path.join(opts.outdir, "index.html") @@ -154,7 +74,6 @@ def imgpath(s): os.path.join(opts.outdir, "presentation.css"), ) - @click.command() @click.option( "-k", @@ -192,6 +111,13 @@ def imgpath(s): required=False, type=click.STRING, ) +@click.option( + "-m", + "--mastodon-handle", + help="Mastodon handle for author", + required=False, + type=click.STRING, +) @click.option( "--skip-builds", is_flag=True, help="Skip build stages", default=False ) @@ -202,6 +128,7 @@ def main( font_size: int, title: str, bluesky_handle: Optional[str], + mastodon_handle: Optional[str], skip_builds: bool, ): pagesize = tuple([int(s) for s in pagesize.split("x")]) @@ -211,6 +138,7 @@ def main( font_size, title, bluesky_handle, + mastodon_handle, skip_builds, ) diff --git a/keynote_export/resources/presentation.css b/keynote_export/resources/presentation.css index 729fa04..4b03bbc 100644 --- a/keynote_export/resources/presentation.css +++ b/keynote_export/resources/presentation.css @@ -146,9 +146,16 @@ footer p { display: inline-flex; align-items: center; } +.mstdn { + display: inline-flex; + align-items: center; +} .bsky .handle { margin-left: 10px; } +.mstdn .handle { + margin-left: 10px; +} .share a, .share a:visited { color: #333; font-weight: 500; diff --git a/keynote_export/resources/share.jinja b/keynote_export/resources/share.jinja index 780ef44..acadfe9 100644 --- a/keynote_export/resources/share.jinja +++ b/keynote_export/resources/share.jinja @@ -3,4 +3,17 @@ @{{ bsky_handle }}
+ + + + + + + + + + + + @{{ mastodon_handle }} + diff --git a/pypi-readme.md b/pypi-readme.md index 2527b31..6feb30c 100644 --- a/pypi-readme.md +++ b/pypi-readme.md @@ -17,5 +17,6 @@ keynote-export \ --keynote= \ --outdir= \ --title= \ - --bluesky-handle= + --bluesky-handle= \ + --mastdoon-handle= ``` From 1e8201e22fea39df00f56360f86a64feffe6d80f Mon Sep 17 00:00:00 2001 From: chrisfinazzo Date: Sun, 2 Mar 2025 19:53:08 -0500 Subject: [PATCH 2/2] Revert --- keynote_export/export.py | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/keynote_export/export.py b/keynote_export/export.py index 893bd0b..176a8b6 100755 --- a/keynote_export/export.py +++ b/keynote_export/export.py @@ -49,6 +49,87 @@ def note_width(self): return w - self.notepadding * 2 +def slides_and_notes(opts, notes): + return zip(sorted(glob("%s/*jpeg" % opts.slidesdir)), notes) + + +def make_dirs(opts): + for d in ( + opts.outdir, + opts.slidesdir, + ): + if not os.path.isdir(d): + os.mkdir(d) + + +def generate_pdf(opts, notes): + outfile = os.path.join(opts.outdir, "out.pdf") + + tallest_note = -1 + for n in notes: + lines = simpleSplit(n, opts.font, opts.font_size, opts.note_width) + tallest_note = max(tallest_note, len(lines)) + + note_height = ((tallest_note + 1) * opts.leading) + (opts.notepadding * 2) + + s = ParagraphStyle("note") + s.fontName = opts.font + s.textColor = "black" + s.alignment = TA_LEFT + s.fontSize = opts.font_size + s.leading = opts.leading + + img_w, img_h = opts.pagesize + pagesize = (img_w, img_h + note_height) + + c = canvas.Canvas(outfile, pagesize=pagesize) + c.setStrokeColorRGB(0, 0, 0) + + for slide, note in slides_and_notes(opts, notes): + c.setFillColor(HexColor("#ffffff")) + c.rect(0, 0, img_w, img_h + note_height, fill=1) + + c.drawImage( + slide, 0, note_height, img_w, img_h, preserveAspectRatio=True + ) + c.line(0, note_height, img_w, note_height) + + if note: + p = Paragraph(note.replace("\n", "
"), s) + p.wrapOn(c, opts.note_width, note_height) + p.breakLines(opts.note_width) + p.drawOn(c, opts.notepadding, note_height - opts.notepadding) + c.showPage() + c.save() + + +def export_keynote(filename, opts): + filename = os.path.abspath(filename) + + keynote = appscript.app("Keynote") + outpath = appscript.mactypes.File(opts.slidesdir) + k = appscript.k + keynote_file = appscript.mactypes.File(filename) + + with closing(keynote.open(keynote_file)) as doc: + notes = doc.slides.presenter_notes() + skipped = doc.slides.skipped() + notes = list(itertools.compress(notes, [not s for s in skipped])) + + doc.export( + as_=k.slide_images, + to=outpath, + with_properties={ + k.export_style: k.IndividualSlides, + k.compression_factor: 0.9, + k.image_format: k.JPEG, + k.all_stages: not opts.skip_builds, + k.skipped_slides: False, + }, + ) + + return notes + def generate_html(opts, notes): def imgpath(s): return s.replace(opts.outdir + "/", "")