Log movies in Day One using IMDB

I'm a film bachelor, so every time I can get away from my obligations for 2 hours or more, I'll be watching a movie. I had ratings for movies spread all over the internet. Criticker, IMDB, Letterboxd, Flixster, you name it, I've been there at some point. I decided to put Day One to good use and store my ratings within it.

A couple months ago, there was a lot of buzz regarding logging actions using Launch Center Pro and Day One. This one for coffee by Ben Tsai, a nice one for TV shows by Matt Birchler. Josiah Wiebe has a good list of logging actions and Jeff Mueller has a comprehensive guide on the concept.

Movie Diary (Old Version):

dayone://post?entry=%7C[prompt:What's the movie?]%7C%7C%0A%7C%3A---%3A%7C---%3A%7C%0A%7C[prompt:Who directed this one?]%7C[prompt-num:When was it released?]%7C%0A%7C[list:What's the rating?|★ ★ ★ ★ ★|★ ★ ★ ★|★ ★ ★|★ ★|★]%7C%7C%0A%0A%23Movies

The idea is pretty simple, you have a MultiMarkdown table and you fill the cells with prompts, then you log the result in Day One. In my original Movie Diary action, I had to fill 3 fields: Title, Director and Year. Here's the problem, I want you to list 5 movies, then tell me the year each one was released and who was the director. Not so easy to remember, right? No one has an obligation to be a walking encyclopedia, specially these days with all information within reach. Often I had to double check my information to see if I wrote it right.

I looked for a good API that would search the movie for me and retrieve all the information I wanted. IMDB was the best alternative and I found something I could use on Stack Overflow. This is not a well-carved API though, I had to appeal for regular expressions to retrieve all information I needed and the results were spread among different dictionary keys. There's no fallback in case of an error, so if you get an alert, let me know.

#coding: utf-8
from urllib import quote
import json
import re
import sys
import webbrowser
import requests
import htmlentitydefs

movie = quote(sys.argv[1])

## Unescape function from: http://effbot.org/zone/re-sub.htm#unescape-html
def unescape(text):
    def fixup(m):
        text = m.group(0)
        if text[:2] == "&#":
            # character reference
            try:
                if text[:3] == "&#x":
                    return unichr(int(text[3:-1], 16))
                else:
                    return unichr(int(text[2:-1]))
            except ValueError:
                pass
        else:
            # named entity
            try:
                text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
            except KeyError:
                pass
        return text # leave as is
    return re.sub("&#?\w+;", fixup, text)

r = requests.get('http://www.imdb.com/xml/find?json=1&nr=1&tt=on&q=%s' % movie).text
t = json.loads(r)

try:
    pop = t['title_popular'] + t['title_exact']
except:
    try:
        pop = t['title_popular']
    except:
        pop = t['title_exact']

films = {}
for film in pop:
    title = unescape(film['title']).encode('utf_8')
    description = re.match("(^\d{4}).*<a href='/name/nm\d+/'>(.*)</a>", film['description'])
    if description:
        year = description.group(1)
        director = unescape(description.group(2)).encode('utf_8')
        the_string = '%s (%s, %s)' % (title, year, director)
        films[the_string] = {'Title': title, 'Year': year, 'Director': director}

if len(films.keys()) == 1:
    for film in films.keys():
        dayone = "dayone://post?entry=%7C{0}%7C%7C%0A%7C%3A---%3A%7C---%3A%7C%0A%7C{1}%7C{2}".format(quote(films[film]['Title']), quote(films[film]['Director']),films[film]['Year'])
else:
    dayone = 'dayone://post?entry=[list:What\'s the movie?'
    for film in films.keys():
        dayone+='|{0}=%7C{1}%7C%7C%0A%7C%3A---%3A%7C---%3A%7C%0A%7C{2}%7C{3}'.format(film, quote(films[film]['Title']), quote(films[film]['Director']), films[film]['Year'])
    dayone+="]"
dayone+="%7C%0A%7C[list:What's the rating?|★ ★ ★ ★ ★={{★ ★ ★ ★ ★}}|★ ★ ★ ★={{★ ★ ★ ★}}|★ ★ ★={{★ ★ ★}}|★ ★={{★ ★}}|★={{★}}]%7C%7C%0A%0A%23Movies"

the_url = 'launchpro://?url=' + quote(dayone)
webbrowser.open(the_url)

If you run into an error (possibly due to the unicode symbols), add it from the gist.

This is how it works, you write the title of the movie in Launch Center Pro and send it as an argument to Pythonista, it will check the exact and the popular results for your query. If there's a single one (for example, try The Social Network), it will send you back to LCP and prompt for the rating, then trigger Day One. If you get more results, Launch Center Pro will trigger a list will all viable results (you can try Straw Dogs) before prompting for a rating.

Add that script to Pythonista as movieDiary and add this action to Launch Center Pro to make it work.

Troubleshooting

  • Having trouble with accented characters? The script was updated on June 25 with a fix for that so you can search for Pokémon or Brüno. I suggest you update the script anyway.
  • If your table is not rendering properly, you probably have Auto-bold First Line turned on in Day One. Turn it off to make it work properly or change the output to skip the first line.
  • If you're running into NoneType errors in Pythonista, grab a newer version, it was updated here and at the Gist.
  • If you're getting weird characters, try copying and pasting from the raw Gist.