X-Git-Url: https://code.delx.au/notipod/blobdiff_plain/091ffd73bb5472213fe7b2e40e85a8ac1a418891..HEAD:/libnotipod.py?ds=sidebyside diff --git a/libnotipod.py b/libnotipod.py index 49af34a..2053b74 100644 --- a/libnotipod.py +++ b/libnotipod.py @@ -2,6 +2,7 @@ # Copyright 2009 James Bunton # 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))