def combos_config(datos_conexion, objeto, tabla, cod): if tabla == "ajustemotivos": lista = ListStore(int, str, int) elif tabla == "impuestos": lista = ListStore(int, str, float) elif tabla == "monedas_s": lista = ListStore(int, str, int, str, str) elif tabla == "turnos": lista = ListStore(int, str, str, str) else: tipo = str if tabla in ("generos", "tipodocumentos", "unidadmedidas") else int lista = ListStore(tipo, str) objeto.set_model(lista) cell = CellRendererText() objeto.pack_start(cell, True) objeto.add_attribute(cell, 'text', 1) # Mostrar segunda columna conexion = conectar(datos_conexion) cursor = consultar(conexion, "*", tabla, " ORDER BY " + cod) datos = cursor.fetchall() cant = cursor.rowcount conexion.close() lista.clear() for i in range(0, cant): listafila = [datos[i][0], datos[i][1]] if tabla in ("ajustemotivos", "impuestos"): listafila.append(datos[i][2]) elif tabla == "monedas_s": listafila.extend([datos[i][2], datos[i][3], datos[i][4]]) elif tabla == "turnos": listafila.extend([str(datos[i][2]), str(datos[i][3])]) lista.append(listafila)
def configurar_combo_pagos(self): lista = ListStore(str) self.obj("cmb_pago").set_model(lista) cell = CellRendererText() self.obj("cmb_pago").pack_start(cell, True) self.obj("cmb_pago").add_attribute(cell, 'text', 0) lista.clear() lista.append(["Mensual"]) lista.append(["Quincenal"]) lista.append(["Semanal"])
def cmb_it_02_config(self): lista = ListStore(int, str, float) objeto.set_model(lista) cell = CellRendererText() objeto.pack_start(cell, True) objeto.add_attribute(cell, 'text', 2) conexion = Op.conectar(self.nav.datos_conexion) cursor = Op.consultar(conexion, "*", tabla, " ORDER BY " + cod) datos = cursor.fetchall() cant = cursor.rowcount conexion.close() lista.clear() for i in range(0, cant): listafila = [datos[i][0], datos[i][1]] if tabla in ("ajustemotivos", "impuestos"): listafila.append(datos[i][2]) if tabla == "turnos": listafila.extend([str(datos[i][2]), str(datos[i][3])]) lista.append(listafila)
class PeersTab(Tab): def __init__(self): super(PeersTab, self).__init__('Peers', 'peers_tab', 'peers_tab_label') self.peer_menu = self.main_builder.get_object('menu_peer_tab') component.get('MainWindow').connect_signals(self) self.listview = self.main_builder.get_object('peers_listview') self.listview.props.has_tooltip = True self.listview.connect('button-press-event', self._on_button_press_event) self.listview.connect('query-tooltip', self._on_query_tooltip) # flag, ip, client, downspd, upspd, country code, int_ip, seed/peer icon, progress self.liststore = ListStore(Pixbuf, str, str, int, int, str, float, Pixbuf, float) self.cached_flag_pixbufs = {} self.seed_pixbuf = icon_seeding self.peer_pixbuf = icon_downloading # key is ip address, item is row iter self.peers = {} # Country column column = TreeViewColumn() render = CellRendererPixbuf() column.pack_start(render, False) column.add_attribute(render, 'pixbuf', 0) column.set_sort_column_id(5) column.set_clickable(True) column.set_resizable(True) column.set_expand(False) column.set_min_width(20) column.set_reorderable(True) self.listview.append_column(column) # Address column column = TreeViewColumn(_('Address')) render = CellRendererPixbuf() column.pack_start(render, False) column.add_attribute(render, 'pixbuf', 7) render = CellRendererText() column.pack_start(render, False) column.add_attribute(render, 'text', 1) column.set_sort_column_id(6) column.set_clickable(True) column.set_resizable(True) column.set_expand(False) column.set_min_width(100) column.set_reorderable(True) self.listview.append_column(column) # Client column column = TreeViewColumn(_('Client')) render = CellRendererText() column.pack_start(render, False) column.add_attribute(render, 'text', 2) column.set_sort_column_id(2) column.set_clickable(True) column.set_resizable(True) column.set_expand(False) column.set_min_width(100) column.set_reorderable(True) self.listview.append_column(column) # Progress column column = TreeViewColumn(_('Progress')) render = CellRendererProgress() column.pack_start(render, True) column.set_cell_data_func(render, cell_data_peer_progress, 8) column.set_sort_column_id(8) column.set_clickable(True) column.set_resizable(True) column.set_expand(False) column.set_min_width(100) column.set_reorderable(True) self.listview.append_column(column) # Down Speed column column = TreeViewColumn(_('Down Speed')) render = CellRendererText() column.pack_start(render, False) column.set_cell_data_func(render, cell_data_speed_down, 3) column.set_sort_column_id(3) column.set_clickable(True) column.set_resizable(True) column.set_expand(False) column.set_min_width(50) column.set_reorderable(True) self.listview.append_column(column) # Up Speed column column = TreeViewColumn(_('Up Speed')) render = CellRendererText() column.pack_start(render, False) column.set_cell_data_func(render, cell_data_speed_up, 4) column.set_sort_column_id(4) column.set_clickable(True) column.set_resizable(True) column.set_expand(False) column.set_min_width(50) # Bugfix: Last column needs max_width set to stop scrollbar appearing column.set_max_width(150) column.set_reorderable(True) self.listview.append_column(column) self.listview.set_model(self.liststore) self.load_state() self.torrent_id = None def save_state(self): # Get the current sort order of the view column_id, sort_order = self.liststore.get_sort_column_id() # Setup state dict state = { 'columns': {}, 'sort_id': column_id, 'sort_order': int(sort_order) if sort_order else None, } for index, column in enumerate(self.listview.get_columns()): state['columns'][column.get_title()] = { 'position': index, 'width': column.get_width(), } save_pickled_state_file('peers_tab.state', state) def load_state(self): state = load_pickled_state_file('peers_tab.state') if state is None: return if len(state['columns']) != len(self.listview.get_columns()): log.warning('peers_tab.state is not compatible! rejecting..') return if state['sort_id'] and state['sort_order'] is not None: self.liststore.set_sort_column_id(state['sort_id'], state['sort_order']) for (index, column) in enumerate(self.listview.get_columns()): cname = column.get_title() if cname in state['columns']: cstate = state['columns'][cname] column.set_sizing(TreeViewColumnSizing.FIXED) column.set_fixed_width( cstate['width'] if cstate['width'] > 0 else 10) if state['sort_id'] == index and state[ 'sort_order'] is not None: column.set_sort_indicator(True) column.set_sort_order(state['sort_order']) if cstate['position'] != index: # Column is in wrong position if cstate['position'] == 0: self.listview.move_column_after(column, None) elif (self.listview.get_columns()[cstate['position'] - 1].get_title() != cname): self.listview.move_column_after( column, self.listview.get_columns()[cstate['position'] - 1]) def update(self): # Get the first selected torrent torrent_id = component.get('TorrentView').get_selected_torrents() # Only use the first torrent in the list or return if None selected if len(torrent_id) != 0: torrent_id = torrent_id[0] else: # No torrent is selected in the torrentview self.liststore.clear() return if torrent_id != self.torrent_id: # We only want to do this if the torrent_id has changed self.liststore.clear() self.peers = {} self.torrent_id = torrent_id component.get('SessionProxy').get_torrent_status( torrent_id, ['peers']).addCallback(self._on_get_torrent_status) def get_flag_pixbuf(self, country): if not country.strip(): return None if country not in self.cached_flag_pixbufs: # We haven't created a pixbuf for this country yet try: self.cached_flag_pixbufs[country] = Pixbuf.new_from_file( deluge.common.resource_filename( 'deluge', os.path.join('ui', 'data', 'pixmaps', 'flags', country.lower() + '.png'), )) except Exception as ex: log.debug('Unable to load flag: %s', ex) return None return self.cached_flag_pixbufs[country] def _on_get_torrent_status(self, status): new_ips = set() for peer in status['peers']: new_ips.add(peer['ip']) if peer['ip'] in self.peers: # We already have this peer in our list, so lets just update it row = self.peers[peer['ip']] if not self.liststore.iter_is_valid(row): # This iter is invalid, delete it and continue to next iteration del self.peers[peer['ip']] continue values = self.liststore.get(row, 3, 4, 5, 7, 8) if peer['down_speed'] != values[0]: self.liststore.set_value(row, 3, peer['down_speed']) if peer['up_speed'] != values[1]: self.liststore.set_value(row, 4, peer['up_speed']) if peer['country'] != values[2]: self.liststore.set_value(row, 5, peer['country']) self.liststore.set_value( row, 0, self.get_flag_pixbuf(peer['country'])) if peer['seed']: icon = self.seed_pixbuf else: icon = self.peer_pixbuf if icon != values[3]: self.liststore.set_value(row, 7, icon) if peer['progress'] != values[4]: self.liststore.set_value(row, 8, peer['progress']) else: # Peer is not in list so we need to add it # Create an int IP address for sorting purposes if peer['ip'].count(':') == 1: # This is an IPv4 address ip_int = sum( int(byte) << shift for byte, shift in zip( peer['ip'].split(':')[0].split('.'), (24, 16, 8, 0))) peer_ip = peer['ip'] else: # This is an IPv6 address import socket import binascii # Split out the :port ip = ':'.join(peer['ip'].split(':')[:-1]) ip_int = int( binascii.hexlify(socket.inet_pton(socket.AF_INET6, ip)), 16) peer_ip = '[%s]:%s' % (ip, peer['ip'].split(':')[-1]) if peer['seed']: icon = self.seed_pixbuf else: icon = self.peer_pixbuf row = self.liststore.append([ self.get_flag_pixbuf(peer['country']), peer_ip, peer['client'], peer['down_speed'], peer['up_speed'], peer['country'], float(ip_int), icon, peer['progress'], ]) self.peers[peer['ip']] = row # Now we need to remove any ips that were not in status["peers"] list for ip in set(self.peers).difference(new_ips): self.liststore.remove(self.peers[ip]) del self.peers[ip] def clear(self): self.liststore.clear() def _on_button_press_event(self, widget, event): """This is a callback for showing the right-click context menu.""" log.debug('on_button_press_event') # We only care about right-clicks if self.torrent_id and event.button == 3: self.peer_menu.popup(None, None, None, None, event.button, event.time) return True def _on_query_tooltip(self, widget, x, y, keyboard_tip, tooltip): is_tooltip, x, y, model, path, _iter = widget.get_tooltip_context( x, y, keyboard_tip) if is_tooltip: country_code = model.get(_iter, 5)[0] if country_code != ' ' and country_code in COUNTRIES: tooltip.set_text(COUNTRIES[country_code]) # widget here is self.listview widget.set_tooltip_cell(tooltip, path, widget.get_column(0), None) return True return False def on_menuitem_add_peer_activate(self, menuitem): """This is a callback for manually adding a peer""" log.debug('on_menuitem_add_peer') builder = Builder() builder.add_from_file( deluge.common.resource_filename( __package__, os.path.join('glade', 'connect_peer_dialog.ui'))) peer_dialog = builder.get_object('connect_peer_dialog') txt_ip = builder.get_object('txt_ip') response = peer_dialog.run() if response: value = txt_ip.get_text() ip, port = parse_ip_port(value) if ip and port: log.info('Adding peer IP: %s port: %s to %s', ip, port, self.torrent_id) client.core.connect_peer(self.torrent_id, ip, port) else: log.error('Error parsing peer "%s"', value) peer_dialog.destroy() return True
class Playlist: def __init__(self, extensionsloader): self.extensions = extensionsloader self.module = {'name': 'Playlist'} self.functions = Functions() self.userconf = ConfigLoader() self.config = {} rpt = self.userconf.config['Playlist']['repeat'] self.config['repeat'] = bool(int(rpt)) shf = self.userconf.config['Playlist']['shuffle'] self.config['shuffle'] = bool(int(shf)) shm = self.userconf.config['Playlist']['shuffle_mode'] self.config['shuffle_mode'] = shm self.lastfm = LastFm() self.playlists_mgmnt = Playlists() self.playlist_content = {} self.playlist_identifier = 0 self.playlist_current = None self.current_playlist_id = 0 self.user_playlists = {} self.last_user_playlist = None self.similar_artists = [] self.is_in_similar_thread = False # Create the Playlist view def launch_playlist(wdg): self.widgets = wdg[1] self.playlist_label = self.widgets.get_object('label_playlist') self.playlist_repeat = self.widgets.get_object('tool-repeat') self.playlist_shuffle = self.widgets.get_object('tool-shuffle') self.playlist_clean = self.widgets.get_object('tool-clean') self.playlist_combo = self.widgets.get_object('combo-playlist') self.playlist_save = self.widgets.get_object('tool-saveplaylist') self.playlist_lyrics = self.widgets.get_object('tool-lyrics') self.playlist_tree = self.widgets.get_object('treeview_playlist') self.playlist_tree.set_headers_visible(False) self.playlist_tree.props.reorderable = True self.playlist_tree.connect('key_press_event', self.key_pressed) self.playlist_tree.connect('row_activated', self.row_activated) self.liststore = ListStore(str, str, str, str, int) self.playlist_tree.set_model(self.liststore) renderer_pix = CellRendererPixbuf() column_pixbuf = TreeViewColumn('1', renderer_pix, icon_name=0) column_pixbuf.set_fixed_width(18) self.playlist_tree.append_column(column_pixbuf) renderer_text = CellRendererText() column_text = TreeViewColumn('2', renderer_text, markup=1) column_text.props.expand = True column_text.props.max_width = 192 self.playlist_tree.append_column(column_text) column_text = TreeViewColumn('3', renderer_text, markup=2) column_text.set_fixed_width(40) self.playlist_tree.append_column(column_text) self.repeat_btn = self.widgets.get_object('tool-repeat') if self.config['repeat']: self.repeat_btn.set_active(True) self.repeat_btn.connect('clicked', self.toggle, 'repeat') self.shuffle_btn = self.widgets.get_object('tool-shuffle') if self.config['shuffle']: self.shuffle_btn.set_active(True) self.shuffle_btn.connect('clicked', self.toggle, 'shuffle') def clean_wdg(widget): # Clean playlist self.clean() # Show popover if self.current_playlist_id > 3: self.clean_btn.set_sensitive(True) self.clean_pop.show_all() self.clean_btn = self.widgets.get_object('tool-clean') self.clean_btn.connect('clicked', clean_wdg) self.clean_pop = Popover.new(self.clean_btn) self.clean_pop.set_size_request(100, 30) gtkpla = join(self.functions.datadir, 'glade', 'plist-del-pop.ui') win = gtk_builder() win.set_translation_domain('bluemindo') win.add_from_file(gtkpla) hbox = win.get_object('box-playlist') lbl = win.get_object('label') lbl.set_text(_('Do you also want to remove the playlist?')) btn = win.get_object('del-btn') btn.set_label(_('Delete')) btn.connect('clicked', self.delete_playlist) self.clean_pop.add(hbox) # Populate combobox self.combolist = ListStore(int, str) self.combobox = self.widgets.get_object('combobox') self.combobox.set_model(self.combolist) self.combobox.set_popup_fixed_width(False) self.combobox.props.expand = False renderer_text = CellRendererText() renderer_text.props.ellipsize = EllipsizeMode.END self.combobox.pack_start(renderer_text, True) self.combobox.set_entry_text_column(1) self.combobox.add_attribute(renderer_text, 'text', 1) self.combolist.append([0, _('Current')]) self.combolist.append([1, _('Top 50 songs')]) self.combolist.append([2, _('Top 10 albums')]) playlists = self.playlists_mgmnt.get_playlists() if len(playlists) > 0: self.combolist.append([3, '']) item_id = 3 playlists.sort(key=lambda it: it[1]) for item in playlists: item_id += 1 self.combolist.append([item_id, item]) self.user_playlists[item_id] = item self.last_user_playlist = item_id def combo_sep(model, iter): if model[iter][0] == 3: return True self.combobox.set_row_separator_func(combo_sep) def on_combo_changed(widget): path = widget.get_active() item_id = self.combolist[path][0] # First, clean the playlist self.clean(None) # Second, populate the playlist if item_id > 0: self.populate(item_id) # Then, update playlist identifier self.current_playlist_id = item_id # Show delete/remove button if the playlist is from the user if item_id > 3: self.clean_btn.set_sensitive(True) self.combobox.set_active(0) self.combobox.connect('changed', on_combo_changed) self.tool_save = self.widgets.get_object('tool-saveplaylist') self.tool_save.connect('clicked', self.save_playlist) self.save_pop = Popover.new(self.tool_save) self.save_pop.set_size_request(100, 30) gtkpla = join(self.functions.datadir, 'glade', 'plist-add-pop.ui') win = gtk_builder() win.set_translation_domain('bluemindo') win.add_from_file(gtkpla) hbox = win.get_object('box-playlist') self.save_pop.add(hbox) self.save_entry = win.get_object('save-entry') self.save_entry.connect('key_press_event', self.save_playlist_key) self.save_btn = win.get_object('save-btn') self.save_btn.connect('clicked', self.save_playlist_button) self.save_btn.set_label(_('Save')) self.clean_btn.set_sensitive(False) self.tool_save.set_sensitive(False) # Acquire the songs tree def acquire_tree(st): self.songs_tree = st self.extensions.connect('OnBluemindoStarted', launch_playlist) self.extensions.connect('OnSongsTreeCreated', acquire_tree) self.extensions.connect('OnSongQueued', self.on_new_song_queued) self.extensions.connect('OnAlbumQueued', self.on_new_album_queued) self.extensions.connect('AskPreviousSong', self.ask_previous_song) self.extensions.connect('AskNextSong', self.ask_next_song) self.extensions.connect('HasStartedSong', self.song_started) def toggle(self, widget, action): if action == 'repeat' and self.config['repeat']: self.config['repeat'] = False self.repeat_btn.set_active(False) self.userconf.update_key('Playlist', 'repeat', str(int(False))) elif action == 'repeat' and not self.config['repeat']: self.config['repeat'] = True self.repeat_btn.set_active(True) self.userconf.update_key('Playlist', 'repeat', str(int(True))) elif action == 'shuffle' and self.config['shuffle']: self.config['shuffle'] = False self.shuffle_btn.set_active(False) self.userconf.update_key('Playlist', 'shuffle', str(int(False))) elif action == 'shuffle' and not self.config['shuffle']: self.config['shuffle'] = True self.shuffle_btn.set_active(True) self.userconf.update_key('Playlist', 'shuffle', str(int(True))) def row_activated(self, widget, path, column): item_iter = self.liststore.get_iter(path) # Get the founded element. item_identifier = self.liststore.get_value(item_iter, 4) current_item = self.playlist_content[item_identifier] # The element is a song. if self.playlist_content[item_identifier].kind == 'song': self.playlist_current = [item_iter, item_identifier, None] self.extensions.load_event('OnPlayNewSong', current_item) # The element is an album. else: self.extensions.load_event('OnAbortPlayback') sng = self.playlist_content[item_identifier].tracks[0] self.playlist_current = [item_iter, item_identifier, 0] self.extensions.load_event('OnPlayNewSong', sng) def key_pressed(self, widget, eventkey): if eventkey.get_keyval()[1] == KEY_Delete: # Delete an item from the playlist selection = self.playlist_tree.get_selection() selected = selection.get_selected_rows() liststore = selected[0] listpath = selected[1] if len(listpath) > 0: selpath = listpath[0] playlist_identifier = liststore[selpath][4] # Are we removing the currently playing item? if self.playlist_current is not None: item_iter, item_path, item_in_album = self.playlist_current if selpath == TreePath.new_from_string(str(item_path)): self.playlist_current = None # Removal del self.playlist_content[playlist_identifier] del liststore[selpath] def clean(self, data=None): self.playlist_content = {} self.playlist_identifier = 0 self.playlist_current = None self.liststore.clear() # Update GUI self.clean_btn.set_sensitive(False) self.tool_save.set_sensitive(False) def populate(self, playlist_id): if playlist_id in (1, 2): # Automatic playlists based on listening stats if playlist_id == 1: tb = 'stats_songs' lm = 50 elif playlist_id == 2: tb = 'stats_albums' lm = 10 result = [] txt = ('select * from %s order by tracks desc limit %u' % (tb, lm)) sql = SQLite() cur = sql.execute(txt) for sg in cur: result.append(sg) sql.close() for item in result: if playlist_id == 1: sng = Song(filename=item[0]) if hasattr(sng, 'title'): self.on_new_song_queued(sng) elif playlist_id == 2: album_name = item[0] for it in self.songs_tree: if album_name in self.songs_tree[it]: self.on_new_album_queued(Album(it, album_name, self.songs_tree)) break elif playlist_id > 3: # User-created playlists user_plist = self.user_playlists[playlist_id] plist = self.playlists_mgmnt.load_playlist(user_plist) for item in plist: sng = Song(filename=item) if hasattr(sng, 'title'): self.on_new_song_queued(sng) def delete_playlist(self, widget): if self.current_playlist_id > 3: user_plist = self.user_playlists[self.current_playlist_id] self.playlists_mgmnt.delete_playlist(user_plist) # Delete the playlist from the list del self.user_playlists[self.current_playlist_id] cblid = 0 for item in self.combolist: if item[0] == self.current_playlist_id: del self.combolist[cblid] break cblid += 1 # Move back to "Current" playlist self.combobox.set_active(0) def save_playlist_key(self, widget, eventkey): if eventkey.get_keyval()[1] == KEY_Return: self.save_playlist_button(None) def save_playlist_button(self, widget): user_entry = self.save_entry.get_text() user_entry = user_entry.replace('\\', '-') user_entry = user_entry.replace('/', '-') user_entry = user_entry.replace('*', '-') user_entry = user_entry.replace('|', '-') if len(user_entry) > 0: rtn_value = self.playlists_mgmnt.create_new_playlist(user_entry) if rtn_value: self.save_pop.hide() # Add playlist to GUI if self.last_user_playlist is None: self.combolist.append([3, '']) self.last_user_playlist = 3 self.last_user_playlist += 1 self.combolist.append([self.last_user_playlist, user_entry]) self.user_playlists[self.last_user_playlist] = user_entry # Write the playlist self.write_playlist(user_entry) # Select the new playlist self.combobox.set_active(self.last_user_playlist) def save_playlist(self, widget): if self.current_playlist_id < 3: # Create a new playlist self.save_entry.set_text('') self.save_pop.show_all() elif self.current_playlist_id > 3: # Update an existing playlist user_plist = self.user_playlists[self.current_playlist_id] self.write_playlist(user_plist) def write_playlist(self, user_plist): plist_content = [] for item in self.liststore: item_id = item[4] plist_content.append(self.playlist_content[item_id]) self.playlists_mgmnt.write_playlist(user_plist, plist_content) def on_new_song_queued(self, song_info): title = song_info.title artist = song_info.artist album = song_info.album filename = song_info.filename length = self.functions.human_length(song_info.length) self.liststore.append(('audio-x-generic-symbolic', '<b>' + self.functions.view_encode(title, 99) + '</b>\n' + self.functions.view_encode(artist), '<span foreground="grey">' + length + '</span>', filename, self.playlist_identifier)) self.playlist_content[self.playlist_identifier] = song_info self.playlist_identifier += 1 # Update GUI self.clean_btn.set_sensitive(True) self.tool_save.set_sensitive(True) def on_new_album_queued(self, album_info): artist = album_info.artist album = album_info.name songs_count = str(len(album_info.tracks)) + ' ♫' self.liststore.append(('media-optical-symbolic', '<b>' + self.functions.view_encode(album, 99) + '</b>\n' + self.functions.view_encode(artist), '<span foreground="grey">' + songs_count + '</span>', '[album]', self.playlist_identifier)) self.playlist_content[self.playlist_identifier] = album_info self.playlist_identifier += 1 # Update GUI self.clean_btn.set_sensitive(True) self.tool_save.set_sensitive(True) def ask_next_song(self, current_song): self.ask_for_a_song(True, current_song) def ask_previous_song(self, current_song): self.ask_for_a_song(False, current_song) def ask_for_a_song(self, next=True, current_song=None): def walk_in_playlist(item_iter, next=True): base_item_iter = item_iter if item_iter is None: # Find first song. item_iter = self.liststore.get_iter_first() elif next: # Find next song. path = self.liststore.get_path(self.playlist_current[0]) path_int = int(path.to_string()) max_id = len(self.playlist_content) - 1 if (path_int + 1 <= max_id): # There is a song to launch! item_iter = self.liststore.get_iter(path_int + 1) else: # There is no song to launch! if not self.config['repeat']: self.extensions.load_event('OnAbortPlayback') return else: item_iter = self.liststore.get_iter_first() elif not next: # Find previous song. path = self.liststore.get_path(self.playlist_current[0]) path_int = int(path.to_string()) max_id = len(self.playlist_content) - 1 if (path_int -1 >= 0): # There is a song to launch. item_iter = self.liststore.get_iter(path_int - 1) else: # There is no song to launch! if not self.config['repeat']: self.extensions.load_event('OnAbortPlayback') return else: item_iter = self.liststore.get_iter_from_string(str(max_id)) # Get the founded element. item_identifier = self.liststore.get_value(item_iter, 4) current_item = self.playlist_content[item_identifier] def launch_founded_item(item_identifier, item_iter, current_item): # The element is a song. if self.playlist_content[item_identifier].kind == 'song': self.playlist_current = [item_iter, item_identifier, None] self.extensions.load_event('OnPlayNewSong', current_item) # The element is an album. else: self.extensions.load_event('OnAbortPlayback') sng = self.playlist_content[item_identifier].tracks[0] sng.rg_mode_guess = 'album' self.playlist_current = [item_iter, item_identifier, 0] self.extensions.load_event('OnPlayNewSong', sng) # Are we currently listening from an album? if base_item_iter is not None: kind = self.playlist_content[self.playlist_current[1]].kind if kind == 'album': base_item_identifier = self.liststore.get_value(base_item_iter, 4) tracks = self.playlist_content[self.playlist_current[1]].tracks max_sng = len(tracks) - 1 if next: if self.playlist_current[2] < max_sng: item_in_album = self.playlist_current[2] + 1 else: return launch_founded_item(item_identifier, item_iter, current_item) elif not next: if self.playlist_current[2] - 1 > -1: item_in_album = self.playlist_current[2] - 1 else: return launch_founded_item(item_identifier, item_iter, current_item) sng = self.playlist_content[base_item_identifier].tracks[item_in_album] sng.rg_mode_guess = 'album' self.playlist_current = [base_item_iter, base_item_identifier, item_in_album] self.extensions.load_event('OnPlayNewSong', sng) return launch_founded_item(item_identifier, item_iter, current_item) if len(self.playlist_content) == 0: # Playlist is empty. if not self.config['shuffle']: # Shuffle disabled: abort playback. self.extensions.load_event('OnAbortPlayback') else: # Shuffle enabled. if self.config['shuffle_mode'] == 'random': # Random mode: seek for shuffle song. self.extensions.load_event('AskShuffleSong') elif self.config['shuffle_mode'] == 'similar': # Similar mode: seek for a similar song. if len(self.similar_artists) == 0: # No similar song founded: seek for any one. self.extensions.load_event('AskShuffleSong') return # Choose one song in the list of similar artists index = randrange(len(self.similar_artists)) artist = self.similar_artists[index] mdb = MusicDatabase(None) songs_list = mdb.load_from_artist(artist) if len(songs_list) > 1: index = randrange(len(songs_list)) song = songs_list[index] sng = Song(filename=song[8]) print ('[SIMILAR] Playing a song from ' + sng.artist) self.extensions.load_event('OnPlayNewSong', sng) else: self.extensions.load_event('AskShuffleSong') else: # Playlist is not empty, walk in it! if self.playlist_current is None: # Currently no current item in playlist, choose the first one! walk_in_playlist(None) else: # The current playling song is in the playlist! if next: walk_in_playlist(self.playlist_current[0]) else: walk_in_playlist(self.playlist_current[0], False) def song_started(self, song): # First, try to download a few similar artists names if self.config['shuffle_mode'] == 'similar': def download_similars(): threads_enter() art = self.lastfm.get_similar_artists(song.artist) self.similar_artists = [] mdb = MusicDatabase(None) for artist in art: if mdb.artist_exists(artist): self.similar_artists.append(artist) self.is_in_similar_thread = False threads_leave() if not self.is_in_similar_thread: self.is_in_similar_thread = True thread = Thread(group=None, target=download_similars, name='similars', args=()) thread.start() # Second, update statistics for this song song.increment_statistics() alb = Album(song.artist, song.album, self.songs_tree) alb.increment_statistics() # Then, highlight currently playing song/album if it's in playlist if self.playlist_current is not None: # Currently playing item is in the playlist item_iter, item_path, item_in_album = self.playlist_current # Remove marker of all items for item in self.liststore: current_label = item[1] if current_label[:2] == '◎ ': item[1] = current_label[2:] # Add marker on one item current_label = self.liststore[item_iter][1] if current_label[:2] != '◎ ': self.liststore[item_iter][1] = '◎ ' + current_label
class AlbumsView: def __init__(self, widgets, extensions): self.widgets = widgets self.extensions = extensions self.functions = Functions() self.userconf = ConfigLoader() self.dblclick = None # Create the IconView self.albumview = self.widgets[1].get_object('albumview') self.albummodel = ListStore(Pixbuf, str, str, str, int, str, str) self.albumview.set_pixbuf_column(0) self.albumview.set_markup_column(1) self.albumview.set_column_spacing(0) self.albumview.set_spacing(0) self.albumview.set_item_width(100) self.albumview.set_property('activate-on-single-click', False) # Add a filter to the ListStore model self.albumfilter = self.albummodel.filter_new(None) self.remove_filter_data() self.matched = False def filter_visible(model, iter, data): usrf = self.widgets[1].get_object('searchentry').get_text() search_a = model.get_value(iter, 3) search_b = model.get_value(iter, 2) pre_result = False if self.matched: usrf_a = self.matched[0] usrf_b = self.matched[1] if usrf_b == 'blm.!ARTIST!': if usrf_a.lower() == search_b.lower(): # Matched an artist pre_result = True else: if (usrf_a.lower() == search_a.lower() and usrf_b.lower() == search_b.lower()): # Matched an album pre_result = True else: if len(model) > 0: if (usrf.lower() in search_a.lower() or usrf.lower() in search_b.lower()): # Found an element (artist or album name is close) pre_result = True else: # No element founded at all, return False anyway return False # Apply filters fdg = self.filter_data['genre'] fdy = self.filter_data['year'] # Filter results by genres if fdg is not None and fdg != model.get_value(iter, 5): pre_result = False # Filter results by years if fdy is not None and fdy != model.get_value(iter, 6): pre_result = False # Return the final result return pre_result self.albumfilter.set_visible_func(filter_visible) self.albumview.set_model(self.albumfilter) # Connect to signals def grab_entry_focus(widget, event): key = event.string if (key.lower() in 'a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,' 'x,y,z,0,1,2,3,4,5,6,7,8,9'.split(',')): self.widgets[1].get_object('searchentry').grab_focus() self.widgets[1].get_object('searchentry').set_text(key) self.widgets[1].get_object('searchentry').set_position(-1) self.albumview.connect('key-press-event', grab_entry_focus) self.albumview.connect('selection_changed', self.on_selection_changed) def populate_albums(self, albums_tree, albums, songs_tree, search): self.albums_tree = albums_tree self.albums = albums self.songs_tree = songs_tree self.search_entry = search.searchentry # Clear the tree model first self.albummodel.clear() # Show albums in the main explorer view self.album_nf = [] album_id = 0 for alb in self.albums_tree: bdir = join(self.userconf.datadir, 'modules', 'player', 'covers') album = alb['album'] artist = alb['artist'] cover = join(bdir, self.functions.get_hash(album, artist)) if isfile(cover): cover_px = Pixbuf.new_from_file_at_scale(cover, 150, 150, True) else: cover_px = Pixbuf.new_from_file(join(self.functions.datadir, 'image', 'logo_head_big.png')) self.albums[album_id] = Album(artist, album, self.songs_tree) ap = self.albummodel.append([cover_px, '<b>' + self.functions.view_encode(album) + '</b>\n<span foreground="grey">' + self.functions.view_encode(artist) + '</span>', artist, album, album_id, '', '']) album_id += 1 if not isfile(cover): self.album_nf.append([cover, ap, None]) # Check if we have to regenerate thumbnail (cover not found at startup) if len(self.album_nf) > 0: def regenerate_thumb(): new_album = [] for alb in self.album_nf: if isfile(alb[0]): item_iter = alb[1] cover_md5 = md5(open(alb[0], 'rb').read()).hexdigest() if alb[2] == None or alb[2] != cover_md5: cover_px = Pixbuf.new_from_file_at_scale(alb[0], 150, 150, True) self.albummodel.set_value(item_iter, 0, cover_px) alb[2] = cover_md5 new_album.append(alb) else: new_album.append(alb) if len(new_album) > 0: self.album_nf = new_album return True timeout_add(15000, regenerate_thumb) def on_album_matched(self, album): for item in self.albummodel: if item[2] == album.artist and item[3] == album.name: self.on_selection_changed(self.albumview, album) def on_selection_changed(self, icon_view, album=None): popup = Popover.new(self.albumview) popup.set_size_request(810, 240) if album is None: selection = icon_view.get_selected_items() if len(selection) != 1: return path = selection[0] treeiter = self.albumfilter.get_iter(path) isset, path, cell = icon_view.get_cursor() isset, rect = icon_view.get_cell_rect(path, cell) popup.set_pointing_to(rect) album_id = self.albumfilter.get_value(treeiter, 4) album_obj = self.albums[album_id] else: album_obj = album popup.set_relative_to(self.search_entry) # Handle double clicks def empty_dblclick(): self.dblclick = None if self.dblclick is None: self.dblclick = album_obj timeout_add(1000, empty_dblclick) elif self.dblclick == album_obj: self.play(album_obj) return album = album_obj.name artist = album_obj.artist glade_album = join(self.functions.datadir, 'glade', 'albumview.ui') box = gtk_builder() box.set_translation_domain('bluemindo') box.add_from_file(glade_album) popup.add(box.get_object('box1')) box.get_object('label_album').set_text(album) box.get_object('label_artist').set_text(artist) bdir = join(self.userconf.datadir, 'modules', 'player', 'covers') cover = join(bdir, self.functions.get_hash(album, artist)) if isfile(cover): cover_px = Pixbuf.new_from_file_at_scale(cover, 180, 180, True) else: cover_px = Pixbuf.new_from_file(join(self.functions.datadir, 'image', 'logo_head_big.png')) box.get_object('album_cover').set_from_pixbuf(cover_px) def play_album(wdg, album): self.play(album) def queue_album(wdg, album): self.queue(album) def change_cover(wdg, ka, album): artist_name = album.artist album_name = album.name fcdialog = FileChooserDialog( title=_('Change the cover picture for this album'), buttons=(_('Select'), ResponseType.OK)) fcdialog.set_transient_for(self.widgets[0][11]) response = fcdialog.run() if response == ResponseType.OK: filename = fcdialog.get_filename() datadir = self.userconf.datadir hash_a = self.functions.get_hash(album_name, artist_name) pictures_dir = join(datadir, 'modules', 'player', 'covers') album_file = join(pictures_dir, hash_a) copyfile(filename, album_file) new = Pixbuf.new_from_file_at_scale(album_file, 180, 180, True) box.get_object('album_cover').set_from_pixbuf(new) fcdialog.destroy() box.get_object('button_play').connect('clicked', play_album, album_obj) box.get_object('button_add').connect('clicked', queue_album, album_obj) box.get_object('coverevent').connect('button-press-event', change_cover, album_obj) i = 0 a = -1 previous_column = 0 grid_songs = box.get_object('grid_songs') grid_songs.set_size_request(-1, 200) grid_songs.set_column_spacing(5) try: kids = grid_songs.get_children() for kid in kids: grid_songs.remove(kid) except IndexError: pass for song in album_obj.tracks: i += 1 a += 1 def queue(wdg, song): self.queue(song) def play(wdg, song): self.play(song) song_wdg = Box(spacing=0) song_btr = Button() song_btr.connect('clicked', play, song) song_btr.set_relief(ReliefStyle.NONE) song_btr_content = Box(spacing=0) song_btr.add(song_btr_content) song_tr = Label() song_tr.set_markup('<span foreground="grey">' + str(song.track) + '</span>') song_tr.set_width_chars(3) song_btr_content.pack_start(song_tr, False, True, 0) song_ti = Label() song_ti.set_markup('<b>' + self.functions.view_encode(song.title, 22) + '</b>') song_ti.set_alignment(0.0, 0.5) song_ti.set_size_request(190, -1) song_btr_content.pack_start(song_ti, False, False, 0) length = self.functions.human_length(song.length) song_le = Label() song_le.set_markup('<span foreground="grey">' + length + '</span>') song_le.set_width_chars(5) song_btr_content.pack_start(song_le, False, True, 0) song_wdg.pack_start(song_btr, False, False, 0) song_add = Button.new_from_icon_name('list-add-symbolic', 0) song_add.set_property('relief', 2) song_add.set_size_request(14, 14) song_add.connect('clicked', queue, song) song_wdg.pack_start(song_add, False, False, 0) if i <= len(album_obj.tracks)/2: column = 0 previous_column = 0 row = a else: if previous_column == 0: a = 0 column = 1 previous_column = 1 row = a grid_songs.attach(song_wdg, column, row, 1, 1) popup.show_all() def play(self, usrobject): kind = usrobject.kind if kind == 'album': self.extensions.load_event('OnPlayNewAlbum', usrobject) else: self.extensions.load_event('OnPlayNewSong', usrobject) def queue(self, usrobject): kind = usrobject.kind if kind == 'album': self.extensions.load_event('OnAlbumQueued', usrobject) else: self.extensions.load_event('OnSongQueued', usrobject) def generate_filter_data(self, album_data): for element in self.albummodel: artist = element[2] album = element[3] datalb = album_data[artist][album] datalb_genre = datalb['genre'] datalb_year = datalb['year'] element[5] = datalb_genre element[6] = datalb_year def add_filter_data(self, value, field): self.filter_data[field] = value self.albumfilter.refilter() def remove_filter_data(self, cmb=None): if cmb is None: self.filter_data = {'genre': None, 'year': None} else: self.filter_data[cmb] = None self.albumfilter.refilter()
class QueuedTorrents(component.Component): def __init__(self): component.Component.__init__( self, 'QueuedTorrents', depend=['StatusBar', 'AddTorrentDialog'] ) self.queue = [] self.status_item = None self.config = ConfigManager('gtk3ui.conf') self.builder = Builder() self.builder.add_from_file( deluge.common.resource_filename( __package__, os.path.join('glade', 'queuedtorrents.ui') ) ) self.builder.get_object('chk_autoadd').set_active(self.config['autoadd_queued']) self.dialog = self.builder.get_object('queued_torrents_dialog') self.dialog.set_icon(get_logo(32)) self.builder.connect_signals(self) self.treeview = self.builder.get_object('treeview') self.treeview.append_column( TreeViewColumn(_('Torrent'), CellRendererText(), text=0) ) self.liststore = ListStore(str, str) self.treeview.set_model(self.liststore) self.treeview.set_tooltip_column(1) def run(self): self.dialog.set_transient_for(component.get('MainWindow').window) self.dialog.show() def start(self): if len(self.queue) == 0: return # Make sure status bar info is showing self.update_status_bar() # We only want the add button sensitive if we're connected to a host self.builder.get_object('button_add').set_sensitive(True) if self.config['autoadd_queued'] or self.config['standalone']: self.on_button_add_clicked(None) else: self.run() def stop(self): # We only want the add button sensitive if we're connected to a host self.builder.get_object('button_add').set_sensitive(False) self.update_status_bar() def add_to_queue(self, torrents): """Adds the list of torrents to the queue""" # Add to the queue while removing duplicates self.queue = list(set(self.queue + torrents)) # Update the liststore self.liststore.clear() for torrent in self.queue: if deluge.common.is_magnet(torrent): magnet = deluge.common.get_magnet_info(torrent) self.liststore.append([magnet['name'], torrent]) else: self.liststore.append([os.path.split(torrent)[1], torrent]) # Update the status bar self.update_status_bar() def update_status_bar(self): """Attempts to update status bar""" # If there are no queued torrents.. remove statusbar widgets and return if len(self.queue) == 0: if self.status_item is not None: component.get('StatusBar').remove_item(self.status_item) self.status_item = None return False try: component.get('StatusBar') except Exception: # The statusbar hasn't been loaded yet, so we'll add a timer to # update it later. timeout_add(100, self.update_status_bar) return False # Set the label text for statusbar if len(self.queue) > 1: label = str(len(self.queue)) + _(' Torrents Queued') else: label = str(len(self.queue)) + _(' Torrent Queued') # Add the statusbar items if needed, or just modify the label if they # have already been added. if self.status_item is None: self.status_item = component.get('StatusBar').add_item( icon='view-sort-descending', text=label, callback=self.on_statusbar_click, ) else: self.status_item.set_text(label) # We return False so the timer stops return False def on_statusbar_click(self, widget, event): log.debug('on_statusbar_click') self.run() def on_button_remove_clicked(self, widget): selected = self.treeview.get_selection().get_selected()[1] if selected is not None: path = self.liststore.get_value(selected, 1) self.liststore.remove(selected) self.queue.remove(path) self.update_status_bar() def on_button_clear_clicked(self, widget): self.liststore.clear() del self.queue[:] self.update_status_bar() def on_button_close_clicked(self, widget): self.dialog.hide() def on_button_add_clicked(self, widget): # Add all the torrents in the liststore def add_torrent(model, path, _iter, data): torrent_path = deluge.common.decode_bytes(model.get_value(_iter, 1)) process_args([torrent_path]) self.liststore.foreach(add_torrent, None) del self.queue[:] self.dialog.hide() self.update_status_bar() def on_chk_autoadd_toggled(self, widget): self.config['autoadd_queued'] = widget.get_active()
def fill_list_store(store: Gtk.ListStore, models: list): store.clear() for model in models: pass
class Filter: def __init__(self, widgets, aview): self.widgets = widgets self.functions = Functions() self.userconf = ConfigLoader() # GUI self.filter_button = self.widgets[1].get_object('tool-filter') self.filter_button.connect('clicked', self.on_button_clicked) gladefile = join(self.functions.datadir, 'glade', 'filterbar.ui') self.fbox = gtk_builder() self.fbox.set_translation_domain('bluemindo') self.fbox.add_from_file(gladefile) self.filter_box = self.fbox.get_object('infobar') wdg_place = self.widgets[1].get_object('filter-emplacement') wdg_place.add(self.filter_box) self.fbox.get_object('label_filter').set_text(_('Filter the results:')) # Create ComboBoxes self.genre_fstore = ListStore(int, str) self.genre_fcombo = self.fbox.get_object('combobox-genre') self.genre_fcombo.set_model(self.genre_fstore) renderer_text = CellRendererText() self.genre_fcombo.pack_start(renderer_text, True) self.genre_fcombo.set_entry_text_column(1) self.genre_fcombo.add_attribute(renderer_text, 'text', 1) self.year_fstore = ListStore(int, str) self.year_fcombo = self.fbox.get_object('combobox-year') self.year_fcombo.set_model(self.year_fstore) renderer_text = CellRendererText() self.year_fcombo.pack_start(renderer_text, True) self.year_fcombo.set_entry_text_column(1) self.year_fcombo.add_attribute(renderer_text, 'text', 1) def on_button_clicked(self, widget): if self.filter_box.props.visible is True: self.filter_box.hide() else: self.filter_box.show_all() # Reset filters self.genre_fcombo.set_active(0) self.year_fcombo.set_active(0) def launch(self, albums_tree, songs_tree, aview): self.albums_tree = albums_tree self.songs_tree = songs_tree self.aview = aview album_data = {} data_genre = [] data_year = [] # Gather data for item in self.albums_tree: item_artist = item['artist'] item_album = item['album'] if item_artist not in album_data.keys(): album_data[item_artist] = {} album_data[item_artist][item_album] = {} album = Album(item_artist, item_album, self.songs_tree) album_genre = '' album_year = '' for sng in album.tracks: if album_genre == '': album_genre = sng.genre if album_year == '': album_year = sng.year if album_genre != '' and album_genre not in data_genre: data_genre.append(album_genre) if album_year != '' and album_year not in data_year: data_year.append(album_year) album_data[item_artist][item_album]['genre'] = album_genre album_data[item_artist][item_album]['year'] = album_year # Populate combobox self.genre_fstore.clear() self.genre_fstore.append([-2, _('All genres')]) self.genre_fstore.append([-1, '']) data_genre.sort() i = 0 for genre in data_genre: self.genre_fstore.append([i, genre]) i += 1 self.year_fstore.clear() self.year_fstore.append([-2, _('All years')]) self.year_fstore.append([-1, '']) data_year.sort() i = 0 for year in data_year: self.year_fstore.append([i, year]) i += 1 def combo_sep(model, iter): if model[iter][0] == -1: return True self.year_fcombo.set_row_separator_func(combo_sep) self.genre_fcombo.set_row_separator_func(combo_sep) self.aview.generate_filter_data(album_data) self.genre_fcombo.connect('changed', self.on_fcombo_changed, 'genre') self.year_fcombo.connect('changed', self.on_fcombo_changed, 'year') # Hide filters self.filter_box.hide() self.filter_button.set_active(False) def on_fcombo_changed(self, widget, cmb): path = widget.get_active() try: if cmb == 'genre': item_value = self.genre_fstore[path][1] item_key = self.genre_fstore[path][0] else: item_value = self.year_fstore[path][1] item_key = self.year_fstore[path][0] except IndexError: item_key = -42 if item_key >= 0: self.aview.add_filter_data(item_value, cmb) else: self.aview.remove_filter_data(cmb)
class Search: def __init__(self, widgets, aview): self.widgets = widgets self.aview = aview self.albumview = aview.albumview self.albumfilter = aview.albumfilter self.matched = aview.matched self.functions = Functions() self.userconf = ConfigLoader() # Create the autocompletion columns self.completion_model = ListStore(Pixbuf, str, str, str, str, str, str, str) ecomplet = EntryCompletion() ecomplet.set_model(self.completion_model) pixbufcell = CellRendererPixbuf() ecomplet.pack_start(pixbufcell, False) ecomplet.add_attribute(pixbufcell, 'pixbuf', 0) markupcell = CellRendererText() markupcell.props.xpad = 10 ecomplet.pack_start(markupcell, True) ecomplet.add_attribute(markupcell, 'markup', 1) markupcell = CellRendererText() markupcell.props.xpad = 5 ecomplet.pack_start(markupcell, False) ecomplet.add_attribute(markupcell, 'markup', 2) pixbufcell = CellRendererPixbuf() ecomplet.pack_start(pixbufcell, False) ecomplet.add_attribute(pixbufcell, 'icon_name', 3) ecomplet.props.text_column = 4 def matched(widget, model, iter): item = model[iter] data_a = item[4] data_b = item[5] self.aview.matched = [data_a, data_b] self.albumfilter.refilter() if data_b == 'blm.!ARTIST!': # Matched an artist: show albums return False elif exists(data_b): # Matched a song: queue to playlist sng = Song(filename=item[5]) self.aview.queue(sng) # Go back to empty search self.aview.matched = False searchentry = widget.get_entry() searchentry.set_text('') return True #elif len(self.albumfilter) == 1: else: # Matched an album: load it in a panel album = Album(data_b, data_a, self.songs_tree) if hasattr(album, 'name'): self.aview.on_album_matched(album) # Go back to empty search self.aview.matched = False searchentry = widget.get_entry() searchentry.set_text('') return True ecomplet.connect('match-selected', matched) searchentry = self.widgets[1].get_object('searchentry') searchentry.set_completion(ecomplet) searchentry.grab_focus() def do_filter(widget): self.albumfilter.refilter() self.aview.matched = False searchentry.connect('changed', do_filter) self.searchentry = searchentry def generate_autocompletion(self, artists, albums, songs_tree): self.songs_tree = songs_tree albums_without_cover = [] artists_without_picture = [] # Launch autocompletion now that the songs tree is generated def append_autocompletion(name, kind): fnf = join(self.functions.datadir, 'image', 'logo_head_big.png') if kind == 1: # Artist icon = 'face-smile-symbolic' pic = join(self.userconf.datadir, 'modules', 'explorer', 'artists', self.functions.get_hash(name, 'picture')) try: if isfile(pic): pxbf = Pixbuf.new_from_file_at_scale(pic, 70, 70, True) else: pxbf = Pixbuf.new_from_file_at_scale(fnf, 70, 70, True) artists_without_picture.append(name) except GLIBError: pxbf = Pixbuf.new_from_file_at_scale(fnf, 70, 70, True) dname = '<b>' + self.functions.view_encode(name, 99) + '</b>' infos = ('<b>' + _('Artist') + '</b>\n' + _('%s albums in collection.' % ('<b>' + str(len(self.songs_tree[name])) + '</b>'))) add = 'blm.!ARTIST!' add_a = '' add_b = '' elif kind == 2: # Album icon = 'media-optical-symbolic' artist = name[0] name = name[1] cover = join(self.userconf.datadir, 'modules', 'player', 'covers', self.functions.get_hash(name, artist)) if isfile(cover): pxbf = Pixbuf.new_from_file_at_scale(cover, 70, 70, True) else: pxbf = Pixbuf.new_from_file_at_scale(fnf, 70, 70, True) albums_without_cover.append([artist, name]) dname = ('<b>' + self.functions.view_encode(name, 99) + '</b>\n<i>' + self.functions.view_encode(artist, 99) + '</i>') length = 0 songs = 0 for song in self.songs_tree[artist][name]: songs += 1 length += song[7] hlgth = self.functions.human_length(length) infos = (_('%s songs' % ('<b>' + str(songs) + '</b>')) + '\n' + _('Total playing time: %s.' % ('<i>' + hlgth + '</i>'))) self.cur_pxbf = pxbf add = artist add_a = '' add_b = '' elif kind == 3: # Song icon = 'media-record-symbolic' artist = name[1] album = name[2] add = name[8] add_a = artist add_b = album name = name[0] dname = ('<b>' + self.functions.view_encode(name, 99) + '</b>\n<i>' + self.functions.view_encode(artist, 99) + ' - ' + self.functions.view_encode(album, 99) + '</i>') infos = '<b>' + _('Song') + '</b>' pxbf = self.cur_pxbf self.completion_model.append( [pxbf, dname, infos, icon, name, add, add_a, add_b]) self.completion_model.clear() for a in artists: append_autocompletion(a, 1) for a in albums: append_autocompletion(a, 2) for sng in self.songs_tree[a[0]][a[1]]: append_autocompletion(sng, 3) # Retrieve album covers lastfm = LastFm() thread = Thread(group=None, target=lastfm.get_albums_pictures, name='coverart', kwargs={'albums': albums_without_cover}) thread.start() # Retrieve artist pictures thread = Thread(group=None, target=lastfm.get_artists_pictures, name='coverart', kwargs={'artists': artists_without_picture}) thread.start()