Reading George Fox

Blogging and the Anti-Social Bookmarker, Part 2

So, to recap one final time, I've cobbled together an AppleScript that copies blogging related links from my Privacy Locked personal Pinboard to the ReadingGeorgeFox account. While I'm not yet back in NYC—now it's Jersey rather than Upstate—I've found a printer and the the time to annotate the script. Some credit: I used Rafael Bugajewski's DEVONthink Pro Pinboard Importer as a starting point; I have modified it a fair amount, though. Anyways, here goes nothing: 1

Lines 1 thru 12

Lines 9 thru 11 download the bookmarks via simple curl2 commands. When I began working on the script, I was still confused about the url syntax for tags, so I set up three separate downloads. This ended up making some later processing simpler, and, as the downloads were so small,3 I decided to keep it this way. As for downloading to files instead of passing the data directly to the rest of the script, it was easier to troubleshoot and AppleScript seems to be happier pulling data from a file on disk. Lastly, I'm using Pinboard API tokens instead of passwords. While I could have used Keychain scripting to be extra secure, these scripts are run locally on my machine and I figured the ability to revoke the tokens would provide enough safety.4

Lines 13 thru 38

Luckily, System Events understands xml5: in line 15, I pull in the contents of the “to_blog” bookmarks. The following lines 19 thru 88 are the heart of script, in which each attribute is parsed. The repeat in line 19 could also be structured as repeat with xDatum in xData; however, Script Debugger did not show any performance improvement, and I felt this format made things clearer.6 The url and time attributes are pretty straightforward—the fun really starts at line 25. Being a newbie at scripting, I had quite the time figuring out why things weren't working7. Pinboard's xml is sent in a nice, human readable format, just chock full of illegal characters when used in urls. Once I finally realized the problem, I turned to Bare Bones' free and wonderful TextWrangler 8 to re-encode the text in lines 29 thru 37. As mentioned in the comments, it is pretty dog slow (outside of AppleScript, grep would be far preferable). On the other hand, I'm not dealing with that much data, the script runs in the middle of the night, and Bare Bones' syntax is a model of what AppleScript should be.

Lines 39 thru 59

Encoding the Description is a repeat of the previous. One note is Pinboard's xml does not include line breaks; first time through I ended up with endless blocks of text. To keep the descriptions readable, I started including four spaces in each line break. In line 50, TextWrangler replaces them with two LF character codes.

Lines 60 thru 89

Lines 68 thru 88 process the tags. I did not want to clutter the blog's account with my idiosyncratic9 tagging system; instead, I settled on bookmark status10 and related posts.11 As the initial curl scripts separated the bookmarks by status, I just needed to deal with the related posts. TextWrangler was again the tool of choice, but, unfortunately, the find verb, unlike replace can only process files, not arbitrary strings. Thus, the performance penalty of writing to disk.12 13 The open for access command prevents a procession of windows from popping up, while, in line 72, TextWrangler performs its grep magic. In line 76, I set the status tag first, allowing the more pertinent related post tags to be listed first online.14

Lines 90 thru 95

All that's left is to send the bookmark to the blog's account. Line 94 exhibits the joy of passing AppleScript variables to the shell. Note the single quotes around curl's url. AppleScript just would not accept escaped double quotes here.15 Also, the day after I got the script working, it started choking in the middle of the “to_blog” bookmarks (the “to_blog?” and “blogged” bookmarks were fine). Turns out I had included straight brackets in a description, and curl throws up an error upon encountering brackets and/or braces. Thankfully, turning globbing off avoids the issue, and neither solution caused any trouble.

Lines 96 thru 106

Done with “to_blog”; onwards to the next!


Here's the downloadable version again. I've slightly changed the content and formatting of the comments, but the actual script does not differ from Friday's. Enjoy!


  1. I'm using images instead of text for code as I have yet to set up syntax highlighting.

  2. Also, note the fun of extra escape characters in AppleScript.

  3. Currently the largest of these temporary files is 42 kilobytes.

  4. While a malicious actor could theoretically erase all my bookmarksa with knowledge of the token, I also run a nightly backup shell script.
    a: The account password is required to sign in, so it wouldn't be possible to change anything else.

  5. And seems to prefer HFS+ style paths. Thankfully Cocoatech's Path Finder makes it super simple to grab paths in a variety of styles.

  6. Always a plus with AppleScript.

  7. Hence the very late night writing this script.

  8. TextWrangler shares its Big Brother's AppleScript dictionarya and understands its syntax modules. To complete the circle, one can find the module for Applescript here.
    a: An overview can be found in Chapter 11 of Textwrangler's manual.

  9. And, let's say, slightly unorganized.

  10. ie: “to_blog”, “to_blog?”, and “blogged”.

  11. Using the “p:postTitle” syntax.

  12. Don't weep too much for me; I just upgrade to an SSD.a
    a: A Crucial M500 960 GB. Ah, the glorious open range of pristine storage.

  13. Again, we get to see the shell's and AppleScript's lovely differing path syntax preferences.

  14. Line 82 inserts the all important “+” between tags. A lesson for me to always RTFM. It took me far too long to figure that out at 3am.

  15. My (uneducated) guess is it got confused with the plethora of quotes already in the line.