This Week's Sponsor:

Kolide

Ensure that if a device isn’t secure it can’t access your apps.  It’s Device Trust for Okta.


Automatically Send Articles From Reading List to Instapaper

Two days ago, Ben Brooks asked on App.net if anyone had come up with a way to share Safari Reading List items to Instapaper. His question made me realize that it would be a fun project to find out, so in my free time I put together a workflow that runs automatically and in the background on my Mac mini.

Please note, what follows is a raw experiment. I have tested it, and it works, but it’s far from stable. It uses GUI scripting in AppleScript to mark Reading List items as read, and it heavily depends on iCloud, which, unfortunately, is far from reliable when it comes to bookmark syncing. Nothing should happen to your bookmarks (the script simply “reads” them), but backups are recommended, as usual.

What you need

In short, the workflow relies on ReadingListReader to parse your unread Reading List items and save them to Instapaper using readinglist2instapaper. To trigger this every time a new item is added to Reading List, you’ll be using Hazel to monitor the Bookmarks.plist file located in ~/Library/Safari/ on your Mac. You’ll then run an AppleScript (also with Hazel) to mark an item as read, so that it won’t be saved multiple times or fetched by the script.

ReadingListReader & InstapaperLibrary

ReadingListReader contains a Python module called readinglistlib that provides a simple way to read Reading List items off your Bookmarks.plist file. With iCloud, Apple decided to store these “read later” articles in the same Bookmarks file that contains your actual bookmarks; for the module, through a simple syntax, it’s possible to “look” at this file and only fetch the URLs that belong to Reading List.

Download ReadingListReader and InstapaperLibrary, which is a Python library to use the Instapaper API. Extract the ReadingListReader archive, and place readinglist2instapaper.py, readinglistreader.py, and readinglistlib in a folder. Download InstapaperLibrary and put instapaperlib in the same folder. I’m choosing the Home folder for convenience, but you could put readinglistreader.py in /usr/local/bin if you want. Just remember to make the file readinglistreader.py executable first.

What you’re doing here is setting up these scripts for the first time: you won’t have to do it again once they’re working. You just need a bit of patience, and, perhaps, a good cup of coffee. I also recommend reading the official ReadingListReader FAQ and installation guide, as it’s very easy to follow.

Next, you’ll have to tell these files how to connect to your Instapaper account. In readinglistreader.py, look for this portion of the file:

The blurred spaces is where you’ll have to put in your Instapaper account and password. Do the same for instapaperlib.py inside the instapaperlib folder.

If you’ve setup everything correctly, you should be able to run python /Users/yourusername/path/to/readinglist2instapaper.py without receiving any errors. It means the file can access your Reading List and Instapaper account. If you have some items in Reading List, they’ll be sent to Instapaper with their title and URL.

Automating the workflow

Next, we want to automate everything so that, no matter the device we’re using, a Mac will run this script and beam items to Instapaper. To accomplish this, obviously, we’ll need iCloud sync on both Mac and iOS, and a computer to do the processing for us. Eventually, you’ll end up with an automated workflow that looks for changes in the Bookmarks.plist file and sends Reading List URLs to Instapaper.

You’ll be able to, say, quickly save a Reading List item from your iPhone and find it after a few seconds on the Instapaper website or app. As long as the iCloud Reading List changes, so will Instapaper.

As usual, I decided to use Hazel to monitor changes to the Bookmarks.plist file. Every time a change is picked up using the good & old “Date Last Matched is before Date Last Modified” filter, the Python script will be executed to take Reading List items and send them off to Instapaper. Reading List items won’t be deleted – the script will just take “unread” ones; that’s why I added an AppleScript to mark them as read afterwards.

In the meantime, to see if the workflow is set up correctly, just create the Hazel rule without the AppleScript. Drop in the ~/Library/Safari/ folder, create the filter, the shell script action, and save the rule. Add a link to Reading List from your iPhone and see what happens. Does Instapaper have that link after a minute? Then the script is working.

GUI scripting

I tend to avoid GUI scripting, as it’s based on visible interface elements rather than actual commands from the AppleScript dictionary. But in Reading List’s case, I don’t think I have a choice. In Lion and Mountain Lion, Safari’s AppleScript dictionary doesn’t have a command to retrieve Reading List items: you can only create new ones using add reading list item.

As I mentioned above, the script defaults to processing unread Reading List items. To avoid an additional processing of the same item, I had to figure out a way to mark it as read. I came up with a quick and dirty hack that, through GUI scripting, shows the Reading List sidebar in Safari, selects the next item (so it is marked as read), closes the sidebar, and closes the blank tab I’m using for this process.

Like I said, it’s a very quick AppleScript put together to see if the selection trick could work. I didn’t even add a check to see if GUI scripting can be used or not (always add one). I am no expert of GUI scripting at all: if you know of a better way to accomplish this – perhaps figure out how to hit “Clear All” – please get in touch.

tell application "Safari"

	tell window 1

		set current tab to (make new tab)

		activate

		tell application "System Events"

			tell process "Safari"

				keystroke "L" using {command down, shift down}

				keystroke down using {command down, option down}

				click menu item "Select Next Item in Reading List" of menu "Bookmarks" of menu bar 1

				delay 3

				keystroke "L" using {command down, shift down}

				delay 2

				click menu item "Close Tab" of menu "File" of menu bar 1

			end tell

		end tell

	end tell

end tell

The current script simply selects the first item – meaning, if you’re adding multiple links at once, those after the first link won’t be selected. If you add a link every few minutes, the script should take care of marking it as read, preventing it from ending up on Instapaper again.

Problems and Reasons

Clearly, this isn’t the best way to process Reading List items and send them to Instapaper, because Apple doesn’t want you to mess with scripting Safari’s bookmarks. The entire workflow may easily fail due to iCloud’s sync (which is surprisingly unstable) and the AppleScript, which may not mark your items as read. In my tests, adding one link at a time, everything went fairly smooth; certainly, the culprit isn’t ReadingListReader, which works as advertised. I wish Reading List had better support for AppleScript.

The interesting fact about this workflow is that, at first, I thought it would be useless: why would I want to do this? As TJ Luoma told me on App.net, though, Reading List is integrated on a system-wide level, while Instapaper isn’t. Sure, most third-party apps offer a “Save to Instapaper” feature nowadays, but it’s still very convenient to be able to add links to Reading List from Mail or Calendar.

In some third-party apps like Downcast and Day One, Reading List is integrated with a single tap & hold, whereas Instapaper is available in a sub-menu of a web view. So, in the end, if you’re into this sort of thing, you’ll also save some taps.

Once again, if you know of a better to achieve the same automated worklfow please let me know on Twitter or App.net (where the original discussion took place).

Unlock More with Club MacStories

Founded in 2015, Club MacStories has delivered exclusive content every week for over six years.

In that time, members have enjoyed nearly 400 weekly and monthly newsletters packed with more of your favorite MacStories writing as well as Club-only podcasts, eBooks, discounts on apps, icons, and services. Join today, and you’ll get everything new that we publish every week, plus access to our entire archive of back issues and downloadable perks.

The Club expanded in 2021 with Club MacStories+ and Club Premier. Club MacStories+ members enjoy even more exclusive stories, a vibrant Discord community, a rotating roster of app discounts, and more. And, with Club Premier, you get everything we offer at every Club level plus an extended, ad-free version of our podcast AppStories that is delivered early each week in high-bitrate audio.

Choose the Club plan that’s right for you:

  • Club MacStories: Weekly and monthly newsletters via email and the web that are brimming with app collections, tips, automation workflows, longform writing, a Club-only podcast, periodic giveaways, and more;
  • Club MacStories+: Everything that Club MacStories offers, plus exclusive content like Federico’s Automation Academy and John’s Macintosh Desktop Experience, a powerful web app for searching and exploring over 6 years of content and creating custom RSS feeds of Club content, an active Discord community, and a rotating collection of discounts, and more;
  • Club Premier: Everything in from our other plans and AppStories+, an extended version of our flagship podcast that’s delivered early, ad-free, and in high-bitrate audio.