<?xml version="1.0" encoding="utf-8"?>

<!--
  Convert iTunes playlists to m3u suitable for slimserver.

  Author: Ovidiu Predescu
  Date: May 11, 2007

  See http://www.webweavertech.com/ovidiu/weblog/archives/000463.html
  for more details. 

  This code is public domain, feel free to do whatever you want with it.

 -->

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0"
  xmlns:saxon="http://icl.com/saxon"
  xmlns="http://www.apple.com/DTDs/PropertyList-1.0.dtd">

  <xsl:output method="text"/>

  <!-- Create an index of the tracks: key is the track id, value is
  the track dictionary describing it. -->
  <xsl:key name='tracks' match="/plist/dict/dict/dict" use="preceding-sibling::key[1]/text()"/>

  <!-- Match only the playlists -->
  <xsl:template match="array[preceding-sibling::key/text() = 'Playlists']">
    <xsl:apply-templates mode="playlist"/>
  </xsl:template>

  <!-- Ignore all the playlists that are not visible and the "Master"
  playlist which is the whole library. -->
  <xsl:template match="key[text() = 'Name' and
                       not(following-sibling::key[text() = 'Master' and following-sibling::true]) and
                       not(following-sibling::key[text() = 'Visible' and following-sibling::false])]" mode="playlist">
    <xsl:variable name="name" select="following-sibling::string[1]"/>
    <xsl:if test="not(following-sibling::key[text() = $name])">
      <xsl:text>  Playlist: </xsl:text><xsl:value-of select="$name"/><xsl:text>
</xsl:text>
      <!-- Emit into a new .m3u file whose file name is that of the playlist -->
      <xsl:result-document href="{$name}.m3u" method="text" escape-uri-attributes="no">
        <!-- The .m3u heading required in each file -->
        <xsl:text>#CURTRACK 0
#EXTM3U
</xsl:text>
        <xsl:apply-templates select="following-sibling::array" mode="track"/>
      </xsl:result-document>
    </xsl:if>
  </xsl:template>

  <!-- On each track in the playlist we output #EXTINF followed by the
  name of the track, followed in the next line by the path to the
  actual file containing the song. -->
  <xsl:template match="dict" mode="track">
    <xsl:text>#EXTINF:-1,</xsl:text>
    <xsl:apply-templates select="key('tracks', integer)" mode="trackinfo"/>
    <xsl:text>
</xsl:text>
  </xsl:template>

  <!-- This extracts the name of the track -->
  <xsl:template match="key[text() = 'Name']" mode="trackinfo">
    <xsl:value-of select="following-sibling::string[1]"/><xsl:text>
</xsl:text>
  </xsl:template>

  <!-- This extracts the file path from the track. It removes the
  file://localhost added by iTunes. -->
  <xsl:template match="key[text() = 'Location']" mode="trackinfo">
    <xsl:value-of select="substring(following-sibling::string[1], string-length('file://localhost/'))"/>
  </xsl:template>

  <!-- Templates to recursively traverse the XML document. -->

  <xsl:template match="*|@*|text()">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="*|@*|text()" mode="playlist">
    <xsl:apply-templates mode="playlist"/>
  </xsl:template>

  <xsl:template match="*|@*|text()" mode="track">
    <xsl:apply-templates mode="track"/>
  </xsl:template>

  <xsl:template match="*|@*|text()" mode="trackinfo">
    <xsl:apply-templates mode="trackinfo"/>
  </xsl:template>

</xsl:stylesheet>
