# Looking for a better playlist import function or ways to improve mine

## Recommended Posts

Has anyone written one?

I have something I tossed together but I'm having a hard time trying to figure out how to handle relative pathnames:

\..\..\..\..\..\this\is\a\path\to\a\song.mp3

Also, there is the issue of dealing with accented chars (see the code below for examples).

Here is what I have which works great as long as the paths in the playlist are absolute:

Func _ImportPlaylist($sPlaylist) ConsoleWrite("Processing playlist: '" &$sPlaylist & "'" & @CRLF)
$sPlaylistDrive = StringTrimRight($sPlaylist, StringLen($sPlaylist) - 2)$sPlaylistPath = StringTrimRight($sPlaylist, StringInStr($sPlaylist, "\", 0, -1))
$aPlaylist = StringSplit($sPlaylist, "\")
$aPlaylistType = StringSplit($aPlaylist[$aPlaylist[0]], ".")$sPlaylistType = StringLower($aPlaylistType[$aPlaylistType[0]])
$aEntries = _ArrayCreate (0) If FileExists($sPlaylist) == 0 Then
ConsoleWrite("(_ImportPlaylist) Supplied playlist file does not exist: " & $sPlaylist & @CRLF) SetError(1); file does not exist Return$aEntries
EndIf
$hFile = FileOpen($sPlaylist, 0)
If $hFile == -1 Then ConsoleWrite("(_ImportPlaylist) Playlist file exists; but cannot open file: " &$sPlaylist & @CRLF)
SetError(2); unable to open file
Return $aEntries EndIf ConsoleWrite("(_ImportPlaylist) Opening playlist: " &$sPlaylist & @CRLF)
Select
Case $sPlaylistType = "m3u" ConsoleWrite("(_ImportPlaylist) Processing M3U file" & @CRLF)$sCommentChars = "#;"
While 1
$sLine = FileReadLine($hFile)
If @error = -1 Then ExitLoop
$sLine = StringStripCR(StringStripWS($sLine, 3))
If StringInStr($sCommentChars, StringTrimRight($sLine, StringLen($sLine) - 1)) Then ContinueLoop If$sLine = "" Then ContinueLoop
If StringLeft($sLine, 1) = "\" Then if StringLeft($sLine, 2) <> "\\" Then $sLine =$sPlaylistDrive & $sLine endif If StringLeft($sLine, 2) = ".." Then $sLine =$sPlaylistDrive & $sPlaylistPath & "\" &$sLine
_ArrayAdd($aEntries,$sLine)
WEnd
FileClose($hFile) Case$sPlaylistType = "pls"
ConsoleWrite("(_ImportPlaylist) Processing PLS file" & @CRLF)
$sCommentChars = "#;" FileClose($hFile)
$iEntryCount = IniRead($sPlaylist, "Playlist", "NumberOfEntries", "")
If $iEntryCount = "" Then SetError(4); bad playlist Return$aEntries
EndIf
For $i = 1 To$iEntryCount
$sLine = IniRead($sPlaylist, "Playlist", "File" & $i, "") If StringInStr($sCommentChars, StringTrimRight($sLine, StringLen($sLine) - 1)) Then ContinueLoop
If $sLine = "" Then ContinueLoop If StringLeft($sLine, 1) = "\" Then
if StringLeft($sLine, 2) <> "\\" Then$sLine = $sPlaylistDrive &$sLine
endif
If StringLeft($sLine, 2) = ".." Then$sLine = $sPlaylistDrive &$sPlaylistPath & "\" & $sLine _ArrayAdd($aEntries, $sLine) Next Case$sPlaylistType = "wpl"
ConsoleWrite("(_ImportPlaylist) Processing WPL file" & @CRLF)
$sCommentChars = "#;" While 1$sLine = FileReadLine($hFile) If @error = -1 Then ExitLoop$sLine = StringStripCR(StringStripWS($sLine, 3)) If StringInStr($sCommentChars, StringTrimRight($sLine, StringLen($sLine) - 1)) Then ContinueLoop
If $sLine = "" Then ContinueLoop If StringInStr($sLine, "<media") Then
$sLine = StringTrimLeft($sLine, StringInStr($sLine, "src=") + 4)$sLine = StringLeft($sLine, StringInStr($sLine, '"') - 1)
$sLine = StringReplace($sLine, "&apos;", "'")
$sLine = StringReplace($sLine, "&amp;", "&")
_ArrayAdd($aEntries,$sLine)
EndIf
WEnd
FileClose($hFile) Case$sPlaylistType = "asx"
ConsoleWrite("(_ImportPlaylist) Processing ASX file" & @CRLF)
$sCommentChars = "#;" While 1$sLine = FileReadLine($hFile) If @error = -1 Then ExitLoop$sLine = StringStripCR(StringStripWS($sLine, 3)) If StringInStr($sCommentChars, StringTrimRight($sLine, StringLen($sLine) - 1)) Then ContinueLoop
If $sLine = "" Then ContinueLoop If StringInStr($sLine, "SourceURL") Then
$sLine = StringTrimLeft($sLine, StringInStr($sLine, "value"))$sLine = StringTrimLeft($sLine, StringInStr($sLine, '"'))
$sLine = StringLeft($sLine, StringInStr($sLine, '"') - 1) _ArrayAdd($aEntries, $sLine) EndIf WEnd FileClose($hFile)
Case $sPlaylistType = "xml" ConsoleWrite("(_ImportPlaylist) Processing XML file" & @CRLF)$sCommentChars = "#;"
While 1
$sLine = FileReadLine($hFile)
If @error = -1 Then ExitLoop
$sLine = StringStripCR(StringStripWS($sLine, 3))
If StringInStr($sCommentChars, StringTrimRight($sLine, StringLen($sLine) - 1)) Then ContinueLoop If$sLine = "" Then ContinueLoop
If StringInStr($sLine, "<key>Location") Then$sLine = StringTrimLeft($sLine, StringInStr($sLine, "<string>") + 7)
$sLine = StringLeft($sLine, StringInStr($sLine, "</string>") - 1) If StringInStr($sLine, "file://localhost/") Then $sLine = StringTrimLeft($sLine, 17)
$sLine = StringReplace($sLine, "&apos;", "'")
$sLine = StringReplace($sLine, "/", "\")
$sLine = StringReplace($sLine, "%20", " ")
$sLine = StringReplace($sLine, "&", "&")
$sLine = StringReplace($sLine, "&amp;", "&")
_ArrayAdd($aEntries,$sLine)
EndIf
WEnd
FileClose($hFile) Case Else ConsoleWrite("(_ImportPlaylist) Playlist file type unsupported: " &$sPlaylistType & @CRLF)
SetError(3); unknown playlist type
EndSelect
$aEntries[0] = ubound($aEntries) - 1
ConsoleWrite("(_ImportPlaylist) Playlist entries extracted: " & $aEntries[0] & @CRLF) Return$aEntries
EndFunc

Any help would be great. TIA.

Edited by sshrum

Sean Shrum :: http://www.shrum.net

All my published AU3-based apps and utilities

'Make it idiot-proof, and someone will make a better idiot'

##### Share on other sites

So, you're trying to read playlist files into an array? Why not just do a directory listing, and skip the playlists all together?

[font="Fixedsys"][list][/list][/font]

##### Share on other sites

So, you're trying to read playlist files into an array? Why not just do a directory listing, and skip the playlists all together?

My project already supports dir-based and dir+subdir-based calls. But when you have close to 30,000 files, play lists are a necessity.

I'm also currently working on a meta tag filter function that will allow one to do cumulative AND comparisons of 'is', 'is not', and 'contains' type filtering on any of the meta tag results (working on the GUI right now).

Think: 'Artist' [is] 'Celine Dion' AND 'WM/Genre' [is not] 'Christmas' AND 'Album' [contains] 'Mountians'.

The filter writeup I can do. I just want to find out if someone has tackled the play list import as that seemed like a more common topic. I can do the playlist import too, but it's just more time I have to spend debugging.

Sean Shrum :: http://www.shrum.net

All my published AU3-based apps and utilities

'Make it idiot-proof, and someone will make a better idiot'

##### Share on other sites

I don't know about the relative path names. Relative to what? Can you post a sample? You can't have a relative reference without also having the parent information somehow available to correlate against.

Also, I'd suggest you load these playlists into a SQL Lite DB. It's already good at doing what you're talking about with the AND and OR and IS NOT stuff.

[font="Fixedsys"][list][/list][/font]

##### Share on other sites

I don't know about the relative path names. Relative to what? Can you post a sample? You can't have a relative reference without also having the parent information somehow available to correlate against.

This is the problem with how WMP generates playlists. If a playlist is stored in 'c:\foo\bar\playlist.wpl', and the song file is in 'c:\this\that\other\Oingo Boingo-Goodbye, Goodbye.mp3', the play list entry is typically written as: '\..\..\this\that\other\Oingo Boingo-Goodbye, Goodbye.mp3'. The location of the playlist is the starting point...but what happens when the playlist is MOVED!?!?! The file now contains invalid references. For those cases, the file is just bad at that point and there is nothing anyone can do to *quickly* get things moving.

Now I'm not sure (haven't tried but assume) that playlists that are stored in another drive letter (say, drive P:) then the content they reference will be written with a fully qualified URL: 'n:\public\media\music\Oingo Boingo-Goodbye, Goodbye.mp3'

I just wish that they would always use a full URL in the playlists.

Also, I'd suggest you load these playlists into a SQL Lite DB. It's already good at doing what you're talking about with the AND and OR and IS NOT stuff.

Databases?....Databases?...We don't need no stinking databases!!!

Aw, dewd, you just LOST geek points with me. The filter I'm doing is pretty simplistic and I can write a func to handle that. Besides, I want to stay away for too many things getting into the fray.

Edited by sshrum

Sean Shrum :: http://www.shrum.net

All my published AU3-based apps and utilities

'Make it idiot-proof, and someone will make a better idiot'

##### Share on other sites

So, what, you're going to store 30,000 records, including full file paths, potentially multiple playlist tags, genre, artist, rating and album information in a multidimensional array? Listen, I once vehemently deplored anything resembling a "database" as you appear to, but experience has taught me that they definitely have their place. And this is one of them. TRUST ME. I transitioned out of doing things the way you are describing, and it has saved me SO MUCH development time. I'm sure that whatever time it takes you to get up to speed on SQL will be far less than what will be required for the behemoth you are preparing to write.

Honestly, once your data is loaded into the DB, your end of the code looks something like this:

$recordset = query("select * from songs where (Artist = 'Celine Dion') AND (Genre != 'Christmas') AND Album like '%Mountians%') for$i = 1 to $recordset.length write($recordset[$i].filepath) next I'm not kidding. Like 4 lines of code. It's worth learning how to do this. Explain how any other way is faster or easier: I'd love to be wrong on this. Oh, and if your database is persistent, meaning you don't recreate it each time you start, you don't need playlists anymore. It can contain all the information and functionality that the playlists were providing. Regarding the relative paths, if you know the playlist is on C:\, and the "\..\..\.." always resolves to C:\ then just do this: If instr($sLine,"\..) then

$sLine = stringReplace($sLine,"\..","")

$sLine = "C:\" &$sLine

endif

However, if the entry is something like "\..\Songs\Dir\file.mp3" then take the playlist filename, stringSplit it by "\" into an array, do the same for the relative link, count the number of ".." entries, and count that far back in the playlist filename array, and you have path's starting point. Easy peasy.

[font="Fixedsys"][list][/list][/font]

##### Share on other sites

I'm just storing the filenames in an array, \$aFiles.

After I WMOPENFILE, I'm querying via WMGet().

The filter is easy enuff....a 'stringinstr()' [contains], a '==' [is], and a '<>' [is not] does the trick.

Not the fastest thing to do but it works well enough. Granted, when the filter is restrictive, there are periods of silence between songs as my util loops to find a song that passes.

It beats trying to query 30,000 records each time and is fast enough that the user (me) doesn't notice the processing time.

Sean Shrum :: http://www.shrum.net

All my published AU3-based apps and utilities

'Make it idiot-proof, and someone will make a better idiot'

##### Share on other sites

Hey, take a look though this, it's really interesting and could help you:

Set objPlayer = CreateObject("WMPlayer.OCX" )

Set objMediaCollection = objPlayer.MediaCollection
Set colSongList = objMediaCollection.getByAuthor("Dire Straits")

For i = 0 to colSongList.Count - 1
Set objSong = colSongList.Item(i)
Wscript.Echo objSong.Name
Next
Edited by lod3n

[font="Fixedsys"][list][/list][/font]

## Create an account

Register a new account