I see what you did there

Today’s project was this little python script. This runs on a Mac, but goes out and grabs the sqlite database from a system that’s running Boxee, finds anything that’s been watched in Boxee in the last two days, then talks to iTunes and marks things watched there as well. This is so if we watch something on Boxee, the blue “unplayed” dot will also go away on the AppleTV in the other room.

Next project, I suppose, is doing the same thing in reverse: letting Boxee know when we’ve watched something on the AppleTV. That’s only possible with the old AppleTV right now, the new one doesn’t even sync the watched flag with iTunes any more. I hope they will add that in an update, but the rental model is their main push right now, not helping me out with my crazy setup.

This requires appscript and tvnamer for Python. tvnamer is a great Python module that is able to parse filenames and turn them into structured TV episode data. It’s often used in conjunction with tvdb_api to get descriptions, banners, etc. in media center applications based on nothing but filenames. I have another project that does just that, but today’s script only needs tvnamer.

This is the first time I’ve used the applescript binding for python, I was happy to see how easy it was. Applescript itself is an awful language, hurray for not actually having to write any! It’s also the first time I’ve used sqlite in a program, though I’ve messed with other programs’ databases by hand before.

#!/usr/bin/env python
import os, sys, datetime, time
import sqlite3
import tvnamer
from appscript import *
 
class iTunesError(Exception):
    """iTunes Error"""
    pass
 
def mark_watched(show, season, episode):
    playlists = app('iTunes').sources['Library'].playlists()
    for p in playlists:
        if p.name() == 'TV Shows':
            tv = p
 
    if not tv:
        print "Can't locate TV Shows playlist, exiting"
        raise iTunesError
 
    found = False
 
    for t in tv.tracks():
        if (t.show().lower() == show.lower() and
            int(t.season_number()) == int(season) and
            int(t.episode_number()) == int(episode)):
            ep = "%s.s%02ds%02d" % (t.show(), t.season_number(), t.episode_number())
            print 'Marking ep watched: ' + ep
            found = True
            t.unplayed.set(False)
            if(t.played_count() < 1):
                t.played_count.set(1)
    if not found:
        print "Failed to find %s s%02de%02d" % (show, season, episode)
    return found
 
os.system('rsync neurosuser@192.168.1.161:.boxee/UserData/profiles/tinyogre/Database/boxee_user_catalog.db .')
 
period = datetime.datetime.now() - datetime.timedelta(days = 2)
since = time.mktime(period.timetuple())
 
conn = sqlite3.connect('boxee_user_catalog.db')
c = conn.cursor()
c.execute('select strPath, iPlayCount from watched where iLastPlayed > ?', (since, ))
for r in c:
    ep = r[0].rpartition('/')[2]
    parsed = tvnamer.processSingleName(ep)
    if parsed is not None:
        mark_watched(parsed['file_seriesname'], parsed['seasno'], parsed['epno'])

Leave a Comment