def populate(self): if self.connected(): self.playlistsdata.clear() playlistinfo = [] playlists = mpdh.call(self.client, 'listplaylists') if playlists is None: playlists = mpdh.call(self.client, 'lsinfo') for item in playlists: if 'playlist' in item: playlistinfo.append(misc.escape_html(mpdh.get(item, 'playlist'))) playlistinfo.sort(key=lambda x: x.lower()) # Remove case sensitivity for item in playlistinfo: self.playlistsdata.append([gtk.STOCK_JUSTIFY_FILL, item]) if mpdh.mpd_major_version(self.client) >= 0.13: self.populate_playlists_for_menu(playlistinfo)
def library_return_search_items(self, genre=None, artist=None, album=None, year=None): # Returns all mpd items, using mpd's 'search', along with # playtime and num_songs. searches = self.library_compose_search_searchlist(genre, artist, album, year) for s in searches: args_tuple = tuple(map(str, s)) playtime = 0 num_songs = 0 results = [] if '' in s and mpdh.mpd_major_version(self.client) <= 0.13: # Can't search for empty tags, search broader and filter instead: # Strip empty tag args from tuple: pos = list(args_tuple).index('') strip_type = list(args_tuple)[pos-1] new_lst = [] for i, item in enumerate(list(args_tuple)): if i != pos and i != pos-1: new_lst.append(item) args_tuple = tuple(new_lst) else: strip_type = None if len(args_tuple) == 0: return None, 0, 0 items = mpdh.call(self.client, 'search', *args_tuple) if items is not None: for item in items: if strip_type is None or (strip_type is not None and not strip_type in item.keys()): match = True pos = 0 # Ensure that if, e.g., "foo" is searched, "foobar" isn't returned too for arg in args_tuple[::2]: if arg in item and unicode(mpdh.get(item, arg)).upper() != unicode(args_tuple[pos+1]).upper(): match = False break pos += 2 if match: results.append(item) num_songs += 1 playtime += mpdh.get(item, 'time', 0, True) return (results, int(playtime), num_songs)
def library_return_search_items(self, genre=None, artist=None, album=None, year=None): # Returns all mpd items, using mpd's 'search', along with # playtime and num_songs. searches = self.library_compose_search_searchlist(genre, artist, album, year) for s in searches: args_tuple = tuple(map(str, s)) playtime = 0 num_songs = 0 results = [] if '' in s and mpdh.mpd_major_version(self.client) <= 0.13: # Can't search for empty tags, search broader and filter instead: # Strip empty tag args from tuple: pos = list(args_tuple).index('') strip_type = list(args_tuple)[pos-1] new_lst = [] for i, item in enumerate(list(args_tuple)): if i != pos and i != pos-1: new_lst.append(item) args_tuple = tuple(new_lst) else: strip_type = None if len(args_tuple) == 0: return None, 0, 0 items = mpdh.call(self.client, 'search', *args_tuple) if items is not None: for item in items: if strip_type is None or (strip_type is not None and not strip_type in item.keys()): match = True pos = 0 # Ensure that if, e.g., "foo" is searched, "foobar" isn't returned too for arg in args_tuple[::2]: if arg in item and unicode(mpdh.get(item, arg)).upper() != unicode(args_tuple[pos+1]).upper(): match = False break pos += 2 if match: results.append(item) num_songs += 1 playtime += int(mpdh.get(item, 'time', '0')) return (results, int(playtime), num_songs)
def library_return_count(self, genre=None, artist=None, album=None, year=None): # Because mpd's 'count' is case sensitive, we have to # determine all equivalent items (case insensitive) and # call 'count' for each of them. Using 'list' + 'count' # involves much less data to be transferred back and # forth than to use 'search' and count manually. searches = self.library_compose_list_count_searchlist(genre, artist, album, year) playtime = 0 num_songs = 0 for s in searches: if '' in s and mpdh.mpd_major_version(self.client) <= 0.13: # Can't return count for empty tags, use search instead: _results, playtime, num_songs = self.library_return_search_items(genre=genre, artist=artist, album=album, year=year) else: count = mpdh.call(self.client, 'count', *s) playtime += mpdh.get(count, 'playtime', 0, True) num_songs += mpdh.get(count, 'songs', 0, True) return (playtime, num_songs)
def library_return_count(self, genre=None, artist=None, album=None, year=None): # Because mpd's 'count' is case sensitive, we have to # determine all equivalent items (case insensitive) and # call 'count' for each of them. Using 'list' + 'count' # involves much less data to be transferred back and # forth than to use 'search' and count manually. searches = self.library_compose_list_count_searchlist(genre, artist, album, year) playtime = 0 num_songs = 0 for s in searches: if '' in s and mpdh.mpd_major_version(self.client) <= 0.13: # Can't return count for empty tags, use search instead: _results, playtime, num_songs = self.library_return_search_items(genre=genre, artist=artist, album=album, year=year) else: count = mpdh.call(self.client, 'count', *s) playtime += int(mpdh.get(count, 'playtime')) num_songs += int(mpdh.get(count, 'songs')) return (playtime, num_songs)
def on_dnd(self, treeview, drag_context, x, y, selection, _info, timestamp): drop_info = treeview.get_dest_row_at_pos(x, y) if selection.data is not None: if not os.path.isdir(misc.file_from_utf8(self.config.musicdir[self.config.profile_num])): return # DND from outside sonata: uri = selection.data.strip() path = urllib.url2pathname(uri) paths = path.rsplit("\n") mpdpaths = [] # Strip off paranthesis so that we can DND entire music dir # if we wish. musicdir = self.config.musicdir[self.config.profile_num][:-1] for i, path in enumerate(paths): paths[i] = path.rstrip("\r") if paths[i].startswith("file://"): paths[i] = paths[i][7:] elif paths[i].startswith("file:"): paths[i] = paths[i][5:] if paths[i].startswith(musicdir): paths[i] = paths[i][len(self.config.musicdir[self.config.profile_num]) :] if len(paths[i]) == 0: paths[i] = "/" listallinfo = mpdh.call(self.client, "listallinfo", paths[i]) for item in listallinfo: if "file" in item: mpdpaths.append(mpdh.get(item, "file")) elif mpdh.mpd_major_version(self.client) >= 0.14: # Add local file, available in mpd 0.14. This currently won't # work because python-mpd does not support unix socket paths, # which is needed for authentication for local files. It's also # therefore untested. if os.path.isdir(misc.file_from_utf8(paths[i])): filenames = misc.get_files_recursively(paths[i]) else: filenames = [paths[i]] for filename in filenames: if os.path.exists(misc.file_from_utf8(filename)): mpdpaths.append("file://" + urllib.quote(filename)) if len(mpdpaths) > 0: # Items found, add to list at drop position: if drop_info: destpath, position = drop_info if position in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): songid = destpath[0] else: songid = destpath[0] + 1 else: songid = len(self.currentdata) for mpdpath in mpdpaths: mpdh.call(self.client, "addid", mpdpath, songid) self.iterate_now() return # Otherwise, it's a DND just within the current playlist model = treeview.get_model() _foobar, selected = self.current_selection.get_selected_rows() # calculate all this now before we start moving stuff drag_sources = [] for path in selected: index = path[0] i = model.get_iter(path) songid = self.current_get_songid(i, model) text = model.get_value(i, 1) drag_sources.append([index, i, songid, text]) # Keep track of the moved iters so we can select them afterwards moved_iters = [] # We will manipulate self.current_songs and model to prevent the entire playlist # from refreshing offset = 0 mpdh.call(self.client, "command_list_ok_begin") for source in drag_sources: index, i, songid, text = source if drop_info: destpath, position = drop_info dest = destpath[0] + offset if dest < index: offset = offset + 1 if position in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): self.current_songs.insert(dest, self.current_songs[index]) if dest < index + 1: self.current_songs.pop(index + 1) mpdh.call(self.client, "moveid", songid, dest) else: self.current_songs.pop(index) mpdh.call(self.client, "moveid", songid, dest - 1) model.insert(dest, model[index]) moved_iters += [model.get_iter((dest,))] model.remove(i) else: self.current_songs.insert(dest + 1, self.current_songs[index]) if dest < index: self.current_songs.pop(index + 1) mpdh.call(self.client, "moveid", songid, dest + 1) else: self.current_songs.pop(index) mpdh.call(self.client, "moveid", songid, dest) model.insert(dest + 1, model[index]) moved_iters += [model.get_iter((dest + 1,))] model.remove(i) else: # dest = int(self.status['playlistlength']) - 1 dest = len(self.currentdata) - 1 mpdh.call(self.client, "moveid", songid, dest) self.current_songs.insert(dest + 1, self.current_songs[index]) self.current_songs.pop(index) model.insert(dest + 1, model[index]) moved_iters += [model.get_iter((dest + 1,))] model.remove(i) # now fixup for source in drag_sources: if dest < index: # we moved it back, so all indexes inbetween increased by 1 if dest < source[0] < index: source[0] += 1 else: # we moved it ahead, so all indexes inbetween decreased by 1 if index < source[0] < dest: source[0] -= 1 mpdh.call(self.client, "command_list_end") # we are manipulating the model manually for speed, so... self.current_update_skip = True if drag_context.action == gtk.gdk.ACTION_MOVE: drag_context.finish(True, True, timestamp) self.header_hide_all_indicators(self.current, False) self.iterate_now() gobject.idle_add(self.dnd_retain_selection, treeview.get_selection(), moved_iters)
def on_dnd(self, treeview, drag_context, x, y, selection, _info, timestamp): drop_info = treeview.get_dest_row_at_pos(x, y) if selection.data is not None: if not os.path.isdir( misc.file_from_utf8( self.config.musicdir[self.config.profile_num])): return # DND from outside sonata: uri = selection.data.strip() path = urllib.url2pathname(uri) paths = path.rsplit('\n') mpdpaths = [] # Strip off paranthesis so that we can DND entire music dir # if we wish. musicdir = self.config.musicdir[self.config.profile_num][:-1] for i, path in enumerate(paths): paths[i] = path.rstrip('\r') if paths[i].startswith('file://'): paths[i] = paths[i][7:] elif paths[i].startswith('file:'): paths[i] = paths[i][5:] if paths[i].startswith(musicdir): paths[i] = paths[i][ len(self.config.musicdir[self.config.profile_num]):] if len(paths[i]) == 0: paths[i] = "/" listallinfo = mpdh.call(self.client, 'listallinfo', paths[i]) for item in listallinfo: if 'file' in item: mpdpaths.append(mpdh.get(item, 'file')) elif mpdh.mpd_major_version(self.client) >= 0.14: # Add local file, available in mpd 0.14. This currently won't # work because python-mpd does not support unix socket paths, # which is needed for authentication for local files. It's also # therefore untested. if os.path.isdir(misc.file_from_utf8(paths[i])): filenames = misc.get_files_recursively(paths[i]) else: filenames = [paths[i]] for filename in filenames: if os.path.exists(misc.file_from_utf8(filename)): mpdpaths.append("file://" + urllib.quote(filename)) if len(mpdpaths) > 0: # Items found, add to list at drop position: if drop_info: destpath, position = drop_info if position in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): songid = destpath[0] else: songid = destpath[0] + 1 else: songid = len(self.currentdata) for mpdpath in mpdpaths: mpdh.call(self.client, 'addid', mpdpath, songid) self.iterate_now() return # Otherwise, it's a DND just within the current playlist model = treeview.get_model() _foobar, selected = self.current_selection.get_selected_rows() # calculate all this now before we start moving stuff drag_sources = [] for path in selected: index = path[0] i = model.get_iter(path) songid = self.current_get_songid(i, model) text = model.get_value(i, 1) drag_sources.append([index, i, songid, text]) # Keep track of the moved iters so we can select them afterwards moved_iters = [] # We will manipulate self.current_songs and model to prevent the entire playlist # from refreshing offset = 0 mpdh.call(self.client, 'command_list_ok_begin') for source in drag_sources: index, i, songid, text = source if drop_info: destpath, position = drop_info dest = destpath[0] + offset if dest < index: offset = offset + 1 if position in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): self.current_songs.insert(dest, self.current_songs[index]) if dest < index + 1: self.current_songs.pop(index + 1) mpdh.call(self.client, 'moveid', songid, dest) else: self.current_songs.pop(index) mpdh.call(self.client, 'moveid', songid, dest - 1) model.insert(dest, model[index]) moved_iters += [model.get_iter((dest, ))] model.remove(i) else: self.current_songs.insert(dest + 1, self.current_songs[index]) if dest < index: self.current_songs.pop(index + 1) mpdh.call(self.client, 'moveid', songid, dest + 1) else: self.current_songs.pop(index) mpdh.call(self.client, 'moveid', songid, dest) model.insert(dest + 1, model[index]) moved_iters += [model.get_iter((dest + 1, ))] model.remove(i) else: #dest = int(self.status['playlistlength']) - 1 dest = len(self.currentdata) - 1 mpdh.call(self.client, 'moveid', songid, dest) self.current_songs.insert(dest + 1, self.current_songs[index]) self.current_songs.pop(index) model.insert(dest + 1, model[index]) moved_iters += [model.get_iter((dest + 1, ))] model.remove(i) # now fixup for source in drag_sources: if dest < index: # we moved it back, so all indexes inbetween increased by 1 if dest < source[0] < index: source[0] += 1 else: # we moved it ahead, so all indexes inbetween decreased by 1 if index < source[0] < dest: source[0] -= 1 mpdh.call(self.client, 'command_list_end') # we are manipulating the model manually for speed, so... self.current_update_skip = True if drag_context.action == gtk.gdk.ACTION_MOVE: drag_context.finish(True, True, timestamp) self.header_hide_all_indicators(self.current, False) self.iterate_now() gobject.idle_add(self.dnd_retain_selection, treeview.get_selection(), moved_iters)