X-Git-Url: https://code.delx.au/notipod/blobdiff_plain/1451ad4d932f060e14b55ff49d4779a31c977ce0..d986ae4a0c2444f97d531451769245a9e6b9ab66:/notipod_gui.py diff --git a/notipod_gui.py b/notipod_gui.py index f4c6dde..f469b48 100644 --- a/notipod_gui.py +++ b/notipod_gui.py @@ -3,6 +3,9 @@ # Licensed for distribution under the GPL version 2, check COPYING for details import logging +import os +import sys +import traceback import objc from Foundation import * @@ -112,12 +115,18 @@ class FolderModel(NSObject): class NotiPodController(NSObject): window = objc.IBOutlet() - playlistModel = objc.IBOutlet() - folderModel = objc.IBOutlet() + loadingSheet = objc.IBOutlet() loadingLabel = objc.IBOutlet() loadingIndicator = objc.IBOutlet() + previewWindow = objc.IBOutlet() + previewText = objc.IBOutlet() + + playlistModel = objc.IBOutlet() + folderModel = objc.IBOutlet() + + def awakeFromNib(self): self.runningGenerator = False @@ -129,7 +138,9 @@ class NotiPodController(NSObject): self.library = libnotipod.ITunesLibrary.alloc().init() def finish(): self.playlistModel.setPlaylists(self.library.get_playlists()) - self.runGenerator(lambda: self.library.load_(None), finish) + def fail(): + sys.exit(0) + self.runGenerator(lambda: self.library.load_(None), finish, fail) def applicationWillTerminate_(self, _): self.prefs().synchronize() @@ -139,47 +150,124 @@ class NotiPodController(NSObject): # Utility methods - def runGenerator(self, func, finish): + def runGenerator(self, func, finish, fail): assert not self.runningGenerator self.runningGenerator = True self.loadingIndicator.startAnimation_(self) NSApp.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_(self.loadingSheet, self.window, None, None, None) - arg = (func(), finish) + arg = (func(), finish, fail) self.performSelectorInBackground_withObject_(self.runGeneratorThread, arg) - def runGeneratorThread(self, (gen, finish)): + def runGeneratorThread(self, (gen, finish, fail)): pool = NSAutoreleasePool.alloc().init() - for msg in gen: - if not self.runningGenerator: - break - self.loadingLabel.performSelectorOnMainThread_withObject_waitUntilDone_( - self.loadingLabel.setStringValue_, msg, True) + try: + for msg in gen: + if not self.runningGenerator: + break + self.loadingLabel.performSelectorOnMainThread_withObject_waitUntilDone_( + self.loadingLabel.setStringValue_, msg, True) + except Exception, e: + NSRunAlertPanel("Error!", str(e), "Ok", None, None) + traceback.print_exc() + finish = fail self.performSelectorOnMainThread_withObject_waitUntilDone_( self.stopGenerator, finish, True) self.runningGenerator = False - del pool def stopGenerator(self, finish): self.runningGenerator = False NSApp.endSheet_(self.loadingSheet) self.loadingSheet.orderOut_(self) self.loadingIndicator.stopAnimation_(self) - finish() + if finish: + finish() @objc.IBAction def doCancel_(self, sender): self.runningGenerator = False + def getDestFolder(self): + folders = self.folders() + if not folders: + NSRunAlertPanel("Error!", "You must choose a folder first!", "Ok", None, None) + return + folder = folders[0] + 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 + + def doPreviewThread(self): + yield "Calculating changes..." + + folder = self.getDestFolder() + if not folder: + return + + all_tracks = set() + for playlist_id in self.playlists(): + playlist = self.library.get_playlist_pid(playlist_id) + if playlist is not None: + all_tracks.update(set(playlist.tracks)) + + all_filenames = [] + for trackID in all_tracks: + all_filenames.append(self.library.get_track_filename(trackID)) + + gen = libnotipod.sync( + dry_run=True, + source=self.library.folder, + dest=folder, + files_to_copy=all_filenames, + ) + self.previewResult = "\n".join(gen) + + @objc.IBAction + def doPreview_(self, sender): + self.previewResult = "" + self.previewWindow.orderOut_(self) + + def finish(): + self.previewText.textStorage().mutableString().setString_(self.previewResult) + self.previewWindow.center() + self.previewWindow.makeKeyAndOrderFront_(self) + + self.runGenerator(self.doPreviewThread, finish, None) + @objc.IBAction def doSync_(self, sender): - folder = self.folders()[0] - playlists = [self.library.get_playlist_pid(pid) for pid in self.playlists()] + folder = self.getDestFolder() + if not folder: + return - all_tracks = [] - for playlist in playlists: - all_tracks.extend(playlist.tracks) + all_tracks = set() + orig_playlists = set(self.playlists()) + all_playlists = orig_playlists.copy() + for playlist_id in all_playlists: + playlist = self.library.get_playlist_pid(playlist_id) + if playlist is None: + print "Forgetting unknown playlist:", playlist_id + self.setPlaylist_selected_(playlist_id, False) + continue + all_tracks.update(set(playlist.tracks)) + + all_filenames = [] + for trackID in all_tracks: + all_filenames.append(self.library.get_track_filename(trackID)) + all_playlists.update(self.library.get_track_playlists(trackID)) + + 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 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=playlist.tracks) + playlist_name=playlist.name, files=tracks) def finish(): NSRunAlertPanel("Complete!", "Synchronisation is complete", "Ok", None, None) @@ -189,10 +277,11 @@ class NotiPodController(NSObject): dry_run=False, source=self.library.folder, dest=folder, - files_to_copy=all_tracks + files_to_copy=all_filenames, ) , - finish + finish, + None )