Last week, I won a Zune at GiveCamp from a raffle... having never owned a portable device with this much storage space before, my thoughts turned this weekend to how I might be able to help me solve some musical logistics problems.
By "musical logistics problems", I mean the 32GB of public domain SXSW music that's been sitting on my computer, unlistened to, for at least a year. It's about 5000 songs, and most of them are - quite frankly - terrible. What I desired was a way to very quickly give thumbs up or thumbs down on a song, and have it remove said song (placing it in a "good" or a "bad" bucket to be listened to and deleted, respectively) and continue to the next until it was all done.
The big problem is that performing such a task is a hassle with most media players. Those that even have a ratings system make you go through a process that isn't laborious until you have to do it 5000 times in a row: choose the "star rating", move the file yourself, and then go to the next record. Tolerable when you have only a couple of songs to rate... unpleasant when there's more than a dozen.
What I needed was an interface that I could - ideally, as it ran in the background - give the thumbs up or thumbs down to as I went about my day.First Pass: Zune App
My first thought was that I could use this as an opportunity to delve into the Zune SDK. This turned out to be a big rabbit hole that ate up much of Saturday afternoon before I realized that it just can't be done with the current SDK, nor with any currently existing hacks that expose the "hidden APIs" of the Zune such as OpenZDK.
I did have a lot of fun toying around with OpenZDK
's framework in particular: they have a clever hack that convinces the Zune to run unmanaged code under the guise of it being a content file in a managed app. Through it, you CAN do neat things: unfortunately, the new neat things that are unleashed all have to do with accessing the NVidia 3D Accelerator on the Zune. (An interesting side note: did you know that the Zune SDK gives absolutely no access to the use of the 3D Accelerator? They put a state of the art NVidia mobile chip in there, and the only people who get to use it are Microsoft and those who figured out how to hack it with OpenZDK. I think that's pretty shameful, and a good indicator as to why the only apps in the Zune store are Microsoft apps... but I digress).
The big problem is that almost everything on a Zune is read only from a programmer's perspective: you can't create playlists, you can't alter playlists, and you certainly can't delete files programmatically. Once I started to think about ways to get around it by using the Zune's wireless network connectivity (ALSO locked out from your use unless you do it through OpenZDK!) and perhaps hosting some kind of RESTful service on my computer that would modify playlists, I knew I was beginning to really hammer a square peg into a round hole. The Zune just wasn't meant to do this.
After I slept on it, I realized that it's probably for the best. If this app - whatever it ended up being - ran on a windows machine, we could easily hook it up to some speakers and have everyone in the room rate the songs, which provides a social and more democratic experience (after all, my wife may end up having to put up with listening to whatever we vote on!)
Noting that OpenZDK could be fun for a future project, I had to move on if I was going to get it done this weekend.Second Pass: Windows Media Player Plugin
My second attempt was to create a plugin for Windows Media Player itself. I'd never done it before - I was having a hard time even finding reference material online for such a thing - but I knew it could be done, and it seemed reasonable.
I found an open source project called WMP Keys
(on SourceForge), and began to tear through its code to see how it worked. It was all in C++, which isn't my preferred language these days but I could get by. WMP Keys had some of the core of what I wanted: namely, the ability to assign complex functions in Windows Media Player to global hotkeys so I could do other tasks and still be rating songs.
Within about an hour, I had modified WMP Keys and its settings interface to accommodate as many features as it could. It was able to automatically rate the current song via hotkey (a feature it already did), move to the next song as needed, and even sort the good and the bad songs into separate playlists.
But there was two tiny - but annoying - things wrong with it. One was that I couldn't really put up the simple UI I wanted to put up (with the up or downvote), for when I didn't want to use the shortcut keys. The other is that as a plugin I couldn't find a way to actually hook in to detect when someone's actions on the player *itself* changed to a different song or even playlist. The former was a minor inconvenience, but the latter felt less acceptable. Looking through the documentation at Microsoft, it sounded like being able to hook in as a plugin just wasn't going to happen: I had to have control of my own instance of Windows Media Player. So though I was 90% there with this concept, I decided to take it one step further and write an app.Third Pass: Using the Windows Media Player Control
In retrospect, I probably should've just been satisfied with my modifications to WMP Keys. But I definitely learned a lot in the process of getting what I wanted working in this app!
Since it was an ActiveX control, I could interface with it in C# which brought me back to a more comfortable language for me. I began creating an app that was bare bones but provided a bit more customizability than I was getting in the WMP mod: the ability to more easily change playlists on the fly, for example, and to control what happened when a new song began to play.
In the course of this, I found out a feature of .NET Windows Forms development that was hidden in plain sight and I never realized it! The old school WndProc method, which I knew must exist in some form under the surface, is actually an overrideable method in Forms that you can use to handle messages directly from the Win32 API! In this situation, it was necessary in order to provide those "act in response to a new song playing, regardless of how it started playing" reactions that I wanted the app to have.
I also did a bit of research and found some great code out there for registering and unregistering global hotkeys (http://www.pinvoke.net/default.aspx/use
r32/RegisterHotKey.html), and worked it into my app. After creating a (frustrating!) hotkey settings assignment screen and doing a bunch of debugging, it was good to go!
Here's a screenshot of the silly app:
The buttons on the side are for approve/disapprove/skip song (to come back to it later). In order for you to start approving/disapproving songs, you have to first choose all three playlists needed: the "to play" list, the "Good" list, and the "Bad" list. (You can also create a playlist on the fly as needed). Once you've done that, the windows controls appear and you can hit play to let it run, and go into the "Hotkeys" area to modify your hotkeys.
The hotkey modification process sucks at the moment, but it's enough to get by. Basically you put your cursor in the textbox for each hotkey, and hold down your CTRL and/or ALT and/or SHIFT and single letter combination. When you do this, it checks off the requisite checkboxes and upon hitting save, your new hotkeys are assigned. Since it's just a quick and dirty app, I'm not planning on going back to fix it... but I'll throw the source somewhere in case anyone wants to play with it.
You can also double-click the menu bar on the main window to shrink it down to just showing the Approve, Reject, and Skip buttons, and double click again to bring back the whole interface.
On the whole, it was an interesting weekend project. I learned a lot more about Zune's SDKs and Windows Media Player's interfacing options than I imagined I would going into the weekend... and I got something that at least I'll genuinely use out of it! =)
Okay, it's up on CodePlex now for your perusal in both hastily-created source and mostly untested binary flavors!
View the source/project: http://yeaornay.codeplex.com/
Download Binary: http://yeaornay.codeplex.com/releases/47530/download/128271
Enjoy, if possible! ;)