Superfast Omnifocus Reminders with Fantastical and LCP

Nov 2 Automation

I add little reminders to Omnifocus all the time, usually with the same relative due date (“Tomorrow am 7am” or “Today at 5pm”). Since Omnifocus’s URL scheme doesn’t support due dates, I need to then set them manually after creating the task. Behold, Fantastical!

Add an action to Launch Center Pro to add an event to Fantastical with the format:

Reminder: [prompt:Reminder] @ 7am tomorrow

The corresponding url will be created as:

fantastical2://parse?sentence=Reminder%3A%20[prompt:Reminder]%20%40%207am%20tomorrow&notes=

I have Omnifocus set to capture reminders, so it alerts me at the desired time.

 

Note: Thanks to @ChewingPencils for the tip that you can create relative-date reminders in Due!

Editorial Pocket Browser

Aug 31 Automation

After the previous post on creating a Pocket workflow in Editorial, someone asked on App.net about viewing your Pocket queue in Editorial. I've hacked together a workflow that presents your Pocket articles in a popover, and clicking on one will open the webpage in Editorial's browser.

The article titles and corresponding urls are stored as two newline-delimetered strings during the execution of the workflow. When you select a title, a Python script turns the strings into arrays and searches for that title within the title array, then opens the url at the matching index in the url array. At the moment, it seems that workflow variables are restricted to strings, so that linear search is not very efficient. Feel free to make improvements!

Download the workflow here

Note: You need to have Pocket authenticated with Editorial, as explained here

Editorial for iPad: OAuth and a Pocket Workflow

Aug 22 Automation

With a little sneakiness, we can make calls to services in Editorial that use OAuth. I'll use Pocket as an example of how OAuth works:

  1. An application obtains a static key to make calls to the Pocket API (so that Pocket can easily invalidate the key and thus prohibit API requests if the application violates their TOS)
  2. The application makes a call to Pocket for a 'request token'. Pocket returns a token. The token is single-use only; once an authentication request has been make with the token, it cannot be used again and another token must be obtained.
  3. The application obtains an authentication url by making an authentication request with the request token. In this request the application also includes a re-direct url.
  4. The application loads the authentication url.
  5. The user grants the application access to their Pocket account.
  6. Pocket re-directs the user to the url specified by the application. The request token is now associated with successful authentication.
  7. The application gets an access token by making a request with the request token.
  8. The access token can now be used to make calls to the user's Pocket account.

The slightly tricky thing about implementing OAuth in a workflow is that it requires persistent state, but that state (the request and access tokens) are dynamically generated. We don't want to have to copy and paste keys all over the place.

The solution: Editorial is a text editor. What if we stored and loaded the keys in a text file? Bingo!

I've made 3 workflows; two for the authentication (Pocket Auth 1 & 2), and one that fetches a random article from the user's unread queue and opens it in the Editorial browser. The Pocket authentication only needs to run once. Here's how the whole thing works:

  1. To authenticate with Pocket, the user runs the Pocket Auth 1 workflow. Pocket Auth 1 gets a request token and an authentication url. It writes the request token to a file. It sets the callback url to the Pocket Auth 2 workflow and loads the auth url in the browser.
  2. Once the user has logged in and authenticated, Pocket Auth 2 is called.
  3. Pocket Auth 2 loads the request token and makes a request for an access token. It writes the access token to a file.
  4. Whenever the 'Random Pocket Article' workflow is executed, it loads the access token and makes the request. A random article from Pocket is loaded in the browser (In Instapaper's mobilizer)

This general OAuth in Editorial algorithm can be used for other services, as well. You can easily modify the 'Random Article from Pocket' workflow to do something else with Pocket.

Get a developer key for Pocket here

Pocket Auth 1

Pocket Auth 2

Random Article from Pocket

Post to App.net from Editorial

Aug 21 Automation

If you’re an App.net Developer, you can post to App.net directly from Editorial. I integrated this workflow into Federico Viticci's Post to WordPress workflow, to post new articles to App.net in addition to Twitter. If you have a developer account, follow the steps below:

  1. Go to account.app.net/developers/apps
  2. Select 'Create an App'
  3. App name, website, callback can be any values
  4. When the app has been created, go to App Settings, and 'Generate a user token for yourself'
  5. Enter the user token as directed in the workflow.

Download the workflow here

Quick Evernote Peek Questions with Pythonista

Aug 17 Automation

Evernote Peek is great tool for studying. It uses the iPad's Smart Cover; open the cover to “peek” at a question, then re-open it to check your answer.

Evernote Peek works with a single notebook in Evernote. The titles of the notes are the questions, and the corresponding note contents are the answers. Because I find creating individual notes too time consuming, I wrote a little python script to help out. It works like this:

  • Create a text document (in markdown if you wish) containing all the questions and answers in the format:

    This is a question. Does it look like a question?
    Yes, it looks like a question. This bit is the answer.

    And here's another question. How are you today?
    I'm feeling fine, thanks.
    Really great.
    Awesome.

  • As you can see, questions are on one line and the answer follows on the next line (the answer can span multiple lines). Question/answer pairs are separated by a blank line.

  • Follow Pythonista Developer Ole Moritz's instructions to download the Evernote SDK module and access your developer token.

  • Copy the full question and answer text and run the script in Pythonista. When the script runs, you'll be prompted to enter a name for the study pack (the notebook).

The script is pretty bare-bones right now, with minimal error checking.

You can find the full script here.

A Tea Drinker in the Coffee Capital

Dec 11 Seattle

So after accepting a very exciting internship, I’m off to Seattle for four months this January. The bad news? I can’t stand the the taste of coffee. Because of border regulations, I’m leaving my stash in the cupboard at home, which means I’ll need to acquire fresh tea ASAP upon landing. And a large mug.

The hunt for Seattle’s Best Tea commences.

Mac App Devs RSS Feeds

Sep 10 Mystery Meat

So if you’re looking for some Mac application developers to fill out your RSS feeds, here’s a boatload!

Download App Devs OPML

If you’re curious, I use Fever for my RSS needs. Can’t wait until Reeder gets Fever support on the iPad!

Why You Should Back App.net

Aug 9 Uncategorized

Would you be willing to pay 50 bucks a year for Twitter? That's the question to which Dalton Caldwell hopes 10,000 people will answer 'yes'. App.net's premise is to re-write what he believes Twitter did wrong; that is, adopting an advertising-based revenue model and a worrying attitude towards 3rd-party client developers. With only 5 days remaining in its kickstarter-esque campaign, App.net needs some serious help to achieve the $500,000 goal. While currently just below 50% of the necessary funding, media outlets like The Next Web have spurred backers; in the past 5 hours, $6000 has been pledged. 50 dollars of that is mine.

For a one-year membership, 50 dollars is a lot of money. For what? For Twitter without promoted tweets? Not exactly. I'm worried about Twitter. 6 years ago, I eagerly created an account on Facebook. And slowly, very slowly, while I messaged my friends and browsed through photos and posted unnessecary status updates, FarmVille and Mafia Wars took over my timeline and Facebook morphed into an experience wholly unlike what I had signed up for. I didn't want to 'like' some stupid 50% off deal in my area. But that's what Facebook is selling: adds. Or, more honestly: us. Facebook is selling us, the users. I don't like that, so I use Facebook as little as possible.

So, what about Twitter? It's making me nervous. For now, I am content to see only the content I want on Tweetbot and nothing else. But with Twitter's new developer guidelines, they're insisting on a 'consistent experience' across clients. I don't know what that means. No one outside of Twitter knows exactly what that means. And that gives them free reign to get rid of Tweetbot or change things completely whenever they please.

App.net has a very different attitude. When consumers are customers, the business model changes. No one will pay for a service they don't like, and that gives App.net an incentive to make their product as user-friendly as possible. 3rd party clients? Sure. Users want changes? OK. That's the sort of Twitter I want to be using.

I hope enough people do, too.

JQuery UI: Putting a Function into the Draggable Helper

Jun 27 Uncategorized

I’ve been tinkering around with JQuery UI–and growing quite frustrated. The plan was to move an element to a different DIV (then move that DIV) when the drag started. I could have rolled my own draggable() functionality, but since I’d built up my code already, I was reluctant to completely restructure. Here’d the thing with JQuery’s built-in draggable(): once you start dragging, good luck manipulating the element! In fact, if you try to access the element’s coordinates during the drag, you’ll be presented with the not-so-helpful UNDEFINED. That’s because of the ‘helper’: an object created to ‘be the face’ of your dragged element. You can access its relative values with ui.position.top and ui.position.left (assuming your start or drag or stop functions have a second argument named ‘ui’). But if you want to start changing DIVs of the element around during the drag, it’s not going to work out. The helper won’t know that things are different–revert functionality, for example, will be an inevitable disaster.

The solution? After much puzzling, I discovered that the helper option can be a function. It just needs to return the helper object, which, for most cases, can just be the object being dragged. What does this mean? Basically, you have a window of time after the drag registers, but before it starts, to do whatever the hell you want. Including changing the drag element’s DIV! Here’s the skeleton code:

$(.draggableClass).draggable({
helper: function(event, ui){
//do stuff!
return this;
},

start: function(event, ui){
//all good! The helper has been executed.
},
//…

Depending on your scenario, you could just perform the action you want in the create() event of the draggable, but that will only execute once. So if you need the action takes before each drag, you’ll need to use the helper. Hope this helps!