From: James Bunton Date: Sun, 2 Jan 2011 07:55:18 +0000 (+1100) Subject: Nearly done! X-Git-Tag: notipod-1.0~8 X-Git-Url: https://code.delx.au/notipod/commitdiff_plain/52fd13a71b7d431ab1c0d1b63a55d19210ee9466 Nearly done! --- diff --git a/English.lproj/NotiPod.xib b/English.lproj/NotiPod.xib index b8f55cd..b1b20bf 100644 --- a/English.lproj/NotiPod.xib +++ b/English.lproj/NotiPod.xib @@ -238,7 +238,7 @@ 268 - {{17, 135}, {254, 17}} + {{17, 125}, {254, 17}} YES @@ -274,7 +274,7 @@ 268 - {{29, 103}, {206, 26}} + {{29, 93}, {335, 26}} YES @@ -343,21 +343,21 @@ - + 268 YES - - + + 2304 YES - - + + 256 {327, 338} - + YES @@ -366,7 +366,7 @@ YES - + selected 4.000000e+01 1.600000e+01 @@ -384,19 +384,19 @@ 3 MC4zMzMzMzI5ODU2AA - + 6 System headerTextColor - + 67239424 131072 - + 1211912703 130 @@ -414,11 +414,11 @@ 1 YES YES - + - + playlist - 2.710000e+02 + 2.810000e+02 1.000000e+01 3.402823e+38 @@ -435,14 +435,14 @@ MQA - + - + 337772096 2048 - + 6 System @@ -453,7 +453,7 @@ 1 YES - + 3.000000e+00 @@ -469,48 +469,48 @@ 1.700000e+01 - -759169024 + 46137344 4 15 0 - YES + NO 1 {{1, 1}, {327, 338}} - - - + + + 4 - - + + -2147483392 {{313, 1}, {15, 323}} - - + + _doScroller: - 9.556213e-01 + 9.970502e-01 - - + + -2147483392 {{1, 324}, {327, 15}} - + 1 - + _doScroller: - 9.159664e-01 + 9.969512e-01 {{32, 160}, {329, 340}} - + 562 - - - + + + QSAAAEEgAABBmAAAQZgAAA @@ -520,9 +520,6 @@ {{0, 0}, {1024, 746}} {3.40282e+38, 3.40282e+38} - - NotiPodController - NotiPodAppDelegate @@ -572,9 +569,12 @@ {{0, 0}, {1024, 746}} {3.40282e+38, 3.40282e+38} - + PlaylistModel + + FolderModel + @@ -628,68 +628,84 @@ 370 - - doSync: - - + + delegate + + - 407 + 435 - window - - + outlineView + + - 420 + 478 + + + + folderPopup + + + + 493 doSelectFolder: - - + + - 421 + 495 - loadingSheet - - + window + + - 434 + 496 - delegate - - + window + + - 435 + 497 - folderPopup - - + playlistModel + + - 451 + 498 - outlineView - - + folderModel + + - 478 + 499 - playlistModel - - + loadingSheet + + - 479 + 500 + + + + doSync: + + + + 501 @@ -852,11 +868,11 @@ YES - - - + + + @@ -902,12 +918,6 @@ - - 404 - - - NotiPodController - 411 @@ -1007,67 +1017,72 @@ 467 - + YES - - - + + + 468 - - + + 469 - - + + 470 - + YES - - + + - + 472 - + YES - + - + 477 - + 484 - - + + 485 - + YES - + - + 486 - - + + + + + 490 + + @@ -1120,7 +1135,6 @@ 394.IBPluginDependency 395.IBPluginDependency 396.IBPluginDependency - 404.IBPluginDependency 411.IBPluginDependency 412.IBPluginDependency 413.IBPluginDependency @@ -1145,6 +1159,7 @@ 472.IBPluginDependency 477.IBPluginDependency 484.IBPluginDependency + 490.IBPluginDependency 56.IBPluginDependency 56.ImportedFromIB2 57.IBPluginDependency @@ -1189,8 +1204,8 @@ {74, 862} {{529, 476}, {148, 20}} - {{253, 91}, {381, 545}} - {{253, 91}, {381, 545}} + {{238, 116}, {381, 545}} + {{238, 116}, {381, 545}} {{505, 213}, {252, 190}} com.apple.InterfaceBuilder.CocoaPlugin @@ -1203,7 +1218,6 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin {{89, 581}, {211, 33}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -1226,6 +1240,7 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -1250,36 +1265,24 @@ - 487 + 502 YES - NotiPodAppDelegate - NSObject - - IBProjectSource - NotiPod.py - - - - NotiPodAppDelegate - NSObject - - IBUserSource - - - - - NotiPodController + FolderModel NSObject + doSelectFolder: + id + + YES YES - doSelectFolder: - doSync: + folderPopup + window YES @@ -1287,11 +1290,23 @@ id + + IBProjectSource + NotiPod.py + + + + NotiPodAppDelegate + NSObject + + doSync: + id + YES YES - folderPopup + folderModel loadingSheet playlistModel window @@ -1307,7 +1322,7 @@ - NotiPodController + NotiPodAppDelegate NSObject IBUserSource diff --git a/NotiPod.py b/NotiPod.py index 68bb1a1..610d405 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 * @@ -25,6 +27,7 @@ class PlaylistModel(NSObject): 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: @@ -58,74 +61,53 @@ class PlaylistModel(NSObject): if col != "selected": return - if v: - NSApp.delegate().addPlaylist_(playlist.pid) - else: - NSApp.delegate().delPlaylist_(playlist.pid) + NSApp.delegate().setPlaylist_selected_(playlist.pid, v) -class NotiPodController(NSObject): - playlistModel = objc.IBOutlet() - folderPopup = objc.IBOutlet() +class FolderModel(NSObject): window = objc.IBOutlet() - loadingSheet = objc.IBOutlet() - + folderPopup = objc.IBOutlet() def awakeFromNib(self): - self.performSelectorInBackground_withObject_(self.loadLibrary, None) - - def finishLoading(self): - self.playlistModel.setPlaylists(self.library.get_playlists()) self.folderPopup.addItemsWithTitles_(NSApp.delegate().folders()) + self.folderPopup.selectItemAtIndex_(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): + if self.folderPopup.indexOfSelectedItem() >= 2: + 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" - class NotiPodAppDelegate(NSObject): + window = objc.IBOutlet() + playlistModel = objc.IBOutlet() + folderModel = objc.IBOutlet() + loadingSheet = objc.IBOutlet() + # Delegate methods def applicationWillFinishLaunching_(self, _): pass def applicationDidFinishLaunching_(self, _): - pass + NSApp.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_(self.loadingSheet, self.window, None, None, None) + self.performSelectorInBackground_withObject_(self.loadFromThread, None) def applicationWillTerminate_(self, _): self.prefs().synchronize() @@ -134,6 +116,33 @@ class NotiPodAppDelegate(NSObject): return True + def loadFromThread(self): + pool = NSAutoreleasePool.alloc().init() + self.library = libsyncitunes.ITunesLibrary.alloc().init() + self.performSelectorOnMainThread_withObject_waitUntilDone_(self.finishLoading, None, True) + del pool + + def finishLoading(self): + self.playlistModel.setPlaylists(self.library.get_playlists()) + NSApp.endSheet_(self.loadingSheet) + self.loadingSheet.close() + + @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: + print playlist.name, playlist.tracks + all_tracks.extend(playlist.tracks) + libsyncitunes.export_m3u(dry_run=True, dest=folder, path_prefix="", + playlist_name=playlist.name, files=playlist.tracks) + + libsyncitunes.sync(dry_run=True, + source=self.library.folder, dest=folder, files=all_tracks) + + # Public accessors def prefs(self): @@ -154,20 +163,27 @@ class NotiPodAppDelegate(NSObject): def addFolder_(self, folder): folders = self.folders() - folders.append(folder) + while folder in folders: + folders.remove(folder) + folders.insert(0, folder) + folders = folders[:10] self._saveArray("folders", folders) - def delPlaylist_(self, playlist): + def setPlaylist_selected_(self, playlist, selected): playlists = self.playlists() - playlists.remove(playlist) - self._saveArray("playlists", playlists) - - def addPlaylist_(self, playlist): - playlists = self.playlists() - playlists.append(playlist) - self._saveArray("playlists", 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() -AppHelper.runEventLoop() +if __name__ == "__main__": + main() diff --git a/libsyncitunes.py b/libsyncitunes.py index 7e955ad..e9ed9cd 100644 --- a/libsyncitunes.py +++ b/libsyncitunes.py @@ -30,7 +30,7 @@ class Playlist(NSObject): self.name = name self.pid = pid self.children = [] - self.tracks = [] + self.tracks = tracks self.parent = parent if parent is not None: parent.children.append(self) @@ -54,7 +54,6 @@ class ITunesLibrary(NSObject): return urllib.splithost(urllib.splittype(urllib.unquote(location))[1])[1] def make_playlist(self, pl_playlist, pl_tracks): -### print pl_playlist name = pl_playlist["Name"] pid = pl_playlist["Playlist Persistent ID"] parent = None @@ -69,20 +68,32 @@ class ITunesLibrary(NSObject): filename = str(pl_tracks[str(trackID)]["Location"]) filename = self.loc2name(filename) filename = eval(repr(filename).lstrip("u")).decode("utf-8") + if not filename.startswith(self.folder): + logging.warn("Skipping: " + filename) + continue + filename = filename[len(self.folder):] + if filename.startswith("/"): + filename = filename[1:] tracks.append(filename) playlist = Playlist.alloc().init() playlist.set(name, pid, tracks, parent) return playlist - def has_playlist(self, playlist): - for p in self.playlists: - if p.name == playlist: + def has_playlist_name(self, name): + for p in self.get_playlists(): + if p.name == name: return True return False - def get_playlist(self, name): - playlist = [p for p in self.playlists if p.name == name][0] - return playlist.tracks + def get_playlist_name(self, name): + for playlist in self.get_playlists(): + if playlist.name == name: + return playlist + + def get_playlist_pid(self, pid): + for playlist in self.get_playlists(): + if playlist.pid == pid: + return playlist def get_playlists(self): return self.playlists.values() @@ -106,13 +117,13 @@ class ITunesLibrary(NSObject): return item.name -def export_m3u(dry_run, dest, drive_letter, music_dir, playlist_name, files): +def export_m3u(dry_run, dest, path_prefix, playlist_name, files): if dry_run: return f = open(os.path.join(dest, playlist_name) + ".m3u", "w") for filename in files: filename = filename.replace("/", "\\").encode("utf-8") - f.write("%s:\\%s\\%s\n" % (drive_letter, music_dir, filename)) + f.write("%s\\%s\\%s\n" % (path_prefix, filename)) f.close() def strip_prefix(s, prefix): diff --git a/syncitunes.py b/syncitunes.py index 0f50780..16c64bf 100755 --- a/syncitunes.py +++ b/syncitunes.py @@ -23,17 +23,14 @@ def parse_options(): action="store_true", dest="dry_run", default=False) parser.add_option("--itunes-library", action="store", dest="itunes_library", default=None) - parser.add_option("--drive-letter", - action="store", dest="drive_letter", default="E") - parser.add_option("--media-dir", - action="store", dest="media_dir", default="iTunes") + parser.add_option("--path-prefix", + action="store", dest="path_prefix", default="E:") opts, args = parser.parse_args(sys.argv[1:]) if len(args) < 2: parser.print_usage() sys.exit(1) opts.dest = args[0] - opts.full_dest = os.path.join(opts.dest, opts.media_dir) opts.playlists = args[1:] return opts @@ -42,11 +39,7 @@ def main(): opts = parse_options() # Set up logging - try: - logging.basicConfig(format="%(levelname)s: %(message)s") - except TypeError: - # Support for Python 2.3 - logging.basicConfig() + logging.basicConfig(format="%(levelname)s: %(message)s") if opts.quiet: logging.getLogger().setLevel(logging.CRITICAL) elif opts.verbose: @@ -66,21 +59,20 @@ def main(): library = library.init() for playlist in opts.playlists: - if not library.has_playlist(playlist): + if not library.has_playlist_name(playlist): logging.fatal("Could not find playlist: " + playlist) sys.exit(1) logging.info("Loading playlists") all_tracks = [] for playlist in opts.playlists: - tracks = list(library.get_playlist(playlist)) + tracks = library.get_playlist_name(playlist).tracks all_tracks.extend(tracks) - libsyncitunes.export_m3u(opts.dry_run, opts.full_dest, - opts.drive_letter, opts.media_dir, + libsyncitunes.export_m3u(opts.dry_run, opts.dest, opts.path_prefix, playlist, tracks) logging.info("Synchronising") - libsyncitunes.sync(opts.dry_run, library.folder, opts.full_dest, all_tracks) + libsyncitunes.sync(opts.dry_run, library.folder, opts.dest, all_tracks) if __name__ == "__main__":