예제 #1
0
파일: player.py 프로젝트: zsau/quodlibet
    def __set_inhibit_play(self, inhibit):
        """Change the inhibit state"""

        if inhibit == self._inhibit_play:
            return
        self._inhibit_play = inhibit

        # task management
        if inhibit:
            if not self._task:
                def stop_buf(*args):
                    self._player.paused = True

                self._task = Task(_("Stream"), _("Buffering"), stop=stop_buf)
        elif self._task:
            self._task.finish()
            self._task = None

        # state management
        if inhibit:
            # save the current state
            status, state, pending = self.bin.get_state(
                timeout=STATE_CHANGE_TIMEOUT)
            if status == Gst.StateChangeReturn.SUCCESS and \
                    state == Gst.State.PLAYING:
                self._wanted_state = state
            else:
                # no idea, at least don't play
                self._wanted_state = Gst.State.PAUSED

            self.bin.set_state(Gst.State.PAUSED)
        else:
            # restore the old state
            self.bin.set_state(self._wanted_state)
            self._wanted_state = None
예제 #2
0
    def rebuild(self, paths, force=False, exclude=[], cofuncid=None):
        """Reload or remove songs if they have changed or been deleted.

        This generator rebuilds the library over the course of iteration.

        Any paths given will be scanned for new files, using the 'scan'
        method.

        Only items present in the library when the rebuild is started
        will be checked.

        If this function is copooled, set "cofuncid" to enable pause/stop
        buttons in the UI.
        """

        print_d("Rebuilding, force is %s." % force, self)

        task = Task(_("Library"), _("Checking mount points"))
        if cofuncid:
            task.copool(cofuncid)
        for i, (point, items) in task.list(enumerate(self._masked.items())):
            if os.path.ismount(point):
                self._contents.update(items)
                del(self._masked[point])
                self.emit('added', items.values())
                yield True

        task = Task(_("Library"), _("Scanning library"))
        if cofuncid:
            task.copool(cofuncid)
        changed, removed = set(), set()
        for i, (key, item) in task.list(enumerate(sorted(self.items()))):
            if key in self._contents and force or not item.valid():
                self.reload(item, changed, removed)
                # These numbers are pretty empirical. We should yield more
            # often than we emit signals; that way the main loop stays
            # interactive and doesn't get bogged down in updates.
            if len(changed) > 100:
                self.emit('changed', changed)
                changed = set()
            if len(removed) > 100:
                self.emit('removed', removed)
                removed = set()
            if len(changed) > 5 or i % 100 == 0:
                yield True
        print_d("Removing %d, changing %d." % (len(removed), len(changed)),
                self)
        if removed:
            self.emit('removed', removed)
        if changed:
            self.emit('changed', changed)

        for value in self.scan(paths, exclude, cofuncid):
            yield value
예제 #3
0
def download_taglist(callback, cofuncid, step=1024 * 10):
    """Generator for loading the bz2 compressed tag list.

    Calls callback with the decompressed data or None in case of
    an error."""

    with Task(_("Internet Radio"), _("Downloading station list")) as task:
        if cofuncid:
            task.copool(cofuncid)

        try:
            response = urlopen(STATION_LIST_URL)
        except EnvironmentError:
            GLib.idle_add(callback, None)
            return

        try:
            size = int(response.info().get("content-length", 0))
        except ValueError:
            size = 0

        decomp = bz2.BZ2Decompressor()

        data = b""
        temp = b""
        read = 0
        while temp or not data:
            read += len(temp)

            if size:
                task.update(float(read) / size)
            else:
                task.pulse()
            yield True

            try:
                data += decomp.decompress(temp)
                temp = response.read(step)
            except (IOError, EOFError):
                data = None
                break
        response.close()

        yield True

        stations = None
        if data:
            stations = parse_taglist(data)

        GLib.idle_add(callback, stations)
예제 #4
0
    def plugin_playlist(self, playlist):
        pattern_text = CONFIG.default_pattern
        dialog = ExportToFolderDialog(self.plugin_window, pattern_text)
        if dialog.run() == Gtk.ResponseType.OK:
            directory = dialog.directory_chooser.get_filename()
            pattern = FileFromPattern(dialog.pattern_entry.get_text())

            task = Task("Export", _("Export Playlist to Folder"),
                        stop=self.__cancel_copy)
            copool.add(self.__copy_songs, task,
                       playlist.songs, directory, pattern,
                       funcid="export-playlist-folder")

        dialog.destroy()
예제 #5
0
 def test_multiple_tasks(self):
     self.assertEquals(self.c.active_tasks, [])
     self.assertNotEqual(self.c.source, "")
     t1 = Task("src", "desc", controller = self.c)
     self.assertEquals(self.c.source, "src")
     self.assertEquals(self.c.active_tasks, [t1])
     t1.update(0.5)
     self.assertEquals(self.c.frac, 0.5)
     t2 = Task("src2", "desc2", controller = self.c)
     self.assertEquals(self.c.source, _("Active tasks"))
     self.assertEquals(self.c.frac, 0.25)
     Task("src3", "desc3", controller = self.c, known_length=False)
     self.assertAlmostEqual(self.c.frac, 0.5/3)
     t1.finish()
     t2.finish()
     self.assertEquals(self.c.desc, "desc3")
     self.assertEquals(self.c.frac, None)
예제 #6
0
파일: player.py 프로젝트: yaoml/quodlibet
    def __set_inhibit_play(self, inhibit):
        """Change the inhibit state"""

        if inhibit == self._inhibit_play:
            return
        self._inhibit_play = inhibit

        # task management
        if inhibit:
            if not self._task:

                def stop_buf(*args):
                    self._player.paused = True

                self._task = Task(_("Stream"), _("Buffering"), stop=stop_buf)
        elif self._task:
            self._task.finish()
            self._task = None

        # state management
        if inhibit:
            # save the current state
            status, state, pending = self.bin.get_state(
                timeout=STATE_CHANGE_TIMEOUT)
            if status == Gst.StateChangeReturn.SUCCESS and \
                    state == Gst.State.PLAYING:
                self._wanted_state = state
            else:
                # no idea, at least don't play
                self._wanted_state = Gst.State.PAUSED

            self.bin.set_state(Gst.State.PAUSED)
        else:
            # restore the old state
            self.bin.set_state(self._wanted_state)
            self._wanted_state = None
예제 #7
0
 def plugin_playlist(self, playlist):
     self.init_server()
     if not self.server.is_connected:
         qltk.ErrorMessage(
             None,
             _("Error finding Squeezebox server"),
             _("Error finding %s. Please check settings") %
             self.server.config
         ).run()
     else:
         name = self.__get_playlist_name(name=playlist.name)
         if name:
             task = Task("Squeezebox", _("Export to Squeezebox playlist"),
                         stop=self.__cancel_add)
             copool.add(self.__add_songs, task, playlist.songs, name,
                        funcid="squeezebox-playlist-save")
예제 #8
0
    def _resume_after_delay(delay, refresh_rate=20):
        if delay <= 0:
            return
        app.player.paused = True
        delay_timer = GLib.timeout_add(1000 * delay, app.player.play)
        task = Task(_("Shuffle by Grouping"),
                    _("Waiting to start new group…"),
                    stop=lambda: GLib.source_remove(delay_timer))

        def countdown():
            for i in range(int(refresh_rate * delay)):
                task.update(i / (refresh_rate * delay))
                yield True
            task.finish()
            yield False
        GLib.timeout_add(1000 / refresh_rate, next, countdown())
예제 #9
0
def _get_stations_from(uri: str,
                       on_done: Callable[[Iterable[IRFile], str], None])\
        -> None:
    """Fetches the URI content and extracts IRFiles
       Called from thread - so no direct GTK+ interaction
       :param uri: URI of station
       :param on_done: a callback taking files when done (or none if errored)
       """

    with Task(_("Internet Radio"), _("Add stations")) as task:
        irfs: Collection[IRFile] = []
        GLib.idle_add(task.pulse)
        if (uri.lower().endswith(".pls")
                or uri.lower().endswith(".m3u")
                or uri.lower().endswith(".m3u8")):
            if not re.match('^([^/:]+)://', uri):
                # Assume HTTP if no protocol given. See #2731
                uri = 'http://' + uri
                print_d("Assuming http: %s" % uri)

            # Error handling outside
            sock = None
            GLib.idle_add(task.pulse)
            _fn, ext = splitext(uri.lower())
            try:
                sock = urlopen(uri, timeout=6)
                if ext == ".pls":
                    irfs = parse_pls(sock)
                elif ext in (".m3u", ".m3u8"):
                    irfs = parse_m3u(sock)
                GLib.idle_add(task.pulse)
            except IOError as e:
                print_e(f"Couldn't download from {uri} ({e})")
            finally:
                if sock:
                    sock.close()
        else:
            try:
                irfs = [IRFile(uri)]
            except ValueError as e:
                print_e("Can't add URI %s" % uri, e)
    on_done(irfs, uri)
예제 #10
0
 def watching_producer():
     # TODO: integrate this better with scanning.
     for fullpath in paths:
         desc = _("Adding watches for %s") % (fsn2text(unexpand(fullpath)))
         with Task(_("Library"), desc) as task:
             normalised = Path(normalize_path(fullpath, True)).expanduser()
             if any(Path(exclude) in normalised.parents
                    for exclude in exclude_dirs):
                 continue
             unpulsed = 0
             self.monitor_dir(normalised)
             for path, dirs, files in os.walk(normalised):
                 normalised = Path(normalize_path(path, True))
                 for d in dirs:
                     self.monitor_dir(normalised / d)
                 unpulsed += len(dirs)
                 if unpulsed > 50:
                     task.pulse()
                     unpulsed = 0
                 yield
예제 #11
0
파일: file.py 프로젝트: tralph3/quodlibet
 def remove_roots(self, old_roots: Iterable[str]) -> Generator[None, None, None]:
     """Remove library roots (scandirs) entirely, and all their songs"""
     old_paths = [Path(normalize_path(root, canonicalise=True)).expanduser()
                  for root in old_roots]
     total = len(self)
     removed = set()
     print_d(f"Removing library roots {old_roots} from {self._name} library")
     yield
     with Task(_("Library"), _("Removing library files")) as task:
         for i, song in enumerate(list(self.values())):
             task.update(i / total)
             key = normalize_path(song.key)
             song_path = Path(key)
             if any(path in song_path.parents for path in old_paths):
                 removed.add(song)
             if not i % 100:
                 yield
     if removed:
         self.remove(removed)
     else:
         print_d(f"No tracks in {old_roots} to remove from {self._name}")
예제 #12
0
파일: library.py 프로젝트: faubi/quodlibet
def emit_signal(songs, signal="changed", block_size=50, name=None,
                cofuncid=None):
    """
    A generator that signals `signal` on the library
    in blocks of `block_size`. Useful for copools.
    """
    i = 0
    with Task(_("Library"), name or signal) as task:
        if cofuncid:
            task.copool(cofuncid)
        total = len(songs)
        while i < total:
            more = songs[i:i + block_size]
            if not more:
                return
            if 0 == ((i / block_size) % 10):
                print_d("Signalling '%s' (%d/%d songs)"
                        % (signal, i, total))
            task.update(float(i) / total)
            app.library.emit(signal, more)
            i += block_size
            yield
예제 #13
0
 def scan(self, paths, exclude=[], cofuncid=None):
     added = []
     exclude = [expanduser(path) for path in exclude if path]
     for fullpath in paths:
         print_d("Scanning %r." % fullpath, self)
         desc = _("Scanning %s") % (unexpand(fsdecode(fullpath)))
         with Task(_("Library"), desc) as task:
             if cofuncid:
                 task.copool(cofuncid)
             fullpath = expanduser(fullpath)
             if filter(fullpath.startswith, exclude):
                 continue
             for path, dnames, fnames in os.walk(util.fsnative(fullpath)):
                 for filename in fnames:
                     fullfilename = os.path.join(path, filename)
                     if filter(fullfilename.startswith, exclude):
                         continue
                     if fullfilename not in self._contents:
                         fullfilename = os.path.realpath(fullfilename)
                         # skip unknown file extensions
                         if not formats.filter(fullfilename):
                             continue
                         if filter(fullfilename.startswith, exclude):
                             continue
                         if fullfilename not in self._contents:
                             item = self.add_filename(fullfilename, False)
                             if item is not None:
                                 added.append(item)
                                 if len(added) > 20:
                                     self.add(added)
                                     added = []
                                     task.pulse()
                                     yield True
                 if added:
                     self.add(added)
                     added = []
                     task.pulse()
                     yield True
예제 #14
0
    def __add_songs(self, task: Task, songs: Collection[AudioFile],
                    spl: DidlPlaylistContainer):
        """Generator for copool to add songs to the temp playlist"""
        assert self.device
        task_total = float(len(songs))
        print_d("Adding %d song(s) to Sonos playlist. "
                "This might take a while..." % task_total)
        for i, song in enumerate(songs):
            if self.__cancel:
                print_d("Cancelled Sonos export")
                return
            lib = self.device.music_library

            # Exact title gets the best results it seems; some problems with ’
            search_term = song("title")
            assert search_term
            results = lib.get_tracks(search_term=search_term,
                                     max_items=self.MAX_RESULTS_PER_SEARCH)
            yield
            total = len(results)
            if total == 1:
                track = results[0]
            elif total > 1:
                desc = song("~~people~album~title")
                candidates = [(self._score(t, song), t) for t in results]
                in_order = sorted(candidates, reverse=True, key=lambda x: x[0])
                track = in_order[0][1]
                print_d(f"From {len(results)} choice(s) for {desc!r}, "
                        f"chose {self.uri_for(track)}")
            else:
                print_w("No results for \"%s\"" % search_term)
                track = None
            if track:
                try:
                    self.device.add_item_to_sonos_playlist(track, spl)
                except SoCoException as e:
                    print_w(f"Couldn't add {track} ({e}, skipping")
            task.update(float(i) / task_total)
            yield
        task.update((task_total - 2) / task_total)
        yield
        task.finish()
        print_d(f"Finished export to {spl.title!r}")
예제 #15
0
 def __init__(self, songs: Collection[AudioFile], task=None) -> None:
     super().__init__()
     self.songs = songs
     self.successful: Set[AudioFile] = set()
     self.failed: Set[AudioFile] = set()
     self.task = task or Task(_("Browser"), _("Downloading files"))
예제 #16
0
파일: player.py 프로젝트: zsau/quodlibet
class BufferingWrapper(object):
    """A wrapper for a Gst.Element (usually GstPlayBin) which pauses the
    elmement in case buffering is needed, but hides the fact that it does.

    Probably not perfect...

    You have to call destroy() before it gets gc'd
    """

    def __init__(self, bin_, player):
        """
        bin_ -- the GstPlaybin instance to wrap
        player -- the GStreamerPlayer instance used
                  for aborting the buffer process
        """

        self.bin = bin_
        self._wanted_state = None
        self._task = None
        self._inhibit_play = False
        self._player = player

        bus = self.bin.get_bus()
        bus.add_signal_watch()
        self.__bus_id = bus.connect('message', self.__message)

    def __message(self, bus, message):
        if message.type == Gst.MessageType.BUFFERING:
            percent = message.parse_buffering()
            self.__update_buffering(percent)

    def __getattr__(self, name):
        return getattr(self.bin, name)

    def __update_buffering(self, percent):
        """Call this with buffer percent values from the bus"""

        if self._task:
            self._task.update(percent / 100.0)

        self.__set_inhibit_play(percent < 100)

    def __set_inhibit_play(self, inhibit):
        """Change the inhibit state"""

        if inhibit == self._inhibit_play:
            return
        self._inhibit_play = inhibit

        # task management
        if inhibit:
            if not self._task:
                def stop_buf(*args):
                    self._player.paused = True

                self._task = Task(_("Stream"), _("Buffering"), stop=stop_buf)
        elif self._task:
            self._task.finish()
            self._task = None

        # state management
        if inhibit:
            # save the current state
            status, state, pending = self.bin.get_state(
                timeout=STATE_CHANGE_TIMEOUT)
            if status == Gst.StateChangeReturn.SUCCESS and \
                    state == Gst.State.PLAYING:
                self._wanted_state = state
            else:
                # no idea, at least don't play
                self._wanted_state = Gst.State.PAUSED

            self.bin.set_state(Gst.State.PAUSED)
        else:
            # restore the old state
            self.bin.set_state(self._wanted_state)
            self._wanted_state = None

    def set_state(self, state):
        if self._inhibit_play:
            # PLAYING, PAUSED change the state for after buffering is finished,
            # everything else aborts buffering
            if state not in (Gst.State.PLAYING, Gst.State.PAUSED):
                # abort
                self.__set_inhibit_play(False)
                self.bin.set_state(state)
                return
            self._wanted_state = state
        else:
            self.bin.set_state(state)

    def get_state(self, *args, **kwargs):
        # get_state also is a barrier (seek/positioning),
        # so call every time but ignore the result in the inhibit case
        res = self.bin.get_state(*args, **kwargs)
        if self._inhibit_play:
            return (Gst.StateChangeReturn.SUCCESS,
                    self._wanted_state, Gst.State.VOID_PENDING)
        return res

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

        self.__set_inhibit_play(False)
        self.bin = None
예제 #17
0
파일: player.py 프로젝트: yaoml/quodlibet
class BufferingWrapper(object):
    """A wrapper for a Gst.Element (usually GstPlayBin) which pauses the
    elmement in case buffering is needed, but hides the fact that it does.

    Probably not perfect...

    You have to call destroy() before it gets gc'd
    """
    def __init__(self, bin_, player):
        """
        bin_ -- the GstPlaybin instance to wrap
        player -- the GStreamerPlayer instance used
                  for aborting the buffer process
        """

        self.bin = bin_
        self._wanted_state = None
        self._task = None
        self._inhibit_play = False
        self._player = player

        bus = self.bin.get_bus()
        bus.add_signal_watch()
        self.__bus_id = bus.connect('message', self.__message)

    def __message(self, bus, message):
        if message.type == Gst.MessageType.BUFFERING:
            percent = message.parse_buffering()
            self.__update_buffering(percent)

    def __getattr__(self, name):
        return getattr(self.bin, name)

    def __update_buffering(self, percent):
        """Call this with buffer percent values from the bus"""

        if self._task:
            self._task.update(percent / 100.0)

        self.__set_inhibit_play(percent < 100)

    def __set_inhibit_play(self, inhibit):
        """Change the inhibit state"""

        if inhibit == self._inhibit_play:
            return
        self._inhibit_play = inhibit

        # task management
        if inhibit:
            if not self._task:

                def stop_buf(*args):
                    self._player.paused = True

                self._task = Task(_("Stream"), _("Buffering"), stop=stop_buf)
        elif self._task:
            self._task.finish()
            self._task = None

        # state management
        if inhibit:
            # save the current state
            status, state, pending = self.bin.get_state(
                timeout=STATE_CHANGE_TIMEOUT)
            if status == Gst.StateChangeReturn.SUCCESS and \
                    state == Gst.State.PLAYING:
                self._wanted_state = state
            else:
                # no idea, at least don't play
                self._wanted_state = Gst.State.PAUSED

            self.bin.set_state(Gst.State.PAUSED)
        else:
            # restore the old state
            self.bin.set_state(self._wanted_state)
            self._wanted_state = None

    def set_state(self, state):
        if self._inhibit_play:
            # PLAYING, PAUSED change the state for after buffering is finished,
            # everything else aborts buffering
            if state not in (Gst.State.PLAYING, Gst.State.PAUSED):
                # abort
                self.__set_inhibit_play(False)
                self.bin.set_state(state)
                return
            self._wanted_state = state
        else:
            self.bin.set_state(state)

    def get_state(self, *args, **kwargs):
        # get_state also is a barrier (seek/positioning),
        # so call every time but ignore the result in the inhibit case
        res = self.bin.get_state(*args, **kwargs)
        if self._inhibit_play:
            return (Gst.StateChangeReturn.SUCCESS, self._wanted_state,
                    Gst.State.VOID_PENDING)
        return res

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

        self.__set_inhibit_play(False)
        self.bin = None
예제 #18
0
 def test_multiple_tasks(self):
     self.assertEquals(self.c.active_tasks, [])
     self.assertNotEqual(self.c.source, "")
     t1 = Task("src", "desc", controller=self.c)
     self.assertEquals(self.c.source, "src")
     self.assertEquals(self.c.active_tasks, [t1])
     t1.update(0.5)
     self.assertEquals(self.c.frac, 0.5)
     t2 = Task("src2", "desc2", controller=self.c)
     self.assertEquals(self.c.source, _("Active tasks"))
     self.assertEquals(self.c.frac, 0.25)
     Task("src3", "desc3", controller=self.c, known_length=False)
     self.assertAlmostEqual(self.c.frac, 0.5 / 3)
     t1.finish()
     t2.finish()
     self.assertEquals(self.c.desc, "desc3")
     self.assertEquals(self.c.frac, None)
예제 #19
0
파일: file.py 프로젝트: Vistaus/quodlibet
    def scan(self,
             paths: Iterable[fsnative],
             exclude: Optional[Iterable[fsnative]] = None,
             cofuncid=None):
        def need_yield(last_yield=[0]):
            current = time.time()
            if abs(current - last_yield[0]) > 0.015:
                last_yield[0] = current
                return True
            return False

        def need_added(last_added=[0]):
            current = time.time()
            if abs(current - last_added[0]) > 1.0:
                last_added[0] = current
                return True
            return False

        # first scan each path for new files
        paths_to_load = []
        for scan_path in paths:
            print_d(f"Scanning {scan_path}", self._name)
            desc = _("Scanning %s") % (fsn2text(unexpand(scan_path)))
            with Task(_("Library"), desc) as task:
                if cofuncid:
                    task.copool(cofuncid)

                for real_path in iter_paths(scan_path, exclude=exclude):
                    if need_yield():
                        task.pulse()
                        yield
                    # skip unknown file extensions
                    if not formats.filter(real_path):
                        continue
                    # already loaded
                    if self.contains_filename(real_path):
                        continue
                    paths_to_load.append(real_path)

        yield

        # then (try to) load all new files
        with Task(_("Library"), _("Loading files")) as task:
            if cofuncid:
                task.copool(cofuncid)

            added = []
            for real_path in task.gen(paths_to_load):
                item = self.add_filename(real_path, False)
                if item is not None:
                    added.append(item)
                    if len(added) > 100 or need_added():
                        self.add(added)
                        added = []
                        yield
                if added and need_yield():
                    yield
            if added:
                self.add(added)
                added = []
                yield True
예제 #20
0
    def search_cover(self, cancellable, songs):
        """Search for all the covers applicable to `songs` across all providers
        Every successful image result emits a 'covers-found' signal
        (unless cancelled)."""

        sources = [source for source in self.sources if not source.embedded]
        processed = {}
        all_groups = {}
        task = Task(_("Cover Art"),
                    _("Querying album art providers"),
                    stop=cancellable.cancel)

        def finished(provider, success):
            processed[provider] = success
            total = self._total_groupings(all_groups)

            frac = len(processed) / total
            print_d("%s is finished: %d / %d" %
                    (provider, len(processed), total))
            task.update(frac)
            if frac >= 1:
                task.finish()
                self.emit('searches-complete', processed)

        def search_complete(provider, results):
            name = provider.name
            if not results:
                print_d('No covers from {0}'.format(name))
                finished(provider, False)
                return
            finished(provider, True)
            if not (cancellable and cancellable.is_cancelled()):
                covers = {
                    CoverData(url=res['cover'],
                              source=name,
                              dimensions=res.get('dimensions', None))
                    for res in results
                }
                self.emit('covers-found', provider, covers)
            provider.disconnect_by_func(search_complete)

        def failure(provider, result):
            finished(provider, False)
            name = provider.__class__.__name__
            print_d('Failed to get cover from {name} ({msg})'.format(
                name=name, msg=result))
            provider.disconnect_by_func(failure)

        def song_groups(songs, sources):
            all_groups = {}
            for plugin in sources:
                groups = {}
                for song in songs:
                    group = plugin.group_by(song) or ''
                    groups.setdefault(group, []).append(song)
                all_groups[plugin] = groups
            return all_groups

        all_groups = song_groups(songs, sources)
        print_d("Got %d plugin groupings" % self._total_groupings(all_groups))

        for plugin, groups in all_groups.items():
            print_d("Getting covers from %s" % plugin)
            for key, group in sorted(groups.items()):
                song = sorted(group, key=lambda s: s.key)[0]
                artists = {s.comma('artist') for s in group}
                if len(artists) > 1:
                    print_d("%d artist groups in %s - probably a compilation. "
                            "Using provider to search for compilation" %
                            (len(artists), key))
                    song = AudioFile(song)
                    try:
                        del song['artist']
                    except KeyError:
                        # Artist(s) from other grouped songs, never mind.
                        pass
                provider = plugin(song)
                provider.connect('search-complete', search_complete)
                provider.connect('fetch-failure', failure)
                provider.search()
        return all_groups
예제 #21
0
    def scan(self, paths, exclude=[], scan_dots=False, cofuncid=None):
        added = []
        exclude = [expanduser(path) for path in exclude if path]

        def need_yield(last_yield=[0]):
            current = time.time()
            if abs(current - last_yield[0]) > 0.015:
                last_yield[0] = current
                return True
            return False

        def need_added(last_added=[0]):
            current = time.time()
            if abs(current - last_added[0]) > 1.0:
                last_added[0] = current
                return True
            return False

        for fullpath in paths:
            print_d("Scanning %r." % fullpath, self)
            desc = _("Scanning %s") % (unexpand(fsn2text(fullpath)))
            with Task(_("Library"), desc) as task:
                if cofuncid:
                    task.copool(cofuncid)
                fullpath = expanduser(fullpath)
                if filter(fullpath.startswith, exclude):
                    continue
                for path, dnames, fnames in os.walk(fullpath):
                    if not scan_dots:
                        index = 0
                        while index < len(dnames):
                            if dnames[index].startswith('.'):
                                del (dnames[index])
                            else:
                                index += 1
                    for filename in fnames:
                        if not scan_dots and filename.startswith('.'):
                            continue
                        fullfilename = os.path.join(path, filename)
                        if filter(fullfilename.startswith, exclude):
                            continue
                        if fullfilename not in self._contents:
                            fullfilename = os.path.realpath(fullfilename)
                            # skip unknown file extensions
                            if not formats.filter(fullfilename):
                                continue
                            if filter(fullfilename.startswith, exclude):
                                continue
                            if fullfilename not in self._contents:
                                item = self.add_filename(fullfilename, False)
                                if item is not None:
                                    added.append(item)
                                    if len(added) > 100 or need_added():
                                        self.add(added)
                                        added = []
                                        task.pulse()
                                        yield
                                if added and need_yield():
                                    yield
                if added:
                    self.add(added)
                    added = []
                    task.pulse()
                    yield True