Anki: Insert the most recent image
I make a lot of Anki cards, so I’m on a constant quest to make the process more efficient. Like a lot of language-learners, I use images on my cards where possible in order to make the word or sentence more memorable.
Process
When I find an image online that I want to use on the card, I download it to ~/Documents/ankibound
. A Hazel rule then grabs the image file and converts it to a .webp
file with relatively low quality and a maximum horizontal dimension of 200px. The size and low quality allow me to store lots of images without overwhelming storage capacity, or more importantly, resulting in long synchronization times.
But, getting the “done” image into Anki is a hole in the process. Yes, I could click the paperclip “insert media” button and browse to the file. Or I could open a Finder window and drag the file into the image field. But a faster solution is to use AnkiConnect to store the image file and then just insert an <img>
tag into the field HTML, then close up. If we set this up as a Keyboard Maestro macro, it’s just a quick keystroke combination.
Here’s how it works:
Finding the most recent file
We’re going to use bash
for this because the composability of its tools make this kind of filesystem work so easy. Here’s the first part of our script.
#!/bin/bash
DIR="$HOME/Documents/ankidone"
fn=$(ls -lt $DIR | head -2 | tail -1 | awk '{print $9}')
lt -lt
gives us a list of files in $DIR
ordered by modification date. Then head -2
returns the first two lines. Why 2 lines? Well ls
insists on printing out a total _n_
line first, so we need to grab that line and the one we want which is next. We find our most recent file line with a call to tail -1
. Finally awk
splits the line into space-separate fields. The filename is the ninth field. So $fn
now has our filename and extension.
Storing the file in collection.media
We will use AnkiConnect to store the file for us.
ip="http://localhost:8765/"
action="storeMediaFile"
json=$(jo -p version=6 action=$action params[filename]=$fn params[path]="$DIR/$fn")
r=$(curl -s -XPOST "$ip" \
-H 'Content-Type: application/json' \
-d "$json"
)
The hard-coded $ip
address is just the standard address of the AnkiConnect server running inside of Anki. The API action we’re interested in is storeMediaFile
, for obvious reasons. Next we use the excellent jo
tool1 to build the required JSON payload for the POST API call.
Inserting the image into the editor
In our Keyboard Maestro macro, we set the Execute Shell Script action to same the result on the clipboard. The last part of our shell script formats an <img>
HTML tag for us to insert. That’s what’s on the clipboard when the shell script exits.
The macro assumes the cursor is sitting in the image field. So with a command+shift+X we can open the HTML field editor. Then just a paste keystroke, and repeat the command+shift+X and the image should appear. Done!
There are definitely other ways we could go about this, that don’t involve AnkiConnect. It’s possible that just moving the image into collection.media
would suffice. But then we would have to hard-code the proper path to that directory and if you use multiple collections, you’d be out of luck.
For reference, here’s the whole script:
#!/bin/bash
DIR="$HOME/Documents/ankidone"
fn=$(ls -lt $DIR | head -2 | tail -1 | awk '{print $9}')
ip="http://localhost:8765/"
action="storeMediaFile"
json=$(jo -p version=6 action=$action params[filename]=$fn params[path]="$DIR/$fn")
r=$(curl -s -XPOST "$ip" \
-H 'Content-Type: application/json' \
-d "$json"
)
echo "<img src=\"$fn\">"
Happy studying!