A group blog from members of the VB team
Well, that was… intense.
You may have noticed the lack of articles coming from my direction. I have been so buried in work, and so far behind, that when I look forwards all I see is backwards. I work, I drive home, I work some more, and it all seems to keep piling up. I would like to say that this is going to change soon, but alas, that’d be a lie. Even though my immediate fire drills in engineering process have died down, I’m going to be flying a lot in October visiting our teams around the world, and then right back into the fires when I get home.
One of the things that have been getting me through the crazy times at work is my new Zune. I *love* my Zune. Now, I’ve never used an iPod, so I can’t compare the two, but my Zune is glued to me pretty much all the time I’m in the car, at work, mowing the lawn, etc. (I drive a Ford Focus, so I have the Microsoft Sync system, and that’s also been a joy to use with my Zune.) I have the 80 GB Zune 2 model. I figure I’ve got 600+ CDs on the thing, all of the home movies I’ve taken of my family (which I like to watch while flying on business trips), and still have a lot of room left over. With the recent updates to allow for gapless playing and the 3.0 firmware, I’m pretty happy right now, media-wise.
Now, of course, my dilemma with shuffled playlists that I first discussed earlier this year still applies, just on a new device. That is, if I shuffle my enormous “Favorite songs” list, I inevitably break apart songs that belong together on one arc. I solved this for Windows Media Player in an earlier blog series, by creating my own on-the-fly shuffled WPL list which kept songs together. (Go ahead & read part 1 and part 2 now if you haven’t already; this blog won’t make much sense without them.) However, Zunes don’t play WPL playlist files; they play ZPL playlist files. So, what to do?
Well, there’s one not-so-secret secret: ZPL files are exactly like WPL files. They have the same format. The only difference is the file extension. So, you might think that all I have to do is copy the generated WPL file to a ZPL file, right? Well… it’s not that easy.
If you look at the original code, the line that saves the new playlist looks something like this:
Private Sub SavePlaylistBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SavePlaylistBtn.Click
' Save new playlist to library and Music\Playlists
This creates a WPL file in the “Playlists” directory, so, in theory, after calling “importPlaylist,” I’d do something like:
where the two arguments are simply strings pointing to the file locations (e.g., "C:\Users\Matt\ Music\Playlists\Favorites.wpl" and "C:\Users\Matt\ Music\Playlists\Favorites.zpl"). However, if you do this, it won’t work – your ZPL file will be empty of everything except boilerplate code (at best).
Why is this? Well, importPlaylist is an asynchronous call. The VB program fires the call and moves on to the next instruction. It will try to copy the file immediately, even if importPlaylist() isn’t finished. importPlaylist(), in turn, creates the playlist in two steps – it creates the boilerplate XML, and then it injects the music entries into the playlist. The trick here is to wait until the importPlaylist() call has completed the creation of the file before copying it. But how to do that?
You could, in theory, keep looping until the size of the file changed twice, but that’s seems sort of, well, silly. Fortunately, there’s a better way. The Windows Media Player object has an event model associated with it – WMPLib.IWMPEvents – and it’s already supported by the WMP object we added to the original project. We can handle the events really easily. In the code editor, go up to the left-hand drop-down at the top of the editor and select “Player” (or whatever you called it in your copy). Now, in the right-hand dropdown, choose “PlaylistCollectionChange”. This will generate the event handler, and we can fill it in with our code. (Yes, I know there’s a “PlaylistCollectionPlaylistAdded” also. I tried it; it’s not useful for this case, since we’re importing, not adding, and so it doesn’t get called.)
Here’s the event handler that gets generated:
Private Sub Player_PlaylistCollectionChange(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles Player.PlaylistCollectionChange
The value “e” is always empty. That’s kind of unfortunate, because the event will be called 3-6 times after importPlaylist() is called, and it would be kind of nice to know which call was due to music injection vs. WMP-specific stuff. So, we’ll do it the hard way. There are two possible states that we care about – the file has been populated with the boilerplate code, and the file has been populated with the music. Let’s add a value to our form class to track the size of the file as it changes:
Public initialSize As Long = 0
We also want to ignore changes except when we explicitly do an import ourselves (i.e., account for someone adding a playlist outside of this program). Because we’ll be checking for specific file changes, it wouldn’t actually harm us if other playlists were changed outside (unless coincidentally the same name was created), but I dislike having my event code run unless it’s meaningful to do so, as it wastes cycles. You could also use AddHandler/RemoveHandler here, which would be even more performant, but I’m feeling lazy and so will just go with a simple Boolean here :
Public listenForEvents As Boolean = False
Now, we’ll make sure these are initialized properly whenever we do an import of the playlist:
Private Sub SavePlaylistBtn_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles SavePlaylistBtn.Click
initialSize = 0 ' File starts at zero
listenForEvents = True ' Start listening
And now we handle the event itself:
If Not listenForEvents Then Return ' Pay no attention; we don't care about this change
' If we're here, then we care. What’s the current size of the file?
Dim fileSize As Long
fileSize = My.Computer.FileSystem.GetFileInfo(newwplfilename).Length
If fileSize > initialSize Then ' Filesize change
If initialSize = 0 Then
initialSize = fileSize ' First step – boilerplate added. Don’t copy yet!
' Jump from one non-zero number to a larger non-zero number – must be the music.
listenForEvents = False
The first time this gets called (at times when we care), the file will exist, but it will have some small size, indicating the first phase of creating the boilerplate XML is complete. At some subsequent call (not necessarily the next one), the size will jump due to the music being added – that’s when we copy, and then tell our event handler not to check anymore.
The next time I hook up my Zune and open the Zune player, it will automatically resync the updated playlist, and I’ll have a new order to play for a while without the songs being broken up.
By the way, I’m not totally happy with this solution; I think it’s a bit hacky, and I’ve been searching for a better way to know when the save is completed. This is new territory for me, so if you have a better way, let me know!
‘Til next time,
PingBack from http://www.easycoded.com/building-a-zune-playlist-matt-gertz/
I had my music set up in folders structures (e.g. Rock --> Classic Rock etc) on my machine based on my liking but could not find easy way to create zune playlists based on folder structure so I wrote a quick tool which would do this... I made it available to be downloaded for free at http://vishaljoshi.blogspot.com/2008/12/kritzu-zune-playlist-generator-based-on.html, you might find it interesting... :-)
can you post the source code for this project?
Yes, I will do that tonight when I get home. (I've actually changed it slightly to make it a little more efficient.)
Thanks that will be really cool!
How do you add songs to the play list. i tried drag and drop other than that i don't know what to do. i browsed the code and i don't see anything that could be sued for handling adding songs
"could be *used* for handling adding songs"
Sorry for any confusion -- "could" in my blog posts means "if you take the concepts you've leanred in these blogs, you could extend it to do even more." Mostly, with these blog posts, I'm trying to introduce the various concepts (or SDKs on occasion) by applying them to a particular problem I'm trying to solve at home. In my case, I generally add songs via the WMP (since I need to do this anyway for my home stereo system), and then use this program to rearrange them in an order that's not offensive to my ears when playing the songs back on the Zune or on Sync. So, that's as much as I do with this program.
That being said, almost every concept you need to add arbitrary songs to a playlist is in this program and in the three blogs that relate to it -- opening of a new or existing playlist and adding media items to it, and I discuss those a bit in the other two blogs (links to them are in the above article) which had the original code. The one missing element is simply the creation of the media object representing the file (i.e., explicitly associating it with the file -- but that's just another method in the class namespace which is (I believe) associated with either playlist or library object.
Hope this clears things up!
I just made a play list in WMP and then renamed it to .zpl so that worked fine. I could have added my own code to make it work like that but then i remembered that i am lazy, so i went and did it in WMP. But thank you for the source code. i am sure i can find some use for it eventually.
Yep, the real point of this post was just to provide an update to the earlier two posts, which dealt with customizing playlists, so that you could copy them to Zune playlists at the same time that you reordered the lists. If you don't care about playlist ordering, then simple renaming or copying is the way to go.
I downloaded some old time radio shows from the net. When they downloaded they were wpl files, so I right clicked each one and said "Open With" Zune. That apparently changed them to MP3's because they downloaded to My Documents folder with file extensions of .mp3.......so here's my problem......when I click on the file it opens with Zune and plays normally in the "Now Playing" area of the Zune Software. When I got to save as a new playlist it saves it and the title is there, but when I try to sync it to the Zune it says the file is empty (no megabytes) Can you offer any help on how to get these files to sync with my Zune? I've already checked my zune settings and it should accept a mp3 file...I don't understand....please help!
I'd like to help, but I'm not quite understanding the question. WPL files are playlist files, which simply contain references to media files -- there's no chance of a WPL being converted to an MP3 file itself. I just tried this myself, and when I do an "Open with Zune" on a WPL file, all that happens is that Zune launches, but it does nothing -- it doesn't actually know what to do with a WPL file. So, I'm wondering if you had some typos in your question?
Here's what I would have expected -- I would download a set of MP3 files (or maybe WMA files), which was perhaps accompanied by a WPL playlist. I'd change the WPL extension to a ZPL extension. I'd launch the Zune software and make sure that it detected the new files (some people have their Zune software set up for manual detection rather than automatic, for example). Then I'd sync my device -- both the MP3's and the ZPL file would get pushed to the device.
Let me know if you have more info. Given that, I may or may not be able to answer (I'm not on the Zune team, and I don't know much more than anyone else about it.)
P.S. I like old time radio shows, too. I'm halfway through a volume of "Fibber McGee and Molly" shows that my wife got me for Christmas -- they're quite fun!