#! /usr/bin/env python # # Convert an M3U playlist to XSPF. # # Usage: m3u2xspf < input.m3u > output.xspf # # Copyright (c) 2006, Matthias Friedrich # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # __revision__ = '$Id: m3u2xspf,v 1.4 2007/03/30 16:31:03 matthias Exp matthias $' __version__ = '0.2' import sys import urllib import urlparse import os.path import optparse import xml.sax.saxutils as saxutils class XmlWriter(object): def __init__(self, outStream, indentAmount=' '): self._out = outStream self._indentAmount = indentAmount self._stack = [ ] def prolog(self, encoding='UTF-8', version='1.0'): pi = '' % (version, encoding) self._out.write(pi + '\n') def start(self, name, attrs={ }): indent = self._getIndention() self._stack.append(name) self._out.write(indent + self._makeTag(name, attrs) + '\n') def end(self): name = self._stack.pop() indent = self._getIndention() self._out.write('%s\n' % (indent, name)) def elem(self, name, value, attrs={ }): # delete attributes with an unset value for (k, v) in attrs.items(): if v is None or v == '': del attrs[k] if value is None or value == '': if len(attrs) == 0: return self._out.write(self._getIndention()) self._out.write(self._makeTag(name, attrs, True) + '\n') else: escValue = saxutils.escape(value or '') self._out.write(self._getIndention()) self._out.write(self._makeTag(name, attrs)) self._out.write(escValue) self._out.write('\n' % name) def _getIndention(self): return self._indentAmount * len(self._stack) def _makeTag(self, name, attrs={ }, close=False): ret = '<' + name for (k, v) in attrs.iteritems(): if v is not None: v = saxutils.quoteattr(str(v)) ret += ' %s=%s' % (k, v) if close: return ret + '/>' else: return ret + '>' def createAnnotation(url): """Get file name part, split off extension, rewrite underscores.""" path = urllib.unquote(urlparse.urlsplit(url)[2]) filename = os.path.splitext(os.path.basename(path))[0] return filename.replace('_', ' ') # # MAIN # optParser = optparse.OptionParser( usage='%prog [-ah] [file]', version='%prog ' + __version__ ) optParser.add_option('-a', '--annotation', action='store_true', dest='add_annotation', default=False, help='create annotation elements based on the file name') (options, args) = optParser.parse_args() # # Write the playlist in XSPF format. # xml = XmlWriter(sys.stdout, indentAmount=' ') xml.prolog() xml.start('playlist', { 'xmlns': 'http://xspf.org/ns/0/', 'version': '1' }) xml.start('trackList') for line in sys.stdin: line = line.rstrip('\n') if line.startswith('#') or len(line.strip()) == 0: continue if line.startswith('http://'): url = line else: url = 'file://' + urllib.pathname2url(line) xml.start('track') xml.elem('location', url) if options.add_annotation: xml.elem('annotation', createAnnotation(url)) xml.end() # track xml.end() # trackList xml.end() # playlist # EOF