Пример #1
0
 def _group_add_service_and_commit(self, group, flags):
     print_d("name=%s, flags=%x, stype=%s, port=%d" %
             (self._real_name, flags, self.stype, self.port))
     group.AddService('(iiussssqaay)', AVAHI_IF_UNSPEC,
                      AvahiProtocol.UNSPEC, flags, self._real_name,
                      self.stype, '', '', self.port, [])
     group.Commit()
Пример #2
0
def _wrap_class(lib, version, base, ptr, prefix, methods):
    for method in methods:
        name, ret, args = method[:3]
        if len(method) > 3 and method[-1] != version:
            continue

        try:
            func = getattr(lib, prefix + name)
        except AttributeError:
            # don't fail on missing ones, just in case..
            print_d("missing libudev symbol: %r" % (prefix + name))
            continue

        func.argtypes = args
        func.restype = ret

        def add_self(f, check_null=False):
            def check(*args):
                # the first arg is the pointer to the struct, check for
                # null pointers before passing it...
                args[0].contents
                return f(*args)
            return check

        if args and args[0] == ptr:
            setattr(ptr, name, add_self(func))
        else:
            setattr(base, name, func)
Пример #3
0
    def add(self, func, *args, **kwargs):
        """Register a routine to run in GLib main loop.

        func should be a function that returns a Python iterator (e.g.
        generator) that provides values until it should stop being called.

        Optional Keyword Arguments:
        priority -- priority to run at (default GLib.PRIORITY_LOW)
        funcid -- mutex/removal identifier for this function
        timeout -- use timeout_add (with given timeout) instead of idle_add
                   (in milliseconds)

        Only one function with the same funcid can be running at once.
        Starting a new function with the same ID will stop the old one. If
        no funcid is given, the function itself is used. The funcid must
        be usable as a hash key.
        """

        funcid = kwargs.pop("funcid", func)
        if funcid in self.__routines:
            remove(funcid)

        priority = kwargs.pop("priority", GLib.PRIORITY_LOW)
        timeout = kwargs.pop("timeout", None)

        print_d("Added copool function %r with id %r" % (func, funcid))
        routine = _Routine(self, func, funcid, priority, timeout, args, kwargs)
        self.__routines[funcid] = routine
        routine.resume()
Пример #4
0
    def _create_waveform(self, song, points):
        # Close any existing pipeline to avoid leaks
        self._clean_pipeline()

        if not song.is_file:
            return

        command_template = """
        uridecodebin name=uridec
        ! audioconvert
        ! level name=audiolevel interval={} post-messages=true
        ! fakesink sync=false"""
        interval = int(song("~#length") * 1E9 / points)
        print_d("Computing data for each %.3f seconds" % (interval / 1E9))

        command = command_template.format(interval)
        pipeline = Gst.parse_launch(command)
        pipeline.get_by_name("uridec").set_property("uri", song("~uri"))

        bus = pipeline.get_bus()
        self._bus_id = bus.connect("message", self._on_bus_message)
        bus.add_signal_watch()

        pipeline.set_state(Gst.State.PLAYING)

        self._pipeline = pipeline
        self._new_rms_vals = []
Пример #5
0
def _wrap_class(lib, version, base, ptr, prefix, methods):
    for method in methods:
        name, ret, args = method[:3]
        if len(method) > 3 and method[-1] != version:
            continue

        try:
            func = getattr(lib, prefix + name)
        except AttributeError:
            # don't fail on missing ones, just in case..
            print_d("missing libudev symbol: %r" % (prefix + name))
            continue

        func.argtypes = args
        func.restype = ret

        def add_self(f, check_null=False):
            def check(*args):
                # the first arg is the pointer to the struct, check for
                # null pointers before passing it...
                args[0].contents
                return f(*args)
            return check

        if args and args[0] == ptr:
            setattr(ptr, name, add_self(func))
        else:
            setattr(base, name, func)
Пример #6
0
    def handle_line(self, app, line):
        """Parses a command line and executes the command.

        Can not fail.

        Args:
            app (Application)
            line (fsnative)
        Returns:
            fsnative or None
        """

        assert isinstance(line, fsnative)

        # only one arg supported atm
        parts = line.split(" ", 1)
        command = parts[0]
        args = parts[1:]

        print_d("command: %r(*%r)" % (command, args))

        try:
            return self.run(app, command, *args)
        except CommandError as e:
            print_e(e)
        except:
            util.print_exc()
Пример #7
0
    def run(self, app, name, *args):
        """Execute the command `name` passing args

        May raise CommandError
        """

        if name not in self._commands:
            raise CommandError("Unknown command %r" % name)

        cmd, argcount, optcount = self._commands[name]
        if len(args) < argcount:
            raise CommandError("Not enough arguments for %r" % name)
        if len(args) > argcount + optcount:
            raise CommandError("Too many arguments for %r" % name)

        print_d("Running %r with params %s " % (cmd.__name__, args))

        try:
            result = cmd(app, *args)
        except CommandError as e:
            raise CommandError("%s: %s" % (name, str(e)))
        else:
            if result is not None and not isinstance(result, fsnative):
                raise CommandError("%s: returned %r which is not fsnative" %
                                   (name, result))
            return result
Пример #8
0
    def __about_to_finish(self, playbin):
        print_d("About to finish (async)")

        try:
            uri = self._runner.call(self.__about_to_finish_sync,
                                    priority=GLib.PRIORITY_HIGH,
                                    timeout=0.5)
        except MainRunnerTimeoutError as e:
            # Due to some locks being held during this signal we can get
            # into a deadlock when a seek or state change event happens
            # in the mainloop before our function gets scheduled.
            # In this case abort and do nothing, which results
            # in a non-gapless transition.
            print_d("About to finish (async): %s" % e)
            return
        except MainRunnerAbortedError as e:
            print_d("About to finish (async): %s" % e)
            return
        except MainRunnerError:
            util.print_exc()
            return

        if uri is not None:
            print_d("About to finish (async): setting uri")
            playbin.set_property('uri', uri)
        print_d("About to finish (async): done")
Пример #9
0
    def _update(self, player):
        if player.info:
            # Position in ms, length in seconds
            position = player.get_position() / 1000.0
            length = player.info("~#length")
            remaining = length - position

            if length != 0:
                self._waveform_scale.set_position(position / length)
            else:
                print_d("Length reported as zero for %s" % player.info)
                self._waveform_scale.set_position(0)

            self._elapsed_label.set_time(position)
            self._remaining_label.set_time(remaining)
            self._remaining_label.set_disabled(not player.seekable)
            self._elapsed_label.set_disabled(not player.seekable)

            self.set_sensitive(player.seekable)
        else:
            self._waveform_scale.set_placeholder(True)
            self._remaining_label.set_disabled(True)
            self._elapsed_label.set_disabled(True)

            self.set_sensitive(player.seekable)

        self._waveform_scale.queue_draw()
Пример #10
0
    def _add_service(self):
        assert not self._group
        assert not self._group_id

        try:
            bus = dbus.SystemBus()
            server_obj = bus.get_object(self.DBUS_NAME, self.DBUS_PATH_SERVER)
            server = dbus.Interface(server_obj, self.DBUS_INTERFACE_SERVER)

            group_path = server.EntryGroupNew()
            group_obj = bus.get_object(self.DBUS_NAME, group_path)
            group = dbus.Interface(group_obj, self.DBUS_INTERFACE_ENTRY_GROUP)

            self._group_id = group.connect_to_signal(
                "StateChanged", self._group_state_change)
            flags = AvahiPublishFlags.NONE

            print_d("name=%s, flags=%x, stype=%s, port=%d" % (
                self._real_name, flags, self.stype, self.port))
            group.AddService(
                AVAHI_IF_UNSPEC, AvahiProtocol.UNSPEC,
                dbus.UInt32(flags), self._real_name, self.stype,
                dbus.String(), dbus.String(), dbus.UInt16(self.port), [])
            group.Commit()
            self._group = group
        except dbus.DBusException:
            self._remove_service()
Пример #11
0
    def plugin_on_song_started(self, song):
        if (song is None and config.get("memory", "order") != "onesong" and
            not app.player.paused):
            browser = app.window.browser

            if not browser.can_filter('album'):
                return

            albumlib = app.library.albums
            albumlib.load()

            if browser.can_filter_albums():
                keys = browser.list_albums()
                values = [albumlib[k] for k in keys]
            else:
                keys = set(browser.list("album"))
                values = [a for a in albumlib if a("album") in keys]

            if self.use_weights:
                # Select 3% of albums, or at least 3 albums
                nr_albums = int(min(len(values), max(0.03 * len(values), 3)))
                chosen_albums = random.sample(values, nr_albums)
                album_scores = sorted(self._score(chosen_albums))
                for score, album in album_scores:
                    print_d("%0.2f scored by %s" % (score, album("album")))
                album = max(album_scores)[1]
            else:
                album = random.choice(values)

            if album is not None:
                self.schedule_change(album)
Пример #12
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)
Пример #13
0
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)
Пример #14
0
 def failure(source, msg):
     name = source.__class__.__name__
     print_d("Didn't get cover from {0}: {1}".format(name, msg))
     source.disconnect_by_func(success)
     source.disconnect_by_func(failure)
     if not cancellable or not cancellable.is_cancelled():
         run()
Пример #15
0
    def _on_bus_message(self, bus, message):
        if message.type == Gst.MessageType.ERROR:
            error, debug = message.parse_error()
            print_d("Error received from element {name}: {error}".format(
                name=message.src.get_name(), error=error))
            print_d("Debugging information: {}".format(debug))
        elif message.type == Gst.MessageType.ELEMENT:
            structure = message.get_structure()
            if structure.get_name() == "level":
                rms_db = structure.get_value("rms")
                if rms_db:
                    # Calculate average of all channels (usually 2)
                    rms_db_avg = sum(rms_db) / len(rms_db)
                    # Normalize dB value to value between 0 and 1
                    rms = pow(10, (rms_db_avg / 20))
                    self._new_rms_vals.append(rms)
            else:
                print_w("Got unexpected message of type {}"
                        .format(message.type))
        elif message.type == Gst.MessageType.EOS:
            self._clean_pipeline()

            # Update the waveform with the new data
            self._rms_vals = self._new_rms_vals
            self._waveform_scale.reset(self._rms_vals)
            self._waveform_scale.set_placeholder(False)
            self._update_redraw_interval()

            # Clear temporary reference to the waveform data
            del self._new_rms_vals
Пример #16
0
 def success(source, result):
     name = source.__class__.__name__
     print_d('Successfully got cover from {0}'.format(name))
     source.disconnect_by_func(success)
     source.disconnect_by_func(failure)
     if not cancellable or not cancellable.is_cancelled():
         callback(True, result)
Пример #17
0
    def _create_waveform(self, song, points):
        # Close any existing pipelines to avoid warnings
        if hasattr(self, "_pipeline") and self._pipeline:
            self._pipeline.set_state(Gst.State.NULL)

        command_template = """
        filesrc name=fs
        ! decodebin ! audioconvert
        ! level name=audiolevel interval={} post-messages=true
        ! fakesink sync=false"""
        interval = int(song("~#length") * 1E9 / points)
        print_d("Computing data for each %.3f seconds" % (interval / 1E9))

        command = command_template.format(interval)
        pipeline = Gst.parse_launch(command)
        pipeline.get_by_name("fs").set_property("location", song("~filename"))

        bus = pipeline.get_bus()
        self._bus_id = bus.connect("message", self._on_bus_message)
        bus.add_signal_watch()

        pipeline.set_state(Gst.State.PLAYING)

        self._pipeline = pipeline
        self._rms_vals = []
Пример #18
0
    def _update(self, player):
        if player.info:
            # Position in ms, length in seconds
            position = player.get_position() / 1000.0
            length = player.info("~#length")
            remaining = length - position

            if length != 0:
                self._waveform_scale.set_position(position / length)
            else:
                print_d("Length reported as zero for %s" % player.info)
                self._waveform_scale.set_position(0)

            self._elapsed_label.set_time(position)
            self._remaining_label.set_time(remaining)
            self._remaining_label.set_disabled(not player.seekable)
            self._elapsed_label.set_disabled(not player.seekable)

            self.set_sensitive(player.seekable)
        else:
            self._waveform_scale.set_placeholder(True)
            self._remaining_label.set_disabled(True)
            self._elapsed_label.set_disabled(True)

            self.set_sensitive(player.seekable)

        self._waveform_scale.queue_draw()
Пример #19
0
    def _create_waveform(self, song, points):
        # Close any existing pipelines to avoid warnings
        if hasattr(self, "_pipeline") and self._pipeline:
            self._pipeline.set_state(Gst.State.NULL)
            self._clean_pipeline()

        command_template = """
        filesrc name=fs
        ! decodebin ! audioconvert
        ! level name=audiolevel interval={} post-messages=true
        ! fakesink sync=false"""
        interval = int(song("~#length") * 1E9 / points)
        print_d("Computing data for each %.3f seconds" % (interval / 1E9))

        command = command_template.format(interval)
        pipeline = Gst.parse_launch(command)
        pipeline.get_by_name("fs").set_property("location", song("~filename"))

        bus = pipeline.get_bus()
        self._bus_id = bus.connect("message", self._on_bus_message)
        bus.add_signal_watch()

        pipeline.set_state(Gst.State.PLAYING)

        self._pipeline = pipeline
        self._new_rms_vals = []
Пример #20
0
 def _remove_empty_dirs(self):
     """
     Delete all empty sub-directories from the given path.
     """
     for root, dirs, __ in os.walk(self.expanded_destination,
                                   topdown=False):
         for dirname in dirs:
             dir_path = os.path.realpath(os.path.join(root, dirname))
             if not os.listdir(dir_path):
                 entry = Entry(None)
                 entry.filename = dir_path
                 entry.tag = Entry.Tags.IN_PROGRESS_DELETE
                 iter_ = self.model.append(row=self._make_model_row(entry))
                 print_d(_('Removing "{}"').format(entry.filename))
                 self.c_songs_delete += 1
                 try:
                     os.rmdir(dir_path)
                 except Exception as ex:
                     entry.tag = Entry.Tags.RESULT_FAILURE + ': ' + str(ex)
                     self._update_model_value(iter_, 'tag', entry.tag)
                     print_exc()
                     self.c_files_failed += 1
                 else:
                     entry.tag = Entry.Tags.RESULT_SUCCESS
                     self._update_model_value(iter_, 'tag', entry.tag)
                     self.c_files_delete += 1
                 self._update_sync_summary()
Пример #21
0
 def _group_add_service_and_commit(self, group, flags):
     print_d("name=%s, flags=%x, stype=%s, port=%d" % (
         self._real_name, flags, self.stype, self.port))
     group.AddService('(iiussssqaay)',
          AVAHI_IF_UNSPEC, AvahiProtocol.UNSPEC, flags,
          self._real_name, self.stype, '', '', self.port, [])
     group.Commit()
Пример #22
0
    def _update_sync_summary(self):
        """
        Update the synchronization summary text field.
        """
        sync_summary_prefix = _('Synchronization has:') + self.summary_sep
        sync_summary = []

        if self.c_files_copy > 0 or self.c_files_skip > 0:
            text = []

            counter = self.c_files_copy
            text.append(
                ngettext('written {count}/{total} file',
                         'written {count}/{total} files',
                         counter).format(count=counter,
                                         total=self.c_songs_copy))

            if self.c_files_skip > 0:
                counter = self.c_files_skip
                text.append(
                    ngettext('(skipped {count} existing file)',
                             '(skipped {count} existing files)',
                             counter).format(count=counter))

            sync_summary.append(self.summary_sep.join(text))

        if self.c_files_dupes > 0:
            counter = self.c_files_dupes
            sync_summary.append(
                ngettext('skipped {count}/{total} duplicate file',
                         'skipped {count}/{total} duplicate files',
                         counter).format(count=counter,
                                         total=self.c_song_dupes))

        if self.c_files_delete > 0:
            counter = self.c_files_delete
            sync_summary.append(
                ngettext('deleted {count}/{total} file',
                         'deleted {count}/{total} files',
                         counter).format(count=counter,
                                         total=self.c_songs_delete))

        if self.c_files_failed > 0:
            counter = self.c_files_failed
            sync_summary.append(
                ngettext('failed to sync {count} file',
                         'failed to sync {count} files',
                         counter).format(count=counter))

        if self.c_files_skip_previous > 0:
            counter = self.c_files_skip_previous
            sync_summary.append(
                ngettext('skipped {count} file synchronized previously',
                         'skipped {count} files synchronized previously',
                         counter).format(count=counter))

        sync_summary_text = self.summary_sep_list.join(sync_summary)
        sync_summary_text = sync_summary_prefix + sync_summary_text
        self.status_progress.set_label(sync_summary_text)
        print_d(sync_summary_text)
Пример #23
0
def __show_quodlibet_uri(uri):
    if uri.path.startswith("/prefs/plugins/"):
        from .pluginwin import PluginWindow
        print_d("Showing plugin prefs resulting from URI (%s)" % (uri, ))
        return PluginWindow().move_to(uri.path[len("/prefs/plugins/"):])
    else:
        return False
Пример #24
0
    def handle_line(self, app, line):
        """Parses a command line and executes the command.

        Can not fail.

        Args:
            app (Application)
            line (fsnative)
        Returns:
            fsnative or None
        """

        assert isinstance(line, fsnative)

        # only one arg supported atm
        parts = line.split(" ", 1)
        command = parts[0]
        args = parts[1:]

        print_d("command: %r(*%r)" % (command, args))

        try:
            return self.run(app, command, *args)
        except CommandError as e:
            print_e(e)
        except:
            util.print_exc()
Пример #25
0
    def _create_waveform(self, song, points):
        # Close any existing pipeline to avoid leaks
        self._clean_pipeline()

        if not song.is_file:
            return

        command_template = """
        uridecodebin name=uridec
        ! audioconvert
        ! level name=audiolevel interval={} post-messages=true
        ! fakesink sync=false"""
        interval = int(song("~#length") * 1E9 / points)
        if not interval:
            return
        print_d("Computing data for each %.3f seconds" % (interval / 1E9))

        command = command_template.format(interval)
        pipeline = Gst.parse_launch(command)
        pipeline.get_by_name("uridec").set_property("uri",
                                                    uri2gsturi(song("~uri")))

        bus = pipeline.get_bus()
        self._bus_id = bus.connect("message", self._on_bus_message, points)
        bus.add_signal_watch()

        pipeline.set_state(Gst.State.PLAYING)

        self._pipeline = pipeline
        self._new_rms_vals = []
Пример #26
0
    def _add_service(self):
        assert not self._group
        assert not self._group_id

        try:
            bus = dbus.SystemBus()
            server_obj = bus.get_object(self.DBUS_NAME, self.DBUS_PATH_SERVER)
            server = dbus.Interface(server_obj, self.DBUS_INTERFACE_SERVER)

            group_path = server.EntryGroupNew()
            group_obj = bus.get_object(self.DBUS_NAME, group_path)
            group = dbus.Interface(group_obj, self.DBUS_INTERFACE_ENTRY_GROUP)

            self._group_id = group.connect_to_signal("StateChanged",
                                                     self._group_state_change)
            flags = AvahiPublishFlags.NONE

            print_d("name=%s, flags=%x, stype=%s, port=%d" %
                    (self._real_name, flags, self.stype, self.port))
            group.AddService(AVAHI_IF_UNSPEC, AvahiProtocol.UNSPEC,
                             dbus.UInt32(flags), self._real_name, self.stype,
                             dbus.String(), dbus.String(),
                             dbus.UInt16(self.port), [])
            group.Commit()
            self._group = group
        except dbus.DBusException:
            self._remove_service()
Пример #27
0
    def plugin_on_song_started(self, song):
        one_song = app.player_options.single
        if song is None and not one_song and not app.player.paused:
            browser = app.window.browser

            if self.disabled_for_browser(browser):
                return

            albumlib = app.library.albums
            albumlib.load()

            if browser.can_filter_albums():
                keys = browser.list_albums()
                values = [albumlib[k] for k in keys]
            else:
                keys = set(browser.list("album"))
                values = [a for a in albumlib if a("album") in keys]

            if self.use_weights:
                # Select 3% of albums, or at least 3 albums
                nr_albums = int(min(len(values), max(0.03 * len(values), 3)))
                chosen_albums = random.sample(values, nr_albums)
                album_scores = sorted(self._score(chosen_albums))
                for score, album in album_scores:
                    print_d("%0.2f scored by %s" % (score, album("album")))
                album = max(album_scores)[1]
            else:
                album = random.choice(values)

            if album is not None:
                self.schedule_change(album)
Пример #28
0
    def remove(self, funcid):
        """Stop a registered routine."""

        routine = self._get(funcid)
        routine.pause()
        del self.__routines[funcid]
        print_d("Removed copool function id %r" % funcid)
Пример #29
0
 def failure(source, msg):
     name = source.__class__.__name__
     print_d("Didn't get cover from {0}: {1}".format(name, msg))
     source.disconnect_by_func(success)
     source.disconnect_by_func(failure)
     if not cancellable or not cancellable.is_cancelled():
         run()
Пример #30
0
    def _start_preview(self, button):
        """
        Start the generation of export paths for all songs.

        :param button: The start preview button.
        """
        print_d(_('Starting synchronization preview'))
        self.running = True

        # Summary labels
        self.status_operation.set_label(
            _('Synchronization preview in progress.'))
        self.status_operation.set_visible(True)
        self.status_progress.set_visible(False)
        self.status_duplicates.set_visible(False)
        self.status_deletions.set_visible(False)

        # Change button visibility
        self.preview_start_button.set_visible(False)
        self.preview_stop_button.set_visible(True)

        self.c_songs_copy = self.c_song_dupes = self.c_songs_delete = 0
        if self._run_preview() is None:
            return

        self._stop_preview()
        self.sync_start_button.set_sensitive(True)
        print_d(_('Finished synchronization preview'))
Пример #31
0
    def _start_sync(self, button):
        """
        Start the song synchronization.

        :param button: The start sync button.
        """
        # Check sort column
        sort_columns = [
            c.get_title() for c in self.details_tree.get_columns()
            if c.get_sort_indicator()
        ]
        if 'Status' in sort_columns:
            self._show_sync_error(
                _('Unable to sync'),
                _('Cannot start synchronization while '
                  'sorting by <b>Status</b>.'))
            return

        print_d(_('Starting song synchronization'))
        self.running = True

        # Summary labels
        self.status_operation.set_label(_('Synchronization in progress.'))
        self.status_duplicates.set_visible(False)
        self.status_deletions.set_visible(False)

        # Change button visibility
        self.sync_start_button.set_visible(False)
        self.sync_stop_button.set_visible(True)

        if not self._run_sync():
            return

        self._stop_sync()
        print_d(_('Finished song synchronization'))
Пример #32
0
 def success(source, result):
     name = source.__class__.__name__
     print_d('Successfully got cover from {0}'.format(name))
     source.disconnect_by_func(success)
     source.disconnect_by_func(failure)
     if not cancellable or not cancellable.is_cancelled():
         callback(True, result)
Пример #33
0
    def _get_songs_from_queries(self):
        """
        Build a list of songs to be synchronized, filtered using the
        selected saved searches.

        :return: A list of the selected songs.
        """
        enabled_queries = []
        for query_name, query in self.queries.items():
            query_config = self.CONFIG_QUERY_PREFIX + query_name
            if self.config_get_bool(query_config):
                enabled_queries.append(query)

        if not enabled_queries:
            self._show_sync_error(
                _('No saved searches selected'),
                _('Please select at least one saved search.'))
            return []

        selected_songs = []
        for song in app.library.itervalues():
            if any(query.search(song) for query in enabled_queries):
                selected_songs.append(song)

        if not selected_songs:
            self._show_sync_error(_('No songs in the selected saved searches'),
                                  _('All selected saved searches are empty.'))
            return []

        print_d(_('Found {} songs to synchronize').format(len(selected_songs)))
        return selected_songs
Пример #34
0
    def _on_bus_message(self, bus, message):
        if message.type == Gst.MessageType.ERROR:
            error, debug = message.parse_error()
            print_d("Error received from element {name}: {error}".format(
                name=message.src.get_name(), error=error))
            print_d("Debugging information: {}".format(debug))
        elif message.type == Gst.MessageType.ELEMENT:
            structure = message.get_structure()
            if structure.get_name() == "level":
                rms_db = structure.get_value("rms")
                # Calculate average of all channels (usually 2)
                rms_db_avg = sum(rms_db) / len(rms_db)
                # Normalize dB value to value between 0 and 1
                rms = pow(10, (rms_db_avg / 20))
                self._new_rms_vals.append(rms)
            else:
                print_w("Got unexpected message of type {}".format(
                    message.type))
        elif message.type == Gst.MessageType.EOS:
            self._clean_pipeline()

            # Update the waveform with the new data
            self._rms_vals = self._new_rms_vals
            self._waveform_scale.reset(self._rms_vals)
            self._waveform_scale.set_placeholder(False)
            self._update_redraw_interval()

            # Clear temporary reference to the waveform data
            del self._new_rms_vals
Пример #35
0
    def run(self, app, name, *args):
        """Execute the command `name` passing args

        May raise CommandError
        """

        if name not in self._commands:
            raise CommandError("Unknown command %r" % name)

        cmd, argcount, optcount = self._commands[name]
        if len(args) < argcount:
            raise CommandError("Not enough arguments for %r" % name)
        if len(args) > argcount + optcount:
            raise CommandError("Too many arguments for %r" % name)

        print_d("Running %r with params %s " % (cmd.__name__, args))

        try:
            result = cmd(app, *args)
        except CommandError as e:
            raise CommandError("%s: %s" % (name, str(e)))
        else:
            if result is not None and not isinstance(result, fsnative):
                raise CommandError(
                    "%s: returned %r which is not fsnative" % (name, result))
            return result
Пример #36
0
    def __about_to_finish_sync(self):
        """Returns a tuple (ok, next_song). ok is True if the next song
        should be set.
        """

        print_d("About to finish (sync)")

        # Chained oggs falsely trigger a gapless transition.
        # At least for radio streams we can safely ignore it because
        # transitions don't occur there.
        # https://github.com/quodlibet/quodlibet/issues/1454
        # https://bugzilla.gnome.org/show_bug.cgi?id=695474
        if self.song.multisong:
            print_d("multisong: ignore about to finish")
            return (False, None)

        if config.getboolean("player", "gst_disable_gapless"):
            print_d("Gapless disabled")
            return (False, None)

        # this can trigger twice, see issue 987
        if self._in_gapless_transition:
            return (False, None)
        self._in_gapless_transition = True

        print_d("Select next song in mainloop..")
        self._source.next_ended()
        print_d("..done.")

        return (True, self._source.current)
Пример #37
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 = 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)
Пример #38
0
    def go_to(self, song_or_iter, explicit=False, source=None):
        """Switch the current active song to song.

        song can be an Gtk.TreeIter or AudioFile.
        explicit should be True of the action comes from the user.
        source should be this model or None.
        """

        assert source is None or source is self

        print_d("Told to go to %r" % getattr(song_or_iter, "key",
                                             song_or_iter))

        iter_ = None
        if isinstance(song_or_iter, Gtk.TreeIter):
            iter_ = song_or_iter
        elif song_or_iter is not None:
            # We were told to go to a song that was valid but couldn't find it.
            # Set it as last current so it gets set current when we find it in
            # the future.
            self.last_current = song_or_iter
            iter_ = self.find(song_or_iter)

        if explicit:
            self.current_iter = self.order.set_explicit(self, iter_)
        else:
            self.current_iter = self.order.set_implicit(self, iter_)

        return self.current_iter
Пример #39
0
    def __about_to_finish_sync(self):
        """Returns the next song uri to play or None"""

        print_d("About to finish (sync)")

        # Chained oggs falsely trigger a gapless transition.
        # At least for radio streams we can safely ignore it because
        # transitions don't occur there.
        # https://github.com/quodlibet/quodlibet/issues/1454
        # https://bugzilla.gnome.org/show_bug.cgi?id=695474
        if self.song.multisong:
            print_d("multisong: ignore about to finish")
            return

        # mod + gapless deadlocks
        # https://github.com/quodlibet/quodlibet/issues/2780
        if isinstance(self.song, ModFile):
            return

        if config.getboolean("player", "gst_disable_gapless"):
            print_d("Gapless disabled")
            return

        # this can trigger twice, see issue 987
        if self._in_gapless_transition:
            return
        self._in_gapless_transition = True

        print_d("Select next song in mainloop..")
        self._source.next_ended()
        print_d("..done.")

        song = self._source.current
        if song is not None:
            return song("~uri")
Пример #40
0
    def __about_to_finish(self, playbin):
        print_d("About to finish (async)")

        try:
            uri = self._runner.call(self.__about_to_finish_sync,
                                    priority=GLib.PRIORITY_HIGH,
                                    timeout=0.5)
        except MainRunnerTimeoutError as e:
            # Due to some locks being held during this signal we can get
            # into a deadlock when a seek or state change event happens
            # in the mainloop before our function gets scheduled.
            # In this case abort and do nothing, which results
            # in a non-gapless transition.
            print_d("About to finish (async): %s" % e)
            return
        except MainRunnerAbortedError as e:
            print_d("About to finish (async): %s" % e)
            return
        except MainRunnerError:
            util.print_exc()
            return

        if uri is not None:
            print_d("About to finish (async): setting uri")
            playbin.set_property('uri', uri)
        print_d("About to finish (async): done")
Пример #41
0
    def go_to(self, song_or_iter, explicit=False, source=None):
        """Switch the current active song to song.

        song can be an Gtk.TreeIter or AudioFile.
        explicit should be True of the action comes from the user.
        source should be this model or None.
        """

        assert source is None or source is self

        print_d("Told to go to %r" %
                getattr(song_or_iter, "key", song_or_iter))

        iter_ = None
        if isinstance(song_or_iter, Gtk.TreeIter):
            iter_ = song_or_iter
        elif song_or_iter is not None:
            # We were told to go to a song that was valid but couldn't find it.
            # Set it as last current so it gets set current when we find it in
            # the future.
            self.last_current = song_or_iter
            iter_ = self.find(song_or_iter)

        if explicit:
            self.current_iter = self.order.set_explicit(self, iter_)
        else:
            self.current_iter = self.order.set_implicit(self, iter_)

        return self.current_iter
Пример #42
0
    def __about_to_finish_sync(self):
        """Returns the next song uri to play or None"""

        print_d("About to finish (sync)")

        # Chained oggs falsely trigger a gapless transition.
        # At least for radio streams we can safely ignore it because
        # transitions don't occur there.
        # https://github.com/quodlibet/quodlibet/issues/1454
        # https://bugzilla.gnome.org/show_bug.cgi?id=695474
        if self.song.multisong:
            print_d("multisong: ignore about to finish")
            return

        # mod + gapless deadlocks
        # https://github.com/quodlibet/quodlibet/issues/2780
        if isinstance(self.song, ModFile):
            return

        if config.getboolean("player", "gst_disable_gapless"):
            print_d("Gapless disabled")
            return

        # this can trigger twice, see issue 987
        if self._in_gapless_transition:
            return
        self._in_gapless_transition = True

        print_d("Select next song in mainloop..")
        self._source.next_ended()
        print_d("..done.")

        song = self._source.current
        if song is not None:
            return song("~uri")
Пример #43
0
    def __destroy_pipeline(self):
        print_d("Destroying Gstreamer pipeline")
        self._remove_plugin_elements()

        if self.__bus_id:
            bus = self.bin.get_bus()
            bus.disconnect(self.__bus_id)
            bus.remove_signal_watch()
            self.__bus_id = None

        if self.__atf_id:
            self.bin.disconnect(self.__atf_id)
            self.__atf_id = None

        if self._seeker is not None:
            self._seeker.destroy()
            self._seeker = None
            self.notify("seekable")

        if self.bin:
            self.bin.set_state(Gst.State.NULL)
            self.bin.get_state(timeout=STATE_CHANGE_TIMEOUT)
            # BufferingWrapper cleanup
            self.bin.destroy()
            self.bin = None

        self._in_gapless_transition = False

        self._ext_vol_element = None
        self._int_vol_element = None
        self._ext_mute_element = None
        self._eq_element = None
Пример #44
0
 def send(self):
     """
     Send the request and receive HTTP headers. Some of the body might
     get downloaded too.
     """
     print_d('Sending {1} request to {0}'.format(self._uri,
                                                 self.message.method))
     session.send_async(self.message, self.cancellable, self._sent, None)
Пример #45
0
 def _get_saved_searches(self):
     filename = self.PATTERNS_FILE + ".saved"
     self._url_pats = StandaloneEditor.load_values(filename)
     # Failing all else...
     if not len(self._url_pats):
         print_d("No saved searches found in %s. Using defaults." %
                 filename)
         self._url_pats = self.DEFAULT_URL_PATS
Пример #46
0
 def send(self):
     """
     Send the request and receive HTTP headers. Some of the body might
     get downloaded too.
     """
     print_d('Sending {1} request to {0}'.format(self._uri,
                                                 self.message.method))
     session.send_async(self.message, self.cancellable, self._sent, None)
Пример #47
0
 def _get_saved_searches(self):
     filename = self.PATTERNS_FILE + ".saved"
     self._url_pats = StandaloneEditor.load_values(filename)
     # Failing all else...
     if not len(self._url_pats):
         print_d("No saved searches found in %s. Using defaults." %
                 filename)
         self._url_pats = self.DEFAULT_URL_PATS
Пример #48
0
 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))
Пример #49
0
 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)
Пример #50
0
 def _make_unique(entry, old_duplicate):
     """ Mark the given entry as a unique file. """
     print_d(entry.filename)
     entry.tag = Entry.Tags.PENDING_COPY
     self.c_songs_copy += 1
     if old_duplicate:
         self.c_song_dupes -= 1
     _update_warnings()
Пример #51
0
 def _make_duplicate(entry, old_unique):
     """ Mark the given entry as a duplicate. """
     print_d(entry.filename)
     entry.tag = Entry.Tags.SKIP_DUPLICATE
     self.c_song_dupes += 1
     if old_unique:
         self.c_songs_copy -= 1
     _update_warnings()
Пример #52
0
 def _sent(self, message):
     if self.cancellable.is_cancelled():
         return self.emit('send-failure', Exception('Cancelled'))
     if 300 <= message.get_property('status-code') < 400:
         return # redirection, wait for another emission of got-headers
     self.istream = Gio.MemoryInputStream.new()
     self.message.connect('got-chunk', self._chunk)
     print_d('Sent request to {0}'.format(self._uri))
     self.emit('sent', self.message)
Пример #53
0
 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)
Пример #54
0
def _repeat(app, value):
    po = app.player_options
    if value in ["0", "off"]:
        po.repeat = False
    elif value in ["1", "on"]:
        print_d("Enabling repeat")
        po.repeat = True
    elif value in ["t", "toggle"]:
        po.repeat = not po.repeat
Пример #55
0
def _repeat(app, value):
    po = app.player_options
    if value in ["0", "off"]:
        po.repeat = False
    elif value in ["1", "on"]:
        print_d("Enabling repeat")
        po.repeat = True
    elif value in ["t", "toggle"]:
        po.repeat = not po.repeat
Пример #56
0
 def update_pattern(cls, pattern_text):
     """Saves `pattern_text` to disk (and caches)"""
     if pattern_text == cls.__pattern_text:
         return
     cls.__pattern_text = pattern_text
     cls.__refresh_pattern()
     cls.refresh_all()
     print_d("Saving pattern for %s to %s" % (cls.__name__, cls._PATTERN_FN))
     with open(cls._PATTERN_FN, "w") as f:
         f.write(pattern_text + "\n")
Пример #57
0
 def test_looks_in_path(self):
     path_dirs = set(os.environ['PATH'].split(os.path.pathsep))
     dirs = path_dirs - set(os.defpath.split(os.path.pathsep))
     for d in dirs:
         if os.path.isdir(d):
             for file_path in os.listdir(d):
                 if os.access(os.path.join(d, file_path), os.X_OK):
                     print_d("Testing %s" % file_path)
                     self.failUnless(iscommand(file_path))
                     return
Пример #58
0
    def _do_upgrade(self, func):
        assert self._loaded_version is not None
        assert self._version is not None

        old_version = self._loaded_version
        new_version = self._version
        if old_version != new_version:
            print_d("Config upgrade: %d->%d (%r)" % (
                old_version, new_version, func))
            func(self, old_version, new_version)