Goofy APIs

In the next release of Rhythmbox Applet, there’s going to be support for rating songs. Two odd wrinkles I’ve encountered, both related to APIs not doing what you’d expect them to do.

The first one I brought up on rhythmbox-devel. Although Rhythmbox displays ratings on a discrete five-star scale, internally they’re stored as a floating point number between 0 and 5. The auto-rating code makes use of fractional ratings, nudging a song up or down a fraction based on user actions (or lack thereof). So fractional ratings in and of themselves aren’t a problem.

The oddity comes in when you look at the Bonobo bindings, which Rhythmbox Applet uses to control Rhythmbox. A song’s rating is only exposed as an integer (technically, a long), not a float. Even worse, the value gets rounded down, whereas they’re rounded up when Rhythmbox displays them. You can’t work around this by just adding 1 to each rating, because ratings the user assigned himself won’t be fractional, and thus won’t be rounded either way.

So either auto-rated songs show up incorrectly, or manually-rated ones show up incorrectly. Nothing much to be done about that, as the aforementioned thread on rhythmbox-devel reveals, without breaking compatibility with other programs using the bindings.

To make matters even goofier, I stole liberated the ratings widget from the Rhythmbox code to use in the applet, and it (naturally) treats ratings as floats. So half the places I deal with a rating in my code, it’s a double, and the other half, it’s a long.

The second one comes up with radio buttons in a panel applet’s right-click menu. Since the menu is specified via an XML file, my interactions with it have to go through BonoboUIComponent. There’s a signal (“ui-event”) you can listen for to find out when a set of radio menu items gets selected; I’m using that to let the rating be set via the menu (in case the user doesn’t want the rating widget doubling the space Rhythmbox Applet uses).

Here’s the thing. A ui-event is triggered when the menu appears on the screen. A ui-event is also triggered when one of the radio items is selected by the user. But here’s the thing: the two events are indistinguishable! Exact-same-arguments-to-the-callback-function indistinguishable.

In other words, there is no way the program can tell if the user has changed the rating via the menu, or just opened the menu.

Originally (i.e., before discovering this oddity), I was setting a song’s rating whenever a ui-event fired. This had the effect of rounding songs’ ratings down ever time the menu was opened (thanks to the Rhythmbox’s rating-rounding-over-Bonobo oddity).

The workaround? Don’t tell Rhythmbox to change the rating if the ui-event’s claimed new rating is the same as the one the applet currently believes it is.

Comments are closed.