Thursday, September 27, 2007

Stupid Notification E-Mails

Web-based services are great for various things. For example, I'm a user of the Game Trading Zone for trading old games, a user of YouTube for publishing short video clips and just today I've signed up on StudiVZ, a social networking site for students.

Of course, I'm not going to sign in to every service every day just to check if there are new messages or something that needs my attention. That's what e-mail notifications are here for. The best and most useful e-mail notifications I get are the ones from the Game Trading Zone: Another user sends you an offer and in the e-mail you get a complete description of the offer (what's offered + details of items, custom message, shipping and other settings) and a link to go directly to the offer site. A dream! As soon as I open the e-mail, I know all about the offer and can decide what to do.

Not so with the two bad examples which upset me so much today that I started writing what you read here. I've often got notifications from YouTube, which sends out a notification e-mail whenever someone posts a comment to a video I've uploaded. BUT the actual comment isn't in the e-mail, for that I have to open the YouTube website. How stupid is that? If they just sent the comment in the mail, I could quickly read it and decide if I have to reply, delete the (spam) comment or just read it and forget about it. Instead I have to open that YouTube page. The same stupid thing is present in StudiVZ, so they also just tell you that there is something new, but don't tell you what it is.

So, instead of a simple "read - react" cycle, I have to do a "click link - wait for browser to open - wait for page to load - search for the information in question - read - react", which is so time consuming and stupid that I really had to write this post (which, of course, takes probably as much time writing as reading one month's worth of stupid notification mails, but anyway..).

If you provide some web service that does e-mail notifications, please include useful, readable and compact information about the change/comment/whatever that you want to get through to your user. Just sending links as in "something's new, click the link to find out what it is" is just plain stupid :(

Wednesday, September 26, 2007

PyGTK applications on Windows

One advantage that you automatically gain when writing Python programs is that they are portable to several other mainstream operating systems (although there are some problems with specific extensions, etc..).

So, after releasing gPodder 0.10.0, which has now only one strict dependency on a pure Python module (feedparser), I wanted to try out if I could get gPodder running on Windows (I have tried it once before, but back then I was spawning a wget process to do the actual downloading, which was kind of awkward on the Windows platform).

What you need to get this working is Alberto Ruiz' All-in-one PyGTK Win32 installer and a check-out of the current SVN trunk head of gPodder. To check out a working copy from a Subversion repository on Win32, you can use TortoiseSVN.

I've found some divide-by-zero errors that I didn't see happening on Linux, so I could quickly fix them in our Subversion repository. I also got rid of some old symlinking code that I didn't use anymore, because symlinks on Windows isn't really possible (except for Vista maybe). Other than that, there were just some minor problems with my code being Unix/X11-specific, for example I'm checking for the $DISPLAY variable in the main script, which isn't needed on Win32.

There were other minor annoyances which I haven't dealt with yet, but which don't interfere with the basic functionality of gPodder:
  • Running .mp3 or .avi files with the preferred media player (how do I do that on Win32?)
  • Getting a GTK Icon Theme into my GTK installation, so all icons in gPodder display properly
  • Removing the GUI for iPod synchronization (or get libgpod + Python bindings working on Win32)
  • Testing, testing testing :)
I wonder if it's possible to use Py2exe to create a nice, self-contained Win32 package of gPodder that has Python2.5, the GTK runtime, PyGTK and python-feedparser integrated and works without installing anything.

Thursday, September 13, 2007

X11 idle time and focused window in Python

For my Evolution New Mail Notification script, I wanted to make the notification popups not enabled when I'm already working within evolution (e.g. the Evolution window is focused) and I also didn't want to play sounds when I'm working on the computer, because I will see the visual notification, anyway (e.g. the X11 idle time is less than some specified timeout).

To accomplish that, I had to write a bit of Python code for two simple tasks:
  • Get the window name and/or class of the currently focused window
  • Get the idle time of the X11 session, e.g. the time since the last input event
The window name/class getting can be done with the help of the Python X Library and the idle time can be done using some obscure ctypes loading of and doing a bit of C-bindings stuff, which I found by searching the web. Here, I want to share the code with you in case you need it for some project of yours:

Window Name and Class for the focused window
import Xlib.display
display = Xlib.display.Display()
focus = display.get_input_focus()
print "WM Class: %s" % ( focus.focus.get_wm_class(), )
print "WM Name: %s" % ( focus.focus.get_wm_name(), )
X11 Idle Time using the XScreenSaver extension
import ctypes
import os

class XScreenSaverInfo( ctypes.Structure):
""" typedef struct { ... } XScreenSaverInfo; """
_fields_ = [('window', ctypes.c_ulong), # screen saver window
('state', ctypes.c_int), # off,on,disabled
('kind', ctypes.c_int), # blanked,internal,external
('since', ctypes.c_ulong), # milliseconds
('idle', ctypes.c_ulong), # milliseconds
('event_mask', ctypes.c_ulong)] # events

xlib = ctypes.cdll.LoadLibrary( '')
dpy = xlib.XOpenDisplay( os.environ['DISPLAY'])
root = xlib.XDefaultRootWindow( dpy)
xss = ctypes.cdll.LoadLibrary( '')
xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo)
xss_info = xss.XScreenSaverAllocInfo()
xss.XScreenSaverQueryInfo( dpy, root, xss_info)
print "Idle time in milliseconds: %d" % ( xss_info.contents.idle, )
If you're interested in a real-world example usage of this code, feel free to check out my new mail notification script that works with Evolution over D-BUS.

Wednesday, September 12, 2007

Downloading in Python?

Currently, I'm using a rather ugly way of downloading files in my Python application by executing a "wget" process and extracting progress and speed information from wget's stderr output. Of course, this is ugly and it depends on many factors (did you know RedHat/Fedora's wget has a different output format?

Ideally, I'd like to replace the current code with something completely Python-ish (using urllib2?). The ideal solution would:
  • Be completely written in Python
  • Download URLs to specified local file names
  • Be threaded (or runnable in threads)
  • Report current speed (e.g. 40kb/s) and progress (40% done)
  • Cancelling in-progress downloads should be possible
  • Optionally provide the "estimated time left"
  • Handle URL redirections, HTTP authentication, etc..
Does anyone know of a (lightweight) library that does this or has anybody some code to share so that I don't have to start writing this thing from scratch? If not, some hints on how to best do these things would be very nice.