def _on_append_songs(info, error=None): if not info or error: logger.error('TopCategories.append_songs(): %s, %s' % (info, error)) return songs, self.songs_total = info if not songs or self.songs_total == 0 or self.use_album: Net.async_call(Net.get_album, self.curr_list_id, callback=_on_get_album) for song in songs: self.liststore_songs.append([ True, Widgets.unescape(song['name']), Widgets.unescape(song['artist']), Widgets.unescape(song['album']), int(song['id']), int(song['artistid']), int(song['albumid']), song['formats'], ]) self.songs_page += 1 if self.songs_page < self.songs_total - 1: self.append_songs()
def _update_songs(songs, error=None): if error or not songs: logger.error('init_songs(): %s, %s' % (songs, error)) return self.playlists[self.radio_id]['songs'] = songs self.playlists[self.radio_id]['curr_song'] = 0 self.update_label()
def _on_show_sub2(sub2_args, error=None): nodes, self.sub2_total = sub2_args if error or not nodes or not self.sub2_total: logger.error('nodes: %s, self.sub2_total: %s, error: %s' % (nodes, self.sub2_total, error)) return urls = [] tree_iters = [] for node in nodes: tree_iter = self.liststore_sub2.append([ self.app.theme['anonymous'], Widgets.unescape(node['name']), int(node['sourceid']), Widgets.unescape(node['info']), Widgets.set_tooltip_with_song_tips(node['name'], node['tips']) ]) urls.append(node['pic']) tree_iters.append(tree_iter) Net.async_call(Net.update_liststore_images, self.liststore_sub2, 0, tree_iters, urls) self.sub2_page += 1 if self.sub2_page < self.sub2_total - 1: self.show_sub2()
def _on_show_sub2(sub2_args, error=None): nodes, self.sub2_total = sub2_args if error or not nodes or not self.sub2_total: logger.error('nodes: %s, self.sub2_total: %s, error: %s' % (nodes, self.sub2_total, error)) return urls = [] tree_iters = [] for node in nodes: tree_iter = self.liststore_sub2.append([ Config.ANONYMOUS_PIXBUF, Widgets.unescape(node['name']), int(node['sourceid']), Widgets.unescape(node['info']), Widgets.set_tooltip_with_song_tips(node['name'], node['tips']) ]) urls.append(node['pic']) tree_iters.append(tree_iter) Net.async_call(Net.update_liststore_images, self.liststore_sub2, 0, tree_iters, urls) self.sub2_page += 1 if self.sub2_page < self.sub2_total - 1: self.show_sub2()
def _append_artist_info(info, error=None): if error or not info: logger.error('appen_artist_info(): %s, %s' % (info, error)) return if info.get('pic', None): self.artist_info_pic.set_from_file(info['pic']) self.artist_info_name.set(info, 'name') self.artist_info_birthday.set(info, 'birthday') self.artist_info_birthplace.set(info, 'birthplace') self.artist_info_height.set(info, 'tall') self.artist_info_weight.set( info, 'weight', ) self.artist_info_country.set(info, 'country') self.artist_info_language.set(info, 'language') self.artist_info_gender.set( info, 'gender', ) self.artist_info_constellation.set(info, 'constellation') if info and 'info' in info: if html2text_imported: self.artist_info_textbuffer.set_text( html2text.html2text(info['info'])) else: self.artist_info_textbuffer.set_text( Widgets.escape(info['info'])) else: self.artist_info_textbuffer.set_text('')
def _append_artist_mv(mv_args, error=None): mvs, self.artist_mv_total = mv_args if error or self.artist_mv_total == 0: logger.error('append_artist_mv(): %s, %s' % (self.artist_mv_total, error)) return urls = [] tree_iters = [] for mv in mvs: tree_iter = self.artist_mv_liststore.append([ Config.ANONYMOUS_PIXBUF, Widgets.unescape(mv['name']), Widgets.unescape(mv['artist']), '', int(mv['musicid']), int(mv['artistid']), 0, Widgets.set_tooltip(mv['name'], mv['artist']), ]) tree_iters.append(tree_iter) urls.append(mv['pic']) Net.async_call(Net.update_mv_images, self.artist_mv_liststore, 0, tree_iters, urls) self.artist_mv_page += 1 if self.artist_mv_page < self.artist_mv_total - 1: self.append_artist_mv()
def _on_append_songs(info, error=None): if error or not info or not info[0] or not info[1]: logger.error('append_songs(): %s, %s' % (info, error)) return songs, self.songs_total = info urls = [] tree_iters = [] for song in songs: tree_iter = self.liststore_songs.append([ Config.ANONYMOUS_PIXBUF, Widgets.unescape(song['name']), Widgets.unescape(song['artist']), Widgets.unescape(song['album']), int(song['id']), int(song['artistid']), int(song['albumid']), Widgets.set_tooltip(song['name'], song['artist']), ]) tree_iters.append(tree_iter) urls.append(song['mvpic']) Net.async_call(Net.update_mv_images, self.liststore_songs, 0, tree_iters, urls) self.songs_page += 1 if self.songs_page < self.songs_total - 1: self.append_songs()
def urlopen(_url, use_cache=True, retries=RETRIES): # set host port from 81 to 80, to fix image problem url = _url.replace(':81', '') if use_cache and ldb_imported: key = hash_byte(url) try: content = ldb_get(key) if content and len(content) > 10: try: timestamp = int(content[:10].decode()) if (time.time() - timestamp) < CACHE_TIMEOUT: return content[10:] except (ValueError, UnicodeDecodeError): logger.info(traceback.format_exc()) except KeyError: logger.error(traceback.format_exc()) for i in range(retries): try: req = request.urlopen(url, timeout=TIMEOUT) req_content = req.read() if use_cache and ldb_imported: ldb_put(key, str(int(time.time())).encode() + req_content) return req_content except URLError: logger.warn(traceback.format_exc()) return None
def iconvtag(song_path, song): def use_id3(): audio = MP3(song_path, ID3=EasyID3) audio.clear() audio['title'] = song['name'] audio['artist'] = song['artist'] audio['album'] = song['album'] audio.save() def use_ape(): audio = APEv2File(song_path) if not audio.tags: audio.add_tags() audio.tags.clear() audio.tags['title'] = song['name'] audio.tags['artist'] = song['artist'] audio.tags['album'] = song['album'] audio.save() # Do nothing if mutagenx is not imported if not mutagenx_imported: return ext = os.path.splitext(song_path)[1].lower() try: if ext == '.mp3': use_id3() # TODO: check flac tag elif ext == '.flac': use_ape() except Exception: logger.error(traceback.format_exc())
def _append_artist_similar(similar_args, error=None): artists, self.artist_similar_total = similar_args if error or not self.artist_similar_total: logger.error('append_artist_similar(): %s, %s' % (self.artist_similar_total, error)) return urls = [] tree_iters = [] for artist in artists: _info = ''.join([ artist['songnum'], _(' songs'), ]) tree_iter = self.artist_similar_liststore.append([ Config.ANONYMOUS_PIXBUF, Widgets.unescape(artist['name']), int(artist['id']), _info, Widgets.set_tooltip(artist['name'], _info), ]) urls.append(artist['pic']) tree_iters.append(tree_iter) Net.async_call(Net.update_artist_logos, self.artist_similar_liststore, 0, tree_iters, urls) self.artist_similar_page += 1 if self.artist_similar_page < self.artist_similar_total - 1: self.append_artist_similar()
def _on_show_sub1(info, error=None): if not info or not info[0] or not info[1] or error: logger.error('show_sub1(): %s, %s' % (info, error)) return nodes, self.sub1_total = info urls = [] tree_iters = [] for node in nodes: id_ = 'id' if self.use_sub2 else 'sourceid' if 'tips' in node and len(node['tips']) > 5: tooltip = Widgets.set_tooltip_with_song_tips( node['name'], node['tips']) else: tooltip = Widgets.set_tooltip(node['name'], node['info']) tree_iter = self.liststore_sub1.append([ Config.ANONYMOUS_PIXBUF, Widgets.unescape(node['name']), int(node[id_]), Widgets.unescape(node['info']), tooltip, ]) urls.append(node['pic']) tree_iters.append(tree_iter) Net.async_call(Net.update_liststore_images, self.liststore_sub1, 0, tree_iters, urls) self.sub1_page += 1 if self.sub1_page < self.sub1_total - 1: self.show_sub1()
def get_image(url, filepath=None): if not url or len(url) < 10: logger.error('Net.get_image: url is invalid, %s' % url) return None if not filepath: filename = os.path.split(url)[1] filepath = os.path.join(Config.IMG_DIR, filename) if os.path.exists(filepath): return filepath image = urlopen(url, use_cache=False) if not image: logger.debug('Net.get_image: failed to get image, %s' % image) return None with open(filepath, 'wb') as fh: fh.write(image) # Now, check its mime type file_ = Gio.File.new_for_path(filepath) file_info = file_.query_info(Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, Gio.FileQueryInfoFlags.NONE) content_type = file_info.get_content_type() if 'image' in content_type: return filepath else: os.remove(filepath) return None
def _on_show_sub1(info, error=None): if not info or not info[0] or not info[1] or error: logger.error('show_sub1(): %s, %s' % (info, error)) return nodes, self.sub1_total = info urls = [] tree_iters = [] for node in nodes: id_ = 'id' if self.use_sub2 else 'sourceid' if 'tips' in node and len(node['tips']) > 5: tooltip = Widgets.set_tooltip_with_song_tips(node['name'], node['tips']) else: tooltip = Widgets.set_tooltip(node['name'], node['info']) tree_iter = self.liststore_sub1.append([ self.app.theme['anonymous'], Widgets.unescape(node['name']), int(node[id_]), Widgets.unescape(node['info']), tooltip, ]) urls.append(node['pic']) tree_iters.append(tree_iter) Net.async_call(Net.update_liststore_images, self.liststore_sub1, 0, tree_iters, urls) self.sub1_page += 1 if self.sub1_page < self.sub1_total - 1: self.show_sub1()
def json_loads_single(s): '''Actually this is not a good idea. ''' try: return json.loads( s.replace('"', '''\\"''').replace("'", '"').replace('\t', '')) except (ValueError, UnicodeDecodeError): logger.error(traceback.format_exc()) return None
def parse_lrc(lrc_txt): '''解析歌词''' try: return parser_lex(lrc_txt) except (lex.LrcError, NameError): logger.error(traceback.format_exc()) logger.debug('LrcParser: fallback to regexp parser') return parser_re(lrc_txt)
def update_image(filepath, tree_iter): try: pix = GdkPixbuf.Pixbuf.new_from_file_at_size( filepath, resize, resize) tree_path = liststore.get_path(tree_iter) if tree_path is not None: liststore[tree_path][col] = pix except Exception: logger.error(traceback.format_exc())
def update_image(filepath, tree_iter): try: pix = GdkPixbuf.Pixbuf.new_from_file_at_size(filepath, resize, resize) tree_path = liststore.get_path(tree_iter) if tree_path is not None: liststore[tree_path][col] = pix except Exception: logger.error(traceback.format_exc())
def _update_mv_link(mv_args, error=None): if error or not mv_args: logger.error('get_mv_link(): %s, %s' % (mv_args, error)) self.use_mtv_btn.set_sensitive(False) else: cached, mv_link, mv_path = mv_args if cached or mv_link: self.use_mtv_btn.set_sensitive(True) else: self.use_mtv_btn.set_sensitive(False)
def _parse_lrc(): url = ('http://newlyric.kuwo.cn/newlyric.lrc?' + Utils.encode_lrc_url(rid)) req_content = urlopen(url, use_cache=False, retries=8) if not req_content: return None try: lrc = Utils.decode_lrc_content(req_content) return lrc except Exception: logger.error(traceback.format_exc()) return None
def _append_fav_artist(info, error=None): if error or not info: logger.error('add_to_fav_artists(): %s, %s' % (info, error)) return if info.get('pic', None): pix = GdkPixbuf.Pixbuf.new_from_file_at_size( info['pic'], 100, 100) else: pix = Config.ANONYMOUS_PIXBUF, tip = Widgets.escape(info.get('info', '')) self.fav_artists_liststore.append( [pix, info['name'], artist_id, tip])
def _append_fav_artist(info, error=None): if error or not info: logger.error('add_to_fav_artists(): %s, %s' % (info, error)) return if info.get('pic', None): pix = GdkPixbuf.Pixbuf.new_from_file_at_size(info['pic'], 100, 100) else: pix = Config.ANONYMOUS_PIXBUF, tip = Widgets.escape(info.get('info', '')) self.fav_artists_liststore.append([pix, info['name'], artist_id, tip])
def set_tooltip_with_song_tips(head, tip): songs = tip.split(';') results = [] fmt = '{0} <small>by {1}</small>' for song in songs: if len(song) < 5: continue item = song.split('@') try: results.append(fmt.format(escape(item[1]), escape(item[3]))) except IndexError: logger.error(traceback.format_exc()) return '<b>{0}</b>\n\n{1}'.format(escape(head), '\n'.join(results))
def _append_album_songs(songs, error=None): if error or not songs: logger.error('append_album_songs(): %s, %s' % (songs, error)) return for song in songs: self.album_songs_liststore.append([ True, Widgets.unescape(song['name']), Widgets.unescape(song['artist']), Widgets.unescape(self.curr_album_name), int(song['id']), int(song['artistid']), int(self.curr_album_id), song['formats'], ])
def _update_pic(info, error=None): if not info or error: logger.error('update_player_info(): %s, %s' % (info, error)) return self.artist_pic.set_tooltip_text( Widgets.short_tooltip(info['info'], length=500)) if info['pic']: self.meta_artUrl = info['pic'] pix = GdkPixbuf.Pixbuf.new_from_file_at_size(info['pic'], 100, 100) self.artist_pic.set_from_pixbuf(pix) else: self.meta_artUrl = self.app.theme_path['anonymous'] self.notify.refresh() self.dbus.update_meta()
def _update_pic(info, error=None): if not info or error: logger.error('update_player_info(): %s, %s' % (info, error)) return self.artist_pic.set_tooltip_text( Widgets.short_tooltip(info['info'], length=500)) if info['pic']: self.meta_artUrl = info['pic'] pix = GdkPixbuf.Pixbuf.new_from_file_at_size( info['pic'], 100, 100) self.artist_pic.set_from_pixbuf(pix) else: self.meta_artUrl = Config.ANONYMOUS_IMG self.notify.refresh() self.dbus.update_meta()
def _on_get_themes_songs(info, error): if not info or not info[0] or not info[1] or error: logger.error('show_songs(): %s, %s' % (info, error)) return songs, self.songs_total = info for song in songs: self.liststore_songs.append([ True, Widgets.unescape(song['name']), Widgets.unescape(song['artist']), Widgets.unescape(song['album']), int(song['id']), int(song['artistid']), int(song['albumid']), song['formats'], ])
def _on_get_toplist_songs(songs, error): if not songs or error: logger.error('show_toplist_songs(), songs: %s, error: %s' % (songs, error)) return self.liststore_songs.clear() for song in songs: self.liststore_songs.append([ True, Widgets.unescape(song['name']), Widgets.unescape(song['artist']), Widgets.unescape(song['album']), int(song['id']), int(song['artistid']), int(song['albumid']), song['formats'], ])
def _on_get_album(songs, error=None): self.songs_total = 1 if not songs or error: logger.error('TopCategories._on_get_album: %s, %s' % (songs, error)) return for song in songs: self.liststore_songs.append([ True, Widgets.unescape(song['name']), Widgets.unescape(song['artist']), Widgets.unescape(self.curr_list_name), int(song['id']), int(song['artistid']), int(self.curr_list_id), song['formats'], ])
def get_index_nodes(nid): '''Get content of nodes from nid=2 to nid=15''' url = ''.join([ QUKU, 'op=query&fmt=json&src=mbox&cont=ninfo&pn=0&rn=', str(ICON_NUM), '&node=', str(nid), ]) req_content = urlopen(url) if not req_content: return None try: nodes_wrap = json.loads(req_content.decode()) except ValueError: logger.error(traceback.format_exc()) return None return nodes_wrap
def get_image(url, filepath=None): if not url or len(url) < 10: logger.error('Net.get_image: url is invalid, %s' % url) return None if not filepath: filename = os.path.split(url)[1] filepath = os.path.join(Config.IMG_DIR, filename) if os.path.exists(filepath): return filepath image = urlopen(url, use_cache=False) if not image: logger.debug('Net.get_image: failed to get image, %s' % image) return None with open(filepath, 'wb') as fh: fh.write(image) return filepath
def reload(self): '''重新设定属性, 然后重绘''' if self.app.conf['osd-locked']: self.toolbar.hide() try: region = cairo.Region() except AttributeError: print('cairo.Region is missing, a patch is required:', 'http://bugs.debian.org/688079') logger.error(traceback.format_exc()) return self.input_shape_combine_region(region) else: self.toolbar.show_all() self.app.conf['osd-toolbar-y'] = self.toolbar.get_allocated_height() self.auto_hide_toolbar() self.input_shape_combine_region(None) self.move(self.app.conf['osd-x'], self.app.conf['osd-y'])
def reload(self): '''重新设定属性, 然后重绘''' if self.app.conf['osd-locked']: self.toolbar.hide() try: region = cairo.Region() except AttributeError: print('cairo.Region is missing, a patch is required:', 'http://bugs.debian.org/688079') logger.error(traceback.format_exc()) return self.input_shape_combine_region(region) else: self.toolbar.show_all() self.app.conf['osd-toolbar-y'] = self.toolbar.get_allocated_height( ) self.auto_hide_toolbar() self.input_shape_combine_region(None) self.move(self.app.conf['osd-x'], self.app.conf['osd-y'])
def get_toplist_songs(nid): # no need to use pn, because toplist contains very few songs url = ''.join([ 'http://kbangserver.kuwo.cn/ksong.s?', 'from=pc&fmt=json&type=bang&data=content&rn=', str(SONG_NUM), '&id=', str(nid), ]) if url not in req_cache: req_content = urlopen(url, use_cache=False) if not req_content: return None req_cache[url] = req_content try: songs_wrap = json.loads(req_cache[url].decode()) except ValueError: logger.error(traceback.format_exc()) return None return songs_wrap['musiclist']
def on_show_sub(info, error=None): if error or not info or not info[0] or not info[1]: logger.error('show_sub(): %s, %s' % (info, error)) return nodes, self.nodes_total = info urls = [] tree_iters = [] for node in nodes: tree_iter = self.liststore_sub.append([ self.app.theme['anonymous'], Widgets.unescape(node['name']), int(node['sourceid']), Widgets.unescape(node['info']), Widgets.set_tooltip_with_song_tips(node['name'], node['tips']), ]) tree_iters.append(tree_iter) urls.append(node['pic']) Net.async_call(Net.update_liststore_images, self.liststore_sub, 0, tree_iters, urls)
def on_show_sub(info, error=None): if error or not info or not info[0] or not info[1]: logger.error('show_sub(): %s, %s' % (info, error)) return nodes, self.nodes_total = info urls = [] tree_iters = [] for node in nodes: tree_iter = self.liststore_sub.append([ Config.ANONYMOUS_PIXBUF, Widgets.unescape(node['name']), int(node['sourceid']), Widgets.unescape(node['info']), Widgets.set_tooltip_with_song_tips(node['name'], node['tips']), ]) tree_iters.append(tree_iter) urls.append(node['pic']) Net.async_call(Net.update_liststore_images, self.liststore_sub, 0, tree_iters, urls)
def get_mv_songs(pid, page): url = ''.join([ QUKU_SONG, 'op=getlistinfo&pn=', str(page), '&rn=', str(ICON_NUM), '&encode=utf-8&keyset=mvpl&pid=', str(pid), ]) req_content = urlopen(url) if not req_content: return (None, 0) try: songs_wrap = json.loads(req_content.decode()) except ValueError: logger.error(traceback.format_exc()) return (None, 0) songs = songs_wrap['musiclist'] pages = math.ceil(int(songs_wrap['total']) / ICON_NUM) return (songs, pages)
def _append_artists(artists_args, error=None): artists, hit, self.artists_total = artists_args if not error and artists and hit: urls, tree_iters = [], [] for artist in artists: tree_iter = self.liststore_artists.append([ Config.ANONYMOUS_PIXBUF, Widgets.unescape(artist['ARTIST']), int(artist['ARTISTID']), Widgets.unescape(artist['COUNTRY']), ]) tree_iters.append(tree_iter) urls.append(artist['PICPATH']) Net.async_call(Net.update_artist_logos, self.liststore_artists, 0, tree_iters, urls) else: logger.error('show_artists(): %s, %s' % (self.artists_total, error)) self.artists_button.set_label('{0} ({1})'.format(_('Artists'), len(self.liststore_artists)))
def on_append_artists(info, error=None): artists, self.artists_total = info if error or not self.artists_total or not artists: logger.error('append_artists(), %s, %s, %s' % (self.artists_total, artists, error)) return urls = [] tree_iters = [] for artist in artists: _info = ' '.join([artist['music_num'], _(' songs'), ]) tree_iter = self.artists_liststore.append([ Config.ANONYMOUS_PIXBUF, Widgets.unescape(artist['name']), int(artist['id']), _info, Widgets.set_tooltip(artist['name'], _info), ]) urls.append(artist['pic']) tree_iters.append(tree_iter) Net.async_call(Net.update_artist_logos, self.artists_liststore, 0, tree_iters, urls)
def _append_artist_songs(songs_args, error=None): if error or not songs_args or not songs_args[1]: logger.error('append_artist_songs(): %s, %s' % (self.artist_songs_total, error)) return songs, self.artist_songs_total = songs_args for song in songs: self.artist_songs_liststore.append([ True, Widgets.unescape(song['name']), Widgets.unescape(song['artist']), Widgets.unescape(song['album']), int(song['musicrid']), int(song['artistid']), int(song['albumid']), song['formats'], ]) # automatically load more songs self.artist_songs_page += 1 if self.artist_songs_page < self.artist_songs_total - 1: self.append_artist_songs()
def _append_artist_songs(songs_args, error=None): if error or not songs_args or not songs_args[1]: logger.error('append_artist_songs(): %s, %s' % (songs_args, error)) return songs, self.artist_songs_total = songs_args for song in songs: self.artist_songs_liststore.append([ True, Widgets.unescape(song['name']), Widgets.unescape(song['artist']), Widgets.unescape(song['album']), int(song['musicrid']), int(song['artistid']), int(song['albumid']), song['formats'], ]) # automatically load more songs self.artist_songs_page += 1 if self.artist_songs_page < self.artist_songs_total - 1: self.append_artist_songs()
def update_liststore_images(liststore, col, tree_iters, urls, url_proxy=None, resize=IMG_SIZE): '''Update a banch of thumbnails consequently. liststore - the tree model, which has timestamp property col - column index tree_iters - a list of tree_iters urls - a list of image urls url_proxy - a function to reconstruct image url, this function run in background thread. default is None, do nothing. resize - will resize pixbuf to specific size, default is 100x100 ''' def update_image(filepath, tree_iter): try: pix = GdkPixbuf.Pixbuf.new_from_file_at_size( filepath, resize, resize) tree_path = liststore.get_path(tree_iter) if tree_path is not None: liststore[tree_path][col] = pix except Exception: logger.error(traceback.format_exc()) timestamp = liststore.timestamp for tree_iter, url in zip(tree_iters, urls): # First, check timestamp matches if liststore.timestamp != timestamp: break if url_proxy: url = url_proxy(url) try: filepath = get_image(url) except Exception: logger.error(traceback.format_exc()) continue if filepath: GLib.idle_add(update_image, filepath, tree_iter)
def get_themes_songs(nid, page): url = ''.join([ QUKU_SONG, 'op=getlistinfo&encode=utf-8&identity=kuwo&keyset=pl2012&rn=', str(SONG_NUM), '&pid=', str(nid), '&pn=', str(page), ]) if url not in req_cache: req_content = urlopen(url, use_cache=False) if not req_content: return (None, 0) req_cache[url] = req_content try: songs_wrap = json.loads(req_cache[url].decode()) except ValueError: logger.error(traceback.format_exc()) return (None, 0) pages = math.ceil(int(songs_wrap['total']) / SONG_NUM) return (songs_wrap['musiclist'], pages)