Update: source code available here.
A few months ago I switched website hosts from Netfirms to Site5, because Site5 had a good deal for a plan with unlimited bandwidth and disk space. The first thing I did was upload my entire music collection.
To access all of my music remotely via any internet-connected web browser, I wrote ZX2C4 Music, which is password protected to avoid the law, but if you’d like to view the interface just for curiosity, ask me in the comments section, and I’ll e-mail you a password. It uses PHP/MySQL for managing the music, hashing each file with an sha1, TagLib for reading tags, and JavaScript/HTML as an interface:

Search queries are done with AJAX, and playing is done with Flash, if available; otherwise it defaults to browser plug-ins. Soon I should add HTML5’s <audio> element support. Since Flash only supports MP3, the php backend optionally transcodes non-mp3 songs on the fly by using ffmpeg. Songs can be downloaded in zipped bundles by using the download basket feature. The web interface still needs some work, most notably scrolling-pagination for the song table, but it’s definitely usable. Many have pointed my attention to Ampache, but I found it too big and overwhelming. You can view the source code here.
Of course, the next step was writing a Qt or KDE application that interfaces directly with the web backend using Phonon. Meet ZMusicPlayer:

It downloads and displays a compressed and sorted xml listing of all the songs and their sha1s. The columns of the list automatically size optimally using an awesome algorithm that still needs some tweaking (why is subtracting 40 required on line 87?). Suggestions?
It plays the songs by passing the appropriate QUrl to Phonon, and this is where the trouble begins. The xine backend on KDE 4.1.2 just skips one song to another most of the time, and when it does miraculously play, seeking (via HTTP partial requests) is unavailable. The headers for each of the server responses for song file requests provide the appropriate parameters for HTTP seeking. Maybe this has already been fixed in trunk, but if not, I aught to investigate the problem as soon as I switch my 4.1.2 desktop completely to trunk. GStreamer with Qt 4.4 allows for proper streaming if a GStreamer HTTP plug-in is installed (gst-plugins-good includes a wrapper plugin for libsoup, which works, for those who don’t want to install the gnome vfs plugin), which is understandable. However, seeking only works for mp3 files; m4a files play but cannot seek, even though the pertinent response headers are the same for both file types. On the Windows backend, the seeking situation is hopeless, and on the OS X backend, songs do not play at all. Also, xine is the only one that emits the proper buffering signals. On some setups though, some of these problems go away. I still need to do some more thorough debugging.
If you’d like to download and build ZMusicPlayer, you can browse the source, clone the repository with git clone http://git.zx2c4.com/zmusicplayer.git, or download a tarball. Depending on your package setup, you may have to tinker with the includes for the phonon headers. I’d love to hear some suggestions, so leave comments below. Once I stabilize the Qt code, I’d like to develop some optional KDE extensions, particularly integration with the KDE’s keyboard shortcuts.
Also: I’ve switched from blogging on kdedevelopers.org to my own Wordpress blog so that anyone can post comments without requiring an approved account. So, comment away. If you wanted to comment on my first post, but were unable to, you can now comment here. To comment on this post, use the link below.
Update Oct 25, 3:31pm: Several of you have e-mailed me to say that the browser hangs when loading a unfiltered giant collection. This is indeed the case, as no current browser is able to write 10,000 rows to a table in a reasonable amount of time. This is why above I speak of “scrolling-pagination”, which means that the table would load 100 or so rows at a time, and then auto-populate the remaining rows in 100 row increments every time the user scrolled to near the end.

