# 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
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"]
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, pl_lookup)
if not 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]
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, ptype, tracks, parent)
return playlist
if playlist.pid == pid:
return playlist
+ def get_track_filename(self, trackID):
+ return self.track2filename.get(trackID, None)
+
+ def get_track_playlists(self, trackID):
+ return self.track2playlist.get(trackID, [])
+
def get_playlists(self):
return self.playlists
except OSError:
pass
-def export_m3u(dry_run, dest, path_prefix, playlist_name, files):
- if dry_run:
+def delete_playlists(dry_run, dest):
+ dest = os.path.join(dest, "-Playlists-")
+ try:
+ filenames = os.listdir(dest)
+ except OSError:
return
- if not path_prefix:
- path_prefix = "../"
- playlist_file = os.path.join(dest, "-Playlists-", playlist_name) + ".m3u"
+
+ 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)
- mkdirhier(os.path.dirname(playlist_file))
logging.info("Writing: " + playlist_file)
+
+ if dry_run:
+ return
+
+ 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))