コード例 #1
0
	def library_return_list_items(self, itemtype, genre=None, artist=None, album=None, year=None, ignore_case=True):
		# Returns all items of tag 'itemtype', in alphabetical order, 
		# using mpd's 'list'. If searchtype is passed, use
		# a case insensitive search, via additional 'list'
		# queries, since using a single 'list' call will be
		# case sensitive.
		results = []
		searches = self.library_compose_list_count_searchlist(genre, artist, album, year)
		if len(searches) > 0:
			for s in searches:
				# If we have untagged tags (''), use search instead
				# of list because list will not return anything.
				if '' in s:
					items = []
					songs, playtime, num_songs = self.library_return_search_items(genre, artist, album, year)
					for song in songs:
						items.append(mpdh.get(song, itemtype))
				else:
					items = mpdh.call(self.client, 'list', itemtype, *s)
				for item in items:
					if len(item) > 0:
						results.append(item)
		else:
			if genre is None and artist is None and album is None and year is None:
				for item in mpdh.call(self.client, 'list', itemtype):
					if len(item) > 0:
						results.append(item)
		if ignore_case:
			results = misc.remove_list_duplicates(results, case=False)
		results.sort(locale.strcoll)
		return results
コード例 #2
0
ファイル: playlists.py プロジェクト: themylogin/sonata
 def on_playlist_save(self, _action):
     plname = self.prompt_for_playlist_name(_("Save Playlist"), 'savePlaylist')
     if plname:
         if self.playlist_name_exists(_("Save Playlist"), 'savePlaylistError', plname):
             return
         self.playlist_create(plname)
         mpdh.call(self.client, 'playlistclear', plname)
         self.add_selected_to_playlist(plname)
コード例 #3
0
ファイル: playlists.py プロジェクト: themylogin/sonata
 def on_playlist_menu_click(self, action):
     plname = misc.unescape_html(action.get_name().replace("Playlist: ", ""))
     response = ui.show_msg(self.window, _("Would you like to replace the existing playlist or append these songs?"), _("Existing Playlist"), "existingPlaylist", (_("Replace playlist"), 1, _("Append songs"), 2), default=self.config.existing_playlist_option)
     if response == 1: # Overwrite
         self.config.existing_playlist_option = response
         mpdh.call(self.client, 'playlistclear', plname)
         self.add_selected_to_playlist(plname)
     elif response == 2: # Append songs:
         self.config.existing_playlist_option = response
         self.add_selected_to_playlist(plname)
コード例 #4
0
ファイル: cli.py プロジェクト: BackupTheBerlios/sonata-svn
	def mpd_connect(self):
		host, port, password = misc.mpd_env_vars()
		if not host:
			host = self.config.host[self.config.profile_num]
		if not port:
			port = self.config.port[self.config.profile_num]
		if not password:
			password = self.config.password[self.config.profile_num]

		mpdh.call(self.client, 'connect', host, port)
		if password:
			mpdh.call(self.client, 'password', password)
コード例 #5
0
    def mpd_connect(self):
        host, port, password = misc.mpd_env_vars()
        if not host:
            host = self.config.host[self.config.profile_num]
        if not port:
            port = self.config.port[self.config.profile_num]
        if not password:
            password = self.config.password[self.config.profile_num]

        mpdh.call(self.client, 'connect', host, port)
        if password:
            mpdh.call(self.client, 'password', password)
コード例 #6
0
 def searchfilter_on_enter(self, _entry):
     model, selected = self.current.get_selection().get_selected_rows()
     song_id = None
     if len(selected) > 0:
         # If items are selected, play the first selected item:
         song_id = self.current_get_songid(model.get_iter(selected[0]), model)
     elif len(model) > 0:
         # If nothing is selected: play the first item:
         song_id = self.current_get_songid(model.get_iter_first(), model)
     if song_id:
         self.searchfilter_toggle(None)
         mpdh.call(self.client, "playid", song_id)
コード例 #7
0
 def on_current_click(self, _treeview, path, _column):
     model = self.current.get_model()
     if self.filterbox_visible:
         self.searchfilter_on_enter(None)
         return
     try:
         i = model.get_iter(path)
         mpdh.call(self.client, "playid", self.current_get_songid(i, model))
     except:
         pass
     self.sel_rows = False
     self.iterate_now()
コード例 #8
0
 def on_current_click(self, _treeview, path, _column):
     model = self.current.get_model()
     if self.filterbox_visible:
         self.searchfilter_on_enter(None)
         return
     try:
         i = model.get_iter(path)
         mpdh.call(self.client, 'playid', self.current_get_songid(i, model))
     except:
         pass
     self.sel_rows = False
     self.iterate_now()
コード例 #9
0
 def searchfilter_on_enter(self, _entry):
     model, selected = self.current.get_selection().get_selected_rows()
     song_id = None
     if len(selected) > 0:
         # If items are selected, play the first selected item:
         song_id = self.current_get_songid(model.get_iter(selected[0]),
                                           model)
     elif len(model) > 0:
         # If nothing is selected: play the first item:
         song_id = self.current_get_songid(model.get_iter_first(), model)
     if song_id:
         self.searchfilter_toggle(None)
         mpdh.call(self.client, 'playid', song_id)
コード例 #10
0
ファイル: playlists.py プロジェクト: themylogin/sonata
 def playlist_name_exists(self, title, role, plname, skip_plname=""):
     # If the playlist already exists, and the user does not want to replace it, return True; In
     # all other cases, return False
     playlists = mpdh.call(self.client, 'listplaylists')
     if playlists is None:
         playlists = mpdh.call(self.client, 'lsinfo')
     for item in playlists:
         if 'playlist' in item:
             if mpdh.get(item, 'playlist') == plname and plname != skip_plname:
                 if ui.show_msg(self.window, _("A playlist with this name already exists. Would you like to replace it?"), title, role, gtk.BUTTONS_YES_NO) == gtk.RESPONSE_YES:
                     return False
                 else:
                     return True
     return False
コード例 #11
0
 def on_remove(self):
     treeviewsel = self.current_selection
     model, selected = treeviewsel.get_selected_rows()
     if len(selected) == len(self.currentdata) and not self.filterbox_visible:
         # Everything is selected, clear:
         mpdh.call(self.client, "clear")
     elif len(selected) > 0:
         # we are manipulating the model manually for speed, so...
         self.current_update_skip = True
         selected.reverse()
         if not self.filterbox_visible:
             # If we remove an item from the filtered results, this
             # causes a visual refresh in the interface.
             self.current.set_model(None)
         mpdh.call(self.client, "command_list_ok_begin")
         for path in selected:
             if not self.filterbox_visible:
                 rownum = path[0]
             else:
                 rownum = self.filter_row_mapping[path[0]]
             i = self.currentdata.get_iter((rownum, 0))
             mpdh.call(self.client, "deleteid", self.current_get_songid(i, self.currentdata))
             # Prevents the entire playlist from refreshing:
             self.current_songs.pop(rownum)
             self.currentdata.remove(i)
         mpdh.call(self.client, "command_list_end")
         if not self.filterbox_visible:
             self.current.set_model(model)
コード例 #12
0
	def playlist_name_exists(self, title, role, plname, skip_plname=""):
		# If the playlist already exists, and the user does not want to replace it, return True; In
		# all other cases, return False
		playlists = mpdh.call(self.client, 'listplaylists')
		if playlists is None:
			playlists = mpdh.call(self.client, 'lsinfo')
		for item in playlists:
			if 'playlist' in item:
				if mpdh.get(item, 'playlist') == plname and plname != skip_plname:
					if ui.show_msg(self.window, _("A playlist with this name already exists. Would you like to replace it?"), title, role, gtk.BUTTONS_YES_NO) == gtk.RESPONSE_YES:
						return False
					else:
						return True
		return False
コード例 #13
0
 def on_remove(self):
     treeviewsel = self.current_selection
     model, selected = treeviewsel.get_selected_rows()
     if len(selected) == len(
             self.currentdata) and not self.filterbox_visible:
         # Everything is selected, clear:
         mpdh.call(self.client, 'clear')
     elif len(selected) > 0:
         # we are manipulating the model manually for speed, so...
         self.current_update_skip = True
         selected.reverse()
         if not self.filterbox_visible:
             # If we remove an item from the filtered results, this
             # causes a visual refresh in the interface.
             self.current.set_model(None)
         mpdh.call(self.client, 'command_list_ok_begin')
         for path in selected:
             if not self.filterbox_visible:
                 rownum = path[0]
             else:
                 rownum = self.filter_row_mapping[path[0]]
             i = self.currentdata.get_iter((rownum, 0))
             mpdh.call(self.client, 'deleteid',
                       self.current_get_songid(i, self.currentdata))
             # Prevents the entire playlist from refreshing:
             self.current_songs.pop(rownum)
             self.currentdata.remove(i)
         mpdh.call(self.client, 'command_list_end')
         if not self.filterbox_visible:
             self.current.set_model(model)
コード例 #14
0
	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)
コード例 #15
0
ファイル: playlists.py プロジェクト: themylogin/sonata
 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)
コード例 #16
0
	def library_get_path_files_recursive(self, path):
		results = []
		for item in mpdh.call(self.client, 'lsinfo', path):
			if 'directory' in item:
				results = results + self.library_get_path_files_recursive(mpdh.get(item, 'directory'))
			elif 'file' in item:
				results.append(mpdh.get(item, 'file'))
		return results
コード例 #17
0
	def libsearchfilter_do_search(self, searchby, todo):
		if not self.prevlibtodo_base in todo:
			# Do library search based on first two letters:
			self.prevlibtodo_base = todo[:2]
			self.prevlibtodo_base_results = mpdh.call(self.client, 'search', searchby, self.prevlibtodo_base)
			subsearch = False
		else:
			subsearch = True
		# Now, use filtering similar to playlist filtering:
		# this make take some seconds... and we'll escape the search text because
		# we'll be searching for a match in items that are also escaped.
		todo = misc.escape_html(todo)
		todo = re.escape(todo)
		todo = '.*' + todo.replace(' ', ' .*').lower()
		regexp = re.compile(todo)
		matches = []
		if searchby != 'any':
			for row in self.prevlibtodo_base_results:
				if regexp.match(unicode(mpdh.get(row, searchby)).lower()):
					matches.append(row)
		else:
			for row in self.prevlibtodo_base_results:
				for meta in row:
					if regexp.match(unicode(mpdh.get(row, meta)).lower()):
						matches.append(row)
						break
		if subsearch and len(matches) == len(self.librarydata):
			# nothing changed..
			return
		self.library.freeze_child_notify()
		currlen = len(self.librarydata)
		newlist = []
		for item in matches:
			if 'file' in item:
				newlist.append([self.sonatapb, self.library_set_data(path=mpdh.get(item, 'file')), self.parse_formatting(self.config.libraryformat, item, True)])
		for i, item in enumerate(newlist):
			if i < currlen:
				j = self.librarydata.get_iter((i, ))
				for index in range(len(item)):
					if item[index] != self.librarydata.get_value(j, index):
						self.librarydata.set_value(j, index, item[index])
			else:
				self.librarydata.append(item)
		# Remove excess items...
		newlen = len(newlist)
		if newlen == 0:
			self.librarydata.clear()
		else:
			for i in range(currlen-newlen):
				j = self.librarydata.get_iter((currlen-1-i,))
				self.librarydata.remove(j)
		self.library.thaw_child_notify()
		if len(matches) == 0:
			gobject.idle_add(self.filtering_entry_make_red, self.searchtext)
		else:
			gobject.idle_add(self.library.set_cursor,'0')
			gobject.idle_add(self.filtering_entry_revert_color, self.searchtext)
コード例 #18
0
	def playlist_create(self, playlistname, oldname=None):
		mpdh.call(self.client, 'rm', playlistname)
		if oldname is not None:
			mpdh.call(self.client, 'rename', oldname, playlistname)
		else:
			mpdh.call(self.client, 'save', playlistname)
		self.populate()
		self.iterate_now()
コード例 #19
0
ファイル: playlists.py プロジェクト: themylogin/sonata
 def playlist_create(self, playlistname, oldname=None):
     mpdh.call(self.client, 'rm', playlistname)
     if oldname is not None:
         mpdh.call(self.client, 'rename', oldname, playlistname)
     else:
         mpdh.call(self.client, 'save', playlistname)
     self.populate()
     self.iterate_now()
コード例 #20
0
	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:
			count = mpdh.call(self.client, 'count', *s)
			playtime += int(mpdh.get(count, 'playtime'))
			num_songs += int(mpdh.get(count, 'songs'))
		return (playtime, num_songs)
コード例 #21
0
	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)
コード例 #22
0
	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)
コード例 #23
0
	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. Note that if one of the args is
		# '', the search results will only be correct for mpd=0.14
		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 = []
			items = mpdh.call(self.client, 'search', *args_tuple)
			if items is not None:
				for item in items:
					results.append(item)
					num_songs += 1
					playtime += int(mpdh.get(item, 'time', '0'))
		return (results, int(playtime), num_songs)
コード例 #24
0
	def on_playlist_menu_click(self, action):
		plname = misc.unescape_html(action.get_name().replace("Playlist: ", ""))
		response = ui.show_msg(self.window, _("Would you like to replace the existing playlist or append these songs?"), _("Existing Playlist"), "existingPlaylist", (_("Replace playlist"), 1, _("Append songs"), 2), default=self.config.existing_playlist_option)
		if response == 1: # Overwrite
			self.config.existing_playlist_option = response
			self.playlist_create(plname)
		elif response == 2: # Append songs:
			self.config.existing_playlist_option = response
			mpdh.call(self.client, 'command_list_ok_begin')
			for song in self.get_current_songs():
				mpdh.call(self.client, 'playlistadd', plname, mpdh.get(song, 'file'))
			mpdh.call(self.client, 'command_list_end')
		return
コード例 #25
0
 def on_sort_reverse(self, _action):
     if self.connected():
         if not self.currentdata:
             return
         while gtk.events_pending():
             gtk.main_iteration()
         top = 0
         bot = len(self.currentdata) - 1
         mpdh.call(self.client, 'command_list_ok_begin')
         while top < bot:
             mpdh.call(self.client, 'swap', top, bot)
             top = top + 1
             bot = bot - 1
         mpdh.call(self.client, 'command_list_end')
         self.iterate_now()
コード例 #26
0
 def on_sort_reverse(self, _action):
     if self.connected():
         if not self.currentdata:
             return
         while gtk.events_pending():
             gtk.main_iteration()
         top = 0
         bot = len(self.currentdata) - 1
         mpdh.call(self.client, "command_list_ok_begin")
         while top < bot:
             mpdh.call(self.client, "swap", top, bot)
             top = top + 1
             bot = bot - 1
         mpdh.call(self.client, "command_list_end")
         self.iterate_now()
コード例 #27
0
	def library_populate_filesystem_data(self, path):
		# List all dirs/files at path
		bd = []
		if path == '/' and self.lib_view_filesystem_cache is not None:
			# Use cache if possible...
			bd = self.lib_view_filesystem_cache
		else:
			for item in mpdh.call(self.client, 'lsinfo', path):
				if 'directory' in item:
					name = mpdh.get(item, 'directory').split('/')[-1]
					data = self.library_set_data(path=mpdh.get(item, 'directory'))
					bd += [('d' + unicode(name).lower(), [self.openpb, data, misc.escape_html(name)])]
				elif 'file' in item:
					data = self.library_set_data(path=mpdh.get(item, 'file'))
					bd += [('f' + unicode(mpdh.get(item, 'file')).lower(), [self.sonatapb, data, self.parse_formatting(self.config.libraryformat, item, True)])]
			bd.sort(key=misc.first_of_2tuple)
			if path != '/' and len(bd) > 0:
				bd = self.library_populate_add_parent_rows() + bd
			if path == '/': 
				self.lib_view_filesystem_cache = bd
		return bd
コード例 #28
0
	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)
コード例 #29
0
	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)
コード例 #30
0
 def on_playlist_menu_click(self, action):
     plname = misc.unescape_html(action.get_name().replace(
         "Playlist: ", ""))
     response = ui.show_msg(
         self.window,
         _("Would you like to replace the existing playlist or append these songs?"
           ),
         _("Existing Playlist"),
         "existingPlaylist",
         (_("Replace playlist"), 1, _("Append songs"), 2),
         default=self.config.existing_playlist_option)
     if response == 1:  # Overwrite
         self.config.existing_playlist_option = response
         self.playlist_create(plname)
     elif response == 2:  # Append songs:
         self.config.existing_playlist_option = response
         mpdh.call(self.client, 'command_list_ok_begin')
         for song in self.get_current_songs():
             mpdh.call(self.client, 'playlistadd', plname,
                       mpdh.get(song, 'file'))
         mpdh.call(self.client, 'command_list_end')
     return
コード例 #31
0
 def _execute_prev(self):
     mpdh.call(self.client, 'previous')
コード例 #32
0
 def _execute_next(self):
     mpdh.call(self.client, 'next')
コード例 #33
0
 def _execute_stop(self):
     mpdh.call(self.client, 'stop')
コード例 #34
0
 def _execute_pause(self):
     mpdh.call(self.client, 'pause', 1)
コード例 #35
0
    def sort(self, mode, column=None):
        if self.connected():
            if not self.currentdata:
                return

            while gtk.events_pending():
                gtk.main_iteration()
            songs = []
            track_num = 0

            if mode[0:3] == 'col':
                col_num = int(mode.replace('col', ''))
                if column.get_sort_indicator():
                    # If this column was already sorted, reverse list:
                    self.column_sorted = (column, self.column_sorted[1])
                    self.on_sort_reverse(None)
                    return
                else:
                    self.column_sorted = (column, gtk.SORT_DESCENDING)
                mode = "col"

            # If the first tag in the format is song length, we will make sure to compare
            # the same number of items in the song length string (e.g. always use
            # ##:##:##) and pad the first item to two (e.g. #:##:## -> ##:##:##)
            custom_sort = False
            if mode == 'col':
                custom_sort, custom_pos = self.sort_get_first_format_tag(
                    self.config.currentformat, col_num, 'L')

            for track in self.current_songs:
                record = {}
                # Those items that don't have the specified tag will be put at
                # the end of the list (hence the 'zzzzzzz'):
                zzz = 'zzzzzzzz'
                if mode == 'artist':
                    record["sortby"] = (misc.lower_no_the(
                        mpdh.get(track, 'artist',
                                 zzz)), mpdh.get(track, 'album', zzz).lower(),
                                        mpdh.getnum(track, 'disc', '0', True,
                                                    0),
                                        mpdh.getnum(track, 'track', '0', True,
                                                    0))
                elif mode == 'album':
                    record["sortby"] = (mpdh.get(track, 'album', zzz).lower(),
                                        mpdh.getnum(track, 'disc', '0', True,
                                                    0),
                                        mpdh.getnum(track, 'track', '0', True,
                                                    0))
                elif mode == 'file':
                    record["sortby"] = mpdh.get(track, 'file',
                                                zzz).lower().split('/')[-1]
                elif mode == 'dirfile':
                    record["sortby"] = mpdh.get(track, 'file', zzz).lower()
                elif mode == 'col':
                    # Sort by column:
                    record["sortby"] = misc.unbold(
                        self.currentdata.get_value(
                            self.currentdata.get_iter((track_num, 0)),
                            col_num).lower())
                    if custom_sort:
                        record["sortby"] = self.sanitize_songlen_for_sorting(
                            record["sortby"], custom_pos)
                else:
                    record["sortby"] = mpdh.get(track, mode, zzz).lower()
                record["id"] = int(track["id"])
                songs.append(record)
                track_num = track_num + 1

            songs.sort(key=lambda x: x["sortby"])

            pos = 0
            mpdh.call(self.client, 'command_list_ok_begin')
            for item in songs:
                mpdh.call(self.client, 'moveid', item["id"], pos)
                pos += 1
            mpdh.call(self.client, 'command_list_end')
            self.iterate_now()

            self.header_update_column_indicators()
コード例 #36
0
ファイル: cli.py プロジェクト: BackupTheBerlios/sonata-svn
	def _execute_play(self):
		mpdh.call(self.client, 'play')
コード例 #37
0
ファイル: cli.py プロジェクト: BackupTheBerlios/sonata-svn
	def _execute_prev(self):
		mpdh.call(self.client, 'previous')
コード例 #38
0
ファイル: cli.py プロジェクト: BackupTheBerlios/sonata-svn
	def _execute_next(self):
		mpdh.call(self.client, 'next')
コード例 #39
0
ファイル: cli.py プロジェクト: BackupTheBerlios/sonata-svn
	def _execute_bool(self, cmd):
		"""Set the reverse the value of cmd"""
		mpdh.call(self.client, cmd, int(not int(self.status[cmd])))
コード例 #40
0
    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)
コード例 #41
0
    def sort(self, mode, column=None):
        if self.connected():
            if not self.currentdata:
                return

            while gtk.events_pending():
                gtk.main_iteration()
            songs = []
            track_num = 0

            if mode[0:3] == "col":
                col_num = int(mode.replace("col", ""))
                if column.get_sort_indicator():
                    # If this column was already sorted, reverse list:
                    self.column_sorted = (column, self.column_sorted[1])
                    self.on_sort_reverse(None)
                    return
                else:
                    self.column_sorted = (column, gtk.SORT_DESCENDING)
                mode = "col"

                # If the first tag in the format is song length, we will make sure to compare
                # the same number of items in the song length string (e.g. always use
                # ##:##:##) and pad the first item to two (e.g. #:##:## -> ##:##:##)
            custom_sort = False
            if mode == "col":
                custom_sort, custom_pos = self.sort_get_first_format_tag(self.config.currentformat, col_num, "L")

            for track in self.current_songs:
                record = {}
                # Those items that don't have the specified tag will be put at
                # the end of the list (hence the 'zzzzzzz'):
                zzz = "zzzzzzzz"
                if mode == "artist":
                    record["sortby"] = (
                        misc.lower_no_the(mpdh.get(track, "artist", zzz)),
                        mpdh.get(track, "album", zzz).lower(),
                        mpdh.getnum(track, "disc", "0", True, 0),
                        mpdh.getnum(track, "track", "0", True, 0),
                    )
                elif mode == "album":
                    record["sortby"] = (
                        mpdh.get(track, "album", zzz).lower(),
                        mpdh.getnum(track, "disc", "0", True, 0),
                        mpdh.getnum(track, "track", "0", True, 0),
                    )
                elif mode == "file":
                    record["sortby"] = mpdh.get(track, "file", zzz).lower().split("/")[-1]
                elif mode == "dirfile":
                    record["sortby"] = mpdh.get(track, "file", zzz).lower()
                elif mode == "col":
                    # Sort by column:
                    record["sortby"] = misc.unbold(
                        self.currentdata.get_value(self.currentdata.get_iter((track_num, 0)), col_num).lower()
                    )
                    if custom_sort:
                        record["sortby"] = self.sanitize_songlen_for_sorting(record["sortby"], custom_pos)
                else:
                    record["sortby"] = mpdh.get(track, mode, zzz).lower()
                record["id"] = int(track["id"])
                songs.append(record)
                track_num = track_num + 1

            songs.sort(key=lambda x: x["sortby"])

            pos = 0
            mpdh.call(self.client, "command_list_ok_begin")
            for item in songs:
                mpdh.call(self.client, "moveid", item["id"], pos)
                pos += 1
            mpdh.call(self.client, "command_list_end")
            self.iterate_now()

            self.header_update_column_indicators()
コード例 #42
0
    def current_update(self, prevstatus_playlist, new_playlist_length):
        if self.connected():

            if self.sonata_loaded():
                playlistposition = self.current.get_visible_rect()[1]

            self.current.freeze_child_notify()

            if not self.current_update_skip:

                if not self.filterbox_visible:
                    self.current.set_model(None)

                if prevstatus_playlist:
                    changed_songs = mpdh.call(self.client, "plchanges", prevstatus_playlist)
                else:
                    changed_songs = mpdh.call(self.client, "plchanges", 0)
                    self.current_songs = []

                newlen = int(new_playlist_length)
                currlen = len(self.currentdata)

                for track in changed_songs:
                    pos = int(mpdh.get(track, "pos"))

                    items = []
                    for part in self.columnformat:
                        items += [self.parse_formatting(part, track, True)]

                    if pos < currlen:
                        # Update attributes for item:
                        i = self.currentdata.get_iter((pos,))
                        trackid = int(mpdh.get(track, "id"))
                        if trackid != self.currentdata.get_value(i, 0):
                            self.currentdata.set_value(i, 0, trackid)
                        for index in range(len(items)):
                            if items[index] != self.currentdata.get_value(i, index + 1):
                                self.currentdata.set_value(i, index + 1, items[index])
                        self.current_songs[pos] = track
                    else:
                        # Add new item:
                        self.currentdata.append([int(mpdh.get(track, "id"))] + items)
                        self.current_songs.append(track)

                if newlen == 0:
                    self.currentdata.clear()
                    self.current_songs = []
                else:
                    # Remove excess songs:
                    for i in range(currlen - newlen):
                        it = self.currentdata.get_iter((currlen - 1 - i,))
                        self.currentdata.remove(it)
                    self.current_songs = self.current_songs[:newlen]

                if not self.filterbox_visible:
                    self.current.set_model(self.currentdata)

            self.current_update_skip = False

            # Update statusbar time:
            self.total_time = 0
            for track in self.current_songs:
                try:
                    self.total_time = self.total_time + int(mpdh.get(track, "time"))
                except:
                    pass

            if "pos" in self.songinfo():
                currsong = int(mpdh.get(self.songinfo(), "pos"))
                self.boldrow(currsong)
                self.prev_boldrow = currsong

            if self.filterbox_visible:
                # Refresh filtered results:
                self.prevtodo = (
                    "RETAIN_POS_AND_SEL"
                )  # Hacky, but this ensures we retain the self.current position/selection
                self.plpos = playlistposition
                self.searchfilter_feed_loop(self.filterpattern)
            elif self.sonata_loaded():
                self.playlist_retain_view(self.current, playlistposition)
                self.current.thaw_child_notify()

            self.header_update_column_indicators()
            self.update_statusbar()
            ui.change_cursor(None)
コード例 #43
0
ファイル: cli.py プロジェクト: BackupTheBerlios/sonata-svn
	def _execute_pp(self):
		if self.status['state'] in ['play']:
			mpdh.call(self.client, 'pause', 1)
		elif self.status['state'] in ['pause', 'stop']:
			mpdh.call(self.client, 'play')
コード例 #44
0
 def _execute_bool(self, cmd):
     """Set the reverse the value of cmd"""
     mpdh.call(self.client, cmd, int(not int(self.status[cmd])))
コード例 #45
0
ファイル: cli.py プロジェクト: BackupTheBerlios/sonata-svn
	def _execute_stop(self):
		mpdh.call(self.client, 'stop')
コード例 #46
0
 def _execute_pp(self):
     if self.status['state'] in ['play']:
         mpdh.call(self.client, 'pause', 1)
     elif self.status['state'] in ['pause', 'stop']:
         mpdh.call(self.client, 'play')
コード例 #47
0
ファイル: cli.py プロジェクト: BackupTheBerlios/sonata-svn
	def _execute_pause(self):
		mpdh.call(self.client, 'pause', 1)
コード例 #48
0
	def library_populate_toplevel_data(self, genreview=False, artistview=False, albumview=False):
		bd = self.library_get_toplevel_cache(genreview, artistview, albumview)
		if bd is not None:
			# We have our cached data, woot.
			return bd
		bd = []
		if genreview or artistview:
			# Only for artist/genre views, album view is handled differently
			# since multiple artists can have the same album name
			if genreview: 
				items = self.library_return_list_items('genre')
				pb = self.genrepb
			else:
				items = self.library_return_list_items('artist')
				pb = self.artistpb
			if not (self.NOTAG in items):
				items.append(self.NOTAG)
			for item in items:
				if genreview: 
					playtime, num_songs = self.library_return_count(genre=item)
					data = self.library_set_data(genre=item)
				else:
					playtime, num_songs = self.library_return_count(artist=item)
					data = self.library_set_data(artist=item)
				display = misc.escape_html(item)
				display += self.add_display_info(num_songs, int(playtime)/60)
				bd += [(misc.lower_no_the(item), [pb, data, display])]
		elif albumview:
			albums = []
			untagged_found = False
			for item in mpdh.call(self.client, 'listallinfo', '/'):
				if 'file' in item and 'album' in item:
					album = mpdh.get(item, 'album')
					artist = mpdh.get(item, 'artist', self.NOTAG)
					year = mpdh.get(item, 'date', self.NOTAG)
					filepath = os.path.dirname(mpdh.get(item, 'file'))
					data = self.library_set_data(album=album, artist=artist, year=year, path=filepath)
					albums.append(data)
					if album == self.NOTAG:
						untagged_found = True
			if not untagged_found:
				albums.append(self.library_set_data(album=self.NOTAG))
			albums = misc.remove_list_duplicates(albums, case=False)
			albums = self.list_identify_VA_albums(albums)
			for item in albums:
				album, artist, year, path = self.library_get_data(item, 'album', 'artist', 'year', 'path')
				playtime, num_songs = self.library_return_count(artist=artist, album=album, year=year)
				if num_songs > 0:
					data = self.library_set_data(artist=artist, album=album, year=year, path=path)
					cache_data = self.library_set_data(artist=artist, album=album, path=path)
					display = misc.escape_html(album)
					if artist and year and len(artist) > 0 and len(year) > 0 and artist != self.NOTAG and year != self.NOTAG:
						display += " <span weight='light'>(" + misc.escape_html(artist) + ", " + misc.escape_html(year) + ")</span>"
					elif artist and len(artist) > 0 and artist != self.NOTAG:
						display += " <span weight='light'>(" + misc.escape_html(artist) + ")</span>"
					elif year and len(year) > 0 and year != self.NOTAG:
						display += " <span weight='light'>(" + misc.escape_html(year) + ")</span>"
					display += self.add_display_info(num_songs, int(playtime)/60)
					pb = self.artwork.get_library_artwork_cached_pb(cache_data, self.albumpb)
					bd += [(misc.lower_no_the(album), [pb, data, display])]
		bd.sort(locale.strcoll, key=misc.first_of_2tuple)
		if genreview:
			self.lib_view_genre_cache = bd
		elif artistview:
			self.lib_view_artist_cache = bd
		elif albumview:
			self.lib_view_album_cache = bd
		return bd
コード例 #49
0
 def _execute_play(self):
     mpdh.call(self.client, 'play')
コード例 #50
0
    def current_update(self, prevstatus_playlist, new_playlist_length):
        if self.connected():

            if self.sonata_loaded():
                playlistposition = self.current.get_visible_rect()[1]

            self.current.freeze_child_notify()

            if not self.current_update_skip:

                if not self.filterbox_visible:
                    self.current.set_model(None)

                if prevstatus_playlist:
                    changed_songs = mpdh.call(self.client, 'plchanges',
                                              prevstatus_playlist)
                else:
                    changed_songs = mpdh.call(self.client, 'plchanges', 0)
                    self.current_songs = []

                newlen = int(new_playlist_length)
                currlen = len(self.currentdata)

                for track in changed_songs:
                    pos = int(mpdh.get(track, 'pos'))

                    items = []
                    for part in self.columnformat:
                        items += [self.parse_formatting(part, track, True)]

                    if pos < currlen:
                        # Update attributes for item:
                        i = self.currentdata.get_iter((pos, ))
                        trackid = int(mpdh.get(track, 'id'))
                        if trackid != self.currentdata.get_value(i, 0):
                            self.currentdata.set_value(i, 0, trackid)
                        for index in range(len(items)):
                            if items[index] != self.currentdata.get_value(
                                    i, index + 1):
                                self.currentdata.set_value(
                                    i, index + 1, items[index])
                        self.current_songs[pos] = track
                    else:
                        # Add new item:
                        self.currentdata.append([int(mpdh.get(track, 'id'))] +
                                                items)
                        self.current_songs.append(track)

                if newlen == 0:
                    self.currentdata.clear()
                    self.current_songs = []
                else:
                    # Remove excess songs:
                    for i in range(currlen - newlen):
                        it = self.currentdata.get_iter((currlen - 1 - i, ))
                        self.currentdata.remove(it)
                    self.current_songs = self.current_songs[:newlen]

                if not self.filterbox_visible:
                    self.current.set_model(self.currentdata)

            self.current_update_skip = False

            # Update statusbar time:
            self.total_time = 0
            for track in self.current_songs:
                try:
                    self.total_time = self.total_time + int(
                        mpdh.get(track, 'time'))
                except:
                    pass

            if 'pos' in self.songinfo():
                currsong = int(mpdh.get(self.songinfo(), 'pos'))
                self.boldrow(currsong)
                self.prev_boldrow = currsong

            if self.filterbox_visible:
                # Refresh filtered results:
                self.prevtodo = "RETAIN_POS_AND_SEL"  # Hacky, but this ensures we retain the self.current position/selection
                self.plpos = playlistposition
                self.searchfilter_feed_loop(self.filterpattern)
            elif self.sonata_loaded():
                self.playlist_retain_view(self.current, playlistposition)
                self.current.thaw_child_notify()

            self.header_update_column_indicators()
            self.update_statusbar()
            ui.change_cursor(None)
コード例 #51
0
    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)