PLS to ASX Converter Using Python
Arne Olav Hallingstad13th December 2010
Home
Introduction
This program was created so I could convert 256 kbps radio streams from Digitally Imported Radio in the PLS file format into Advanced Stream Redirector (ASX) files. The ASX files could then be played in Windows Media Player (WMP).
There's a python based command line tool and a wxPython based GUI tool available as both a python script and a stand-alone executable.
For full details about the program see this
Download
Example input file: di.fm.favorites.premium.pls
Command line python source: download
wxPython based GUI Executable: download
wxPython based GUI python source: download
Dependencies
- wxPython
- pyInstaller ("PyInstaller is a program that converts (packages) Python programs into stand-alone executables, under Windows, Linux, and Mac OS X.")
- Ultimate Packer for eXecutables (UPX, "UPX is a free, portable, extendable, high-performance executable packer for several executable formats.")
Command Line Converter in Python
from __future__ import with_statement from optparse import OptionParser import re, os def main(): # parse command line parser = OptionParser() parser.usage = "%prog < input pls file > < output asx file >" (options, args) = parser.parse_args() if len( args ) != 2: parser.error( "source and destination arguments required" ) # set up variables from command line values src = os.path.normpath( args[ 0 ] ) dst = os.path.normpath( args[ 1 ] ) if src == dst: parser.error( "Source and destination file cannot be the same" ) # create a list of strings, one per line in the source file lines = [] with open( src, "r" ) as f: lines = f.readlines() # parse lines if lines != None: # open the destination for writing with open( dst, "w" ) as f: for line in lines: # search for the URI match = re.match( "^[ \\t]*file[0-9]*[ \\t]*=[ \\t]*(.*$)", line, flags=re.IGNORECASE ) if match != None: if match.group( 1 ) != None: # URI found, it's saved in the second match group # output the URI to the destination file print "Found '%s'" % match.group( 1 ) f.write( match.group( 1 ) ) f.write( "\n" ) print "Done writing to '%s'" % dst else: print "Source file '%s' is empty or does not exist, nothing to do..." % src if __name__ == "__main__": main()
wxPython Based GUI Converter
from __future__ import with_statement import sys import wx import os import re # # Reads the input src and writes to the output dst # def PLSToASXConverter( src, dst ): # source and destination is the same, just ignore if src == dst: return # read pls lines = [] with open( src, "r" ) as f: lines = f.readlines() # parse lines if lines != None: # open the destination for writing with open( dst, "w" ) as f: for line in lines: # search for the URI match = re.match( "^[ \\t]*file[0-9]*[ \\t]*=[ \\t]*(.*$)", line, flags=re.IGNORECASE ) if match != None: if match.group( 1 ) != None: # URI found, it's saved in the second match group # output the URI to the destination file print "Found '%s'" % match.group( 1 ) f.write( match.group( 1 ) ) f.write( "\n" ) print "Done writing to '%s'" % dst else: print "Source file '%s' is empty or does not exist, nothing to do..." % src # # wxWidgets application frame # implements the application window frame # class AppFrame(wx.Frame): def __init__(self, parent, ID, title, pos=wx.DefaultPosition, size=(250, 75), style=wx.MINIMIZE_BOX | wx.SYSTEM_MENU |wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN ): wx.Frame.__init__(self, parent, ID, title, pos, size, style) # bind the windows close event wx.EVT_CLOSE(self, self.OnCloseWindow) # create a button, it's the only # item in the frame so it will # automatically stretch button = wx.Button(self, 1004, "Load Play List File (*.pls)") # bind to the button press event wx.EVT_BUTTON(self, 1004, self.OnPressMe) # on button press def OnPressMe(self, event): # open a file dialog so user can locate the pls file srcDlg = wx.FileDialog( self, "Locate pls file...", "", "", "pls files (*.pls)|*.pls|All files|*", wx.FD_OPEN ) # user located a valid file if srcDlg.ShowModal() == wx.ID_OK: # get path to the source file srcPath = os.path.join( srcDlg.GetDirectory(), srcDlg.GetFilename() ) print "src: '%s'" % srcPath # specify where and what name to use for output dstDlg = wx.FileDialog( self, "Save asx file...", "", "", "asx files (*.asx)|*.asx|All files|*", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT ) # user specified an output file if dstDlg.ShowModal() == wx.ID_OK: # get path to the dest file dstPath = os.path.join( dstDlg.GetDirectory(), dstDlg.GetFilename() ) print "dst: '%s'" % dstPath # actually write to output file given the input file PLSToASXConverter( srcPath, dstPath ) # closing window def OnCloseWindow(self, event): # destroy window self.Destroy() # # The wxWidgets application # class MyApp(wx.App): def OnInit(self): # create a frame for this application frame = AppFrame(None, -1, "PLS to ASX Converter") # tell the frame to show frame.Show(True) # bring application window to front self.SetTopWindow(frame) return True if __name__ == "__main__": # create the application app = MyApp(0) # let wxWidgets take over the main loop app.MainLoop()
Using the File Dialogues:
Input/Output
The program takes an input file and and writes to the output file:
Input pls file
[playlist] NumberOfEntries=9 File1=http://72.26.216.106:80/trance_hi Title1=Trance Length1=-1 File2=http://72.26.216.106:80/chillout_hi Title2=Chillout Length2=-1 File3=http://72.26.216.106:80/goapsy_hi Title3=Goa-Psy Trance Length3=-1 File4=http://72.26.216.106:80/drumandbass_hi Title4=Drum and Bass Length4=-1 File5=http://72.26.216.106:80/psychill_hi Title5=PsyChill Length5=-1 File6=http://72.26.216.106:80/dubstep_hi Title6=Dubstep Length6=-1 File7=http://72.26.216.106:80/liquiddnb_hi Title7=Liquid DnB Length7=-1 File8=http://72.26.216.106:80/techno_hi Title8=Techno Length8=-1 File9=http://72.26.216.106:80/chilloutdreams_hi Title9=Chillout Dreams Length9=-1 Version=2
Output asx file
http://72.26.216.106:80/trance_hi http://72.26.216.106:80/chillout_hi http://72.26.216.106:80/goapsy_hi http://72.26.216.106:80/drumandbass_hi http://72.26.216.106:80/psychill_hi http://72.26.216.106:80/dubstep_hi http://72.26.216.106:80/liquiddnb_hi http://72.26.216.106:80/techno_hi http://72.26.216.106:80/chilloutdreams_hi
