def _moveid(self, cmd_args): """ Move id in playlist @syntax move track_id destination @param args as str @return msg as str """ try: tracks_ids = Lp().playlists.get_tracks_ids(Type.MPD) arg = self._get_args(cmd_args) track_id = int(arg[0]) orig = tracks_ids.index(track_id) dst = int(arg[1]) del tracks_ids[orig] tracks_ids.insert(dst, track_id) Lp().playlists.clear(Type.MPD) tracks = [] for track_id in tracks_ids: tracks.append(Track(track_id)) Lp().player.set_user_playlist_by_id(Type.NONE) Lp().playlists.add_tracks(Type.MPD, tracks, False) except: pass return ""
def __init__(self): """ Init popover """ Gtk.Popover.__init__(self) party_grid = Gtk.Grid() party_grid.set_property('margin-start', 10) party_grid.set_property('margin-end', 10) party_grid.set_property('margin-bottom', 5) party_grid.set_property('margin-top', 5) party_grid.set_column_spacing(10) party_grid.set_row_spacing(7) party_grid.show() scrolled = Gtk.ScrolledWindow() scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) scrolled.add(party_grid) scrolled.show() self.add(scrolled) size = Lp().window.get_size() self.set_size_request(-1, size[1] * 0.6) genres = Lp().genres.get() genres.insert(0, (Type.POPULARS, _("Populars"))) genres.insert(1, (Type.RECENTS, _("Recently added"))) ids = Lp().player.get_party_ids() i = 0 x = 0 for genre_id, genre in genres: label = Gtk.Label() label.set_property('halign', Gtk.Align.START) # Hack as ellipsize not working as I want, help welcome ;) label_text = genre[0:20] if len(label_text) != len(genre): label_text += "..." label.set_text(label_text) label.set_tooltip_text(genre) label.show() switch = Gtk.Switch() if genre_id in ids: switch.set_state(True) switch.connect("state-set", self.__on_switch_state_set, genre_id) switch.show() party_grid.attach(label, x, i, 1, 1) party_grid.attach(switch, x + 1, i, 1, 1) if x == 0: x += 2 else: label.set_property('margin-start', 15) i += 1 x = 0
def __init__(self): """ Init popover """ Gtk.Popover.__init__(self) party_grid = Gtk.Grid() party_grid.set_property('margin-start', 10) party_grid.set_property('margin-end', 10) party_grid.set_property('margin-bottom', 5) party_grid.set_property('margin-top', 5) party_grid.set_column_spacing(10) party_grid.set_row_spacing(7) party_grid.show() scrolled = Gtk.ScrolledWindow() scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) scrolled.add(party_grid) scrolled.show() self.add(scrolled) size = Lp().window.get_size() self.set_size_request(-1, size[1]*0.6) genres = Lp().genres.get() genres.insert(0, (Type.POPULARS, _("Populars"))) genres.insert(1, (Type.RECENTS, _("Recently added"))) ids = Lp().player.get_party_ids() i = 0 x = 0 for genre_id, genre in genres: label = Gtk.Label() label.set_property('halign', Gtk.Align.START) label.set_ellipsize(Pango.EllipsizeMode.END) label.set_text(genre) label.set_tooltip_text(genre) label.show() switch = Gtk.Switch() if genre_id in ids: switch.set_state(True) switch.connect("state-set", self._on_switch_state_set, genre_id) switch.show() party_grid.attach(label, x, i, 1, 1) party_grid.attach(switch, x+1, i, 1, 1) if x == 0: x += 2 else: label.set_property('margin-start', 15) i += 1 x = 0
def _playlistid(self, cmd_args): """ Send informations about current playlist @param playlistid @param args as str @return msg as str """ msg = "" try: track_id = int(self._get_args(cmd_args)) msg += self._string_for_track_id(track_id) except: currents = Lp().playlists.get_tracks_ids(Type.MPD) if Lp().player.is_party(): currents.insert(0, Lp().player.current_track.id) if Lp().player.prev_track.id is not None: currents.insert(0, Lp().player.prev_track.id) if Lp().player.next_track.id is not None: currents.append(Lp().player.next_track.id) for track_id in currents: msg += self._string_for_track_id(track_id) return msg
def _playlistinfo(self, cmd_args): """ Send informations about current playlist @syntax playlistinfo [[pos]|[start:end]] @param playlistinfo @param args as str @return msg as str """ msg = "" try: arg = self._get_args(cmd_args)[0] except: arg = None start = end = pos = None if arg is not None: # Check for a range try: splited = arg.split(':') start = int(splited[0]) end = int(splited[1]) except: start = end = None pos = int(arg) currents = Lp().playlists.get_tracks_ids(Type.MPD) if Lp().player.is_party(): currents.insert(0, Lp().player.current_track.id) if Lp().player.prev_track.id is not None: currents.insert(0, Lp().player.prev_track.id) if Lp().player.next_track.id is not None: currents.append(Lp().player.next_track.id) i = 0 for track_id in currents: if (start is not None and start <= i <= end) or\ (pos is not None and pos == i) or\ (start == end == pos is None): msg += self._string_for_track_id(track_id) i += 1 return msg
def _move(self, cmd_args): """ Move range in playlist @syntax move position destination @param args as str @return msg as str """ # TODO implement range tracks_ids = Lp().playlists.get_tracks_ids(Type.MPD) arg = self._get_args(cmd_args) orig = int(arg[0]) dst = int(arg[1]) if orig != dst: track_id = tracks_ids[orig] del tracks_ids[orig] tracks_ids.insert(dst, track_id) Lp().playlists.clear(Type.MPD, False) tracks = [] for track_id in tracks_ids: tracks.append(Track(track_id)) Lp().player.set_user_playlist_by_id(Type.NONE) Lp().playlists.add_tracks(Type.MPD, tracks, False) return ""
class ShufflePlayer(BasePlayer): """ Shuffle player Manage shuffle tracks and party mode """ def __init__(self): """ Init shuffle player """ BasePlayer.__init__(self) self.reset_history() # Party mode self._is_party = False Lp().settings.connect('changed::shuffle', self._set_shuffle) def reset_history(self): """ Reset history """ # Tracks already played self._history = [] # Used by shuffle albums to restore playlist before shuffle self._albums_backup = [] # Albums already played self._already_played_albums = [] # Tracks already played for albums self._already_played_tracks = {} # Reset user playlist self._user_playlist = [] self._user_playlist_ids = [] def next(self): """ Next shuffle track @return Track """ track_id = None if self._shuffle == Shuffle.TRACKS or self._is_party: if self._history and self._history.has_next(): track_id = self._history.get_next().get_value() elif self._albums: track_id = self._shuffle_next() return Track(track_id) def prev(self): """ Prev track based on history @return Track """ track_id = None if self._shuffle == Shuffle.TRACKS or self._is_party: if self._history and self._history.has_prev(): track_id = self._history.get_prev().get_value() else: track_id = self.current_track.id return Track(track_id) def get_party_ids(self): """ Return party ids @return [ids as int] """ party_settings = Lp().settings.get_value('party-ids') ids = [] genre_ids = Lp().genres.get_ids() genre_ids.append(Type.POPULARS) genre_ids.append(Type.RECENTS) for setting in party_settings: if isinstance(setting, int) and\ setting in genre_ids: ids.append(setting) return ids def set_party(self, party): """ Set party mode on if party is True Play a new random track if not already playing @param party as bool """ if party == self._is_party: return self._is_party = party self.reset_history() self.context.genre_ids = {} if self.plugins1.rgvolume is not None and\ self.plugins2.rgvolume is not None: if party: self.context.next = NextContext.NONE self.plugins1.rgvolume.props.album_mode = 0 self.plugins2.rgvolume.props.album_mode = 0 else: self.plugins1.rgvolume.props.album_mode = 1 self.plugins2.rgvolume.props.album_mode = 1 if party: self._external_tracks = [] self.context.genre_ids = {} self.context.track_id = None party_ids = self.get_party_ids() if party_ids: self._albums = Lp().albums.get_party_ids(party_ids) else: self._albums = Lp().albums.get_ids() # We do not store genre_ids for ALL/POPULARS/... genre_ids = [] for genre_id in party_ids: if genre_id > 0: genre_ids.append(genre_id) # Set context for each album for album_id in self._albums: self.context.genre_ids[album_id] = genre_ids self.context.artist_ids[album_id] = [] # Start a new song if not playing if (self.current_track.id in [None, Type.RADIOS])\ and self._albums: track_id = self._get_random() self.load(Track(track_id)) elif not self.is_playing(): self.play() else: # We need to put some context, take first available genre if self.current_track.id: self.set_albums(self.current_track.id, [self.current_track.album_artist_id], []) self.emit('party-changed', party) def is_party(self): """ True if party mode on @return bool """ return self._is_party def shuffle_albums(self, shuffle): """ Shuffle album list @param shuffle as bool """ if shuffle and self._shuffle == Shuffle.ALBUMS: if self._albums: self._albums_backup = list(self._albums) random.shuffle(self._albums) # In album shuffle, keep current album on top if self.current_track.album.id in self._albums: self._albums.remove(self.current_track.album.id) self._albums.insert(0, self.current_track.album.id) elif self._albums_backup: self._albums = self._albums_backup self._albums_backup = [] ####################### # PRIVATE # ####################### def _set_shuffle(self, settings, value): """ Set shuffle mode to gettings value @param settings as Gio.Settings, value as str """ self._shuffle = Lp().settings.get_enum('shuffle') if self.plugins1.rgvolume is not None and\ self.plugins2.rgvolume is not None: if self._shuffle == Shuffle.TRACKS or self._user_playlist: self.plugins1.rgvolume.props.album_mode = 0 self.plugins2.rgvolume.props.album_mode = 0 else: self.plugins1.rgvolume.props.album_mode = 1 self.plugins2.rgvolume.props.album_mode = 1 if self._user_playlist: self._shuffle_playlist() elif self._shuffle == Shuffle.NONE: self.shuffle_albums(False) elif self._shuffle == Shuffle.ALBUMS: self.shuffle_albums(True) if self.current_track.id is not None: self.set_next() def _shuffle_next(self): """ Next track in shuffle mode @return track id as int """ try: track_id = self._get_random() # Need to clear history if track_id is None: self._albums = self._already_played_albums self.reset_history() return self._shuffle_next() return track_id except: # Recursion error return None def _get_random(self): """ Return a random track and make sure it has never been played """ for album_id in sorted(self._albums, key=lambda *args: random.random()): # We need to check this as in party mode, some items do not # have a valid genre (Populars, ...) if album_id in self.context.genre_ids.keys(): genre_ids = self.context.genre_ids[album_id] else: genre_ids = [] tracks = Album(album_id, genre_ids).tracks_ids for track in sorted(tracks, key=lambda *args: random.random()): if album_id not in self._already_played_tracks.keys() or\ track not in self._already_played_tracks[album_id]: return track self._finished = NextContext.STOP_ALBUM # No new tracks for this album, remove it # If albums not in shuffle history, it's not present # in db anymore (update since shuffle set) if album_id in self._already_played_tracks.keys(): self._already_played_tracks.pop(album_id) self._already_played_albums.append(album_id) self._albums.remove(album_id) self._finished = NextContext.STOP_ALL return None def _add_to_shuffle_history(self, track): """ Add a track to shuffle history @param track as Track """ if track.album_id not in self._already_played_tracks.keys(): self._already_played_tracks[track.album_id] = [] if track.id not in self._already_played_tracks[track.album_id]: self._already_played_tracks[track.album_id].append(track.id) def _on_stream_start(self, bus, message): """ On stream start add to shuffle history """ # Add track to shuffle history if needed if self._shuffle != Shuffle.NONE or self._is_party: if self._history: next = self._history.get_next() prev = self._history.get_prev() # Next track if next is not None and\ self.current_track.id == next.get_value(): next = self._history.get_next() next.set_prev(self._history) self._history = next # Previous track elif prev is not None and\ self.current_track.id == prev.get_value(): prev = self._history.get_prev() prev.set_next(self._history) self._history = prev # New track elif self._history.get_value() != self.current_track.id: new_list = LinkedList(self.current_track.id, None, self._history) self._history = new_list else: new_list = LinkedList(self.current_track.id) self._history = new_list self._add_to_shuffle_history(self.current_track)
def __init__(self): """ Init dialog """ self._choosers = [] builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/SettingsDialog.ui') self._settings_dialog = builder.get_object('settings_dialog') self._settings_dialog.set_transient_for(Lp().window) if not Lp().settings.get_value('disable-csd'): self._settings_dialog.set_titlebar( builder.get_object('header_bar')) switch_scan = builder.get_object('switch_scan') switch_scan.set_state(Lp().settings.get_value('auto-update')) switch_view = builder.get_object('switch_dark') switch_view.set_state(Lp().settings.get_value('dark-ui')) switch_background = builder.get_object('switch_background') switch_background.set_state(Lp().settings.get_value('background-mode')) switch_state = builder.get_object('switch_state') switch_state.set_state(Lp().settings.get_value('save-state')) switch_autoplay = builder.get_object('switch_autoplay') switch_autoplay.set_state(Lp().settings.get_value('auto-play')) switch_mpd = builder.get_object('switch_mpd') switch_mpd.set_state(not Lp().settings.get_value('disable-mpd')) switch_genres = builder.get_object('switch_genres') switch_genres.set_state(Lp().settings.get_value('show-genres')) switch_compilations = builder.get_object('switch_compilations') switch_compilations.set_state( Lp().settings.get_value('show-compilations')) self._settings_dialog.connect('destroy', self._edit_settings_close) builder.connect_signals(self) main_chooser_box = builder.get_object('main_chooser_box') self._chooser_box = builder.get_object('chooser_box') party_grid = builder.get_object('party_grid') # # Music tab # dirs = [] for directory in Lp().settings.get_value('music-path'): dirs.append(directory) # Main chooser self._main_chooser = ChooserWidget() image = Gtk.Image.new_from_icon_name("list-add-symbolic", Gtk.IconSize.MENU) self._main_chooser.set_icon(image) self._main_chooser.set_action(self._add_chooser) main_chooser_box.pack_start(self._main_chooser, False, True, 0) if len(dirs) > 0: path = dirs.pop(0) else: path = GLib.get_user_special_dir( GLib.UserDirectory.DIRECTORY_MUSIC) self._main_chooser.set_dir(path) # Others choosers for directory in dirs: self._add_chooser(directory) # # Party mode tab # genres = Lp().genres.get() genres.insert(0, (Type.POPULARS, _("Populars"))) genres.insert(1, (Type.RECENTS, _("Recently added"))) ids = Lp().player.get_party_ids() i = 0 x = 0 for genre_id, genre in genres: label = Gtk.Label() label.set_property('margin-start', 10) label.set_property('halign', Gtk.Align.START) label.set_property('hexpand', True) label.set_ellipsize(Pango.EllipsizeMode.END) label.set_text(genre) label.set_tooltip_text(genre) label.show() switch = Gtk.Switch() if genre_id in ids: switch.set_state(True) switch.connect("state-set", self._party_switch_state, genre_id) switch.set_property('margin-end', 50) switch.show() party_grid.attach(label, x, i, 1, 1) party_grid.attach(switch, x+1, i, 1, 1) if x == 0: x += 2 else: i += 1 x = 0 # # Last.fm tab # if Lp().lastfm is not None and Secret is not None: self._test_img = builder.get_object('test_img') self._login = builder.get_object('login') self._password = builder.get_object('password') schema = Secret.Schema.new("org.gnome.Lollypop", Secret.SchemaFlags.NONE, SecretSchema) Secret.password_lookup(schema, SecretAttributes, None, self._on_password_lookup) builder.get_object('lastfm_grid').set_sensitive(True) builder.get_object('lastfm_error').hide() self._login.set_text( Lp().settings.get_value('lastfm-login').get_string())
def __init__(self): """ Init dialog """ self._choosers = [] self._timeout_id = None builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/SettingsDialog.ui') self._settings_dialog = builder.get_object('settings_dialog') self._settings_dialog.set_transient_for(Lp().window) if not Lp().settings.get_value('disable-csd'): self._settings_dialog.set_titlebar( builder.get_object('header_bar')) switch_scan = builder.get_object('switch_scan') switch_scan.set_state(Lp().settings.get_value('auto-update')) switch_view = builder.get_object('switch_dark') switch_view.set_state(Lp().settings.get_value('dark-ui')) switch_background = builder.get_object('switch_background') switch_background.set_state(Lp().settings.get_value('background-mode')) switch_state = builder.get_object('switch_state') switch_state.set_state(Lp().settings.get_value('save-state')) switch_autoplay = builder.get_object('switch_autoplay') switch_autoplay.set_state(Lp().settings.get_value('auto-play')) switch_mpd = builder.get_object('switch_mpd') switch_mpd.set_state(not Lp().settings.get_value('disable-mpd')) switch_genres = builder.get_object('switch_genres') switch_genres.set_state(Lp().settings.get_value('show-genres')) switch_compilations = builder.get_object('switch_compilations') switch_compilations.set_state( Lp().settings.get_value('show-compilations')) scale_coversize = builder.get_object('scale_coversize') scale_coversize.set_range(100, 300) scale_coversize.set_value( Lp().settings.get_value('cover-size').get_int32()) self._settings_dialog.connect('destroy', self._edit_settings_close) builder.connect_signals(self) main_chooser_box = builder.get_object('main_chooser_box') self._chooser_box = builder.get_object('chooser_box') party_grid = builder.get_object('party_grid') # # Music tab # dirs = [] for directory in Lp().settings.get_value('music-path'): dirs.append(directory) # Main chooser self._main_chooser = ChooserWidget() image = Gtk.Image.new_from_icon_name("list-add-symbolic", Gtk.IconSize.MENU) self._main_chooser.set_icon(image) self._main_chooser.set_action(self._add_chooser) main_chooser_box.pack_start(self._main_chooser, False, True, 0) if len(dirs) > 0: path = dirs.pop(0) else: path = GLib.get_user_special_dir( GLib.UserDirectory.DIRECTORY_MUSIC) self._main_chooser.set_dir(path) # Others choosers for directory in dirs: self._add_chooser(directory) # # Party mode tab # genres = Lp().genres.get() genres.insert(0, (Type.POPULARS, _("Populars"))) genres.insert(1, (Type.RECENTS, _("Recently added"))) ids = Lp().player.get_party_ids() i = 0 x = 0 for genre_id, genre in genres: label = Gtk.Label() label.set_property('margin-start', 10) label.set_property('halign', Gtk.Align.START) label.set_property('hexpand', True) label.set_ellipsize(Pango.EllipsizeMode.END) label.set_text(genre) label.set_tooltip_text(genre) label.show() switch = Gtk.Switch() if genre_id in ids: switch.set_state(True) switch.connect("state-set", self._party_switch_state, genre_id) switch.set_property('margin-end', 50) switch.show() party_grid.attach(label, x, i, 1, 1) party_grid.attach(switch, x + 1, i, 1, 1) if x == 0: x += 2 else: i += 1 x = 0 # # Last.fm tab # if Lp().lastfm is not None and Secret is not None: self._test_img = builder.get_object('test_img') self._login = builder.get_object('login') self._password = builder.get_object('password') schema = Secret.Schema.new("org.gnome.Lollypop", Secret.SchemaFlags.NONE, SecretSchema) Secret.password_lookup(schema, SecretAttributes, None, self._on_password_lookup) builder.get_object('lastfm_grid').set_sensitive(True) builder.get_object('lastfm_error').hide() self._login.set_text( Lp().settings.get_value('lastfm-login').get_string())