X-Git-Url: https://code.delx.au/notipod/blobdiff_plain/3216c6dfd93329cc260f69cbb617bde23d307c40..2a63113c140f7b0d41c5980fab90af8510129d34:/NotiPod.py diff --git a/NotiPod.py b/NotiPod.py index bb810ba..4bb501d 100644 --- a/NotiPod.py +++ b/NotiPod.py @@ -2,6 +2,8 @@ # Copyright 2009 James Bunton # Licensed for distribution under the GPL version 2, check COPYING for details +import logging + import objc from Foundation import * from AppKit import * @@ -10,126 +12,216 @@ from PyObjCTools import AppHelper import libsyncitunes -class PlaylistTableModel(NSObject): - tableView = objc.IBOutlet() +class PlaylistModel(NSObject): + outlineView = objc.IBOutlet() def awakeFromNib(self): - self.playlists = [] - self.tableView.setDataSource_(self) - + self.root = [] + self.playlists = {} + self.outlineView.setDataSource_(self) + def setPlaylists(self, playlists): + self.root = [] self.playlists = playlists - self.tableView.reloadData() - - def tableView_objectValueForTableColumn_row_(self, tableView, col, row): - assert 0 <= row < len(self.playlists) - return self.playlists[row] - - def numberOfRowsInTableView_(self, tableView): - print "get number of rows", len(self.playlists) - return len(self.playlists) - - - -class NotiPodController(NSObject): - playlistModel = objc.IBOutlet() - folderPopup = objc.IBOutlet() + for playlist in self.playlists: + if playlist.parent is None: + self.root.append(playlist) + self.outlineView.reloadData() + self.outlineView.expandItem_expandChildren_(None, True) + + def outlineView_child_ofItem_(self, _, childIndex, playlist): + if playlist == None: + return self.root[childIndex] + else: + return playlist.children[childIndex] + + def outlineView_isItemExpandable_(self, _, playlist): + if playlist == None: + return True + else: + return len(playlist.children) > 0 + + def outlineView_numberOfChildrenOfItem_(self, _, playlist): + if playlist == None: + return len(self.root) + else: + return len(playlist.children) + + def outlineView_objectValueForTableColumn_byItem_(self, _, col, playlist): + col = col.identifier() if col else "playlist" + + if col == "selected": + selected = NSApp.delegate().playlists() + return playlist.pid in selected + if col == None or col == "playlist": + return playlist.name + + def outlineView_setObjectValue_forTableColumn_byItem_(self, _, v, col, playlist): + col = col.identifier() if col else "playlist" + + if col != "selected": + return + NSApp.delegate().setPlaylist_selected_(playlist.pid, v) + + +class FolderModel(NSObject): window = objc.IBOutlet() - loadingSheet = objc.IBOutlet() - + folderPopup = objc.IBOutlet() def awakeFromNib(self): - self.performSelectorInBackground_withObject_(self.loadLibrary, None) - print "awakeFromNib" - - def finishLoading(self): - self.playlistModel.setPlaylists(self.library.list_playlists()) self.folderPopup.addItemsWithTitles_(NSApp.delegate().folders()) + self.folderPopup.selectItemAtIndex_(2) + self.lastIndex = 2 - def loadLibrary(self): - pool = NSAutoreleasePool.alloc().init() - NSApp.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_(self.loadingSheet, self.window, None, None, None) - self.library = libsyncitunes.ITunesLibrary.alloc().init() - self.loadingSheet.close() - self.performSelectorOnMainThread_withObject_waitUntilDone_(self.finishLoading, None, True) - del pool + @objc.IBAction + def doSelectFolder_(self, sender): + currentIndex = self.folderPopup.indexOfSelectedItem() + if currentIndex >= 2: + self.lastIndex = currentIndex + NSApp.delegate().addFolder_(self.folderPopup.titleOfSelectedItem()) + return + panel = NSOpenPanel.openPanel() + panel.setCanChooseFiles_(False) + panel.setCanChooseDirectories_(True) + panel.setAllowsMultipleSelection_(False) + panel.beginSheetForDirectory_file_types_modalForWindow_modalDelegate_didEndSelector_contextInfo_( + None, None, [], self.window, self, self.selectFolderEnd_returnCode_contextInfo_, None) @objc.signature("v@:@ii") def selectFolderEnd_returnCode_contextInfo_(self, panel, ret, _): if ret == NSOKButton: assert len(panel.filenames()) == 1 folder = panel.filenames()[0] -### NSApp.delegate().addFolder_(folder) + NSApp.delegate().addFolder_(folder) self.folderPopup.insertItemWithTitle_atIndex_(folder, 2) self.folderPopup.selectItemAtIndex_(2) - - @objc.IBAction - def doSelectFolder_(self, sender): - print "select folder" - try: - folders = NSApp.delegate().folders() - if len(folders) > 0: - folder = folders[0] - else: - folder = None - panel = NSOpenPanel.openPanel() - panel.setCanChooseFiles_(False) - panel.setCanChooseDirectories_(True) - panel.setAllowsMultipleSelection_(False) - panel.beginSheetForDirectory_file_types_modalForWindow_modalDelegate_didEndSelector_contextInfo_(folder, None, None, self.window, self, self.selectFolderEnd_returnCode_contextInfo_, None) - except: - import traceback - traceback.print_exc() - - @objc.IBAction - def doSync_(self, sender): - print "hello me" + else: + self.folderPopup.selectItemAtIndex_(self.lastIndex) class NotiPodAppDelegate(NSObject): + window = objc.IBOutlet() + playlistModel = objc.IBOutlet() + folderModel = objc.IBOutlet() + loadingSheet = objc.IBOutlet() + loadingLabel = objc.IBOutlet() - # Delegate methods + def awakeFromNib(self): + self.gen = None + # Delegate methods def applicationWillFinishLaunching_(self, _): - print "loading prefs" - prefs = NSUserDefaults.standardUserDefaults() - self._playlists = prefs.stringArrayForKey_("playlists") - self._folders = prefs.stringArrayForKey_("folders") - print "folders", self._folders - print "playlists", self._playlists + pass def applicationDidFinishLaunching_(self, _): - pass + self.library = libsyncitunes.ITunesLibrary.alloc().init() + def finish(): + self.playlistModel.setPlaylists(self.library.get_playlists()) + self.runGenerator(lambda: self.library.load_(None), finish) def applicationWillTerminate_(self, _): - prefs = NSUserDefaults.standardUserDefaults() - prefs.synchronize() + self.prefs().synchronize() def applicationShouldTerminateAfterLastWindowClosed_(self, _): return True - # Public accessors + # Utility methods + def runGenerator(self, func, finish): + NSApp.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_(self.loadingSheet, self.window, None, None, None) + self.gen = func() + self.finish = finish + self.runGeneratorNext() - def playlists(self): - return self._playlists + def runGeneratorNext(self): + if self.gen is None or self.finish is None: + return + try: + msg = self.gen.next() + self.loadingLabel.setStringValue_(msg) + self.performSelector_withObject_afterDelay_( + self.runGeneratorNext, None, 0) + except StopIteration: + self.stopGenerator() + + def stopGenerator(self): + self.gen = None + NSApp.endSheet_(self.loadingSheet) + self.loadingSheet.orderOut_(self) + self.finish() + self.finish = None - def folders(self): - return self._folders or [] + @objc.IBAction + def doCancel_(self, sender): + self.stopGenerator() - def addFolder_(self, folder): - self._folders.insert(0, folder) + @objc.IBAction + def doSync_(self, sender): + folder = self.folders()[0] + playlists = [self.library.get_playlist_pid(pid) for pid in self.playlists()] + + all_tracks = [] + for playlist in playlists: + all_tracks.extend(playlist.tracks) + libsyncitunes.export_m3u(dry_run=False, dest=folder, path_prefix="", + playlist_name=playlist.name, files=playlist.tracks) + + def finish(): + NSRunAlertPanel("Complete!", "Synchronisation is complete", "Ok", None, None) + self.runGenerator( + lambda: + libsyncitunes.sync( + dry_run=False, + source=self.library.folder, + dest=folder, + files_to_copy=all_tracks + ) + , + finish + ) + + + # Public accessors + + def prefs(self): + return NSUserDefaults.standardUserDefaults() + + def _getArray(self, key): + res = self.prefs().stringArrayForKey_(key) + return list(res) if res else [] - def hasPlaylist_(self, playlist): - return playlist in self._playlists - - def removePlaylist_(self, playlist): - self._playlists.remove(playlist) - - def addPlaylist_(self, playlist): - self._playlists.append(playlist) + def _saveArray(self, key, array): + self.prefs().setObject_forKey_(array, key) + def playlists(self): + return self._getArray("playlists") + def folders(self): + return self._getArray("folders") -AppHelper.runEventLoop() + def addFolder_(self, folder): + folders = self.folders() + while folder in folders: + folders.remove(folder) + folders.insert(0, folder) + folders = folders[:10] + self._saveArray("folders", folders) + + def setPlaylist_selected_(self, playlist, selected): + playlists = self.playlists() + if selected: + playlists.append(playlist) + else: + playlists.remove(playlist) + playlists = list(set(playlists)) + self._saveArray("playlists", list(set(playlists))) + + +def main(): +### logging.basicConfig(format="%(levelname)s: %(message)s") +### logging.getLogger().setLevel(logging.DEBUG) + AppHelper.runEventLoop() + +if __name__ == "__main__": + main()