def _check(self, song): old_threshold = Gst.debug_get_default_threshold() Gst.debug_set_default_threshold(Gst.DebugLevel.NONE) pipeline = Gst.parse_launch("uridecodebin uri=%s ! fakesink" % song("~uri")) bus = pipeline.get_bus() pipeline.set_state(Gst.State.PLAYING) try: while 1: message = bus.timed_pop(Gst.SECOND * 10) if not message or message.type == Gst.MessageType.ERROR: if message: debug = message.parse_error()[0].message else: debug = "timed out" # only print a warning for platforms where we control # the shipped dependencies. if sys.platform == "darwin" or os.name == "nt": print_w("GStreamer: Decoding %r failed (%s)" % (song("~format"), debug)) break if message.type == Gst.MessageType.EOS: break finally: pipeline.set_state(Gst.State.NULL) Gst.debug_set_default_threshold(old_threshold)
def _check(self, song): old_threshold = Gst.debug_get_default_threshold() Gst.debug_set_default_threshold(Gst.DebugLevel.NONE) pipeline = Gst.parse_launch( "uridecodebin uri=%s ! fakesink" % song("~uri")) bus = pipeline.get_bus() pipeline.set_state(Gst.State.PLAYING) try: while 1: message = bus.timed_pop(Gst.SECOND * 10) if not message or message.type == Gst.MessageType.ERROR: if message: debug = message.parse_error()[0].message else: debug = "timed out" # only print a warning for platforms where we control # the shipped dependencies. if sys.platform == "darwin" or os.name == "nt": print_w("GStreamer: Decoding %r failed (%s)" % (song("~format"), debug)) break if message.type == Gst.MessageType.EOS: break finally: pipeline.set_state(Gst.State.NULL) Gst.debug_set_default_threshold(old_threshold)
def is_accel(event, *accels): """Checks if the given keypress Gdk.Event matches any of accelerator strings. example: is_accel(event, "<shift><ctrl>z") """ assert accels if event.type != Gdk.EventType.KEY_PRESS: return False # ctrl+shift+x gives us ctrl+shift+X and accelerator_parse returns # lowercase values for matching, so lowercase it if possible keyval = event.keyval if not keyval & ~0xFF: keyval = ord(chr(keyval).lower()) default_mod = Gtk.accelerator_get_default_mod_mask() for accel in accels: accel_keyval, accel_mod = Gtk.accelerator_parse(accel) # If the accel contains non default modifiers matching will # never work and since no one should use them, complain non_default = accel_mod & ~default_mod if non_default: print_w("Accelerator '%s' contains a non default modifier '%s'." % (accel, Gtk.accelerator_name(0, non_default) or "")) # Remove everything except default modifiers and compare if (accel_keyval, accel_mod) == (keyval, event.state & default_mod): return True return False
def _exec_command(self, command, args, no_ack=False): self._command = command if command not in self._commands: print_w("Unhandled command %r, sending OK." % command) command = "ping" # Unhandled command, default to OK for now.. if not self._use_command_list: self.ok() elif self._command_list_ok: self.write_line(u"list_OK") return cmd, do_ack, permission = self._commands[command] if permission != (self.permission & permission): raise MPDRequestError("Insufficient permission", AckError.PERMISSION) cmd(self, self.service, args) if self._use_command_list: if self._command_list_ok: self.write_line(u"list_OK") elif do_ack: self.ok()
def init(app_id): if not dbus: return try: bus = dbus.Bus(dbus.Bus.TYPE_SESSION) manager = bus.get_object("org.gnome.SessionManager", "/org/gnome/SessionManager") iface = dbus.Interface(manager, "org.gnome.SessionManager") client_path = iface.RegisterClient(app_id, "") if client_path is None: # https://github.com/quodlibet/quodlibet/issues/2435 print_w("Broken session manager implementation, likely LXDE") return client = bus.get_object("org.gnome.SessionManager", client_path) client_priv = dbus.Interface(client, "org.gnome.SessionManager.ClientPrivate") def end_session_cb(*args): print_d("GSM sent EndSession: going down") client_priv.EndSessionResponse(True, "") app.quit() def query_end_session_cb(*args): print_d("GSM sent QueryEndSession") client_priv.EndSessionResponse(True, "") client_priv.connect_to_signal("QueryEndSession", query_end_session_cb) client_priv.connect_to_signal("EndSession", end_session_cb) except dbus.DBusException: print_d("Connecting with the gnome session manager failed") else: print_d("Connected with gnome session manager: %s" % client_path)
def show_uri(label, uri): """Shows a uri. The uri can be anything handled by GIO or a quodlibet specific one. Currently handled quodlibet uris: - quodlibet:///prefs/plugins/<plugin id> Args: label (str) uri (str) the uri to show Returns: True on success, False on error """ parsed = urlparse(uri) if parsed.scheme == "quodlibet": if parsed.netloc != "": print_w("Unknown QuodLibet URL format (%s)" % uri) return False else: return __show_quodlibet_uri(parsed) else: # Gtk.show_uri_on_window exists since 3.22 if hasattr(Gtk, "show_uri_on_window"): from quodlibet.qltk import get_top_parent return Gtk.show_uri_on_window(get_top_parent(label), uri, 0) else: return Gtk.show_uri(None, uri, 0)
def __save(self, save, song, buffer, delete): start, end = buffer.get_bounds() text = buffer.get_text(start, end, True) # First, write back to the tags. song["lyrics"] = text.decode("utf-8") try: song.write() except AudioFileError: util.print_exc() # Then, write to file. # TODO: write to file only if could not write to tags, otherwise delete # the file. lyricname = song.lyric_filename try: os.makedirs(os.path.dirname(lyricname)) except EnvironmentError as err: pass try: with open(lyricname, "w") as f: f.write(text) except EnvironmentError as err: encoding = util.get_locale_encoding() print_w(err.strerror.decode(encoding, "replace")) delete.set_sensitive(True) save.set_sensitive(False)
def load_dir_modules(path, package, load_compiled=False): """Load all modules and packages in path (recursive). Load pyc files if load_compiled is True. In case the module is already loaded, doesn't reload it. """ # needed for pickle etc. assert package in sys.modules try: modules = [e[0] for e in get_importables(path, load_compiled)] except OSError: util.print_w("%r not found" % path) return [] # get_importables can yield py and pyc for the same module # and we want to load it only once modules = set(modules) loaded = [] for name in modules: try: mod = load_module(name, package, path) except Exception: util.print_exc() continue if mod: loaded.append(mod) return loaded
def _check_feed(self): """Validate stream a bit - failing fast where possible. Constructs an equivalent(ish) HEAD request, without re-writing feedparser completely. (it never times out if reading from a stream - see #2257)""" req = feedparser._build_urllib2_request( self.uri, feedparser.USER_AGENT, None, None, None, None, {}) req.method = "HEAD" opener = build_opener(feedparser._FeedURLHandler()) try: result = opener.open(req) ct_hdr = result.headers.get('Content-Type', "Unknown type") content_type = ct_hdr.split(';')[0] status = result.code if PY2 else result.status print_d("Pre-check: %s returned %s with content type '%s'" % (self.uri, status, content_type)) if content_type not in feedparser.ACCEPT_HEADER: print_w("Unusable content: %s. Perhaps %s is not a feed?" % (content_type, self.uri)) return False # No real need to check HTTP Status - errors are very unlikely # to be a usable content type, and we should always try to parse finally: opener.close() return True
def do_draw(self, cairo_context): pixbuf = self._get_pixbuf() if not pixbuf: return alloc = self.get_allocation() width, height = alloc.width, alloc.height scale_factor = self.get_scale_factor() width *= scale_factor height *= scale_factor if self._path: if width < (2 * scale_factor) or height < (2 * scale_factor): return pixbuf = scale( pixbuf, (width - 2 * scale_factor, height - 2 * scale_factor)) pixbuf = add_border_widget(pixbuf, self) else: pixbuf = scale(pixbuf, (width, height)) style_context = self.get_style_context() if not pixbuf: print_w(f"Failed to scale pixbuf for {self._path}") return surface = get_surface_for_pixbuf(self, pixbuf) Gtk.render_icon_surface(style_context, cairo_context, surface, 0, 0)
def plugin_songs(self, songs): # Check this is a launch, not a configure if self.chosen_site: url_pat = self.get_url_pattern(self.chosen_site) pat = Pattern(url_pat) urls = set() for song in songs: # Generate a sanitised AudioFile; allow through most tags subs = AudioFile() for k in (USER_TAGS + MACHINE_TAGS): vals = song.comma(k) if vals: try: encoded = text_type(vals).encode('utf-8') subs[k] = (encoded if k == 'website' else quote_plus(encoded)) # Dodgy unicode problems except KeyError: print_d("Problem with %s tag values: %r" % (k, vals)) url = str(pat.format(subs)) if not url: print_w("Couldn't build URL using \"%s\"." "Check your pattern?" % url_pat) return # Grr, set.add() should return boolean... if url not in urls: urls.add(url) website(url)
def _check_feed(self): """Validate stream a bit - failing fast where possible. Constructs an equivalent(ish) HEAD request, without re-writing feedparser completely. (it never times out if reading from a stream - see #2257)""" req = feedparser._build_urllib2_request( self.uri, feedparser.USER_AGENT, None, None, None, None, {}) req.method = "HEAD" opener = build_opener(feedparser._FeedURLHandler()) try: result = opener.open(req) ct_hdr = result.headers.get('Content-Type', "Unknown type") content_type = ct_hdr.split(';')[0] try: status = result.status except AttributeError: print_w("Missing status code for feed %s" % self.uri) else: print_d("Pre-check: %s returned %s with content type '%s'" % (self.uri, status, content_type)) if content_type not in feedparser.ACCEPT_HEADER: print_w("Unusable content: %s. Perhaps %s is not a feed?" % (content_type, self.uri)) return False # No real need to check HTTP Status - errors are very unlikely # to be a usable content type, and we should try to parse finally: opener.close() return True
def __lookup_cb(self, lresult): with self.__update_row(lresult.song) as entry: entry.status = Status.DONE entry.result = lresult # count how many times each release ID is present and weight by the # score for release in lresult.releases: id_ = release.id # to prevent favoring releases which are a superset of # the release we actually want (say 8 CD box containing # every song of an artist), try to reduce the medium count. score = score_release(release) / release.medium_count self._release_scores.setdefault(id_, 0) self._release_scores[id_] += score # do the same again but group by directory dir_ = lresult.song("~dirname") release_scores = self._directory_scores.setdefault(dir_, {}) release_scores.setdefault(id_, 0) release_scores[id_] += score # update display if lresult.releases: self.__update_active_releases() elif lresult.error: entry.status = Status.ERROR # we don't expose in the UI, so at least print it print_w(lresult.error) else: entry.status = Status.UNKNOWN self.__inc_done()
def plugin_songs(self, songs): # Check this is a launch, not a configure if self.chosen_site: url_pat = self.get_url_pattern(self.chosen_site) pat = Pattern(url_pat) urls = set() for song in songs: # Generate a sanitised AudioFile; allow through most tags subs = AudioFile() for k in (USER_TAGS + MACHINE_TAGS): vals = song.comma(k) if vals: try: encoded = unicode(vals).encode('utf-8') subs[k] = (encoded if k == 'website' else quote_plus(encoded)) # Dodgy unicode problems except KeyError: print_d("Problem with %s tag values: %r" % (k, vals)) url = str(pat.format(subs)) if not url: print_w("Couldn't build URL using \"%s\"." "Check your pattern?" % url_pat) return # Grr, set.add() should return boolean... if url not in urls: urls.add(url) website(url)
def _enable_server(self): port_num = get_port_num() print_d("Starting MPD server on port %d" % port_num) self._server = MPDServer(app, self, port_num) try: self._server.start() except ServerError as e: print_w(str(e))
def _update_avahi(self): assert self._avahi port_num = get_port_num() try: self._avahi.register(app.name, port_num, "_mpd._tcp") except AvahiError as e: print_w(e)
def _enable_server(self): port_num = get_port_num() print_d("Starting MPD server on port %d" % port_num) self._server = MPDServer(app, self, port_num) try: self._server.start() except ServerError as e: print_w(e)
def _update_avahi(self): assert self._avahi port_num = get_port_num() try: self._avahi.register(app.name, port_num, "_mpd._tcp") except AvahiError as e: print_w(str(e))
def _sent(self, session, task, data): try: self.istream = session.send_finish(task) print_d('Sent {1} request to {0}'.format(self._uri, self.message.method)) self.emit('sent', self.message) except GLib.GError as e: print_w('Failed sending request to {0}'.format(self._uri)) self.emit('send-failure', e)
def port_activate(entry, *args): try: port_num = int(entry.get_text()) except ValueError as e: print_w(e) else: if get_port_num() != port_num: set_port_num(port_num) self._refresh()
def port_activate(entry, *args): try: port_num = int(entry.get_text()) except ValueError as e: print_w(str(e)) else: if get_port_num() != port_num: set_port_num(port_num) self._refresh()
def apply(self): if not self.player_has_eq: return levels = self._enabled and get_config()["Current"] or [] lbands = len(app.player.eq_bands) if len(levels) != lbands: print_w("Number of bands didn't match current. Using flat EQ.") levels = [0.] * lbands app.player.eq_values = levels
def MusicFile(filename): """Returns a AudioFile instance or None""" loader = get_loader(filename) if loader is not None: try: return loader(filename) except AudioFileError: print_w("Error loading %r" % filename) util.print_exc()
def cover(self): """ Method to get cover file from cover provider for a specific song. Should always return a file-like object opened as read-only if any and None otherwise. """ cp = self.cover_path try: return open(cp, 'rb') if cp and path.isfile(cp) else None except IOError: print_w('Failed reading album art "%s"'.format(path))
def conclude(self, fails, reason): if fails: def format_occurrences(e): occurences = [(self.lang + ".po", e.linenum)] occurences += e.occurrences return ", ".join("%s:%s" % o for o in occurences) messages = ['"%s" - "%s" (%s)' % (e.msgid, e.msgstr, format_occurrences(e)) for e in fails] for message in messages: print_w(message) self.fail("One or more messages did not pass (%s).\n" "Please check the warning messages above." % reason)
def _callback(self, data): try: messages = list(fifo.split_message(data)) except ValueError: print_w("invalid message: %r" % data) return for command, path in messages: response = self._cmd_registry.handle_line(self._app, command) if path is not None: with open(path, "wb") as h: if response is not None: h.write(response)
def should_process(self): """Returns true if the album needs analysis, according to prefs""" mode = self.__process_mode if mode == UpdateMode.ALWAYS: return True elif mode == UpdateMode.ANY_MISSING: return not all([s.has_all_rg_tags for s in self.songs]) elif mode == UpdateMode.ALBUM_MISSING: return not all([s.album_gain for s in self.songs]) else: print_w("Invalid setting for update mode: " + mode) # Safest to re-process probably. return True
def is_accel(event, *accels): """Checks if the given keypress Gdk.Event matches any of accelerator strings. example: is_accel(event, "<shift><ctrl>z") Args: *accels: one ore more `str` Returns: bool Raises: ValueError: in case any of the accels could not be parsed """ assert accels if event.type != Gdk.EventType.KEY_PRESS: return False # ctrl+shift+x gives us ctrl+shift+X and accelerator_parse returns # lowercase values for matching, so lowercase it if possible keyval = event.keyval if not keyval & ~0xFF: keyval = ord(chr(keyval).lower()) default_mod = Gtk.accelerator_get_default_mod_mask() keymap = Gdk.Keymap.get_default() for accel in accels: accel_keyval, accel_mod = Gtk.accelerator_parse(accel) if accel_keyval == 0 and accel_mod == 0: raise ValueError("Invalid accel: %s" % accel) # If the accel contains non default modifiers matching will # never work and since no one should use them, complain non_default = accel_mod & ~default_mod if non_default: print_w("Accelerator '%s' contains a non default modifier '%s'." % (accel, Gtk.accelerator_name(0, non_default) or "")) # event.state contains the real mod mask + the virtual one, while # we usually pass only virtual one as text. This adds the real one # so they match in the end. accel_mod = keymap.map_virtual_modifiers(accel_mod)[1] # Remove everything except default modifiers and compare if (accel_keyval, accel_mod) == (keyval, event.state & default_mod): return True return False
def _fetch_image(self, url): try: data = urlopen(url).read() except Exception as e: print_w("Couldn't read web image from %s (%s)" % (url, e)) return None try: loader = GdkPixbuf.PixbufLoader() except GLib.GError as e: print_w("Couldn't create GdkPixbuf (%s)" % e) else: loader.write(data) loader.close() print_d("Got web image from %s" % url) return loader.get_pixbuf()
def set_transient_for(self, parent): """Set a parent for the window. In case parent=None, fall back to the main window. """ is_toplevel = parent and parent.props.type == Gtk.WindowType.TOPLEVEL if parent is None or not is_toplevel: if parent: print_w("Not a toplevel window set for: %r" % self) from quodlibet import app parent = app.window super(Window, self).set_transient_for(parent)
def _sent(self, session, task, data): try: status = int(self.message.get_property('status-code')) if status >= 400: msg = 'HTTP {0} error in {1} request to {2}'.format( status, self.message.method, self._uri) print_w(msg) return self.emit('send-failure', Exception(msg)) self.istream = session.send_finish(task) print_d('Sent {1} request to {0}'.format(self._uri, self.message.method)) self.emit('sent', self.message) except GLib.GError as e: print_w('Failed sending request to {0}'.format(self._uri)) self.emit('send-failure', e)
def set_transient_for(self, parent): """Set a parent for the window. In case parent=None, fall back to the main window. """ is_toplevel = parent and parent.props.type == Gtk.WindowType.TOPLEVEL if parent is None or not is_toplevel: if parent: print_w("Not a toplevel window set for: %r" % self) from quodlibet import app parent = app.window super().set_transient_for(parent)
def MusicFile(filename): """Returns a AudioFile instance or None""" lower = filename.lower() for ext in _extensions: if lower.endswith(ext): try: return _infos[ext](filename) except: print_w("Error loading %r" % filename) util.print_exc() return else: print_w("Unknown file extension %r" % filename) return
def __send(self, urldata): if self.__stopped: return gatekeeper.wait() self.__done += len(urldata) basedata = urlencode({ "format": "xml", "client": APP_KEY, "user": get_api_key(), }) urldata = "&".join([basedata] + map(urlencode, urldata)) obj = cBytesIO() gzip.GzipFile(fileobj=obj, mode="wb").write(urldata) urldata = obj.getvalue() headers = { "Content-Encoding": "gzip", "Content-type": "application/x-www-form-urlencoded" } req = Request(self.URL, urldata, headers) error = None try: response = urlopen(req, timeout=self.TIMEOUT) except EnvironmentError as e: error = "urllib error: " + str(e) else: xml = response.read() try: dom = parseString(xml) except: error = "xml error" else: status = dom.getElementsByTagName("status") if not status or not status[0].childNodes or not \ status[0].childNodes[0].nodeValue == "ok": error = "response status error" if error: print_w("[fingerprint] Submission failed: " + error) # emit progress self.__idle(self.__progress_cb, float(self.__done) / len(self.__results))
def __send(self, urldata): if self.__stopped: return gatekeeper.wait() self.__done += len(urldata) basedata = urlencode({ "format": "xml", "client": APP_KEY, "user": get_api_key(), }) urldata = "&".join([basedata] + list(map(urlencode, urldata))) obj = BytesIO() gzip.GzipFile(fileobj=obj, mode="wb").write(urldata.encode()) urldata = obj.getvalue() headers = { "Content-Encoding": "gzip", "Content-type": "application/x-www-form-urlencoded" } req = Request(self.URL, urldata, headers) error = None try: response = urlopen(req, timeout=self.TIMEOUT) except EnvironmentError as e: error = "urllib error: " + str(e) else: xml = response.read() try: dom = parseString(xml) except: error = "xml error" else: status = dom.getElementsByTagName("status") if not status or not status[0].childNodes or not \ status[0].childNodes[0].nodeValue == "ok": error = "response status error" if error: print_w("[fingerprint] Submission failed: " + error) # emit progress self.__idle(self.__progress_cb, float(self.__done) / len(self.__results))
def plugin_songs(self, songs, launch=True) -> bool: # Check this is a launch, not a configure if self.chosen_site: url_pat = self.get_url_pattern(self.chosen_site) pat = Pattern(url_pat) # Remove Nones, and de-duplicate collection urls = set(filter(None, (website_for(pat, s) for s in songs))) if not urls: print_w("Couldn't build URLs using \"%s\"." "Check your pattern?" % url_pat) return False print_d("Got %d websites from %d songs" % (len(urls), len(songs))) if launch: for url in urls: website(url) return True
def _sent(self, session, task, data): try: status = int(self.message.get_property('status-code')) if status >= 400: msg = 'HTTP {0} error in {1} request to {2}'.format( status, self.message.method, self._uri) print_w(msg) return self.emit('send-failure', Exception(msg)) self.istream = session.send_finish(task) print_d('Got HTTP {code} on {method} request to {uri}.'.format( uri=self._uri, code=status, method=self.message.method)) self.emit('sent', self.message) except GLib.GError as e: print_w('Failed sending {method} request to {uri} ({err})'.format( method=self.message.method, uri=self._uri, err=e)) self.emit('send-failure', e)
def conclude(self, fails, reason): if fails: def format_occurrences(e): occurences = [(self.lang + ".po", e.linenum)] occurences += e.occurrences return ', '.join('%s:%s' % o for o in occurences) messages = [ '"%s" - "%s" (%s)' % (e.msgid, e.msgstr, format_occurrences(e)) for e in fails ] for message in messages: print_w(message) self.fail("One or more messages did not pass (%s).\n" "Please check the warning messages above." % reason)
def _callback(self, data): try: messages = list(fifo.split_message(data)) except ValueError: print_w("invalid message: %r" % data) return for command, path in messages: command = bytes2fsn(command, None) response = self._cmd_registry.handle_line(self._app, command) if path is not None: path = bytes2fsn(path, None) with open(path, "wb") as h: if response is not None: assert isinstance(response, fsnative) h.write(fsn2bytes(response, None))
def list(self, wlb): if self.__load_db() is None: return [] songs = [] orphaned = False for track in gpod.sw_get_tracks(self.__itdb): filename = gpod.itdb_filename_on_ipod(track) if filename: songs.append(IPodSong(track)) else: # Remove orphaned iTunesDB track orphaned = True print_w(_("Removing orphaned iPod track")) self.__remove_track(track) if orphaned: self.__save_db() self.__close_db() return songs
def received(request, ostream): ostream.close(None) bs = ostream.steal_as_bytes().get_data() if not try_decode: callback(message, bs, data) return # Otherwise try to decode data code = int(message.get_property('status-code')) if code >= 400: print_w("HTTP %d error received on %s" % (code, request._uri)) return ctype = message.get_property('response-headers').get_content_type() encoding = ctype[1].get('charset', 'utf-8') try: callback(message, bs.decode(encoding), data) except UnicodeDecodeError: callback(message, bs, data)