Exemple #1
0
    def fetch(self):
        """
            Collects covers for all outstanding items
        """
        self.emit('fetch-started', len(self.outstanding))

        # Speed up the following loop
        get_cover = COVER_MANAGER.get_cover
        save = COVER_MANAGER.save

        for i, album in enumerate(self.outstanding[:]):
            if self.stopper.is_set():
                # Allow for "fetch-completed" signal to be emitted
                break

            cover_data = get_cover(self.album_tracks[album][0],
                                   save_cover=True)
            cover_pixbuf = pixbuf_from_data(cover_data) if cover_data else None

            self.emit('fetch-progress', i + 1)

            if not cover_pixbuf:
                continue

            self.outstanding.remove(album)
            self.emit('cover-fetched', album, cover_pixbuf)

            if i % 50 == 0:
                logger.debug('Saving cover database')
                save()

        logger.debug('Saving cover database')
        save()

        self.emit('fetch-completed', len(self.outstanding))
Exemple #2
0
    def set_cover(self, *args, **kwargs):
        if self.exaile is None:
            return
        elif not hasattr(self.exaile, 'player'):
            log.debug("Player not loaded, ignoring set_cover call")
            return

        try:
            os.remove(self.temp_icon_path)
        except (TypeError, OSError):
            pass

        if player.PLAYER.current is None:
            log.debug("Player stopped, removing AWN cover")
            self.unset_cover()
        elif not self.cover_display:
            self.unset_cover()
        else:
            image_data = covers.MANAGER.get_cover(player.PLAYER.current,
                                                  set_only=True,
                                                  use_default=True)
            pixbuf = pixbuf_from_data(image_data)
            descriptor, self.temp_icon_path = tempfile.mkstemp()
            pixbuf.save(self.temp_icon_path, 'png')
            self.awn.SetTaskIconByXid(self.xid(), self.temp_icon_path)
Exemple #3
0
    def on_cover_chosen(self, cover_chooser, track, cover_data):
        """
            Updates the cover of the current album after user selection
        """
        path = cover_chooser.path

        if path:
            album = self.model[path][0]
            pixbuf = pixbuf_from_data(cover_data)

            self.emit('cover-fetched', album, pixbuf)

            try:
                self.outstanding.remove(album)
            except ValueError:
                pass
            else:
                outstanding = len(self.outstanding)

                if outstanding > 0:
                    progress_text = self.outstanding_text.format(
                        outstanding=outstanding)
                else:
                    progress_text = self.completed_text

                self.progress_bar.set_text(progress_text)
Exemple #4
0
    def fetch_cover(self):
        """
        Searches for covers for the current track
        """
        db_strings = COVER_MANAGER.find_covers(self.track)

        if db_strings:
            for db_string in db_strings:
                if self.stopper.is_set():
                    return

                coverdata = COVER_MANAGER.get_cover_data(db_string)
                # Pre-render everything for faster display later
                pixbuf = pixbuf_from_data(coverdata)

                if pixbuf:
                    self.covers_model.append(
                        [
                            (db_string, coverdata),
                            pixbuf,
                            pixbuf.scale_simple(50, 50, GdkPixbuf.InterpType.BILINEAR),
                        ]
                    )

        self.emit('covers-fetched', db_strings)
Exemple #5
0
    def set_cover_from_track(self, track):
        """
        Updates the cover image and triggers cross-fading
        """
        cover_data = covers.MANAGER.get_cover(track, set_only=True)

        if cover_data is None:
            self.hide()
            return

        if not self.props.visible:
            self.show()

        size = settings.get_option('plugin/desktopcover/size', 200)
        upscale = settings.get_option('plugin/desktopcover/override_size', False)
        pixbuf = self.image.get_pixbuf()
        next_pixbuf = pixbuf_from_data(cover_data, size=(size, size), upscale=upscale)
        fading = settings.get_option('plugin/desktopcover/fading', False)

        if fading and pixbuf is not None and self._cross_fade_id is None:
            # Prescale to allow for proper crossfading
            width, height = next_pixbuf.get_width(), next_pixbuf.get_height()
            pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR)
            self.image.set_from_pixbuf(pixbuf)

            duration = settings.get_option('plugin/desktopcover/fading_duration', 50)

            self._cross_fade_id = GLib.timeout_add(
                int(duration), self.cross_fade, pixbuf, next_pixbuf, duration
            )
        else:
            self.image.set_from_pixbuf(next_pixbuf)
Exemple #6
0
    def set_cover(self, *args, **kwargs):
        if self.exaile is None:
            return
        elif not hasattr(self.exaile, 'player'):
            log.debug("Player not loaded, ignoring set_cover call")
            return

        try:
            os.remove(self.temp_icon_path)
        except (TypeError, OSError):
            pass

        if player.PLAYER.current is None:
            log.debug("Player stopped, removing AWN cover")
            self.unset_cover()
        elif not self.cover_display:
            self.unset_cover()
        else:
            image_data = covers.MANAGER.get_cover(
                player.PLAYER.current, set_only=True, use_default=True
            )
            pixbuf = pixbuf_from_data(image_data)
            descriptor, self.temp_icon_path = tempfile.mkstemp()
            pixbuf.save(self.temp_icon_path, 'png')
            self.awn.SetTaskIconByXid(self.xid(), self.temp_icon_path)
Exemple #7
0
    def set_cover_from_track(self, track):
        """
            Updates the cover image and triggers cross-fading
        """
        cover_data = covers.MANAGER.get_cover(track, set_only=True)

        if cover_data is None:
            self.hide()
            return

        if not self.props.visible:
            self.show()

        size = settings.get_option('plugin/desktopcover/size', 200)
        upscale = settings.get_option('plugin/desktopcover/override_size', False)
        pixbuf = self.image.get_pixbuf()
        next_pixbuf = pixbuf_from_data(cover_data, size=(size, size), upscale=upscale)
        fading = settings.get_option('plugin/desktopcover/fading', False)

        if fading and pixbuf is not None and self._cross_fade_id is None:
            # Prescale to allow for proper crossfading
            width, height = next_pixbuf.get_width(), next_pixbuf.get_height()
            pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR)
            self.image.set_from_pixbuf(pixbuf)

            duration = settings.get_option('plugin/desktopcover/fading_duration', 50)

            self._cross_fade_id = GLib.timeout_add(
                int(duration), self.cross_fade, pixbuf, next_pixbuf, duration
            )
        else:
            self.image.set_from_pixbuf(next_pixbuf)
Exemple #8
0
    def prefetch(self, collection):
        """
            Collects all albums and sets the list of outstanding items
        """
        albums = set()

        for track in collection:
            if self.stopper.is_set():
                return

            try:
                artist = track.get_tag_raw('artist')[0]
                album = track.get_tag_raw('album')[0]
            except TypeError:
                continue

            if not album or not artist:
                continue

            album = (artist, album)

            try:
                self.album_tracks[album].append(track)
            except KeyError:
                self.album_tracks[album] = [track]

            albums.add(album)

        albums = sorted(albums)

        outstanding = []
        # Speed up the following loop
        get_cover = COVER_MANAGER.get_cover
        default_cover_pixbuf = self.default_cover_pixbuf
        cover_size = self.cover_size

        self.emit('prefetch-started')

        for i, album in enumerate(albums):
            if self.stopper.is_set():
                return

            cover_data = get_cover(self.album_tracks[album][0], set_only=True)
            cover_pixbuf = pixbuf_from_data(cover_data) if cover_data else None

            try:
                thumbnail_pixbuf = cover_pixbuf.scale_simple(
                    *cover_size, interp_type=GdkPixbuf.InterpType.BILINEAR)
            except AttributeError:  # cover_pixbuf is None
                thumbnail_pixbuf = default_cover_pixbuf
                outstanding.append(album)

            label = '{0} - {1}'.format(*album)
            iter = self.model.append((album, thumbnail_pixbuf, label))
            self.model_path_cache[album] = self.model.get_path(iter)

            self.emit('prefetch-progress', i + 1)

        self.outstanding = outstanding
        self.emit('prefetch-completed', len(self.outstanding))
Exemple #9
0
    def do_drag_data_get(self, context, selection, info, time):
        """
            Fills the selection with the current cover
        """
        if self.filename is None:
            self.filename = tempfile.mkstemp(prefix='exaile_cover_')[1]

        pixbuf = pixbuf_from_data(self.cover_data)
        save_pixbuf(pixbuf, self.filename, 'png')
        selection.set_uris([Gio.File.new_for_path(self.filename).get_uri()])
Exemple #10
0
    def __init__(self, parent, collection):
        """
        Initializes the window
        """
        GObject.GObject.__init__(self)

        # List of identifiers of albums without covers
        self.outstanding = []
        # Map of album identifiers and their tracks
        self.album_tracks = {}

        self.outstanding_text = _('{outstanding} covers left to fetch')
        self.completed_text = _('All covers fetched')
        self.cover_size = (90, 90)
        self.default_cover_pixbuf = pixbuf_from_data(
            COVER_MANAGER.get_default_cover(), self.cover_size
        )

        builder = Gtk.Builder()
        builder.add_from_file(xdg.get_data_path('ui', 'covermanager.ui'))
        builder.connect_signals(self)

        self.window = builder.get_object('window')
        self.window.set_transient_for(parent)

        self.message = dialogs.MessageBar(
            parent=builder.get_object('content_area'), buttons=Gtk.ButtonsType.CLOSE
        )

        self.previews_box = builder.get_object('previews_box')
        self.model = builder.get_object('covers_model')
        # Map of album identifiers and model paths
        self.model_path_cache = {}
        self.menu = CoverMenu(self)
        self.menu.attach_to_widget(self.previews_box, lambda menu, widget: True)

        self.progress_bar = builder.get_object('progressbar')
        self.progress_bar.set_text(_('Collecting albums and covers...'))
        self.progress_bar.pulse_timeout = GLib.timeout_add(
            100, self.on_progress_pulse_timeout
        )
        self.close_button = builder.get_object('close_button')
        self.stop_button = builder.get_object('stop_button')
        self.stop_button.set_sensitive(False)
        self.fetch_button = builder.get_object('fetch_button')

        self.window.show_all()

        self.stopper = threading.Event()
        thread = threading.Thread(
            target=self.prefetch, name='CoverPrefetch', args=(collection,)
        )
        thread.daemon = True
        thread.start()
Exemple #11
0
 def __get_icon(self, track, media_icon):
     # TODO: icons are too small, even with settings.resize_covers=False
     icon_name = None
     if media_icon and self.settings.use_media_icons:
         icon_name = media_icon
     elif self.settings.show_covers:
         cover_data = covers.MANAGER.get_cover(track,
                                               set_only=True,
                                               use_default=True)
         size = DEFAULT_ICON_SIZE if self.settings.resize_covers else None
         new_icon = pixbuf_from_data(cover_data, size)
         self.notification.set_image_from_pixbuf(new_icon)
     return icon_name
Exemple #12
0
    def set_blank(self):
        """
            Sets the default cover to display
        """

        self.drag_dest_unset()

        pixbuf = pixbuf_from_data(COVER_MANAGER.get_default_cover())
        self.image.set_from_pixbuf(pixbuf)
        self.set_drag_source_enabled(False)
        self.cover_data = None

        self.emit('cover-found', None)
Exemple #13
0
 def __get_icon(self, track, media_icon):
     # TODO: icons are too small, even with settings.resize_covers=False
     icon_name = None
     if media_icon and self.settings.use_media_icons:
         icon_name = media_icon
     elif self.settings.show_covers:
         cover_data = covers.MANAGER.get_cover(
             track, set_only=True, use_default=True
         )
         size = DEFAULT_ICON_SIZE if self.settings.resize_covers else None
         new_icon = pixbuf_from_data(cover_data, size)
         self.notification.set_image_from_pixbuf(new_icon)
     return icon_name
Exemple #14
0
    def show_cover(self):
        """
            Shows the current cover
        """
        if not self.cover_data:
            return

        pixbuf = pixbuf_from_data(self.cover_data)

        if pixbuf:
            savedir = Gio.File.new_for_uri(self.__track.get_loc_for_io()).get_parent()
            if savedir:
                savedir = savedir.get_path()
            window = CoverWindow(self.get_toplevel(), pixbuf,
                                 self.__track.get_tag_display('album'), savedir)
            window.show_all()
Exemple #15
0
    def on_cover_chosen(self, object, track, cover_data):
        """
            Called when a cover is selected
            from the coverchooser
        """

        if self.__track != track:
            return

        width = settings.get_option('gui/cover_width', 100)
        pixbuf = pixbuf_from_data(cover_data, (width, width))
        self.image.set_from_pixbuf(pixbuf)
        self.set_drag_source_enabled(True)
        self.cover_data = cover_data

        self.emit('cover-found', pixbuf)
Exemple #16
0
 def get_drag_cover_icon(self, tracks):
     """
         Get drag cover icon (stacked covers pixbuf)
         Asynchronous load covers for tracks taking at most 0.333 seconds
         :param tracks: iterable for tracks (xl.trax.Track)
         :return: GdkPixbuf.Pixbuf or None if none found
     """
     cover_width = settings.get_option('gui/cover_width', 100)
     as_pixbuf = lambda data: pixbuf_from_data(
         data=data, size=(cover_width, cover_width))
     get_cover_for_tracks = covers.MANAGER.get_cover_for_tracks
     db_string_list = []
     cover_for_tracks = lambda tracks: get_cover_for_tracks(
         tracks, db_string_list)
     filtered_covers = filter(None, map(cover_for_tracks,
                                        tracks))  # Remove None cover tracks
     async_loader = common.AsyncLoader(map(as_pixbuf, filtered_covers))
     async_loader.end(0.333)
     return self.__create_drag_cover_icon(async_loader.result, cover_width)
Exemple #17
0
    def show_cover(self):
        """
        Shows the currently selected cover
        """
        paths = self.previews_box.get_selected_items()

        if paths:
            path = paths[0]
            album = self.model[path][0]
            track = self.album_tracks[album][0]  # Arbitrary track in album
            cover_data = COVER_MANAGER.get_cover(track, set_only=True)
            cover_pixbuf = pixbuf_from_data(cover_data) if cover_data else None

            # Do not bother showing the dialog if there is no cover
            if cover_pixbuf:
                savedir = Gio.File.new_for_uri(track.get_loc_for_io()).get_parent()
                if savedir:
                    savedir = savedir.get_path()
                cover_window = CoverWindow(self.window, cover_pixbuf, album[1], savedir)
                cover_window.show_all()
Exemple #18
0
    def do_drag_data_received(self, context, x, y, selection, info, time):
        """
        Sets the cover based on the dragged data
        """
        if self.__track is not None:
            uri = selection.get_uris()[0]
            db_string = 'localfile:%s' % uri

            try:
                stream = Gio.File.new_for_uri(uri).read()
            except GLib.Error:
                return

            self.cover_data = stream.read()
            width = settings.get_option('gui/cover_width', 100)
            pixbuf = pixbuf_from_data(self.cover_data, (width, width))

            if pixbuf is not None:
                self.image.set_from_pixbuf(pixbuf)
                COVER_MANAGER.set_cover(self.__track, db_string, self.cover_data)
Exemple #19
0
 def get_drag_cover_icon(self, tracks):
     """
         Get drag cover icon (stacked covers pixbuf)
         Asynchronous load covers for tracks taking at most 0.333 seconds
         :param tracks: iterable for tracks (xl.trax.Track)
         :return: GdkPixbuf.Pixbuf or None if none found
     """
     cover_width = settings.get_option('gui/cover_width', 100)
     as_pixbuf = lambda data: pixbuf_from_data(
         data=data, size=(cover_width, cover_width)
     )
     get_cover_for_tracks = covers.MANAGER.get_cover_for_tracks
     db_string_list = []
     cover_for_tracks = lambda tracks: get_cover_for_tracks(tracks, db_string_list)
     filtered_covers = ifilter(
         None, imap(cover_for_tracks, tracks)
     )  # Remove None cover tracks
     async_loader = common.AsyncLoader(imap(as_pixbuf, filtered_covers))
     async_loader.end(0.333)
     return self.__create_drag_cover_icon(async_loader.result, cover_width)
Exemple #20
0
    def __fetch_metadata(self, *_args):
        # "gtk-menu-images" is deprecated and is being ignored on most
        # platforms. On GNOME/Wayland it can be enabled by editing
        # ~/.config/gtk-3.0/settings.ini and adding `gtk-menu-images=1`.
        use_covers = Gtk.Settings.get_default().props.gtk_menu_images

        try:
            item = trax.Track(self.__path)
            if not self.__title:
                self.__title = item.get_tag_display('title')
            if use_covers:
                image = covers.MANAGER.get_cover(item, set_only=True)
                if image:
                    try:
                        self.__cover_pixbuf = pixbuf_from_data(image, size=(16, 16))
                    except GLib.GError:
                        LOGGER.warning('Could not load cover')
            else:
                self.__cover_pixbuf = None
        except Exception:
            LOGGER.exception("Cannot open %s", self.__path)
            return
Exemple #21
0
    def __fetch_metadata(self, *_args):
        # "gtk-menu-images" is deprecated and is being ignored on most
        # platforms. On GNOME/Wayland it can be enabled by editing
        # ~/.config/gtk-3.0/settings.ini and adding `gtk-menu-images=1`.
        use_covers = Gtk.Settings.get_default().props.gtk_menu_images

        try:
            item = trax.Track(self.__path)
            if not self.__title:
                self.__title = item.get_tag_display('title')
            if use_covers:
                image = covers.MANAGER.get_cover(item, set_only=True)
                if image:
                    try:
                        self.__cover_pixbuf = pixbuf_from_data(image,
                                                               size=(16, 16))
                    except GLib.GError:
                        LOGGER.warning('Could not load cover')
            else:
                self.__cover_pixbuf = None
        except Exception:
            LOGGER.exception("Cannot open %s", self.__path)
            return