예제 #1
0
 def _on_map(self, widget):
     """
         Disable global shortcuts
         @param widget as Gtk.Widget
     """
     Lp().window.enable_global_shorcuts(False)
예제 #2
0
 def _on_volume_changed(self, player, data=None):
     self.PropertiesChanged(self.MPRIS_PLAYER_IFACE,
                            {"Volume": dbus.Double(
                             Lp().player.volume), },
                            [])
예제 #3
0
 def Previous(self):
     if Lp().notify is not None:
         Lp().notify.inhibit()
     Lp().player.prev()
예제 #4
0
 def load():
     genres = Lp().genres.get_charts()
     return genres
예제 #5
0
 def Set(self, interface, property_name, new_value):
     if property_name == "Volume":
         Lp().player.set_volume(new_value)
예제 #6
0
    def __init__(self, album_id, genre_ids, artist_ids, show_cover):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param lazy as LazyLoadingView
            @param show cover as bool
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids)
        self._album.set_artists(artist_ids)
        self.__width = None
        # Cover + rating + spacing
        self.__height = ArtSize.BIG + 26
        self.__orientation = None
        self.__child_height = TrackRow.get_best_height(self)
        # Header + separator + spacing + margin
        self.__requested_height = self.__child_height + 6
        # Discs to load, will be emptied
        self.__discs = self._album.discs
        self.__locked_widget_right = True
        self._filter_ids = artist_ids
        self.set_property('height-request', self.__height)
        self.connect('size-allocate', self.__on_size_allocate)
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/AlbumDetailedWidget.ui')
        self._widget = builder.get_object('widget')
        self.__overlay = builder.get_object('overlay')
        self._play_button = builder.get_object('play-button')
        self._artwork_button = builder.get_object('artwork-button')
        self._action_button = builder.get_object('action-button')
        self._action_event = builder.get_object('action-event')

        builder.connect_signals(self)
        rating = RatingWidget(self._album)
        rating.show()

        artist_label = builder.get_object('artist')
        if show_cover:
            self._cover = builder.get_object('cover')
            builder.get_object('duration').set_hexpand(True)
            self._cover.get_style_context().add_class('cover-frame')
            self.__coverbox = builder.get_object('coverbox')
            self.__coverbox.show()
            # 6 for 2*3px (application.css)
            self.__coverbox.set_property('width-request', ArtSize.BIG + 6)
            self.__coverbox.add(rating)
            if Lp().window.get_view_width() < WindowSize.MEDIUM:
                self.__coverbox.hide()
            if len(artist_ids) > 1:
                artist_label.set_text(", ".join(self._album.artists))
                artist_label.show()
        else:
            builder.get_object('header').attach(rating, 4, 0, 1, 1)
            rating.set_hexpand(True)
            rating.set_property('halign', Gtk.Align.END)
            rating.set_property('valign', Gtk.Align.CENTER)
            artist_label.set_text(", ".join(self._album.artists))
            artist_label.show()
            self._cover = None

        label = builder.get_object('duration')
        duration = Lp().albums.get_duration(album_id, genre_ids)
        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                label.set_text(_("%s h") % hours)
        else:
            label.set_text(_("%s m") % mins)

        self.__box = Gtk.Grid()
        self.__box.set_column_homogeneous(True)
        self.__box.set_property('valign', Gtk.Align.START)
        self.__box.show()
        builder.get_object('albuminfo').add(self.__box)

        self._tracks_left = {}
        self._tracks_right = {}

        self.set_cover()
        self.update_state()

        builder.get_object('title').set_label(self._album.name)
        if self._album.year:
            year = builder.get_object('year')
            year.set_label(self._album.year)
            year.show()

        for disc in self.__discs:
            self.__add_disc_container(disc.number)
            self.__set_disc_height(disc)

        self.add(self._widget)
        # We start transparent, we switch opaque at size allocation
        # This prevent artifacts
        self.set_opacity(0)

        self._menu = builder.get_object('menu')
        self._menu.connect('clicked', self.__pop_menu)
        # TODO Remove this later
        if Gtk.get_minor_version() > 16:
            self._menu.show()
        else:
            self.connect('map', self.__on_map)
        if self._album.is_youtube and show_cover:
            self._cover.get_style_context().add_class('cover-frame-youtube')
예제 #7
0
 def load():
     genres = Lp().genres.get()
     return genres
예제 #8
0
 def __init__(self, rowid, num, show_headers):
     """
         Init row widget
         @param rowid as int
         @param num as int
         @param show headers as bool
     """
     Row.__init__(self, rowid, num)
     self.__parent_filter = False
     self.__show_headers = show_headers
     self._indicator.set_margin_start(5)
     self._row_widget.set_margin_start(5)
     self._row_widget.set_margin_top(2)
     self._row_widget.set_margin_end(5)
     self._grid.insert_row(0)
     self._grid.insert_column(0)
     self._grid.insert_column(1)
     self._grid.attach(self._indicator, 1, 1, 1, 2)
     self.__cover = Gtk.Image()
     self.__cover.set_property("halign", Gtk.Align.CENTER)
     self.__cover.set_property("valign", Gtk.Align.CENTER)
     self.__cover.get_style_context().add_class("small-cover-frame")
     self.__cover.set_no_show_all(True)
     # We force width with a Box
     box = Gtk.Box()
     box.set_homogeneous(True)
     box.add(self.__cover)
     box.set_property("width-request", ArtSize.MEDIUM+2)
     self._grid.attach(box, 0, 0, 1, 2)
     self.show_all()
     self.__header = Gtk.Grid()
     self.__header.set_column_spacing(5)
     if self._track.album.artist_ids[0] != Type.COMPILATIONS:
         self.__album_artist_label = Gtk.Label()
         self.__album_artist_label.set_markup(
                              "<b>" +
                              GLib.markup_escape_text(
                                    ", ".join(self._track.album.artists)) +
                              "</b>")
         self.__album_artist_label.set_ellipsize(Pango.EllipsizeMode.END)
         self.__album_artist_label.get_style_context().add_class(
                                                                "dim-label")
         artist_eventbox = Gtk.EventBox()
         artist_eventbox.add(self.__album_artist_label)
         artist_eventbox.connect("realize", self.__on_eventbox_realize)
         artist_eventbox.connect("button-press-event",
                                 self.__on_artist_button_press)
         artist_eventbox.show()
         self.__header.add(artist_eventbox)
     self.__album_label = Gtk.Label.new(self._track.album.name)
     self.__album_label.set_ellipsize(Pango.EllipsizeMode.END)
     self.__album_label.get_style_context().add_class("dim-label")
     self.__album_label.set_hexpand(True)
     self.__album_label.set_property("halign", Gtk.Align.END)
     self.__header.add(self.__album_label)
     self._num_label.set_property("valign", Gtk.Align.END)
     self._title_label.set_property("valign", Gtk.Align.END)
     if self._artists_label is not None:
         self._artists_label.set_property("valign", Gtk.Align.END)
     self._duration_label.set_property("valign", Gtk.Align.END)
     self._indicator.set_property("valign", Gtk.Align.END)
     if self._artists_label is not None:
         self._grid.attach(self.__header, 1, 0, 5, 1)
     else:
         self._grid.attach(self.__header, 1, 0, 4, 1)
     self.set_indicator(Lp().player.current_track.id == self._track.id,
                        utils.is_loved(self._track.id))
     self.show_headers(self.__show_headers)
     self.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, [],
                          Gdk.DragAction.MOVE)
     self.drag_source_add_text_targets()
     self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION,
                        [('text/plain', 0, 0)], Gdk.DragAction.MOVE)
     self.drag_dest_add_text_targets()
     self.connect("drag-begin", self.__on_drag_begin)
     self.connect("drag-data-get", self.__on_drag_data_get)
     self.connect("drag-data-received", self.__on_drag_data_received)
     self.connect("drag-motion", self.__on_drag_motion)
     self.connect("drag-leave", self.__on_drag_leave)
예제 #9
0
    def __init__(self, album_id, genre_ids, artist_ids, popover, size_group):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param popover as bool
            @param size group as Gtk.SizeGroup
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids)
        self._artist_ids = artist_ids
        self._pop_allowed = not popover or Gtk.get_minor_version() > 16
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/%s.ui' %
                                  type(self).__name__)
        self._color = builder.get_object('color')
        rating = RatingWidget(self._album)
        rating.show()
        builder.get_object('coverbox').add(rating)
        builder.connect_signals(self)

        self._artist_label = builder.get_object('artist')
        if len(artist_ids) > 1:
            self._artist_label.set_text(self._album.artist_name)
            self._artist_label.show()
        label = builder.get_object('duration')
        duration = Lp().albums.get_duration(album_id, genre_ids)
        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                label.set_text(_("%s h") % hours)
        else:
            label.set_text(_("%s m") % mins)

        grid = builder.get_object('tracks')
        self._discs = self._album.discs
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        i = 0
        for disc in self._discs:
            index = disc.number
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % index)
                label.set_property('halign', Gtk.Align.START)
                label.get_style_context().add_class('dim-label')
                if i:
                    label.set_property('margin-top', 30)
                label.show()
                grid.attach(label, 0, i, 2, 1)
                i += 1
            self._tracks_left[index] = TracksWidget(self._pop_allowed, True)
            self._tracks_right[index] = TracksWidget(self._pop_allowed, True)
            grid.attach(self._tracks_left[index], 0, i, 1, 1)
            grid.attach(self._tracks_right[index], 1, i, 1, 1)
            size_group.add_widget(self._tracks_left[index])
            size_group.add_widget(self._tracks_right[index])

            self._tracks_left[index].connect('activated', self._on_activated)
            self._tracks_left[index].connect('button-press-event',
                                             self._on_button_press_event)
            self._tracks_right[index].connect('activated', self._on_activated)
            self._tracks_right[index].connect('button-press-event',
                                              self._on_button_press_event)

            self._tracks_left[index].show()
            self._tracks_right[index].show()
            i += 1

        self._cover = builder.get_object('cover')
        self.set_cover()
        self.update_state()

        builder.get_object('title').set_label(self._album.name)
        if self._album.year:
            year = builder.get_object('year')
            year.set_label(self._album.year)
            year.show()

        self.add(builder.get_object('widget'))

        # TODO: Remove this test later
        if self._pop_allowed:
            self._menu = builder.get_object('menu')
            self._menu.connect('clicked', self._pop_menu)
            self._menu.show()
예제 #10
0
    def save_album_artwork(self, data, album_id):
        """
            Save data for album id
            @param data as bytes
            @param album id as int
        """
        try:
            album = Album(album_id)
            arturi = None
            # Check portal for kid3-cli
            can_set_cover = False
            try:
                bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
                proxy = Gio.DBusProxy.new_sync(
                                            bus, Gio.DBusProxyFlags.NONE, None,
                                            'org.gnome.Lollypop.Portal',
                                            '/org/gnome/LollypopPortal',
                                            'org.gnome.Lollypop.Portal', None)
                can_set_cover = proxy.call_sync(
                                               'CanSetCover', None,
                                               Gio.DBusCallFlags.NO_AUTO_START,
                                               500, None)[0]
            except:
                print("You are missing lollypop-portal: "
                      "https://github.com/gnumdk/lollypop-portal")
            save_to_tags = Lp().settings.get_value('save-to-tags') and\
                can_set_cover and not album.is_web

            uri_count = Lp().albums.get_uri_count(album.uri)
            filename = self.get_album_cache_name(album) + ".jpg"
            if save_to_tags:
                t = Thread(target=self.__save_artwork_tags,
                           args=(data, album))
                t.daemon = True
                t.start()

            store_path = self._STORE_PATH + "/" + filename
            if album.uri == "" or is_readonly(album.uri):
                arturi = GLib.filename_to_uri(store_path)
            # Many albums with same path, suffix with artist_album name
            elif uri_count > 1:
                arturi = album.uri + "/" + filename
                favorite_uri = album.uri + "/" + self.__favorite
                favorite = Lio.File.new_for_uri(favorite_uri)
                if favorite.query_exists():
                    favorite.trash()
            else:
                arturi = album.uri + "/" + self.__favorite
            f = Lio.File.new_for_uri(arturi)
            # Update cover file if exists even if we have written to tags
            if not save_to_tags or f.query_exists():
                stream = Gio.MemoryInputStream.new_from_data(data, None)
                pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(
                                                               stream,
                                                               ArtSize.MONSTER,
                                                               ArtSize.MONSTER,
                                                               True,
                                                               None)
                stream.close()
                pixbuf.savev(store_path, "jpeg", ["quality"],
                             [str(Lp().settings.get_value(
                                                'cover-quality').get_int32())])
                dst = Lio.File.new_for_uri(arturi)
                src = Lio.File.new_for_path(store_path)
                src.move(dst, Gio.FileCopyFlags.OVERWRITE, None, None)
                del pixbuf
                self.clean_album_cache(album)
                GLib.idle_add(self.album_artwork_update, album.id)
        except Exception as e:
            print("Art::save_album_artwork(): %s" % e)
예제 #11
0
 def __init__(self, rowid, num, artist_ids=[]):
     """
         Init row widgets
         @param rowid as int
         @param num as int
         @param artist_ids as [int]: Allow to tell Row that artist_ids
                should not be displayed
     """
     # We do not use Gtk.Builder for speed reasons
     Gtk.ListBoxRow.__init__(self)
     self._artists_label = None
     self._track = Track(rowid)
     self.__number = num
     self.__preview_timeout_id = None
     self.__context_timeout_id = None
     self.__context = None
     self._indicator = IndicatorWidget(self._track.id)
     self.set_indicator(Lp().player.current_track.id == self._track.id,
                        utils.is_loved(self._track.id))
     self._row_widget = Gtk.EventBox()
     self._row_widget.connect("button-press-event", self.__on_button_press)
     self._row_widget.connect("enter-notify-event", self.__on_enter_notify)
     self._row_widget.connect("leave-notify-event", self.__on_leave_notify)
     self._grid = Gtk.Grid()
     self._grid.set_column_spacing(5)
     self._row_widget.add(self._grid)
     self._title_label = Gtk.Label.new(self._track.name)
     self._title_label.set_property("has-tooltip", True)
     self._title_label.connect("query-tooltip",
                               self.__on_query_tooltip)
     self._title_label.set_property("hexpand", True)
     self._title_label.set_property("halign", Gtk.Align.START)
     self._title_label.set_ellipsize(Pango.EllipsizeMode.END)
     featuring_ids = self._track.get_featuring_ids(artist_ids)
     if featuring_ids:
         artists = []
         for artist_id in featuring_ids:
             artists.append(Lp().artists.get_name(artist_id))
         self._artists_label = Gtk.Label.new(GLib.markup_escape_text(
                                                        ", ".join(artists)))
         self._artists_label.set_use_markup(True)
         self._artists_label.set_property("has-tooltip", True)
         self._artists_label.connect("query-tooltip",
                                     self.__on_query_tooltip)
         self._artists_label.set_property("hexpand", True)
         self._artists_label.set_property("halign", Gtk.Align.END)
         self._artists_label.set_ellipsize(Pango.EllipsizeMode.END)
         self._artists_label.set_opacity(0.3)
         self._artists_label.set_margin_end(5)
         self._artists_label.show()
     self._duration_label = Gtk.Label.new(
                                    seconds_to_string(self._track.duration))
     self._duration_label.get_style_context().add_class("dim-label")
     self._num_label = Gtk.Label()
     self._num_label.set_ellipsize(Pango.EllipsizeMode.END)
     self._num_label.set_property("valign", Gtk.Align.CENTER)
     self._num_label.set_width_chars(4)
     self._num_label.get_style_context().add_class("dim-label")
     self.update_num_label()
     self.__menu_button = Gtk.Button.new()
     # Here a hack to make old Gtk version support min-height css attribute
     # min-height = 24px, borders = 2px, we set directly on stack
     # min-width = 24px, borders = 2px, padding = 8px
     self.__menu_button.set_size_request(34, 26)
     self.__menu_button.set_relief(Gtk.ReliefStyle.NONE)
     self.__menu_button.get_style_context().add_class("menu-button")
     self.__menu_button.get_style_context().add_class("track-menu-button")
     self._grid.add(self._num_label)
     self._grid.add(self._title_label)
     if self._artists_label is not None:
         self._grid.add(self._artists_label)
     self._grid.add(self._duration_label)
     self._grid.add(self.__menu_button)
     self.add(self._row_widget)
     self.get_style_context().add_class("trackrow")
예제 #12
0
    def get_album_artwork(self, album, size, scale):
        """
            Return a cairo surface for album_id, covers are cached as jpg.
            @param album as Album
            @param pixbuf size as int
            @param scale factor as int
            @return cairo surface
        """
        size *= scale
        filename = self.get_album_cache_name(album)
        cache_path_jpg = "%s/%s_%s.jpg" % (self._CACHE_PATH, filename, size)
        pixbuf = None

        try:
            # Look in cache
            f = Lio.File.new_for_path(cache_path_jpg)
            if f.query_exists():
                pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(cache_path_jpg,
                                                                size,
                                                                size)
            else:
                # Use favorite folder artwork
                if pixbuf is None:
                    uri = self.get_album_artwork_uri(album)
                    data = None
                    if uri is not None:
                        f = Lio.File.new_for_uri(uri)
                        (status, data, tag) = f.load_contents(None)
                        ratio = self._respect_ratio(uri)
                        stream = Gio.MemoryInputStream.new_from_data(data,
                                                                     None)
                        pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(
                                                                       stream,
                                                                       size,
                                                                       size,
                                                                       ratio,
                                                                       None)
                        stream.close()
                # Use tags artwork
                if pixbuf is None and album.tracks:
                    try:
                        pixbuf = self.pixbuf_from_tags(
                                    album.tracks[0].uri, size)
                    except Exception as e:
                        print("AlbumArt::get_album_artwork()", e)

                # Use folder artwork
                if pixbuf is None and album.uri != "":
                    uri = self.get_first_album_artwork(album)
                    # Look in album folder
                    if uri is not None:
                        f = Lio.File.new_for_uri(uri)
                        (status, data, tag) = f.load_contents(None)
                        ratio = self._respect_ratio(uri)
                        stream = Gio.MemoryInputStream.new_from_data(data,
                                                                     None)
                        pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(
                                                                       stream,
                                                                       size,
                                                                       size,
                                                                       ratio,
                                                                       None)
                        stream.close()
                # Use default artwork
                if pixbuf is None:
                    self.cache_album_art(album.id)
                    return self.get_default_icon('folder-music-symbolic',
                                                 size,
                                                 scale)
                else:
                    pixbuf.savev(cache_path_jpg, "jpeg", ["quality"],
                                 [str(Lp().settings.get_value(
                                                'cover-quality').get_int32())])
            surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale, None)
            del pixbuf
            return surface

        except Exception as e:
            print("AlbumArt::get_album_artwork()", e)
            return self.get_default_icon('folder-music-symbolic', size, scale)
예제 #13
0
 def _on_playlist_clicked(self, button):
     """
         Prepend track to queue
         @param button as Gtk.Button
     """
     Lp().window.show_playlist_manager(self.id, None, not self.is_track)
예제 #14
0
 def _on_unmap(self, widget):
     """
         Enable global shortcuts
         @param widget as Gtk.Widget
     """
     Lp().window.enable_global_shorcuts(True)
예제 #15
0
 def _on_action_press_event(self, widget, event):
     """
         Append album to current list if not present
         Remove it if present
         @param: widget as Gtk.EventBox
         @param: event as Gdk.Event
     """
     if Lp().player.has_album(self._album):
         if Lp().player.current_track.album.id == self._album.id:
             # If not last album, skip it
             if len(Lp().player.get_albums()) > 1:
                 Lp().player.set_next_context(NextContext.START_NEW_ALBUM)
                 Lp().player.set_next()
                 Lp().player.next()
                 Lp().player.remove_album(self._album)
             # remove it and stop playback by going to next track
             else:
                 Lp().player.remove_album(self._album)
                 Lp().player.set_next()
                 Lp().player.next()
         else:
             Lp().player.remove_album(self._album)
         self.__show_append(True)
     else:
         if Lp().player.is_playing() and not Lp().player.get_albums():
             Lp().player.play_album(self._album)
         else:
             Lp().player.add_album(self._album)
         self.__show_append(False)
     return True
예제 #16
0
 def PlayPause(self):
     Lp().player.play_pause()
예제 #17
0
 def _show_overlay_func(self, set):
     """
         Set overlay
         @param set as bool
     """
     if self._lock_overlay or\
        self._show_overlay == set or\
        (set is True and Lp().player.locked):
         return
     if set:
         # Play button
         self._play_event = Gtk.EventBox()
         self._play_event.set_property('has-tooltip', True)
         self._play_event.set_tooltip_text(_("Play"))
         self._play_event.connect('realize', self._on_eventbox_realize)
         self._play_event.connect('button-press-event',
                                  self._on_play_press_event)
         self._play_button = Gtk.Image.new_from_icon_name(
             'media-playback-start-symbolic', Gtk.IconSize.BUTTON)
         self._play_button.set_opacity(0)
         # Play all button
         self._play_all_event = Gtk.EventBox()
         self._play_all_event.set_property('has-tooltip', True)
         self._play_all_event.set_tooltip_text(_("Play albums"))
         self._play_all_event.set_property('halign', Gtk.Align.END)
         self._play_all_event.connect('realize', self._on_eventbox_realize)
         self._play_all_event.connect('button-press-event',
                                      self._on_play_all_press_event)
         self._play_all_button = Gtk.Image.new()
         self._play_all_button.set_opacity(0)
         # Artwork button
         self._artwork_event = Gtk.EventBox()
         self._artwork_event.set_property('has-tooltip', True)
         self._artwork_event.set_tooltip_text(_("Change artwork"))
         self._artwork_event.set_property('halign', Gtk.Align.END)
         self._artwork_event.connect('realize', self._on_eventbox_realize)
         self._artwork_event.connect('button-press-event',
                                     self._on_artwork_press_event)
         self._artwork_button = Gtk.Image.new_from_icon_name(
             'image-x-generic-symbolic', Gtk.IconSize.BUTTON)
         self._artwork_button.set_opacity(0)
         # Action button
         self._action_event = Gtk.EventBox()
         self._action_event.set_property('has-tooltip', True)
         self._action_event.set_property('halign', Gtk.Align.END)
         self._action_event.connect('realize', self._on_eventbox_realize)
         self._action_event.connect('button-press-event',
                                    self._on_action_press_event)
         self._action_button = Gtk.Image.new()
         self._action_button.set_opacity(0)
         self.__overlay_grid.set_orientation(self._overlay_orientation)
         if self._overlay_orientation == Gtk.Orientation.VERTICAL:
             self._play_event.set_hexpand(False)
             self._play_event.set_vexpand(True)
             self._play_event.set_property('halign', Gtk.Align.END)
             self._play_event.set_property('valign', Gtk.Align.START)
             self.__overlay_grid.set_property('valign', Gtk.Align.FILL)
             self.__overlay_grid.set_property('halign', Gtk.Align.END)
         else:
             self._play_event.set_hexpand(True)
             self._play_event.set_vexpand(False)
             self._play_event.set_property('halign', Gtk.Align.START)
             self._play_event.set_property('valign', Gtk.Align.END)
             self.__overlay_grid.set_property('halign', Gtk.Align.FILL)
             self.__overlay_grid.set_property('valign', Gtk.Align.END)
         self._play_event.add(self._play_button)
         self._play_all_event.add(self._play_all_button)
         self._artwork_event.add(self._artwork_button)
         self._action_event.add(self._action_button)
         self.__overlay_grid.add(self._play_event)
         self.__overlay_grid.add(self._play_all_event)
         self.__overlay_grid.add(self._action_event)
         self.__overlay_grid.add(self._artwork_event)
         self.__overlay_grid.show_all()
         AlbumWidget._show_overlay_func(self, True)
     else:
         AlbumWidget._show_overlay_func(self, False)
         self._play_event.destroy()
         self._play_event = None
         self._play_button.destroy()
         self._play_button = None
         self._play_all_event.destroy()
         self._play_all_event = None
         self._play_all_button.destroy()
         self._play_all_button = None
         self._action_event.destroy()
         self._action_event = None
         self._action_button.destroy()
         self._action_button = None
         self._artwork_event.destroy()
         self._artwork_event = None
         self._artwork_button.destroy()
         self._artwork_button = None
예제 #18
0
 def Stop(self):
     Lp().player.stop()
예제 #19
0
 def __on_activated(self, widget, track_id):
     """
         On track activation, play track
         @param widget as TracksWidget
         @param track id as int
     """
     # Add to queue by default
     if Lp().player.locked:
         if track_id in Lp().player.get_queue():
             Lp().player.del_from_queue(track_id)
         else:
             Lp().player.append_to_queue(track_id)
     # Play track with no album, force repeat on track
     elif self._button_state & Gdk.ModifierType.SHIFT_MASK:
         Lp().player.clear_albums()
         self.__show_spinner(widget, track_id)
         track = Track(track_id)
         Lp().player.load(track)
     else:
         # Do not modify album list if in party mode
         if not Lp().player.is_party:
             # If in artist view, reset album list
             if self._filter_ids:
                 Lp().player.set_albums(track_id, self._filter_ids,
                                        self._album.genre_ids)
             # Else, add album if missing
             elif not Lp().player.has_album(self._album):
                 Lp().player.add_album(self._album)
         self.__show_spinner(widget, track_id)
         track = Track(track_id)
         Lp().player.load(track)
         if self._button_state & Gdk.ModifierType.CONTROL_MASK:
             Lp().player.set_next_context(NextContext.STOP_TRACK)
예제 #20
0
 def Play(self):
     if Lp().player.current_track.id is None:
         Lp().player.set_party(True)
     else:
         Lp().player.play()
예제 #21
0
 def load():
     artists = Lp().artists.get(genre_ids)
     compilations = Lp().albums.get_compilation_ids(genre_ids)
     return (artists, compilations)
예제 #22
0
 def SetPosition(self, track_id, position):
     Lp().player.seek(position/1000000)
예제 #23
0
 def load():
     items = []
     is_compilation = artist_ids and artist_ids[0] == Type.COMPILATIONS
     if genre_ids and genre_ids[0] == Type.ALL:
         if is_compilation or\
                 Lp().settings.get_value('show-compilations'):
             items = Lp().albums.get_compilation_ids()
         if not is_compilation:
             items += Lp().albums.get_ids()
     elif genre_ids and genre_ids[0] == Type.POPULARS:
         items = Lp().albums.get_rated()
         count = 100 - len(items)
         for album in Lp().albums.get_populars(count):
             if album not in items:
                 items.append(album)
     elif genre_ids and genre_ids[0] == Type.LOVED:
         items = Lp().albums.get_loves()
     elif genre_ids and genre_ids[0] == Type.RECENTS:
         items = Lp().albums.get_recents()
     elif genre_ids and genre_ids[0] == Type.RANDOMS:
         items = Lp().albums.get_randoms()
     elif genre_ids and genre_ids[0] in [Type.SPOTIFY, Type.LASTFM]:
         items = Lp().tracks.get_charts_ids(genre_ids)
     elif genre_ids and genre_ids[0] == Type.ITUNES:
         items = Lp().albums.get_charts_ids(genre_ids)
     elif artist_ids and artist_ids[0] == Type.CHARTS:
         items = Lp().albums.get_charts_ids(genre_ids)
     else:
         if is_compilation or\
                 Lp().settings.get_value('show-compilations'):
             items = Lp().albums.get_compilation_ids(genre_ids)
         if not is_compilation:
             items += Lp().albums.get_ids([], genre_ids)
     return items
예제 #24
0
    def __init__(self, object, button):
        """
            Init widget
            @param object as Track/Album
            @param button as Gtk.Button
        """
        Gtk.Grid.__init__(self)
        self.__object = object
        self.__button = button

        can_launch = False

        if self.__object.is_web:
            if self.__object.genre_ids == [Type.CHARTS]:
                if isinstance(self.__object, Album):
                    save = HoverWidget('document-save-symbolic',
                                       self.__save_object)
                    save.set_tooltip_text(_("Save into collection"))
                    save.set_margin_end(10)
                    save.show()
            else:
                trash = HoverWidget('user-trash-symbolic',
                                    self.__remove_object)
                if isinstance(self.__object, Album):
                    trash.set_tooltip_text(_("Remove album"))
                else:
                    trash.set_tooltip_text(_("Remove track"))
                trash.set_margin_end(10)
                trash.show()
        else:
            # Check portal for tag editor
            try:
                bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
                proxy = Gio.DBusProxy.new_sync(bus, Gio.DBusProxyFlags.NONE,
                                               None,
                                               'org.gnome.Lollypop.Portal',
                                               '/org/gnome/LollypopPortal',
                                               'org.gnome.Lollypop.Portal',
                                               None)
                can_launch = proxy.call_sync('CanLaunchTagEditor', None,
                                             Gio.DBusCallFlags.NO_AUTO_START,
                                             500, None)[0]
            except:
                print("You are missing lollypop-portal: "
                      "https://github.com/gnumdk/lollypop-portal")
            if can_launch:
                edit = HoverWidget('document-properties-symbolic',
                                   self.__edit_tags)
                edit.set_tooltip_text(_("Modify information"))
                edit.set_margin_end(10)
                edit.show()

        playlist = HoverWidget('view-list-symbolic',
                               self.__show_playlist_manager)
        playlist.set_tooltip_text(_("Playlists"))
        playlist.show()

        if isinstance(self.__object, Album):
            if Lp().player.album_in_queue(self.__object):
                queue = HoverWidget('list-remove-symbolic',
                                    self.__add_to_queue)
                queue.set_tooltip_text(_("Remove from queue"))
            else:
                queue = HoverWidget('list-add-symbolic', self.__add_to_queue)
                queue.set_tooltip_text(_("Add to queue"))
            queue.set_margin_start(10)
            queue.show()
        else:
            rating = RatingWidget(object)
            rating.set_margin_top(5)
            rating.set_margin_bottom(5)
            rating.set_property('halign', Gtk.Align.END)
            rating.set_property('hexpand', True)
            rating.show()

            loved = LovedWidget(object.id)
            loved.set_margin_end(5)
            loved.set_margin_top(5)
            loved.set_margin_bottom(5)
            loved.show()

            if self.__object.is_web:
                web = Gtk.LinkButton(self.__object.uri)
                icon = Gtk.Image.new_from_icon_name('web-browser-symbolic',
                                                    Gtk.IconSize.MENU)
                web.set_image(icon)
                web.get_style_context().add_class('no-padding')
                web.set_margin_start(5)
                web.set_tooltip_text(self.__object.uri)
                web.show_all()
                uri = "https://www.youtube.com/results?search_query=%s" %\
                    (self.__object.artists[0] + " " + self.__object.name,)
                search = Gtk.LinkButton(uri)
                icon = Gtk.Image.new_from_icon_name('edit-find-symbolic',
                                                    Gtk.IconSize.MENU)
                search.set_image(icon)
                search.get_style_context().add_class('no-padding')
                search.set_tooltip_text(uri)
                search.show_all()

        if self.__object.is_web:
            if self.__object.genre_ids == [Type.CHARTS]:
                if isinstance(self.__object, Album):
                    self.add(save)
            else:
                self.add(trash)
        elif can_launch:
            self.add(edit)
        self.add(playlist)
        if isinstance(self.__object, Album):
            self.add(queue)
        else:
            if self.__object.album.is_web:
                self.add(web)
                self.add(search)
            self.add(rating)
            self.add(loved)
예제 #25
0
 def _update_metadata(self):
     if self._get_status() == "Stopped":
         self._metadata = {}
     else:
         if Lp().player.current_track.id >= 0:
             self._metadata["mpris:trackid"] = dbus.ObjectPath(
                 "/org/lollypop/%s" % Lp().player.current_track.id)
         else:
             # MPRIS SUX
             track_id = randint(10000000, 90000000)
             self._metadata["mpris:trackid"] = dbus.ObjectPath(
                 "/org/lollypop/%s" % track_id)
         track_number = Lp().player.current_track.number
         if track_number is None:
             track_number = 1
         self._metadata["xesam:trackNumber"] = track_number
         self._metadata["xesam:title"] = Lp().player.current_track.name
         self._metadata["xesam:album"] = Lp(
                                           ).player.current_track.album.name
         self._metadata["xesam:artist"] = Lp().player.current_track.artists
         self._metadata["xesam:albumArtist"] = \
             ", ".join(Lp().player.current_track.album_artists)
         self._metadata["mpris:length"] = dbus.Int64(
             Lp().player.current_track.duration * (1000 * 1000))
         self._metadata["xesam:genre"] = Lp().player.current_track.genres\
             or "Web"
         self._metadata["xesam:url"] = Lp().player.current_track.uri
         rate = Lp().player.current_track.get_rate()
         if rate == Type.NONE:
             rate = Lp().player.current_track.get_popularity()
         self._metadata["xesam:userRating"] = dbus.Double(rate / 5)
         if Lp().player.current_track.id == Type.RADIOS:
             cover_path = Lp().art.get_radio_cache_path(
                  ", ".join(Lp().player.current_track.artists),
                  ArtSize.MONSTER)
         elif Lp().player.current_track.id == Type.EXTERNALS:
             cover_path = "/tmp/lollypop_mpris.jpg"
             pixbuf = Lp().art.pixbuf_from_tags(
                 GLib.filename_from_uri(Lp().player.current_track.uri)[0],
                 ArtSize.MONSTER)
             if pixbuf is not None:
                 pixbuf.savev(cover_path, "jpeg",
                              ["quality"], ["90"])
         else:
             cover_path = Lp().art.get_album_cache_path(
                 Lp().player.current_track.album, ArtSize.MONSTER)
         if cover_path is not None:
             self._metadata["mpris:artUrl"] = "file://" + cover_path
         elif "mpris:artUrl" in self._metadata:
             self._metadata["mpris:artUrl"] = ""
예제 #26
0
    def get_ids(self, artist_ids=[], genre_ids=[]):
        """
            Get albums ids
            @param artist ids as [int]
            @param genre ids as [int]
            @return albums ids as [int]
        """
        genre_ids = remove_static_genres(genre_ids)
        orderby = Lp().settings.get_enum('orderby')
        if orderby == OrderBy.ARTIST:
            order = " ORDER BY artists.sortname\
                     COLLATE NOCASE COLLATE LOCALIZED,\
                     albums.year,\
                     albums.name\
                     COLLATE NOCASE COLLATE LOCALIZED"

        elif orderby == OrderBy.NAME:
            order = " ORDER BY albums.name\
                     COLLATE NOCASE COLLATE LOCALIZED"

        elif orderby == OrderBy.YEAR:
            order = " ORDER BY albums.year,\
                     albums.name\
                     COLLATE NOCASE COLLATE LOCALIZED"

        else:
            order = " ORDER BY albums.popularity DESC,\
                     albums.name\
                     COLLATE NOCASE COLLATE LOCALIZED"

        with SqlCursor(Lp().db) as sql:
            result = []
            # Get albums for all artists
            if not artist_ids and not genre_ids:
                filters = (Type.CHARTS, )
                request = "SELECT DISTINCT albums.rowid\
                           FROM albums, artists,\
                           album_artists, album_genres as AG\
                           WHERE artists.rowid=album_artists.artist_id\
                           AND ? NOT IN (\
                                SELECT album_genres.genre_id\
                                FROM album_genres\
                                WHERE AG.album_id=album_genres.album_id)\
                           AND AG.album_id=albums.rowid\
                           AND albums.rowid=album_artists.album_id"

                if not get_network_available():
                    request += " AND albums.synced!=%s" % Type.NONE
                request += order
                result = sql.execute(request, filters)
            # Get albums for genre
            elif not artist_ids:
                # Only show charts if wanted
                if Type.CHARTS in genre_ids:
                    filters = tuple(genre_ids)
                else:
                    filters = (Type.CHARTS, ) + tuple(genre_ids)
                request = "SELECT DISTINCT albums.rowid FROM albums,\
                           album_genres as AG, artists, album_artists\
                           WHERE artists.rowid=album_artists.artist_id\
                           AND albums.rowid=album_artists.album_id "

                if Type.CHARTS not in genre_ids:
                    request += "AND ? NOT IN (\
                                  SELECT album_genres.genre_id\
                                  FROM album_genres\
                                  WHERE AG.album_id=album_genres.album_id)"

                request += " AND AG.album_id=albums.rowid AND ( "
                for genre_id in genre_ids:
                    request += "AG.genre_id=? OR "
                request += "1=0)"
                if not get_network_available():
                    request += " AND albums.synced!=%s" % Type.NONE
                request += order
                result = sql.execute(request, filters)
            # Get albums for artist
            elif not genre_ids:
                filters = (Type.CHARTS, )
                filters += tuple(artist_ids)
                request = "SELECT DISTINCT albums.rowid\
                           FROM albums, artists,\
                           album_artists, album_genres as AG\
                           WHERE artists.rowid=album_artists.artist_id\
                           AND ? NOT IN (\
                                SELECT album_genres.genre_id\
                                FROM album_genres\
                                WHERE AG.album_id=album_genres.album_id)\
                           AND AG.album_id=albums.rowid\
                           AND album_artists.album_id=albums.rowid AND ("

                for artist_id in artist_ids:
                    request += "album_artists.artist_id=? OR "
                request += "1=0)"
                if not get_network_available():
                    request += " AND albums.synced!=%s" % Type.NONE
                request += order
                result = sql.execute(request, filters)
            # Get albums for artist id and genre id
            else:
                filters = (Type.CHARTS, )
                filters += tuple(artist_ids)
                filters += tuple(genre_ids)
                request = "SELECT DISTINCT albums.rowid\
                           FROM albums, album_genres as AG,\
                           artists, album_artists\
                           WHERE AG.album_id=albums.rowid\
                           AND artists.rowid=album_artists.artist_id\
                           AND ? NOT IN (\
                                SELECT album_genres.genre_id\
                                FROM album_genres\
                                WHERE AG.album_id=album_genres.album_id)\
                           AND album_artists.album_id=albums.rowid AND ("

                for artist_id in artist_ids:
                    request += "album_artists.artist_id=? OR "
                request += "1=0) AND ("
                for genre_id in genre_ids:
                    request += "AG.genre_id=? OR "
                request += "1=0)"
                if not get_network_available():
                    request += " AND albums.synced!=%s" % Type.NONE
                request += order
                result = sql.execute(request, filters)
            return list(itertools.chain(*result))
예제 #27
0
 def Next(self):
     if Lp().notify is not None:
         Lp().notify.inhibit()
     Lp().player.next()
예제 #28
0
 def load():
     return Lp().player.get_user_playlist()
예제 #29
0
 def Pause(self):
     Lp().player.pause()
예제 #30
0
    def _populate(self):
        """
            Populate treeview searching items
            in db based on text entry current text
        """
        results = []
        albums = []

        tracks_non_album_artist = []

        # Get all albums for all artists and non album_artist tracks
        for artist_id in Lp().artists.search(self._current_search):
            for album_id in Lp().albums.get_ids([artist_id], None):
                if (album_id, artist_id) not in albums:
                    albums.append((album_id, artist_id))
            for track_id, track_name in Lp().tracks.get_as_non_album_artist(
                    artist_id):
                tracks_non_album_artist.append((track_id, track_name))

        albums += Lp().albums.search(self._current_search)

        for album_id, artist_id in albums:
            search_obj = SearchObject()
            search_obj.artist = Lp().artists.get_name(artist_id)
            search_obj.title = Lp().albums.get_name(album_id)
            search_obj.count = Lp().albums.get_count(album_id, None)
            search_obj.id = album_id
            search_obj.album_id = album_id
            results.append(search_obj)

        for track_id, track_name in Lp().tracks.search(
                self._current_search) + tracks_non_album_artist:
            search_obj = SearchObject()
            search_obj.title = track_name
            search_obj.id = track_id
            search_obj.album_id = Lp().tracks.get_album_id(track_id)
            search_obj.is_track = True

            artist_id = Lp().albums.get_artist_id(search_obj.album_id)
            if artist_id == Type.COMPILATIONS:
                search_obj.artist = Lp().tracks.get_artist_names(track_id)
            else:
                search_obj.artist = Lp().artists.get_name(artist_id)

            results.append(search_obj)

        if not self._stop_thread:
            self._clear(results)
            GLib.idle_add(self._add_rows, results)
        else:
            self._in_thread = False
            self._stop_thread = False