Hear me now, ye gentle people, my brethren here in London;

(103)

while I tell ye of my method for posting these moon photos.

The text record

I have a text file at https://www.acdw.net/moon-photos.txt that keeps track of all the titles for this project, along with a little x indicating whether they’ve been done or not. This file (or rather, its copy on my personal computer) is the canonical source of truth for which moon photos have been taken and which are still available to write.

I’ve written and added to a script to make bookkeeping this file and grabbing a new title each day from this file easier to do.

Grabbing a title

The first couple of days I was doing this, I went to https://www.random.org to generate a random number between 1 and 400 (the number of lines in my file). Then I’d manually look up the numbered line (usually by opening the file in ViM and typing <number>G, you ViMmers understand me), and open a new file, copying and pasting in the title. This process quickly became tedious.

So the first thing I wrote was a quick one-liner to grab myself a title and print it out:

$ sed -n "$((RANDOM % 400))p" moon-photos.txt

Adding numbers

I do a lot of writing at work. So after a few days, I wanted to add the text file to my site and look up titles the old random.org way at work. Adding the file was easy enough, but I didn’t have any line numbers in the web browser, which meant that I had to copy and paste the whole thing every day to ViM at work, then find the line number I wanted. It was too much. So I added line numbers to the beginning of each line, too:

$ cat -n moon-photos.txt > moon-photos.txt~
$ mv moon-photos.txt~ moon-photos.txt

Adding x-s

Around this time, I realized it would be much easier to pull titles if I just wrote a script on my computer. To make that work, though, I needed some way to mark titles as completed. I decided a little x on the left side would work best. So, I added an extra <TAB> to the beginning of each line:

$ sed 's/^/ /' < moon-photos.txt > moon-photos.txt~
$ mv moon-photos.txt~ moon-photos.txt

I’ll include the completed script at the bottom of this post. (In fact, I actually started with the script, but I’m writing this narrative kind of backwards in a sort of idiot attempt to make this more interesting.)

Generating a header

Okay, so pulling a title is great, but each post has a whole header block that’s required at the beginning, and each header has a lot of repeated information (and typing). So I wrote this little function to generate a header:

generate_header() {
    while :
    do
        trynum=$(randrange 1 $(wc -l "$1" | cut -d' ' -f1))
        getvars $trynum "$1"
        if [ -z "$X" ]; then break; fi
    done

    cat <<-EOH
    ---
    title: "$TITLE"
    subtitle: "($((N+0)))"
    series: moon photos
    tags:
    ---


    EOH
}

randrange is another little function I pulled from StackOverflow:

randrange() {
    # randrange MIN MAX
    MIN="$1"; MAX="$2"
    echo $(((RANDOM % (MAX - MIN + 1)) + MIN))
}

And getvars is a thing I wrote to split a line into done-ness, number, and title:

getvars() {
    # getvars LINE_NUMBER FILE
    #X  number  title
    line="$(sed -n "${1}p" "$2")"
    X="$(cut -f1 <<<"$line")"
    N="$(cut -f2 <<<"$line")"
    TITLE="$(cut -f3 <<<"$line")"
}

Emailing it to myself

This worked for a while. It was fun. But soon, it became tedious as well – I didn’t want to bother with using my computer (and remembering to use my computer!) to pull titles and get my posts started. So I thought, Let’s email titleblocks to myself!

It took somea setup with msmtp, which I won’t get into here – but here’s the command I used to mail each header to myself:

$ ( echo "Subject: moonphoto: $(date +%F)"; cat "$tmp" ) | msmtp "$email"

Of course, $tmp is a temporary file I’ve piped the header to, and $email is my email address.

Putting it all together

That’s about it – I’ve set up a cron job so that every day at 12:00 AM, moonphoto (clever name, right?) sends an email to me with the next moonphoto header block, randomly selected from my list.

I’ve also added an option to mark a line as done and commit the file in my git repo, as well as the standard usage option.

The script in toto goes thus:

#!/usr/bin/env bash
# write a new moon photo post

blogdir=~/acdw.net/content
titles="$blogdir"/static/moon-photos.txt
email='REDACTED@example.com'

randrange() {
    # randrange MIN MAX
    MIN="$1"; MAX="$2"
    echo $(((RANDOM % (MAX - MIN + 1)) + MIN))
}

getvars() {
    # getvars LINE_NUMBER FILE
    #X  number  title
    line="$(sed -n "${1}p" "$2")"
    X="$(cut -f1 <<<"$line")"
    N="$(cut -f2 <<<"$line")"
    TITLE="$(cut -f3 <<<"$line")"
}

remove_line() {
    # remove_line LINE_NUMBER FILE
    tf=$(mktemp)
    echo "Marking \"$TITLE\" ($N) done..."
    sed "${1} s/^[^x]/x&/" "$2" > "$tf" &&
        mv "$tf" "$2" &&
        chmod 744 "$2"
}

add_and_commit() {
    # add_and_commit LINE_NUMBER FILE
    echo "Committing changes..."
    pushd "$blogdir"
    git add .
    git commit -m "Add moonphoto ($1)"
    echo "Pushing changes..."
    git push
    popd
}

generate_header() {
    # generate_header FILE
    while :
    do
        trynum=$(randrange 1 $(wc -l "$1" | cut -d' ' -f1))
        getvars $trynum "$1"
        if [ -z "$X" ]; then break; fi
    done

    cat <<-EOH
    ---
    title: "$TITLE"
    subtitle: "($((N+0)))"
    series: moon photos
    tags:
    ---


    EOH
}

main() {
    MAIL=false;
    case "$1" in
        (-h)
            echo "moonphoto: generate a title"
            echo "usage: moonphoto [-h|-l|-m|-x NUM|-c NUM]"
            echo "-h:   show this help"
            echo "-l:   list all titles"
            echo "-m:   email the header"
            echo "-x NUM:   mark the line NUM as 'done'"
            echo "-c NUM:   marke line NUM as 'done' and commit changes"
            echo
            exit 0
            ;;
        (-x)
            [[ -n "$2" ]] || exit 1
            getvars "$2" "$titles"
            remove_line "$N" "$titles"
            exit 0
            ;;
        (-c)
            [[ -n "$2" ]] || exit 1
            getvars "$2" "$titles"
            remove_line "$N" "$titles"
            add_and_commit "$N" "$titles"
            exit 0
        (-l)
            cat "$titles"
            exit 0
            ;;
        (-m) MAIL=true ;;
        (*) ;;
    esac

    tmp="$(mktemp /tmp/mp-XXX.md)"
    echo "Generating header > $tmp ..."
    generate_header "$titles" | tee "$tmp"

    if $MAIL; then
        echo "Emailing header to $email..."
        (
            echo "Subject: moonphoto: $(date +%F)"
            cat "$tmp"
        ) | msmtp "$email"
    fi
}

main "$@"