Binary Elysium

Hey there! My name is Casey. I'm a software developer, nomad, language lover, and coffee fiend.

GSoC Report Week 2: libmp3tunes goodness

10 June 2008

Project: MP3tunes + Amarok Integration

Total Commits: 35 Weekly Commits: 15

Past 7 Days

This was a busy week. I migrated the existing MP3tunes service in Amarok 2 from making REST calls and parsing XML manually to use libmp3tunes. I created an object oriented encapsulation framework in C++ for libmp3tunes, which is written entirely in c. This means instead of mucking about crafting http queries and worrying about parsing data from XML one can manipulate the Locker in an OO fasion. Here’s a little snippet of how libmp3tunes saves work.

Without libmp3tunes if you wanted to fetch a list of artists this is what it would look like:

    QString urlString = "http://ws.mp3tunes.com/api/v1/lockerData?sid=&partner_token=&output=xml&type=artist";

    urlString = "http://ws.mp3tunes.com/api/v1/lockerSearch?output=xml&sid=&partner_token=&type=artist&s=" + m_artistFilter;
    
    urlString.replace( "", m_sessionId);
    urlString.replace( "", CENSORED);

    debug() << "url: " << urlString;

    m_storedTransferJob =  KIO::storedGet(  KUrl( urlString ), KIO::NoReload, KIO::HideProgressInfo );
        connect( m_storedTransferJob, SIGNAL( result( KJob * ) )
            , this, SLOT( artistDownloadComplete( KJob *) ) );

    ArtistList artists;

     //so lets figure out what we got here:
    QDomDocument doc( "reply" );
    doc.setContent( m_storedTransferJob->data() );
    QDomElement root = doc.firstChildElement( "mp3tunes" );
    root = root.firstChildElement( "artistList" );

    QDomNode n = root.firstChild();
    while( !n.isNull() )
    {
        QDomElement e = n.toElement(); // try to convert the node to an element.

        QDomElement element = n.firstChildElement("artistName");
        ServiceArtist * artist = new ServiceArtist( element.text() );

        element = n.firstChildElement("artistId");
        artist->setId( element.text().toInt() );

        ArtistPtr artistPtr( artist );

        artists.push_back( artistPtr );

        m_collection->acquireWriteLock();
        m_collection->addArtist( artistPtr );
        m_collection->releaseLock();

        n = n.nextSibling();
    }

With libmp3tunes it looks like this:

    Mp3tunesArtistFetcher * artistFetcher = new Mp3tunesArtistFetcher( m_locker );
    connect( artistFetcher, SIGNAL( artistsFetched( QList ) ), this, SLOT( artistDownloadComplete( QList ) ) );

    ThreadWeaver::Weaver::instance()->enqueue( artistFetcher );

    ArtistList artists;

    foreach(Mp3tunesLockerArtist artist, artistList) {
        ServiceArtist * serviceArtist = new ServiceArtist( artist.artistName() );
        
        serviceArtist->setId( artist.artistId() );

        ArtistPtr artistPtr( serviceArtist );

        artists.push_back( artistPtr );

        m_collection->acquireWriteLock();
        m_collection->addArtist( artistPtr );
        m_collection->releaseLock();

    }

Both of those code samples produce this:

MP3tunes Collection Browser

Notice that instead of looping through XML and ripping out data, I was able to call getter methods to retrieve the same data. Of course the XML parsing has only been moved to libmp3tunes, but by hiding the MP3tunes API implementation from Amarok it creates more maintainable code.

If none of that made much sense, no worries, the important bit to grasp is that libmp3tunes does these important things:

  • Encapsulates the MP3tunes API so it is separate from the rest of Amarok.
  • Provides an Object Oriented interface to the mp3tunes API. Creating a new session is as easy as Mp3TunesLocker locker = new Mp3tunesLocker();
  • Ensures Amarok is officially supported by mp3tunes as long as they support libmp3tunes.

Upcoming 7 Days:

There are a few libmp3tunes shortcomings. One is the lack of a means to detect when a session has expired. Each MP3tunes API request requires a valid session (except of course the initial session-establishing request), and each session times out eventually. When using MP3tunes in Amarok it will be important to elegantly handle session timeouts, for the user does not care about sessions or timeouts. When the user clicks play on an artist they expect it to play, while currently, if the session has timed out Amarok doesn’t do anything. This week I will patch libmp3tunes to support detection of timed out sessions.

Another goal for this week is to fix the search box, so it actually searches.

MP3tunes Collection Search

Also, if you right click on an artist in the MP3tunes collection browser you get a “Copy to Collection” option. At the moment it doesn’t do anything. After this week is over, hopefully, selecting the “Copy to Collection” option will let you do just that.

Copy to Collection

Foreseeable Roadblocks:

Last week’s roadblock still stands. In the next few weeks I’ll be getting closer to the time when I will need to implement that syncing part of libmp3tunes into Amarok. The licensing issue won’t stop me from developing it on my own workstation of course, but it will have to be resolved before I can commit that part of library or code that implements it.

Recent Posts

← More Awesome Stuff

binaryelysium.com · page layout by Sean Palmer
·header image by cloaks