X-Git-Url: https://code.delx.au/notipod/blobdiff_plain/fd23beafb68339a9c4c5dd35e6c2d14fce0bb2ce..940330ce5a487a919446ee62f920646c2e38fee5:/notipod_gui.py diff --git a/notipod_gui.py b/notipod_gui.py index 52b4456..11c6880 100644 --- a/notipod_gui.py +++ b/notipod_gui.py @@ -5,6 +5,7 @@ import logging import os import sys +import time import traceback import uuid @@ -122,6 +123,10 @@ class NotiPodController(NSObject): loadingLabel = objc.IBOutlet() loadingIndicator = objc.IBOutlet() + advancedSheet = objc.IBOutlet() + advancedSyncFolder = objc.IBOutlet() + advancedPathPrefix = objc.IBOutlet() + previewWindow = objc.IBOutlet() previewText = objc.IBOutlet() @@ -143,13 +148,9 @@ class NotiPodController(NSObject): for target in self.targets: folders.append(target["folder"]) self.folderModel.loadFolders_(folders) - + self.library = libnotipod.ITunesLibrary.alloc().init() - def finish(): - self.playlistModel.setPlaylists(self.library.get_playlists()) - def fail(): - sys.exit(0) - self.runGenerator(lambda: self.library.load_(None), finish, fail) + self.loadLibrary_(self) def applicationWillTerminate_(self, _): self.prefs().synchronize() @@ -157,6 +158,10 @@ class NotiPodController(NSObject): def applicationShouldTerminateAfterLastWindowClosed_(self, _): return True + def windowDidBecomeKey_(self, _): + if self.library.needs_reload(): + self.loadLibrary_(self) + # Utility methods def runGenerator(self, func, finish, fail): @@ -169,12 +174,15 @@ class NotiPodController(NSObject): def runGeneratorThread(self, (gen, finish, fail)): pool = NSAutoreleasePool.alloc().init() + last_time = 0 try: for msg in gen: if not self.runningGenerator: break - self.loadingLabel.performSelectorOnMainThread_withObject_waitUntilDone_( - self.loadingLabel.setStringValue_, msg, True) + now = time.time() + if now - last_time > 0.1: + self.loadingLabel.performSelectorOnMainThread_withObject_waitUntilDone_( + self.loadingLabel.setStringValue_, msg, True) except Exception, e: NSRunAlertPanel("Error!", str(e), "Ok", None, None) traceback.print_exc() @@ -191,26 +199,64 @@ class NotiPodController(NSObject): if finish: finish() + + @objc.IBAction + def loadLibrary_(self, sender): + if self.runningGenerator: + return + + def finish(): + self.playlistModel.setPlaylists(self.library.get_playlists()) + def fail(): + NSRunAlertPanel("Error!", "Unable to load iTunes library! Exiting...", "Ok", None, None) + os._exit(0) + self.runGenerator(lambda: self.library.load_(None), finish, fail) + + @objc.IBAction + def showAdvancedOptions_(self, sender): + if self.runningGenerator: + return + target = self.getCurrentTarget() + self.advancedSyncFolder.setStringValue_(target["folder"]) + self.advancedPathPrefix.setStringValue_(target["path_prefix"]) + NSApp.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_(self.advancedSheet, self.window, None, None, None) + + @objc.IBAction + def finishAdvancedOptions_(self, sender): + target = self.getCurrentTarget() + target["folder"] = self.advancedSyncFolder.stringValue() + target["path_prefix"] = self.advancedPathPrefix.stringValue() + self._savePrefs() + NSApp.endSheet_(self.advancedSheet) + self.advancedSheet.orderOut_(self) + @objc.IBAction def doCancel_(self, sender): self.runningGenerator = False - def getDestFolder(self): + def getCheckTarget(self): target = self.getCurrentTarget() if not target: NSRunAlertPanel("Error!", "You must choose a folder first!", "Ok", None, None) return folder = target["folder"] + if not os.path.isdir(folder.encode("utf-8")): NSRunAlertPanel("Error!", "Destination " + folder + " does not exist, try mounting it first?", "Ok", None, None) return - return folder + + folder_contents = [f for f in os.listdir(folder) if not f.startswith(".")] + if len(folder_contents) > 0 and "-Playlists-" not in folder_contents: + NSRunAlertPanel("Error!", "Refusing to clobber files in non-empty folder: " + folder, "Ok", None, None) + return + + return target def doPreviewThread(self): yield "Calculating changes..." - folder = self.getDestFolder() - if not folder: + target = self.getCheckTarget() + if not target: return all_tracks = set() @@ -221,12 +267,14 @@ class NotiPodController(NSObject): all_filenames = [] for trackID in all_tracks: - all_filenames.append(self.library.get_track_filename(trackID)) + f = self.library.get_track_filename(trackID) + if f: + all_filenames.append(f) gen = libnotipod.sync( dry_run=True, source=self.library.folder, - dest=folder, + dest=target["folder"], files_to_copy=all_filenames, ) self.previewResult = "\n".join(gen) @@ -245,8 +293,8 @@ class NotiPodController(NSObject): @objc.IBAction def doSync_(self, sender): - folder = self.getDestFolder() - if not folder: + target = self.getCheckTarget() + if not target: return all_tracks = set() @@ -262,21 +310,33 @@ class NotiPodController(NSObject): all_filenames = [] for trackID in all_tracks: - all_filenames.append(self.library.get_track_filename(trackID)) + f = self.library.get_track_filename(trackID) + if f: + all_filenames.append(f) all_playlists.update(self.library.get_track_playlists(trackID)) + libnotipod.delete_playlists(dry_run=False, dest=target["folder"]) + for playlist_id in all_playlists: playlist = self.library.get_playlist_pid(playlist_id) if playlist is None: continue tracks = [] for trackID in playlist.tracks: - if trackID in all_tracks: - tracks.append(self.library.get_track_filename(trackID)) + if trackID not in all_tracks: + continue + f = self.library.get_track_filename(trackID) + if f: + tracks.append(f) if playlist_id not in orig_playlists and len(tracks) < 10: continue - libnotipod.export_m3u(dry_run=False, dest=folder, path_prefix="", - playlist_name=playlist.name, files=tracks) + libnotipod.export_m3u( + dry_run=False, + dest=target["folder"], + path_prefix=target["path_prefix"], + playlist_name=playlist.name, + files=tracks + ) def finish(): NSRunAlertPanel("Complete!", "Synchronisation is complete", "Ok", None, None) @@ -285,7 +345,7 @@ class NotiPodController(NSObject): libnotipod.sync( dry_run=False, source=self.library.folder, - dest=folder, + dest=target["folder"], files_to_copy=all_filenames, ) , @@ -301,7 +361,7 @@ class NotiPodController(NSObject): def _migratePrefs(self): p = self.prefs() - + playlists = p.stringArrayForKey_("playlists") if playlists is not None: p.removeObjectForKey_("playlists") @@ -318,7 +378,8 @@ class NotiPodController(NSObject): target = {} target["folder"] = f target["playlists"] = list(playlists) - target["uuid"] = uuid.uuid1().get_hex() + target["uuid"] = uuid.uuid4().get_hex() + target["path_prefix"] = "../" if first: first = False self.setCurrentTarget_(target["uuid"]) @@ -329,8 +390,8 @@ class NotiPodController(NSObject): def _loadPrefs(self): p = self.prefs() - self.current_target = None - self.setCurrentTarget_(p.stringForKey_("current_target")) + self.currentTarget = None + self.setCurrentTarget_(p.stringForKey_("currentTarget")) self.targets = self.prefs().arrayForKey_("targets") if self.targets is None: @@ -343,22 +404,22 @@ class NotiPodController(NSObject): def _savePrefs(self): p = self.prefs() - p.setObject_forKey_(self.current_target, "current_target") + p.setObject_forKey_(self.currentTarget, "currentTarget") p.setObject_forKey_(self.targets, "targets") p.synchronize() def getCurrentTarget(self): for target in self.targets: - if target["uuid"] == self.current_target: + if target["uuid"] == self.currentTarget: return target return None - - def setCurrentTarget_(self, target_uuid): - old_uuid = self.current_target - self.current_target = target_uuid - if old_uuid is None and target_uuid is not None: + + def setCurrentTarget_(self, targetUuid): + oldUuid = self.currentTarget + self.currentTarget = targetUuid + if oldUuid is None and targetUuid is not None: self.playlistModel.outlineView.setEnabled_(True) - if old_uuid != target_uuid: + if oldUuid != targetUuid: self.playlistModel.outlineView.reloadItem_reloadChildren_(None, True) def playlists(self): @@ -377,7 +438,8 @@ class NotiPodController(NSObject): target = {} target["folder"] = folder target["playlists"] = self.playlists() - target["uuid"] = uuid.uuid1().get_hex() + target["uuid"] = uuid.uuid4().get_hex() + target["path_prefix"] = "../" self.targets.insertObject_atIndex_(target, 0) self.setCurrentTarget_(target["uuid"])