#!/usr/bin/python
# -*- coding: utf-8 -*-

# last change: 18.08.2007
# author: Mario Wehbrink <wehbrink@web.de>
# license: GPLv2 or later

# Generate Playlists for iRiver T10 (with UMS firmware). Maybe works also with
# other MP3-Players from iRiver (not tested)

# Simply put this script in your playerroot.
# if you have your music in /Music and your playlists in /Playlists
# then just do a python iRiverPlaMaker3.py and it walks through all files and dirs
# in /Music and creates a playlist for each folder in /Playlists

# thanks to Martin Owen for explanation of the iRiver playlists format.
# http://wiki.bath.ac.uk/display/~ma9mjo/iRiver+s10


import sys
import os
import struct
import optparse

class Playlist(object):

    def __init__(self, name, playlistpath):
        self.name = name
        self.playlistpath = playlistpath
        self.filename = self.playlistpath+self.name+".pla"
        self.songs = []

        if not os.path.isdir(playlistpath):
            # try to create Playlistdir
            # if this fails, something is really wrong (ro mounted player for example)
            try:
                os.mkdir('Playlists')
            except OSError:
                print "\nFailed to create Playlist!\n"
                sys.exit(1)

    def calcOffset(self, name):
        offset = name.rfind('\\') + 2      # standard offset. needs to be increased by 1 for every ord(char) > 128
        for char in name:
            if ord(char) > 128:
                offset += 1
        return offset


    def __replSlashes(self, string):
        return string.replace("/","\\")

    def addSong(self, name):
        if name[0] != '/':
            name = '/'+name
        (path, songname) = os.path.split(name)
        name = self.__replSlashes(name)
        offset = self.calcOffset(name)
        print name
        # 512 bytes per song
        # blame iriver for this strange UTF encoding. Playlist has 2 bytes per character, but Umlauts etc are
        # encoded in UTF-8 with leading \x00. Maybe someone has an idea how to
        # solve this in a more consistent and nicer way, I think this will not really work with 
        # chars, that do not fit into latin1. Any hints appreciated.
        song = struct.pack('>H510s',offset,name.encode('utf8').decode('latin1').encode('utf-16-be'))
        self.songs.append(song)

    def write(self):
        # 512 bytes header
        hdr = struct.pack('>i14s14x480s',len(self.songs),"iriver UMS PLA","iRiverPlaMakerv3")
        playlist = []
        playlist.append(hdr)
        playlist = playlist + self.songs
        try:
            file = open(self.filename,'wb')
            file.writelines(playlist)
        except:
            print "Error writing playlist"
            return False

    def list(self):
        for song in self.songs:
            print song

    def __repr__(self):
        return self.name

def main():

    musicdirs = []

    # parse commandline
    parser = optparse.OptionParser()
    parser.add_option("-p", "--playlist", action="store", type="string", dest="playlistDir", default=u"Playlists/", help="where to put the Playlists. Default is ./Playlists")
    parser.add_option("-m", "--musik", action="store", type="string", dest="musicList", default=u"Music", help="Comma seperated list of directories, that will be searched for music. Defaults to ./Music")
    (options, args) = parser.parse_args()

    # are there any unprocessed arguments?
    if len(args) > 0:
        print "error parsing commandline"
        sys.exit(1)

    # split list of dirs
    musicdirs = options.musicList.split(",")
    # just for shorter code below
    playlistdir = options.playlistDir

    # need trailing '/'
    if playlistdir[-1:] != "/":
        playlistdir = playlistdir+"/"

    print "Creating playlists in "+playlistdir
    # lets walk through the musicdirs
    for music in musicdirs:
        for root,dirs,files in os.walk(music):
            if len(files) == 0:
                continue                     # only process dirs that have files in it
            print "Entering directory: "+root
            p = root.split("/")
            playlistname = p[len(p)-1]      # Take dirname as playlistname
            playlist = Playlist(playlistname, playlistdir)   # create new playlistobject
            files.sort()
            print "Creating playlist "+playlistname+".pla"
            for file in files:
                playlist.addSong("/"+root+"/"+file)
            playlist.write()
            print "\n"
    print "Finished. Bye!"


if __name__ == "__main__":
    main()

