]> code.delx.au - notipod/blobdiff - libnotipod.py
category
[notipod] / libnotipod.py
index 49af34a64288ff5056169be1c11875981f75c3da..2053b749dc984a9c53c8845b8818b9ebab863d50 100644 (file)
@@ -2,6 +2,7 @@
 # Copyright 2009 James Bunton <jamesbunton@fastmail.fm>
 # Licensed for distribution under the GPL version 2, check COPYING for details
 
+import collections
 import logging
 import os
 import shutil
@@ -27,9 +28,10 @@ class Playlist(NSObject):
        def init(self):
                return self
 
-       def set(self, name, pid, tracks, parent):
+       def set(self, name, pid, ptype, tracks, parent):
                self.name = name
                self.pid = pid
+               self.ptype = ptype
                self.children = []
                self.tracks = tracks
                self.parent = parent
@@ -37,45 +39,92 @@ class Playlist(NSObject):
                        parent.children.append(self)
 
 class ITunesLibrary(NSObject):
-       def load_(self, filename):
+       def load_(self, filename=None):
                if filename is None:
-                       filename = "~/Music/iTunes/iTunes Music Library.xml"
-               filename = os.path.expanduser(filename)
+                       filename = getattr(self, "filename", None)
+               if filename is None:
+                       filename = os.path.expanduser("~/Music/iTunes/iTunes Music Library.xml")
+               self.filename = filename
+               self.mtime = os.stat(filename).st_mtime
                yield "Reading library..."
                plist = read_plist(os.path.expanduser(filename))
+               if plist is None:
+                       raise Exception("Could not find music library: " + filename)
                self.folder = self.loc2name(plist["Music Folder"])
                pl_tracks = plist["Tracks"]
-               self.playlists = {}
+               pl_lookup = {}
+               self.playlists = []
+               self.track2playlist = collections.defaultdict(set)
+               self.track2filename = {}
                for pl_playlist in plist["Playlists"]:
-                       playlist = self.make_playlist(pl_playlist, pl_tracks)
+                       playlist = self.make_playlist(pl_playlist, pl_tracks, pl_lookup)
+                       if not playlist:
+                               continue
                        yield "Read playlist: " + playlist.name
-                       self.playlists[playlist.pid] = playlist
+                       self.playlists.append(playlist)
+                       pl_lookup[playlist.pid] = playlist
+
+       def needs_reload(self):
+               return os.stat(self.filename).st_mtime > self.mtime
 
        def loc2name(self, location):
                return urllib.splithost(urllib.splittype(urllib.unquote(location))[1])[1]
 
-       def make_playlist(self, pl_playlist, pl_tracks):
+       def make_playlist(self, pl_playlist, pl_tracks, pl_lookup):
+               if int(pl_playlist.get("Master", 0)):
+                       return
+               kind = int(pl_playlist.get("Distinguished Kind", -1))
+               if kind == 26:
+                       # Don't do genius
+                       return
+
                name = pl_playlist["Name"]
                pid = pl_playlist["Playlist Persistent ID"]
+               if kind > 0:
+                       ptype = {
+                               2: "movies",
+                               3: "tv-shows",
+                               4: "music",
+                               5: "books",
+                               10: "podcasts",
+                               19: "purchased",
+                               22: "itunes-dj",
+                               31: "itunes-u",
+                       }.get(kind, "playlist")
+               elif pl_playlist.has_key("Smart Info"):
+                       ptype = "smart-playlist"
+               elif int(pl_playlist.get("Folder", 0)):
+                       ptype = "folder"
+               else:
+                       ptype = "playlist"
+
                parent = None
                try:
                        parent_pid = pl_playlist["Parent Persistent ID"]
-                       parent = self.playlists.get(parent_pid)
+                       parent = pl_lookup[parent_pid]
                except KeyError:
                        pass
+
                tracks = []
                for item in pl_playlist.get("Playlist Items", []):
                        trackID = item["Track ID"]
-                       filename = str(pl_tracks[str(trackID)]["Location"])
-                       filename = self.loc2name(filename)
-                       filename = filename.decode("utf-8")
-                       if not filename.startswith(self.folder):
-                               logging.warn("Skipping: " + filename)
-                               continue
-                       filename = strip_prefix(filename, self.folder)
-                       tracks.append(filename)
+                       item = pl_tracks[str(trackID)]
+                       self.track2playlist[trackID].add(pid)
+                       tracks.append(trackID)
+                       if trackID not in self.track2filename:
+                               if item["Track Type"] != "File":
+                                       continue
+                               filename = str(item["Location"])
+                               filename = self.loc2name(filename)
+                               filename = filename.decode("utf-8")
+                               if not filename.startswith(self.folder):
+                                       logging.warn("Skipping: " + filename)
+                                       continue
+                               filename = strip_prefix(filename, self.folder)
+                               self.track2filename[trackID] = filename
+
                playlist = Playlist.alloc().init()
-               playlist.set(name, pid, tracks, parent)
+               playlist.set(name, pid, ptype, tracks, parent)
                return playlist
 
        def has_playlist_name(self, name):
@@ -94,26 +143,14 @@ class ITunesLibrary(NSObject):
                        if playlist.pid == pid:
                                return playlist
 
-       def get_playlists(self):
-               return self.playlists.values()
-
-       def outlineView_numberOfChildrenOfItem_(self, view, item):
-               if item == None:
-                       return len(self.playlists)
-               else:
-                       return 0
-
-       def outlineView_isItemExpandable_(self, view, item):
-               return False
+       def get_track_filename(self, trackID):
+               return self.track2filename.get(trackID, None)
 
-       def outlineView_child_ofItem_(self, view, index, item):
-               if item == None:
-                       return self.playlists[index]
-               else:
-                       return None
+       def get_track_playlists(self, trackID):
+               return self.track2playlist.get(trackID, [])
 
-       def outlineView_objectValueForTableColumn_byItem_(self, view, column, item):
-               return item.name
+       def get_playlists(self):
+               return self.playlists
 
 
 encoded_names = {}
@@ -153,17 +190,44 @@ def mkdirhier(path):
                except OSError:
                        pass
 
+def delete_playlists(dry_run, dest):
+       dest = os.path.join(dest, "-Playlists-")
+       try:
+               filenames = os.listdir(dest)
+       except OSError:
+               return
+
+       for filename in filenames:
+               if not filename.lower().endswith(".m3u"):
+                       continue
+               filename = os.path.join(dest, filename)
+               logging.info("Deleting: " + filename)
+               if not dry_run:
+                       try:
+                               os.unlink(filename)
+                       except OSError:
+                               pass
+
 def export_m3u(dry_run, dest, path_prefix, playlist_name, files):
+       dest = os.path.join(dest, "-Playlists-")
+       mkdirhier(dest)
+       playlist_name = playlist_name.replace("/", "-")
+       playlist_file = os.path.join(dest, playlist_name) + ".m3u"
+       playlist_file = encode_filename(playlist_file)
+       logging.info("Writing: " + playlist_file)
+
        if dry_run:
                return
-       if not path_prefix:
-               path_prefix = "../"
-       playlist_file = os.path.join(dest, "-Playlists-", playlist_name) + ".m3u"
-       mkdirhier(os.path.dirname(playlist_file))
-       logging.info("Writing: " + playlist_file)
+
+       sep = "/"
+       if path_prefix.find("\\") > 0:
+               sep = "\\"
+       if path_prefix[-1] != sep:
+               path_prefix += sep
+
        f = open(playlist_file, "w")
        for filename in files:
-               if path_prefix.find("\\") > 0:
+               if sep == "\\":
                        filename = filename.replace("/", "\\")
                filename = encode_filename(filename)
                f.write("%s%s\n" % (path_prefix, filename))