Seitunes 1.0

Seitunes v1 is here! I think everything I need it to do is in here. I’m not planning on adding new features in the near future – if anything, I’ll concentrate on optimizing performance.

Sei what?

Seitunes is a command-line interface for iTunes.

It allows you to see what’s playing in iTunes and control it (play, pause, set volume, toggle shuffle, select a playlist, set song rating) from your terminal.

Overview of v1.0

I finally decided to split the program in two separate parts.

libseitunes.(c|h) is a C API to access iTunes through Applescript calls. It is also under GPL.

Seitunes.(c|h) is the higher-level part of the application, which is now completely Applescript-free.

New Features

Support for rating (display and modification).

Playlists: Seitunes now displays the playlist currently playing. You can also see all available playlists, and select the one you want to play (with ‘/’).

Bug fixes

A bug caused Seitunes to think iTunes was completely stopped (hence not displaying data about artist and song) if you went to next track whilst playback was paused. iTunes actually reports such a condition as “stopped”, so I added some code to handle this case (it basically checks if there is a “current track”, and if so, displays the data).

GitHub

Seitunes is now on GitHub!

MeWare?

I’ve stumbled upon this very interesting blog post by Eric Sink, classifying software into three big categories: ThemWare (someone writes software, only other people use it), MeWare (someone write software, only he uses it) and UsWare (someone writes software, he uses it and other people do so).

I have currently no idea if anyone else uses Seitunes, or even downloaded it once to see. If you do use it, I’d be delighted to hear from you!

Seitunes v0.8

Version 0.8 of Seitunes is here!

Apart from finishing implementing the core functions, I focused on code clarity and performance enhancements.

Code

All major Applescript interactions with iTunes now go through separate C functions instead of “oh hey just do it here in main()” as before. These functions act as wrappers to access iTunes, and can be re-used for any other project. I could even put them in a separate file and call it a library :)

Performance

Seitunes used to refresh data (artist, song, volume, shuffle, playlist) all the time, with Applescript, to get data directly from iTunes itself. I reduced the number of interactions and reduced the calls to iTunes.
For example, the “+” key used to tell iTunes to increase the volume, then call Applescript to refresh all data, including the new Volume value. Now it just tell iTunes to increase Volume, computes the new Volume value to display and goes along with it.
I kept refresh mandatory for the iTunes status in case anything goes wrong (playlist ended, etc).
Refresh is also forced when changing songs – obviously we don’t want to wait 3 seconds to see the song we just changed.

Of course it creates a problem when a song ends by itself. If we never refresh automatically, we can’t display up-to-date data.
I solved this by adding a “decay” counter that forces a refresh if the data is more than 3 seconds old.

All of this seem to have a positive effect: Seitunes now feels as snappy and reactive as directly using iTunes.

New features

> Quit iTunes
> Toggle shuffle
> Display current playlist
> Less Applescript errors (yay!)

Actually there shouldn’t be any Applescript error left (and yes that’s a feature!).

OS X 10.6.3 broke ncurses

As I was working on my Seitunes project, I noticed something strange: the arrows didn’t quite work any more. Instead of their proper action (up & down to change volume, right & left to change song), they all quit the program and printed -respectively- “OA”, “OB”, “OC” and “OD” on the stdout.

I tried to go back to a working state by progressively deleting new features I was implementing, until I had exactly the same code as the (known working!) 0.5 version, but it was still quitting. gdb told me it wasn’t a crash (“Program exited normally”).

After some testing, I noticed Seitunes worked on my laptop, but not on my MacBook Pro. The only difference between them being that my laptop was still in OS X 10.6.2, while my mbp has upgraded to 10.6.3.

After a bit of digging into curses functions, I started to suspect keypad(WINDOW *, BOOL) to not work properly after the update. keypad() is supposed to dictate whether getch() should interpret an arrow as one non-ASCII value (with the boolean argument set to TRUE) or a set of ASCII values beginning by the escape char, a.k.a. 27 (FALSE). I explicitly call keypad(stdscr, TRUE) in Seitunes, but the FALSE state would perfectly explain the quit-then-print-two-chars behaviour I had was having: I use the escape character to quit Seitunes.

I wrote two very simple pieces of code -one for keypad true, one for keypad false- that plainly outputs the value returned by getch(). They look like:

#include <curses.h>

int main( int argc, char** argv )
{
	int key;
	initscr();
	cbreak();
	noecho();
	nonl();
	intrflush(stdscr, FALSE);
	keypad(stdscr, TRUE);
	printw("getch() should produce only one value when hitting an arrow.\n");
	while ( (key = getch() ) != 'q' ) {
		printw("You entered key %d\n", key);	
	}
	endwin();
	return 0;
}

Code and makefile available here (testCurses.zip) if you want to give it a try.

Under both OS X 10.6.2 and Linux Mint 6 “Felicia” (based on Ubuntu 8.10), these programs behave as they’re supposed to: when keypad is TRUE, an arrow is shown as a single value; when FALSE, an arrow becomes a set of values.

Under OS X 10.6.3, these two programs behave the same way. Both output several values for an arrow.

I filed a bug report to Apple (vintage interface by the way!).

While this bug is present, we’ll have to manually parse the ASCII values for the arrows, which are mapped as follows:

Up	27 79 65	('escape' 'O' 'A')
Down	27 79 66	('escape' 'O' 'B')
Right	27 79 67	('escape' 'O' 'C')
Left	27 79 68	('escape' 'O' 'D')

Edit: these values assume OS X 10.6.3 and keypad(stdscr, TRUE), a.k.a. when the bug is present.

If you want to use keypad(stdscr, FALSE) in 10.6.3, the arrows are mapped as:

Up	27 91 65	('escape' '[' 'A')
Down	27 91 66	('escape' '[' 'B')
Right	27 91 67	('escape' '[' 'C')
Left	27 91 68	('escape' '[' 'D')

Update, March 1st: Apple answered to my bugreport (ID #7812788). They told me it was a known issue (duplicate of bug #7812932) currently being investigated by engineering.

Seitunes, an iTunes command-line interface

My home main computer is a MacBook Pro, on which I frequently play music with iTunes. However, I’m often on my laptop, without direct access to the MBP’s screen or keyboard/mouse to pause, change song, change volume, etc. I can connect to the MBP using VNC, but I was looking for something more lightweight.

I therefore decided to design a command-line interface for iTunes, that I would run via SSH. I called it Seitunes for reasons I can’t really remember right now, but there it is!

Seitunes is

– written in C and interfaces with iTunes through AppleScript
– designed for OS X – should be compatible with quite old versions actually, because it doesn’t rely on a lot of cutting edge features
– built upon the curses library
– very very small
– still under development
– Free software (GPLv3)
– available here

Features

> Display iTunes playing track and status

Seitunes main screen

> Control iTunes playback (play/pause, volume, next song/previous song)

Seitunes, main screen, playing, with help

> If iTunes is stopped when Seitunes starts, it starts iTunes and starts a song from the Library.

To do

> Add more tests to better check iTunes state and not trigger Applescript errors
> Add info about playlists in order to be able to play a specific playlist instead of the whole library
> Add an option to toggle shuffle
> Implement the “quit iTunes” function and check that it doesn’t cause more Applescript problems

Known bugs

> An error message flickers when an Applescript error is triggered (often when iTunes quit while Seitunes is opened)