Jump to content
Sign in to follow this  
sshrum

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

Recommended Posts

sshrum

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 this post


Link to post
Share on other sites
lod3n

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][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Share this post


Link to post
Share on other sites
sshrum

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 this post


Link to post
Share on other sites
lod3n

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][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Share this post


Link to post
Share on other sites
sshrum

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 this post


Link to post
Share on other sites
lod3n

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][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Share this post


Link to post
Share on other sites
sshrum

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 this post


Link to post
Share on other sites
lod3n

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

http://www.microsoft.com/technet/scriptcen...one/player.mspx

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][*]All of my AutoIt Example Scripts[*]http://saneasylum.com[/list][/font]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×