Skip to content

Instantly share code, notes, and snippets.

@apiarian
Created July 23, 2017 19:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apiarian/0a3e5c376ef5515efa69f5e405792f3b to your computer and use it in GitHub Desktop.
Save apiarian/0a3e5c376ef5515efa69f5e405792f3b to your computer and use it in GitHub Desktop.
#!/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