Anki Pidgin integration

I've previously mentioned timeboxing, and I find it very useful with Anki. I also use Pidgin, permanently connected to various instant messaging networks. This means people can message me while I'm timeboxing, breaking my concentration and defeating the purpose. If my Pidgin status is set to "Available" this is my own fault, and it would be rude to blame or ignore the third party. The only solution is to consistently set my status to "Do Not Disturb", and it's a lot of hassle to do this manually each time. Fortunately, Pidgin is easy to automate.

Pidgin can be compiled to expose its API over D-Bus. Anki is written in Python and D-Bus bindings are available. Both the D-Bus compile of Pidgin and the Python bindings are available on Ubuntu, which I'm using.

In addition to the "Do Not Disturb" status itself, Pidgin allows a text message associated with the status. This can be used to report the remaining minutes until I reach the end of the timebox. I'd also like to automatically reply to IMs received during the timebox with a message explaining the situation. Pidgin has an option for automatic replies, but this is protocol dependent and in practice useless for this purpose. This means I'll need to receive D-Bus messages from Pidgin as well as sending them. Anki is written with PyQt, which supports D-Bus in the main Qt event loop, but because of better documentation I decided to use a separate python-dbus's gobject based event loop for now. I'll run this in a separate Python thread, so threading needs to be enabled using gobject.threads_init().

Anki has a stateful UI, with state transitions handled by moveToState in Reviewing cards (and therefore timeboxing) takes place in the "review" state. Anki includes various transient states and can transition from the "review" state to the same "review" state again, so watching for the "review" state is insufficient. As far as I can tell a genuine review session always starts with a transition from "overview" to "review", and ends when it enters "overview" or "deckBrowser". The Anki documentation explains how to monkey patch Anki, and I'll use this to modify moveToState to watch for these specific transitions. I'll also save and restore the original Pidgin status on these transitions.

Because the timeboxing timer continues when editing or browsing cards, only updating Pidgin's status when a card is answered could result in inaccurate times reported. For this reason I'll use a repeating timer event running in the same thread as the D-Bus main loop.

I wrote a minimal working implementation, available from my GitHub account. There are some obvious improvements possible:

  • Error checking
  • Configuration and GUI
  • Smarter handling of partial timeboxes. Anki 1 could display an estimate of time remaining. It was never very accurate, but more accurate than assuming a full timebox time-unit when only a few cards remain.
  • Cleaning up the Pidgin transient statuses. Pidgin saves transient statuses for reuse, which is useless menu clutter in this case because the Anki related statuses are never activated manually.
  • Delayed reporting of status changes like with Pidgin's GUI. A status change could be accidental, so there's no need to send network traffic if it's canceled immediately.

The same automatic reporting of status could be extended to other applications which monopolize the user's attention for a predetermined length of time, eg. watching movies with mplayer. In that case it might be necessary to use a proxy server rather than controlling Pidgin directly, to avoid multiple applications fighting over the status.