PLS to ASX Converter Using Python

Arne Olav Hallingstad
13th 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

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

References

  • PLS File Format
  • ASX File Format
  • Windows Media Player
  • Digitally Imported Radio

  • Tweet

    Creative Commons License
    This work is licensed under a Creative Commons Attribution 3.0 Unported License.