From Bob Brandt's Projects Site

N900: Playlist Sync

While the N900 is AWESOME, it is really new and some things are just not quite perfect yet! One of these things is the playlist editor for the default Media Player. That is to say that there ISN'T a playlist editor!!

Now my computer at home has an many, many great playlist editors... So why not use them??

This program will sync playlists between your N900 and your home machine. (Actually it will sync playlists between any two machines)

This is a work in progress so nothing is guaranteed! Right now I am using my Wiki as a means of transferring code between different sites.


#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
    PlaylistSync by Bob Brandt (projects@brandt.ie).
    Licensed under GPL version 3
    Created on 10 March 2010
"""  
import sys, os, optparse, re
version = "0.1"

class playlistsync(object):
    '''
    This class is used to sync a playlist from one device to another and all relevant files
    '''

    def __init__(self, sourceRoot, destMountPoint, destRoot = None, hierarchical = False, debug = False):
        if os.path.isdir(sourceRoot):
            self.__sourceRoot = sourceRoot
        else:
            raise IOError, "There is no such directory: '%s'" % sourceRoot
        if os.path.isdir(destMountPoint):
            self.__destMountPoint = destMountPoint
        else:
            raise IOError, "There is no such directory: '%s'" % destMountPoint     
        if not destRoot: destRoot = destMountPoint
        self.__destRoot = destRoot
        self.__hierarchical = bool(hierarchical)
        self.__sourcePlaylists = self.__loadplaylists(self.__sourceRoot)
        self.__destPlaylists = self.__loadplaylists(self.__destMountPoint)
        self.__playlists = {}
        for playlist in self.__sourcePlaylists.keys():
            if playlist in self.__destPlaylists.keys():
                self.__playlists[playlist] = {"source":self.__sourcePlaylists[playlist], "dest":self.__destPlaylists[playlist]}


    playlistextenstions = property(lambda self: (".m3u",".pls") )
    sourcePlaylists = property(lambda self: self.__sourcePlaylists )
    destPlaylists = property(lambda self: self.__destPlaylists )
    playlists = property(lambda self: self.__playlists )

    def __loadplaylists(self, root):
        playlists = {}
        def checknames(junk, dirpath, namelist):
            for name in namelist:
                if os.path.splitext(name)[1].lower() in self.playlistextenstions:
                    playlists[os.path.splitext(name)[0].lower()] = os.path.join(dirpath,name)
        os.path.walk(root, checknames, None)
        return playlists

    def __isInPlaylist(self, Playlist, PlayLists):
        Playlist = str(Playlist).lower()
        if Playlist in PlayLists.keys():
            return {"name":Playlist, "path":PlayLists[Playlist] }
        for tmp in PlayLists.keys():
            if Playlist == str(PlayLists[tmp]).lower():
                return {"name":Playlist, "path":PlayLists[tmp] }
        return None

    def addPlaylist(self, Playlist):
        tmpPlaylist = str(Playlist).lower()
        path = ""
        if self.__isInPlaylist(tmpPlaylist, self.__playlists):
            raise ValueError, "%s is already being synced." % Playlist
        self.__convertplaylist(tmpPlaylist)

    def __convertplaylist(self, Playlist):
        if not self.__isInPlaylist(Playlist, self.__sourcePlaylists):
            raise IOError, "There is no such playlist: '%s' underneath: %s" % ( Playlist , self.__sourceRoot )  

        f = open(self.__isInPlaylist(Playlist, self.__sourcePlaylists)["path"], "r")
        playlisttext = f.read()
        f.close()

        pathseperator = os.path.normpath("/")
        extension = os.path.splitext(self.__isInPlaylist(Playlist, self.__sourcePlaylists)["path"])[1].lower()
        if extension == ".m3u" and self.__hierarchical:
            search = re.compile("^" + self.__sourceRoot + pathseperator, re.IGNORECASE | re.MULTILINE | re.UNICODE)
            replace = self.__destRoot + pathseperator
        elif extension == ".m3u" and not self.__hierarchical:
            search = re.compile("^" + self.__sourceRoot + ".*" + pathseperator, re.IGNORECASE | re.MULTILINE | re.UNICODE)
            replace = self.__destRoot + pathseperator
        elif extension == ".pls" and self.__hierarchical:
            search = re.compile("=" + self.__sourceRoot + pathseperator, re.IGNORECASE | re.MULTILINE | re.UNICODE)
            replace = "=" + self.__destRoot + pathseperator
        elif extension == ".pls" and not self.__hierarchical:
            search = re.compile("=" + self.__sourceRoot + ".*" + pathseperator, re.IGNORECASE | re.MULTILINE | re.UNICODE)
            replace = "=" + self.__destRoot + pathseperator
        else:
            search = None
            replace = None

        if not (search and replace) :
            raise ValueError, "Invalid Extension or Hierarchical Setting: %s, %s" % ( str(extension), str(self.__hierarchical) )

        playlisttext = search.sub(replace, playlisttext)

        if self.__hierarchical:        
            search = re.compile("^/home/BrandtB/Desktop/playlists-orig.*" + pathseperator, re.IGNORECASE | re.MULTILINE | re.UNICODE)
        else:
            search = re.compile("^/home/BrandtB/Desktop/playlists-orig" + pathseperator, re.IGNORECASE | re.MULTILINE | re.UNICODE)
        replace = "/home/BrandtB/Desktop/playlists-dest" + pathseperator        
        filename = search.sub(replace, self.__isInPlaylist(Playlist, self.__sourcePlaylists)["path"])

        f = open(filename, "w")
        f.write(playlisttext)
        f.flush()
        f.close()

    def removePlaylist(self, Playlist):
        tmpPlaylist = str(Playlist).lower()
        path = ""
        if not self.__isInPlaylist(tmpPlaylist, self.__playlists):
            raise ValueError, "%s is not being synced." % Playlist
        os.remove(self.__destPlaylists[tmpPlaylist])

    def listPlayLists(self):
        allplaylists = {}
        for playlist in self.__sourcePlaylists.keys(): 
            allplaylists[playlist] = {"source":True, "dest":False}
        for playlist in self.__destPlaylists.keys():
            if allplaylists.has_key(playlist):
                allplaylists[playlist]["dest"] = True
            else:
                allplaylists[playlist] = {"dest":True, "source":False}

        length = 0
        for playlist in allplaylists.keys():
            if len(playlist) > length: length = len(playlist)

        print "Playlists:"
        for playlist in allplaylists.keys():
            if allplaylists[playlist]["source"] and allplaylists[playlist]["dest"]:
                print playlist + " " * (length - len(playlist)) + "\t" + "Sync"
            else:
                print playlist + " " * (length - len(playlist)) + "\t" + "Available"
        print "\n"

    def syncPlaylists(self):
        pass

    def cleanupPlaylists(self):
        pass

if __name__ == '__main__':
    usageText="usage: %prog [options] Source Destination RemotePath"
    versionText =  "\n" + " ".join(["GNU","%prog",str(version)]) + "\n"
    versionText += "This program is distributed in the hope that it will be useful,\n"
    versionText += "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
    versionText += "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
    versionText += "GNU General Public License for more details.\n\n"
    versionText += "Originally written by Bob Brandt <projects@brandt.ie>.\n"

    parser = optparse.OptionParser(usage=usageText, version=versionText)
    parser.add_option("-a", "--add", dest="add", default="", type="string", help="Add playlist to sync list.")
    parser.add_option("-r", "--remove", dest="remove", default="", type="string", help="Remove playlist from sync list.")    
    parser.add_option("-l", "--list", dest="list", action="store_true", default=False, help="List all playlists and whether or not they will be synced.")
    parser.add_option("-c", "--cleanup", dest="cleanup", action="store_true", default=False, help="Remove all media not specified in the playlists.")    
    parser.add_option("-t", "--tree",  dest="tree",  action="store_true", default=False, help="Keep tree structure when copying files.")
    parser.add_option("-d", "--debug",  dest="debug",  action="store_true", default=False, help="To run the command in Debug mode.")

    (options, args) = parser.parse_args()

#    Source = args[0]
#    Destination = args[1]
#    RemotePath = args[2]

    Source = "/home/BrandtB/Desktop/playlists-orig"
    Destination = "/home/BrandtB/Desktop/playlists-dest"
    RemotePath = "/home/user/MyDocs/Music"
    options.tree = False
    options.list = True

    temp = playlistsync(Source, Destination, RemotePath, options.tree, options.debug)

    if options.add:
        temp.addPlaylist(options.add)
    if options.remove:
        temp.removePlaylist(options.remove)
    if options.list:
        temp.listPlayLists()
    if not (options.add or options.remove or options.list or options.cleanup):
        temp.syncPlaylists()
        if options.cleanup:
            temp.cleanupPlaylists()        

sys.exit()


Retrieved from /projects/pmwiki.php?n=N900.PlaylistSync
Page last modified on March 12, 2010, at 03:03 PM