def _update_song(self, songinfo): artistlabel = self.info_labels['artist'] tracklabel = self.info_labels['track'] albumlabel = self.info_labels['album'] filelabel = self.info_labels['file'] for name in ['title', 'date', 'genre']: label = self.info_labels[name] label.set_text(mpdh.get(songinfo, name)) tracklabel.set_text(mpdh.get(songinfo, 'track', '', False)) artistlabel.set_markup( misc.link_markup(misc.escape_html(mpdh.get(songinfo, 'artist')), False, False, self.linkcolor)) albumlabel.set_markup( misc.link_markup(misc.escape_html(mpdh.get(songinfo, 'album')), False, False, self.linkcolor)) path = misc.file_from_utf8( os.path.join(self.config.musicdir[self.config.profile_num], mpdh.get(songinfo, 'file'))) if os.path.exists(path): filelabel.set_text( os.path.join(self.config.musicdir[self.config.profile_num], mpdh.get(songinfo, 'file'))) self._editlabel.set_markup( misc.link_markup(_('edit tags'), True, True, self.linkcolor)) else: filelabel.set_text(mpdh.get(songinfo, 'file')) self._editlabel.set_text('')
def _update_song(self, songinfo): artistlabel = self.info_labels['artist'] tracklabel = self.info_labels['track'] albumlabel = self.info_labels['album'] filelabel = self.info_labels['file'] for name in ['title', 'date', 'genre']: label = self.info_labels[name] label.set_text(mpdh.get(songinfo, name)) tracklabel.set_text(mpdh.get(songinfo, 'track', '', False)) artistlabel.set_markup(misc.link_markup(misc.escape_html( mpdh.get(songinfo, 'artist')), False, False, self.linkcolor)) albumlabel.set_markup(misc.link_markup(misc.escape_html( mpdh.get(songinfo, 'album')), False, False, self.linkcolor)) path = misc.file_from_utf8(os.path.join( self.config.musicdir[self.config.profile_num], mpdh.get(songinfo, 'file'))) if os.path.exists(path): filelabel.set_text(os.path.join( self.config.musicdir[self.config.profile_num], mpdh.get(songinfo, 'file'))) self._editlabel.set_markup(misc.link_markup(_("edit tags"), True, True, self.linkcolor)) else: filelabel.set_text(mpdh.get(songinfo, 'file')) self._editlabel.set_text("")
def fullscreen_cover_art_set_text(self): if self.status_is_play_or_pause(): line1, line2 = self.get_current_song_text() self.fullscreenalbumlabel.set_markup("<span size='20000' color='white'>" + misc.escape_html(line1) + "</span>") self.fullscreenalbumlabel2.set_markup("<span size='12000' color='white'>" + misc.escape_html(line2) + "</span>") else: self.fullscreen_cover_art_reset_text()
def populate(self): self.streamsdata.clear() streamsinfo = [{'name' : misc.escape_html(name), 'uri' : misc.escape_html(uri)} for name, uri in zip(self.config.stream_names, self.config.stream_uris)] streamsinfo.sort(key=lambda x: x["name"].lower()) # Remove case sensitivity for item in streamsinfo: self.streamsdata.append([gtk.STOCK_NETWORK, item["name"], item["uri"]])
def fullscreen_cover_art_set_text(self): if self.status_is_play_or_pause(): line1, line2 = self.get_current_song_text() self.fullscreenalbumlabel.set_markup(('<span size=\'20000\' ' 'color=\'white\'>%s</span>') % (misc.escape_html(line1))) self.fullscreenalbumlabel2.set_markup(('<span size=\'12000\' ' 'color=\'white\'>%s</span>') % (misc.escape_html(line2))) else: self.fullscreen_cover_art_reset_text()
def populate(self): self.streamsdata.clear() streamsinfo = [] for i in range(len(self.config.stream_names)): record = {} record["name"] = misc.escape_html(self.config.stream_names[i]) record["uri"] = misc.escape_html(self.config.stream_uris[i]) streamsinfo.append(record) streamsinfo.sort(key=lambda x: x["name"].lower()) # Remove case sensitivity for item in streamsinfo: self.streamsdata.append([gtk.STOCK_NETWORK, item["name"], item["uri"]])
def populate(self): self.streamsdata.clear() streamsinfo = [] for i in range(len(self.config.stream_names)): record = {} record["name"] = misc.escape_html(self.config.stream_names[i]) record["uri"] = misc.escape_html(self.config.stream_uris[i]) streamsinfo.append(record) streamsinfo.sort( key=lambda x: x["name"].lower()) # Remove case sensitivity for item in streamsinfo: self.streamsdata.append( [gtk.STOCK_NETWORK, item["name"], item["uri"]])
def on_library_query_tooltip(self, widget, x, y, keyboard_mode, tooltip): if keyboard_mode or not self.search_visible(): widget.set_tooltip_text(None) return False bin_x, bin_y = widget.convert_widget_to_bin_window_coords(x, y) pathinfo = widget.get_path_at_pos(bin_x, bin_y) if not pathinfo: widget.set_tooltip_text(None) return False treepath, _col, _x2, _y2 = pathinfo i = self.librarydata.get_iter(treepath[0]) path = misc.escape_html(self.library_get_data(self.librarydata.get_value(i, 1), 'path')) song = self.librarydata.get_value(i, 2) new_tooltip = "<b>" + _("Song") + ": </b>" + song + "\n<b>" + _("Path") + ": </b>" + path if new_tooltip != self.libsearch_last_tooltip: self.libsearch_last_tooltip = new_tooltip self.library.set_property('has-tooltip', False) gobject.idle_add(self.library_search_tooltips_enable, widget, x, y, keyboard_mode, tooltip) return gobject.idle_add(widget.set_tooltip_markup, new_tooltip) self.libsearch_last_tooltip = new_tooltip return False #api says we should return True, but this doesn't work?
def _show_lyrics(self, artist_then, title_then, lyrics=None, error=None): # For error messages where there is no appropriate info: if not artist_then or not title_then: self._searchlabel.set_markup('') self._editlyricslabel.set_markup('') if error: self.lyricsText.set_markup(error) elif lyrics: self.lyricsText.set_markup(lyrics) else: self.lyricsText.set_markup('') return # Verify that we are displaying the correct lyrics: songinfo = self.get_playing_song() if not songinfo: return artist_now = misc.strip_all_slashes(mpdh.get(songinfo, 'artist', None)) title_now = misc.strip_all_slashes(mpdh.get(songinfo, 'title', None)) if artist_now == artist_then and title_now == title_then: self._searchlabel.set_markup(misc.link_markup( _('search'), True, True, self.linkcolor)) self._editlyricslabel.set_markup(misc.link_markup( _('edit'), True, True, self.linkcolor)) if error: self.lyricsText.set_markup(error) elif lyrics: try: self.lyricsText.set_markup(misc.escape_html(lyrics)) except: # XXX why would this happen? self.lyricsText.set_text(lyrics) else: self.lyricsText.set_markup('')
def _show_lyrics(self, artist_then, title_then, lyrics=None, error=None): # For error messages where there is no appropriate info: if not artist_then or not title_then: self._searchlabel.set_markup('') self._editlyricslabel.set_markup('') if error: self.lyricsText.set_markup(error) elif lyrics: self.lyricsText.set_markup(lyrics) else: self.lyricsText.set_markup('') return # Verify that we are displaying the correct lyrics: songinfo = self.get_playing_song() if not songinfo: return artist_now = misc.strip_all_slashes(mpdh.get(songinfo, 'artist', None)) title_now = misc.strip_all_slashes(mpdh.get(songinfo, 'title', None)) if artist_now == artist_then and title_now == title_then: self._searchlabel.set_markup( misc.link_markup(_('search'), True, True, self.linkcolor)) self._editlyricslabel.set_markup( misc.link_markup(_('edit'), True, True, self.linkcolor)) if error: self.lyricsText.set_markup(error) elif lyrics: try: self.lyricsText.set_markup(misc.escape_html(lyrics)) except: # XXX why would this happen? self.lyricsText.set_text(lyrics) else: self.lyricsText.set_markup('')
def on_library_query_tooltip(self, widget, x, y, keyboard_mode, tooltip): if keyboard_mode or not self.search_visible(): widget.set_tooltip_text(None) return False bin_x, bin_y = widget.convert_widget_to_bin_window_coords(x, y) pathinfo = widget.get_path_at_pos(bin_x, bin_y) if not pathinfo: widget.set_tooltip_text(None) # If the user hovers over an empty row and then back to # a row with a search result, this will ensure the tooltip # shows up again: gobject.idle_add(self.library_search_tooltips_enable, widget, x, y, keyboard_mode, None) return False treepath, _col, _x2, _y2 = pathinfo i = self.librarydata.get_iter(treepath[0]) path = misc.escape_html(self.library_get_data(self.librarydata.get_value(i, 1), 'path')) song = self.librarydata.get_value(i, 2) new_tooltip = "<b>%s:</b> %s\n<b>%s:</b> %s" % (_("Song"), song, _("Path"), path) if new_tooltip != self.libsearch_last_tooltip: self.libsearch_last_tooltip = new_tooltip self.library.set_property('has-tooltip', False) gobject.idle_add(self.library_search_tooltips_enable, widget, x, y, keyboard_mode, tooltip) gobject.idle_add(widget.set_tooltip_markup, new_tooltip) return self.libsearch_last_tooltip = new_tooltip return False #api says we should return True, but this doesn't work?
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)
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 info_show_lyrics(self, lyrics, artist, title, force=False): if force: # For error messages where there is no appropriate artist or # title, we pass force=True: self.lyricsText.set_text(lyrics) elif self.get_playing_song(): # Verify that we are displaying the correct lyrics: songinfo = self.get_playing_song() try: if misc.strip_all_slashes(mpdh.get(songinfo, 'artist')) == artist and misc.strip_all_slashes(mpdh.get(songinfo, 'title')) == title: try: self.lyricsText.set_markup(misc.escape_html(lyrics)) except: self.lyricsText.set_text(lyrics) except: pass
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
def update_breadcrumbs(self): # remove previous buttons for b in self.breadcrumbs: self.breadcrumbs.remove(b) # add the views button first b = ui.button(text=_(" v "), can_focus=False, relief=gtk.RELIEF_NONE) b.connect('clicked', self.library_view_popup) self.breadcrumbs.pack_start(b, False, False) b.show() # add the ellipsis explicitly XXX make this unnecessary b = ui.label("...") self.breadcrumbs.pack_start(b, False, False) b.show() # find info for current view view, _name, icon, label = [v for v in self.VIEWS if v[0] == self.config.lib_view][0] # the first crumb is the root of the current view crumbs = [(label, icon, None, self.library_set_data(path='/'))] # rest of the crumbs are specific to the view if view == consts.VIEW_FILESYSTEM: path = self.library_get_data(self.config.wd, 'path') if path and path != '/': parts = path.split('/') else: parts = [] # no crumbs for / # append a crumb for each part for i, part in enumerate(parts): partpath = '/'.join(parts[:i+1]) target = self.library_set_data(path=partpath) crumbs.append((part, gtk.STOCK_OPEN, None, target)) else: if view == consts.VIEW_ALBUM: # We don't want to show an artist button in album view keys = 'genre', 'album' nkeys = 2 else: keys = 'genre', 'artist', 'album' nkeys = 3 parts = self.library_get_data(self.config.wd, *keys) # append a crumb for each part for i, key, part in zip(range(nkeys), keys, parts): if part is None: continue partdata = dict(zip(keys, parts)[:i+1]) target = self.library_set_data(**partdata) pb, icon = None, None if key == 'album': # Album artwork, with self.alumbpb as a backup: artist, album, path = self.library_get_data(self.config.wd, 'artist', 'album', 'path') cache_data = self.library_set_data(artist=artist, album=album, path=path) pb = self.artwork.get_library_artwork_cached_pb(cache_data, None) if pb is None: icon = 'album' elif key == 'artist': icon = 'artist' else: icon = gtk.STOCK_ORIENTATION_PORTRAIT crumbs.append((part, icon, pb, target)) # add a button for each crumb for crumb in crumbs: text, icon, pb, target = crumb text = misc.escape_html(text) if crumb is crumbs[-1]: text = "<b>%s</b>" % text label = ui.label(markup=text) if icon: image = ui.image(stock=icon) elif pb: pb = pb.scale_simple(16, 16, gtk.gdk.INTERP_HYPER) image = ui.image(pb=pb) b = breadcrumbs.CrumbButton(image, label) if crumb is crumbs[-1]: # FIXME makes the button request minimal space: # label.props.ellipsize = pango.ELLIPSIZE_END b.props.active = True # FIXME why doesn't the tooltip show? b.set_tooltip_text(label.get_label()) b.connect('toggled', self.library_browse, target) self.breadcrumbs.pack_start(b, False, False) b.show_all()
def parse(format, item, use_escape_html, wintitle=False, songpos=None): substrings = _return_substrings(format) text = "".join( _format_substrings(sub, item, wintitle, songpos) for sub in substrings) return misc.escape_html(text) if use_escape_html else text
def parse(format, item, use_escape_html, wintitle=False, songpos=None): substrings = _return_substrings(format) text = "".join(_format_substrings(sub, item, wintitle, songpos) for sub in substrings) return misc.escape_html(text) if use_escape_html else text
def format(self, item, wintitle, songpos): path = item['file'] full_path = re.match(r"^(http://|ftp://)", path) self.default = path if full_path else os.path.basename(path) self.default = misc.escape_html(self.default) return FormatCode.format(self, item, wintitle, songpos)
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. # # Note that the searching is not order specific. That is, "foo bar" # will match on "fools bar" and "barstool foo". todos = todo.split(" ") regexps = [] for i in range(len(todos)): todos[i] = misc.escape_html(todos[i]) todos[i] = re.escape(todos[i]) todos[i] = '.*' + todos[i].lower() regexps.append(re.compile(todos[i])) matches = [] if searchby != 'any': for row in self.prevlibtodo_base_results: is_match = True for regexp in regexps: if not regexp.match(unicode(mpdh.get(row, searchby)).lower()): is_match = False break if is_match: matches.append(row) else: for row in self.prevlibtodo_base_results: allstr = " ".join(mpdh.get(row, meta) for meta in row) is_match = True for regexp in regexps: if not regexp.match(unicode(allstr).lower()): is_match = False break if is_match: matches.append(row) if subsearch and len(matches) == len(self.librarydata): # nothing changed.. return self.library.freeze_child_notify() currlen = len(self.librarydata) bd = [] for item in matches: if 'file' in item: bd += [(self.parse_formatting(self.config.libraryformat, item, True), [self.sonatapb, self.library_set_data(path=mpdh.get(item, 'file')), self.parse_formatting(self.config.libraryformat, item, True)])] bd.sort(locale.strcoll, key=operator.itemgetter(0)) i = 0 for _sort, item in bd: 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) i += 1 # Remove excess items... newlen = len(bd) 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)
def searchfilter_loop(self): while self.filterbox_visible: # copy the last command or pattern safely self.filterbox_cond.acquire() try: while self.filterbox_cmd_buf == "$$$DONE###": self.filterbox_cond.wait() todo = self.filterbox_cmd_buf self.filterbox_cond.release() except: todo = self.filterbox_cmd_buf self.current.freeze_child_notify() matches = gtk.ListStore(*([int] + [str] * len(self.columnformat))) matches.clear() filterposition = self.current.get_visible_rect()[1] _model, selected = self.current_selection.get_selected_rows() filterselected = [] for path in selected: filterselected.append(path) rownum = 0 # Store previous rownums in temporary list, in case we are # about to populate the songfilter with a subset of the # current filter. This will allow us to preserve the mapping. prev_rownums = [] for song in self.filter_row_mapping: prev_rownums.append(song) self.filter_row_mapping = [] if todo == "$$$QUIT###": gobject.idle_add(self.searchfilter_revert_model) return elif len(todo) == 0: for row in self.currentdata: self.filter_row_mapping.append(rownum) rownum = rownum + 1 song_info = [row[0]] for i in range(len(self.columnformat)): song_info.append(misc.unbold(row[i + 1])) matches.append(song_info) else: # 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) rownum = 0 if self.prevtodo in todo and len(self.prevtodo) > 0: # If the user's current filter is a subset of the # previous selection (e.g. "h" -> "ha"), search # for files only in the current model, not the # entire self.currentdata subset = True use_data = self.current.get_model() if len(use_data) != len(prev_rownums): # Not exactly sure why this happens sometimes # so lets just revert to prevent a possible, but # infrequent, crash. The only downside is speed. subset = False use_data = self.currentdata else: subset = False use_data = self.currentdata for row in use_data: song_info = [row[0]] for i in range(len(self.columnformat)): song_info.append(misc.unbold(row[i + 1])) # Search for matches in all columns: for i in range(len(self.columnformat)): if regexp.match(unicode(song_info[i + 1]).lower()): matches.append(song_info) if subset: self.filter_row_mapping.append(prev_rownums[rownum]) else: self.filter_row_mapping.append(rownum) break rownum = rownum + 1 if self.prevtodo == todo or self.prevtodo == "RETAIN_POS_AND_SEL": # mpd update, retain view of treeview: retain_position_and_selection = True if self.plpos: filterposition = self.plpos self.plpos = None else: retain_position_and_selection = False self.filterbox_cond.acquire() self.filterbox_cmd_buf = "$$$DONE###" try: self.filterbox_cond.release() except: pass gobject.idle_add( self.searchfilter_set_matches, matches, filterposition, filterselected, retain_position_and_selection ) self.prevtodo = todo
def info_update(self, playing_or_paused, newbitrate, songinfo, update_all, blank_window=False, skip_lyrics=False): # update_all = True means that every tag should update. This is # only the case on song and status changes. Otherwise we only # want to update the minimum number of widgets so the user can # do things like select label text. if playing_or_paused: bitratelabel = self.info_labels[self.info_type[_("Bitrate")]] titlelabel = self.info_labels[self.info_type[_("Title")]] artistlabel = self.info_labels[self.info_type[_("Artist")]] albumlabel = self.info_labels[self.info_type[_("Album")]] datelabel = self.info_labels[self.info_type[_("Date")]] genrelabel = self.info_labels[self.info_type[_("Genre")]] tracklabel = self.info_labels[self.info_type[_("Track")]] filelabel = self.info_labels[self.info_type[_("File")]] if not self.last_info_bitrate or self.last_info_bitrate != newbitrate: bitratelabel.set_text(newbitrate) self.last_info_bitrate = newbitrate if update_all: # Use artist/album Wikipedia links? artist_use_link = False if 'artist' in songinfo: artist_use_link = True album_use_link = False if 'album' in songinfo: album_use_link = True titlelabel.set_text(mpdh.get(songinfo, 'title')) if artist_use_link: artistlabel.set_markup( misc.link_markup( misc.escape_html(mpdh.get(songinfo, 'artist')), False, False, self.linkcolor)) else: artistlabel.set_text(mpdh.get(songinfo, 'artist')) if album_use_link: albumlabel.set_markup( misc.link_markup( misc.escape_html(mpdh.get(songinfo, 'album')), False, False, self.linkcolor)) else: albumlabel.set_text(mpdh.get(songinfo, 'album')) datelabel.set_text(mpdh.get(songinfo, 'date')) genrelabel.set_text(mpdh.get(songinfo, 'genre')) if 'track' in songinfo: tracklabel.set_text( mpdh.getnum(songinfo, 'track', '0', False, 0)) else: tracklabel.set_text("") path = misc.file_from_utf8( self.config.musicdir[self.config.profile_num] + os.path.dirname(mpdh.get(songinfo, 'file'))) if os.path.exists(path): filelabel.set_text( self.config.musicdir[self.config.profile_num] + mpdh.get(songinfo, 'file')) self.info_editlabel.set_markup( misc.link_markup(_("edit tags"), True, True, self.linkcolor)) else: filelabel.set_text(mpdh.get(songinfo, 'file')) self.info_editlabel.set_text("") if 'album' in songinfo: # Update album info: artist, tracks = self.album_return_artist_and_tracks() trackinfo = "" album = mpdh.get(songinfo, 'album') year = mpdh.get(songinfo, 'date', None) if album is not None: albuminfo = album + "\n" playtime = 0 if len(tracks) > 0: for track in tracks: playtime += int(mpdh.get(track, 'time', 0)) if 'title' in track: trackinfo = trackinfo + mpdh.getnum( track, 'track', '0', False, 2) + '. ' + mpdh.get(track, 'title') + '\n' else: trackinfo = trackinfo + mpdh.getnum( track, 'track', '0', False, 2) + '. ' + mpdh.get( track, 'file').split('/')[-1] + '\n' if artist is not None: albuminfo += artist + "\n" if year is not None: albuminfo += year + "\n" albuminfo += misc.convert_time(playtime) + "\n" albuminfo += "\n" + trackinfo else: albuminfo = _("Album info not found.") self.albumText.set_markup(misc.escape_html(albuminfo)) else: self.albumText.set_text(_("Album name not set.")) # Update lyrics: if self.config.show_lyrics and not skip_lyrics: global ServiceProxy if ServiceProxy is None: try: from ZSI import ServiceProxy # Make sure we have the right version.. _test = ServiceProxy.ServiceProxy except: ServiceProxy = None if ServiceProxy is None: self.info_searchlabel.set_text("") self.info_show_lyrics( _("ZSI not found, fetching lyrics support disabled." ), "", "", True) elif 'artist' in songinfo and 'title' in songinfo: self.get_lyrics_start( mpdh.get(songinfo, 'artist'), mpdh.get(songinfo, 'title'), mpdh.get(songinfo, 'artist'), mpdh.get(songinfo, 'title'), os.path.dirname(mpdh.get(songinfo, 'file'))) else: self.info_searchlabel.set_text("") self.info_show_lyrics( _("Artist or song title not set."), "", "", True) else: blank_window = True if blank_window: for label in self.info_labels: label.set_text("") self.info_editlabel.set_text("") if self.config.show_lyrics: self.info_searchlabel.set_text("") self.info_editlyricslabel.set_text("") self.info_show_lyrics("", "", "", True) self.albumText.set_text("") self.last_info_bitrate = ""
def searchfilter_loop(self): while self.filterbox_visible: # copy the last command or pattern safely self.filterbox_cond.acquire() try: while (self.filterbox_cmd_buf == '$$$DONE###'): self.filterbox_cond.wait() todo = self.filterbox_cmd_buf self.filterbox_cond.release() except: todo = self.filterbox_cmd_buf self.current.freeze_child_notify() matches = gtk.ListStore(*([int] + [str] * len(self.columnformat))) matches.clear() filterposition = self.current.get_visible_rect()[1] _model, selected = self.current_selection.get_selected_rows() filterselected = [] for path in selected: filterselected.append(path) rownum = 0 # Store previous rownums in temporary list, in case we are # about to populate the songfilter with a subset of the # current filter. This will allow us to preserve the mapping. prev_rownums = [] for song in self.filter_row_mapping: prev_rownums.append(song) self.filter_row_mapping = [] if todo == '$$$QUIT###': gobject.idle_add(self.searchfilter_revert_model) return elif len(todo) == 0: for row in self.currentdata: self.filter_row_mapping.append(rownum) rownum = rownum + 1 song_info = [row[0]] for i in range(len(self.columnformat)): song_info.append(misc.unbold(row[i + 1])) matches.append(song_info) else: # 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) rownum = 0 if self.prevtodo in todo and len(self.prevtodo) > 0: # If the user's current filter is a subset of the # previous selection (e.g. "h" -> "ha"), search # for files only in the current model, not the # entire self.currentdata subset = True use_data = self.current.get_model() if len(use_data) != len(prev_rownums): # Not exactly sure why this happens sometimes # so lets just revert to prevent a possible, but # infrequent, crash. The only downside is speed. subset = False use_data = self.currentdata else: subset = False use_data = self.currentdata for row in use_data: song_info = [row[0]] for i in range(len(self.columnformat)): song_info.append(misc.unbold(row[i + 1])) # Search for matches in all columns: for i in range(len(self.columnformat)): if regexp.match(unicode(song_info[i + 1]).lower()): matches.append(song_info) if subset: self.filter_row_mapping.append( prev_rownums[rownum]) else: self.filter_row_mapping.append(rownum) break rownum = rownum + 1 if self.prevtodo == todo or self.prevtodo == "RETAIN_POS_AND_SEL": # mpd update, retain view of treeview: retain_position_and_selection = True if self.plpos: filterposition = self.plpos self.plpos = None else: retain_position_and_selection = False self.filterbox_cond.acquire() self.filterbox_cmd_buf = '$$$DONE###' try: self.filterbox_cond.release() except: pass gobject.idle_add(self.searchfilter_set_matches, matches, filterposition, filterselected, retain_position_and_selection) self.prevtodo = todo
def library_populate_data(self, genre=None, artist=None, album=None, year=None): # Create treeview model info bd = [] if genre is not None and artist is None and album is None: # Artists within a genre artists = self.library_return_list_items('artist', genre=genre) if len(artists) > 0: if not self.NOTAG in artists: artists.append(self.NOTAG) for artist in artists: playtime, num_songs = self.library_return_count(genre=genre, artist=artist) if num_songs > 0: display = misc.escape_html(artist) display += self.add_display_info(num_songs, int(playtime)/60) data = self.library_set_data(genre=genre, artist=artist) bd += [(misc.lower_no_the(artist), [self.artistpb, data, display])] elif artist is not None and album is None: # Albums/songs within an artist and possibly genre # Albums first: if genre is not None: albums = self.library_return_list_items('album', genre=genre, artist=artist) else: albums = self.library_return_list_items('album', artist=artist) for album in albums: if genre is not None: years = self.library_return_list_items('date', genre=genre, artist=artist, album=album) else: years = self.library_return_list_items('date', artist=artist, album=album) if not self.NOTAG in years: years.append(self.NOTAG) for year in years: if genre is not None: playtime, num_songs = self.library_return_count(genre=genre, artist=artist, album=album, year=year) if num_songs > 0: files = self.library_return_list_items('file', genre=genre, artist=artist, album=album, year=year) path = os.path.dirname(files[0]) data = self.library_set_data(genre=genre, artist=artist, album=album, year=year, path=path) else: playtime, num_songs = self.library_return_count(artist=artist, album=album, year=year) if num_songs > 0: files = self.library_return_list_items('file', artist=artist, album=album, year=year) path = os.path.dirname(files[0]) data = self.library_set_data(artist=artist, album=album, year=year, path=path) if num_songs > 0: cache_data = self.library_set_data(artist=artist, album=album, path=path) display = misc.escape_html(album) if 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) ordered_year = year if ordered_year == self.NOTAG: ordered_year = '9999' pb = self.artwork.get_library_artwork_cached_pb(cache_data, self.albumpb) bd += [(ordered_year + misc.lower_no_the(album), [pb, data, display])] # Now, songs not in albums: bd += self.library_populate_data_songs(genre, artist, self.NOTAG, None) else: # Songs within an album, artist, year, and possibly genre bd += self.library_populate_data_songs(genre, artist, album, year) if len(bd) > 0: bd = self.library_populate_add_parent_rows() + bd bd.sort(locale.strcoll, key=misc.first_of_2tuple) return bd
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
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. # # Note that the searching is not order specific. That is, "foo bar" # will match on "fools bar" and "barstool foo". todos = todo.split(" ") regexps = [] for i in range(len(todos)): todos[i] = misc.escape_html(todos[i]) todos[i] = re.escape(todos[i]) todos[i] = '.*' + todos[i].lower() regexps.append(re.compile(todos[i])) matches = [] if searchby != 'any': for row in self.prevlibtodo_base_results: is_match = True for regexp in regexps: if not regexp.match(unicode(mpdh.get(row, searchby)).lower()): is_match = False break if is_match: matches.append(row) else: for row in self.prevlibtodo_base_results: allstr = " ".join(mpdh.get(row, meta) for meta in row) is_match = True for regexp in regexps: if not regexp.match(unicode(allstr).lower()): is_match = False break if is_match: matches.append(row) if subsearch and len(matches) == len(self.librarydata): # nothing changed.. return self.library.freeze_child_notify() currlen = len(self.librarydata) bd = [[self.sonatapb, self.library_set_data(path=mpdh.get(item, 'file')), formatting.parse(self.config.libraryformat, item, True)] for item in matches if 'file' in item] bd.sort(locale.strcoll, key=operator.itemgetter(2)) for i, item in enumerate(bd): 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(bd) 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)
def info_update(self, playing_or_paused, newbitrate, songinfo, update_all, blank_window=False, skip_lyrics=False): # update_all = True means that every tag should update. This is # only the case on song and status changes. Otherwise we only # want to update the minimum number of widgets so the user can # do things like select label text. if playing_or_paused: bitratelabel = self.info_labels[self.info_type[_("Bitrate")]] titlelabel = self.info_labels[self.info_type[_("Title")]] artistlabel = self.info_labels[self.info_type[_("Artist")]] albumlabel = self.info_labels[self.info_type[_("Album")]] datelabel = self.info_labels[self.info_type[_("Date")]] genrelabel = self.info_labels[self.info_type[_("Genre")]] tracklabel = self.info_labels[self.info_type[_("Track")]] filelabel = self.info_labels[self.info_type[_("File")]] if not self.last_info_bitrate or self.last_info_bitrate != newbitrate: bitratelabel.set_text(newbitrate) self.last_info_bitrate = newbitrate if update_all: # Use artist/album Wikipedia links? artist_use_link = False if 'artist' in songinfo: artist_use_link = True album_use_link = False if 'album' in songinfo: album_use_link = True titlelabel.set_text(mpdh.get(songinfo, 'title')) if artist_use_link: artistlabel.set_markup(misc.link_markup(misc.escape_html(mpdh.get(songinfo, 'artist')), False, False, self.linkcolor)) else: artistlabel.set_text(mpdh.get(songinfo, 'artist')) if album_use_link: albumlabel.set_markup(misc.link_markup(misc.escape_html(mpdh.get(songinfo, 'album')), False, False, self.linkcolor)) else: albumlabel.set_text(mpdh.get(songinfo, 'album')) datelabel.set_text(mpdh.get(songinfo, 'date')) genrelabel.set_text(mpdh.get(songinfo, 'genre')) if 'track' in songinfo: tracklabel.set_text(mpdh.getnum(songinfo, 'track', '0', False, 0)) else: tracklabel.set_text("") path = misc.file_from_utf8(self.config.musicdir[self.config.profile_num] + os.path.dirname(mpdh.get(songinfo, 'file'))) if os.path.exists(path): filelabel.set_text(self.config.musicdir[self.config.profile_num] + mpdh.get(songinfo, 'file')) self.info_editlabel.set_markup(misc.link_markup(_("edit tags"), True, True, self.linkcolor)) else: filelabel.set_text(mpdh.get(songinfo, 'file')) self.info_editlabel.set_text("") if 'album' in songinfo: # Update album info: artist, tracks = self.album_return_artist_and_tracks() trackinfo = "" album = mpdh.get(songinfo, 'album') year = mpdh.get(songinfo, 'date', None) if album is not None: albuminfo = album + "\n" playtime = 0 if len(tracks) > 0: for track in tracks: playtime += int(mpdh.get(track, 'time', 0)) if 'title' in track: trackinfo = trackinfo + mpdh.getnum(track, 'track', '0', False, 2) + '. ' + mpdh.get(track, 'title') + '\n' else: trackinfo = trackinfo + mpdh.getnum(track, 'track', '0', False, 2) + '. ' + mpdh.get(track, 'file').split('/')[-1] + '\n' if artist is not None: albuminfo += artist + "\n" if year is not None: albuminfo += year + "\n" albuminfo += misc.convert_time(playtime) + "\n" albuminfo += "\n" + trackinfo else: albuminfo = _("Album info not found.") self.albumText.set_markup(misc.escape_html(albuminfo)) else: self.albumText.set_text(_("Album name not set.")) # Update lyrics: if self.config.show_lyrics and not skip_lyrics: global ServiceProxy if ServiceProxy is None: try: from ZSI import ServiceProxy # Make sure we have the right version.. _test = ServiceProxy.ServiceProxy except: ServiceProxy = None if ServiceProxy is None: self.info_searchlabel.set_text("") self.info_show_lyrics(_("ZSI not found, fetching lyrics support disabled."), "", "", True) elif 'artist' in songinfo and 'title' in songinfo: self.get_lyrics_start(mpdh.get(songinfo, 'artist'), mpdh.get(songinfo, 'title'), mpdh.get(songinfo, 'artist'), mpdh.get(songinfo, 'title'), os.path.dirname(mpdh.get(songinfo, 'file'))) else: self.info_searchlabel.set_text("") self.info_show_lyrics(_("Artist or song title not set."), "", "", True) else: blank_window = True if blank_window: for label in self.info_labels: label.set_text("") self.info_editlabel.set_text("") if self.config.show_lyrics: self.info_searchlabel.set_text("") self.info_editlyricslabel.set_text("") self.info_show_lyrics("", "", "", True) self.albumText.set_text("") self.last_info_bitrate = ""