Created
July 23, 2017 19:21
-
-
Save apiarian/0a3e5c376ef5515efa69f5e405792f3b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# This script reads a journal located at the basedir in the following format: | |
# YYYY/MM/journal-entry.md (I usually have a YYYY-MM-DD HH-MM-SS Mon.md | |
# formatted entry name). It deletes the contents of the outputdir and replaces | |
# them with an HTML representation of the markdown files, complete with handy | |
# index pages and some keyboard navigation. Requires multimarkdown. Other files | |
# that might be in the basedir are copied to to the output directory structure | |
# alongside the generated HTML, so you can include things like images and even | |
# sounds in the markdown and they should "just work". Adjust as necessary. I | |
# use this in conjunction with the following Editorial workflow: | |
# http://www.editorial-workflows.com/workflow/5873227049992192/ZwG8rKFROSk . | |
# Use at own risk. | |
import os | |
import shutil | |
import re | |
import subprocess | |
basedir = '~/Dropbox/Editorial/Journal' | |
basedir = os.path.expanduser(basedir) | |
outputdir = '~/Journal-HTML' | |
outputdir = os.path.expanduser(outputdir) | |
class Year(object): | |
def __init__(self, year): | |
self.year = year | |
self.link_part = year | |
self.text = year | |
self.months = [] | |
class Month(object): | |
def __init__(self, month, year): | |
self.month = month | |
self.year = year | |
self.link_part = month.replace(' ', '') | |
self.text = month | |
self.entries = [] | |
self.extra_files = [] | |
self.year.months.append(self) | |
entry_menu = ''' | |
<p><a id=previous_link href={prev_link}>prev</a> | <a id=up_link href={up_link}>up</a> | <a id=next_link href={next_link}>next</a></p> | |
''' | |
entry_menu_no_prev = ''' | |
<p>prev | <a id=up_link href={up_link}>up</a> | <a id=next_link href={next_link}>next</a></p> | |
''' | |
entry_menu_no_next = ''' | |
<p><a id=previous_link href={prev_link}>prev</a> | <a id=up_link href={up_link}>up</a> | next</p> | |
''' | |
class Entry(object): | |
def __init__(self, entry, origin, month): | |
self.entry = entry | |
self.month = month | |
self.origin = origin | |
self.text = entry.replace('.md', '') | |
self.link_base = entry.replace(' ', '-').replace('.md', '') | |
self.month.entries.append(self) | |
self.previous_entry = None | |
self.next_entry = None | |
def make_menu_p(self): | |
if self.previous_entry is None: | |
return entry_menu_no_prev.format( | |
up_link = './index.html', | |
next_link = '../../{}/{}/{}.html'.format( | |
self.next_entry.month.year.link_part, | |
self.next_entry.month.link_part, | |
self.next_entry.link_base, | |
), | |
) | |
elif self.next_entry is None: | |
return entry_menu_no_next.format( | |
prev_link = '../../{}/{}/{}.html'.format( | |
self.previous_entry.month.year.link_part, | |
self.previous_entry.month.link_part, | |
self.previous_entry.link_base, | |
), | |
up_link = './index.html', | |
) | |
else: | |
return entry_menu.format( | |
prev_link = '../../{}/{}/{}.html'.format( | |
self.previous_entry.month.year.link_part, | |
self.previous_entry.month.link_part, | |
self.previous_entry.link_base, | |
), | |
up_link = './index.html', | |
next_link = '../../{}/{}/{}.html'.format( | |
self.next_entry.month.year.link_part, | |
self.next_entry.month.link_part, | |
self.next_entry.link_base, | |
), | |
) | |
def make_content(self): | |
return subprocess.run( | |
[ | |
'/usr/local/bin/multimarkdown', | |
'--smart', | |
'--notes', | |
'--snippet', | |
self.origin, | |
], | |
universal_newlines = True, | |
stdout = subprocess.PIPE, | |
).stdout | |
class ExtraFile(object): | |
def __init__(self, origin, month): | |
self.origin = origin | |
self.month = month | |
self.filename = os.path.basename(origin) | |
self.month.extra_files.append(self) | |
structure = {} | |
os.chdir(basedir) | |
years = [Year(n) for n in sorted(os.listdir()) if re.match(r'^[\d]{4}$', n)] | |
last_entry_seen = None | |
for year in years: | |
os.chdir(os.path.join(basedir, year.year)) | |
months = [Month(n, year) for n in sorted(os.listdir()) if re.match(r'^[\d]{2} - [\w]*$', n)] | |
for month in months: | |
os.chdir(os.path.join(basedir, year.year, month.month)) | |
entries = [n for n in sorted(os.listdir()) if n.endswith('.md')] | |
for entry in entries: | |
e = Entry(entry, os.path.join(basedir, year.year, month.month, entry), month) | |
e.previous_entry = last_entry_seen | |
last_entry_seen = e | |
extra_files = [n for n in os.listdir() if not n.endswith('.md') and n != '.DS_Store'] | |
for extra_file in extra_files: | |
ExtraFile(os.path.join(basedir, year.year, month.month, extra_file), month) | |
current_entry = years[-1].months[-1].entries[-1] | |
while True: | |
previous_entry = current_entry.previous_entry | |
if previous_entry is None: | |
break | |
previous_entry.next_entry = current_entry | |
current_entry = previous_entry | |
try: | |
shutil.rmtree(outputdir) | |
except: | |
pass | |
os.mkdir(outputdir) | |
header = ''' | |
<html> | |
<head> | |
<title>{title}</title> | |
<style> | |
body {{ | |
background-color: 444444; | |
color: dddddd; | |
font-family: Helvetica; | |
max-width: 40em; | |
}} | |
h1, h2, h3, h4 {{ | |
color: eee; | |
}} | |
a {{ | |
color: 4e4; | |
}} | |
strong {{ | |
color: efe; | |
}} | |
</style> | |
</head> | |
<body> | |
''' | |
footer = ''' | |
</body> | |
<script> | |
function checkKey(e) { | |
e = e || window.event; | |
if (e.keyCode == '38') { | |
// up arrow | |
document.getElementById('up_link').click(); | |
} | |
else if (e.keyCode == '40') { | |
// down arrow | |
} | |
else if (e.keyCode == '37') { | |
// left arrow | |
document.getElementById('previous_link').click(); | |
} | |
else if (e.keyCode == '39') { | |
// right arrow | |
document.getElementById('next_link').click(); | |
} | |
} | |
document.onkeydown = checkKey; | |
</script> | |
</html> | |
''' | |
list_top = '<ul>' | |
list_element = '<li><a href="{link}">{link_text}</a></li>' | |
list_bottom = '</ul>' | |
for year in years: | |
yeardir = os.path.join(outputdir, year.link_part) | |
os.mkdir(yeardir) | |
for month in year.months: | |
monthdir = os.path.join(yeardir, month.link_part) | |
os.mkdir(monthdir) | |
for entry in month.entries: | |
entryfilename = os.path.join(monthdir, entry.link_base+'.html') | |
with open(entryfilename, 'w') as f: | |
f.write(header.format( | |
title = entry.text | |
)) | |
f.write(entry.make_menu_p()) | |
f.write(entry.make_content()) | |
f.write(footer) | |
for extra_file in month.extra_files: | |
shutil.copy( | |
extra_file.origin, | |
os.path.join(monthdir, extra_file.filename) | |
) | |
with open(os.path.join(monthdir, 'index.html'), 'w') as f: | |
f.write(header.format( | |
title = month.text | |
)) | |
f.write(list_top) | |
f.write(list_element.format( | |
link = '../index.html', | |
link_text = month.year.text | |
)) | |
for entry in month.entries: | |
f.write(list_element.format( | |
link = './{}.html'.format(entry.link_base), | |
link_text = entry.text | |
)) | |
f.write(list_bottom) | |
f.write(footer) | |
with open(os.path.join(yeardir, 'index.html'), 'w') as f: | |
f.write(header.format( | |
title = year.text | |
)) | |
f.write(list_top) | |
f.write(list_element.format( | |
link = '../index.html', | |
link_text = 'years', | |
)) | |
for month in year.months: | |
f.write(list_element.format( | |
link = './{}/index.html'.format(month.link_part), | |
link_text = month.text, | |
)) | |
f.write(list_bottom) | |
f.write(footer) | |
with open(os.path.join(outputdir, 'index.html'), 'w') as f: | |
f.write(header.format( | |
title = 'years', | |
)) | |
f.write(list_top) | |
for year in years: | |
f.write(list_element.format( | |
link = './{}/index.html'.format(year.link_part), | |
link_text = year.text, | |
)) | |
f.write(list_bottom) | |
f.write(footer) | |
# import bpython | |
# bpython.embed(locals_ = locals()) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment