def _on_map(self, widget): """ Disable global shortcuts @param widget as Gtk.Widget """ Lp().window.enable_global_shorcuts(False)
def _on_volume_changed(self, player, data=None): self.PropertiesChanged(self.MPRIS_PLAYER_IFACE, {"Volume": dbus.Double( Lp().player.volume), }, [])
def Previous(self): if Lp().notify is not None: Lp().notify.inhibit() Lp().player.prev()
def load(): genres = Lp().genres.get_charts() return genres
def Set(self, interface, property_name, new_value): if property_name == "Volume": Lp().player.set_volume(new_value)
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')
def load(): genres = Lp().genres.get() return genres
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)
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()
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)
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")
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)
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)
def _on_unmap(self, widget): """ Enable global shortcuts @param widget as Gtk.Widget """ Lp().window.enable_global_shorcuts(True)
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
def PlayPause(self): Lp().player.play_pause()
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
def Stop(self): Lp().player.stop()
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)
def Play(self): if Lp().player.current_track.id is None: Lp().player.set_party(True) else: Lp().player.play()
def load(): artists = Lp().artists.get(genre_ids) compilations = Lp().albums.get_compilation_ids(genre_ids) return (artists, compilations)
def SetPosition(self, track_id, position): Lp().player.seek(position/1000000)
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
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)
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"] = ""
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))
def Next(self): if Lp().notify is not None: Lp().notify.inhibit() Lp().player.next()
def load(): return Lp().player.get_user_playlist()
def Pause(self): Lp().player.pause()
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