/ :: blog

How I Publish Notes

What happens when I can't sleep at night and have time to think

I have a love/hate relationship with writing blog posts. On the one hand, I love looking back at stuff that I have written, and I like the sense of accomplishment I get when I look at the post in all its glory, formatted nicely, on the Internet for the world to see. On the other hand, I find it really hard to commit to a single idea in enough detail to make it worthwhile spending the time writing a blog post.

What I do enjoy is writing little snippets of ideas, notes, and memories; the effort involved in writing a blog post (given my blog source is git-controlled, and built on commits to master1) means that it just isn't worth it for smaller pieces of text. I realised that I needed a way to quickly share notes that would keep me in control of my data.

I thought about my requirements, in order to help decide how I would go about this:

  1. I should be able to write the note from theoretically anywhere2
  2. I should be able to write the note in Markdown and have it converted to HTML as part of the deployment
  3. The relevant <meta> tags should be generated so that sharing the post looks decent
  4. There should be an automatically generated index that is updated each time a new note is added

1. Write the note from anywhere

Being able to write the note anywhere is easy enough if I am writing it in Markdown. The issues comes when it is time to upload the file to the server. If I am writing it on any of my computers, then obviously I can just scp the file into the correct directory for processing. The sticking point was how to get the text from my phone to the server. Let's face it, as a millennial I am constantly on my phone, and so most of my content would be created using this method.

I am an iOS user for my sins, and iOS has a great built-in application called Shortcuts. This allows you to string actions together (including from third-party applications) in order to achieve your goals. One of the inbuilt actions is to run a script over SSH

cd /var/www/htdocs/ols.wtf/notes/data
file=$(date +%Y-%m-%d-%H:%M.html)
cat header > $file
cat << "EOF" | lowdown --html-no-head-ids >> $file
{Text from Input}
EOF
cat footer >> $file
./set-title.sh $file
cd ..
./update-index.sh

The shortcut first opens up a text box to write the note in, which is stored as a variable to use later. It then connects to the server using an SSH key defined in the shortcut, and changes to the notes data directory. From here it creates a file in the format YYYY-MM-DD-HH:MM.html and fills it with the contents of a file called header within the data directory. This includes the HTML structure up to the start of the note content, and some boilerplate metadata to be edited later.

From here, we cat the contents of the text and pipe it through lowdown, which we will cover shortly, before adding the contents of footer to the file. It then kicks off running some additional scripts to deal with metadata and the index page.

2. Markdown to HTML

I have used lowdown3 in the past for other projects that needed to convert Markdown to HTML. You can use it to produce an entire HTML5 document, but as I was handling the structure of the document myself, I only needed it to produce a fragment from the Markdown provided.

I prefer lowdown to other tools, because it supports additional Markdown features beyond the traditional ones, including tables, footnotes, and fenced code.

I run it with the --html-no-head-ids flag so that my elements look like this:

<h1>This is a test</h1>

rather than this

<h1 id="This%20is%20a%20test">This is a test</h1>

3. Generate <meta> tags

Once the HTML document has been created, the <meta> tags are pre-filled with placeholder text as follows:

<title>REPLACE_TITLE</title>
<meta description="REPLACE_DESCRIPTION">

The set-title.sh script contains a handy little one-liner so change the title and description placeholders in the HTML document into something relevant to the note. It takes a single argument of the file name to run the operations on.

file=$1
sed -ibak "s/REPLACE_TITLE/$(grep h1 $file | head -1 | sed 's/.*>\(.*\)<.*/\1/') \&mdash; Oliver Leaver-Smith/;s/REPLACE_DESCRIP
TION/$(grep '<p>' $file | grep -v "<--" | head -1 | sed 's/<[^>]*>//g')/" $file ; rm ${file}bak

To start off, it grabs the first <h1> tag from the page, and treats that as the title. It then sets the title to that followed by — Oliver Leaver-Smith. Next it takes the first paragraph of the main body, strips out all HTML tags, and replaces the description placeholder with that. An example of the after product is below:

<title>Supporting dark mode &mdash; Oliver Leaver-Smith</title>
<meta description="Given I had created this little site from a clean slate, I thought I’d try making it support dark mode automatically">

The above is just a snippet of the tags that are created, it has all the Twitter and OpenGraphs ones it needs, so looks good on all platforms.

4. Dynamically-created index page

What good are new posts if there is no way to find them? An RSS feed is on my todo list, but in the mean time there is an index page which is created as part of the Shortcut running the update-index.sh script. This is also nearly a one-liner, purely because I wrote in on the command line and moved it to a script when it became unwieldy. The script cats the contents of header and footer into the index.html, but in the middle we have a glorious loop.

cat header > index.html
find ./data/*.html | sort -r | while read file ; do printf "<div class=\"post\">\n<h3>$(printf $file | awk -F\/ '{print $3}' | awk -F. '{print $1}' | sed 's/\(.*\)-/\1 /') <a href=\"$file\">$(grep h1 $file | head -1 | sed 's/.*>\(.*\)<.*/\1/')</a></h3>\n"; cat $file | sed -n '/<body>/,/<\/body>/p' | sed -e '1s/.*<body>//' -e '$s/<\/body>.*//'  | grep -v "<h1>" | grep -v "<--" ; printf "</div>\n\n" ; done >> index.html
cat footer >> index.html

We first look for all .html files in the data directory and sort them date descending. Looping over each file, we write the date (pulled from the file name and slightly reformatted) and the note title (again pulling the first <h1> tag from the file contents). These are wrapped in a <h3> tag, with the title itself linking to the actual note. After this, we extract everything between the <body> tags from the note, remove the <h1> because it is now a <h3> above the content, and also remove the “<– index” link which is a way to get back to the index from the individual notes.

And that's it, there are a few caveats to using this method, namely I can't use <h1> tags in my notes because they will be filtered out, and the first paragraph of each note must be a suitable summary for sharing. Because I have set these restrictions myself, of course I am happy with them, but it is something to keep in mind if you use this method yourself.

I may change my blog to use something similar to this in future, and maybe even combine the feeds, but that is a task for another bout of insomnia.


  1. You can read more about this here 

  2. Realistically, any of my computers, and my phone 

  3. lowdown, the simple markdown translator