def next(self): """ Return next radio name, uri @return Track """ track = Track() if self.current_track.id != Type.RADIOS: return track radios_manager = RadiosManager() radios = radios_manager.get() i = 0 for (radio_id, name) in radios: i += 1 if self.current_track.album_artist == name: break # Get next radio if i >= len(radios): i = 0 name = radios[i][1] uris = radios_manager.get_tracks(name) if len(uris) > 0: track.set_radio(name, uris[0]) return track
def prev(self): """ Return prev radio name, uri @return Track """ track = Track() if self.current_track.id != Type.RADIOS: return track radios_manager = RadiosManager() radios = radios_manager.get() i = len(radios) - 1 for (radio_id, name) in reversed(radios): i -= 1 if self.current_track.album_artist == name: break # Get prev radio if i < 0: i = len(radios) - 1 name = radios[i][1] uris = radios_manager.get_tracks(name) if len(uris) > 0: track.set_radio(name, uris[0]) return track
def __init__(self): View.__init__(self) self._signal = None self._radios_manager = RadiosManager() self._radios_manager.connect('playlists-changed', self._on_radios_changed) builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/RadiosView.ui') builder.connect_signals(self) widget = builder.get_object('widget') self._pop_tunein = TuneinPopover(self._radios_manager) self._pop_tunein.set_relative_to(builder.get_object('search_btn')) self._sizegroup = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.BOTH) self._radiobox = Gtk.FlowBox() self._radiobox.set_sort_func(self._sort_radios) self._radiobox.set_selection_mode(Gtk.SelectionMode.NONE) self._radiobox.connect("child-activated", self._on_album_activated) self._radiobox.set_property('column-spacing', 5) self._radiobox.set_property('row-spacing', 5) self._radiobox.set_homogeneous(True) self._radiobox.set_max_children_per_line(1000) self._radiobox.show() self._viewport.set_property("valign", Gtk.Align.START) self._viewport.set_property('margin', 5) self._viewport.add(self._radiobox) self._scrolledWindow.set_property('expand', True) self.add(widget) self.add(self._scrolledWindow)
def __init__(self): """ Init view """ View.__init__(self) self._signal = None self._radios_manager = RadiosManager() self._radios_manager.connect('playlists-changed', self._on_radios_changed) builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/RadiosView.ui') builder.connect_signals(self) widget = builder.get_object('widget') self._empty = builder.get_object('empty') self._pop_tunein = TuneinPopover(self._radios_manager) self._pop_tunein.set_relative_to(builder.get_object('search_btn')) self._sizegroup = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.BOTH) self._radiobox = Gtk.FlowBox() self._radiobox.set_sort_func(self._sort_radios) self._radiobox.set_selection_mode(Gtk.SelectionMode.NONE) self._radiobox.connect("child-activated", self._on_album_activated) self._radiobox.set_property('column-spacing', 5) self._radiobox.set_property('row-spacing', 5) self._radiobox.set_homogeneous(True) self._radiobox.set_max_children_per_line(1000) self._radiobox.show() self._stack = Gtk.Stack() self._stack.set_transition_duration(500) self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) self._stack.add(self._scrolledWindow) self._stack.add(self._empty) self._stack.show() self._viewport.set_property("valign", Gtk.Align.START) self._viewport.set_property('margin', 5) self._viewport.add(self._radiobox) self._scrolledWindow.set_property('expand', True) self.add(widget) self.add(self._stack)
def __init__(self): """ Init Popover """ Gtk.Popover.__init__(self) self._tunein = TuneIn() self._radio_manager = RadiosManager() self._current_url = None self._previous_urls = [] self._current_items = [] self._stack = Gtk.Stack() self._stack.set_property('expand', True) self._stack.show() builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/TuneinPopover.ui') builder.connect_signals(self) widget = builder.get_object('widget') widget.attach(self._stack, 0, 2, 4, 1) self._back_btn = builder.get_object('back_btn') self._home_btn = builder.get_object('home_btn') self._label = builder.get_object('label') self._view = Gtk.FlowBox() self._view.set_selection_mode(Gtk.SelectionMode.NONE) self._view.set_max_children_per_line(100) self._view.set_property('row-spacing', 10) self._view.set_property('expand', True) self._view.show() builder.get_object('viewport').add(self._view) builder.get_object('viewport').set_property('margin', 10) self._scrolled = builder.get_object('scrolled') self._spinner = builder.get_object('spinner') self._not_found = builder.get_object('notfound') self._stack.add(self._spinner) self._stack.add(self._not_found) self._stack.add(self._scrolled) self._stack.set_visible_child(self._spinner) self.add(widget) size_setting = Lp.settings.get_value('window-size') if isinstance(size_setting[1], int): self.set_size_request(700, size_setting[1]*0.7) else: self.set_size_request(700, 400)
def __init__(self): """ Init toolbar """ Gtk.Bin.__init__(self) builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/ToolbarInfos.ui') builder.connect_signals(self) infobox = builder.get_object('infos') infobox.set_property('has-tooltip', True) self.add(infobox) self._title_label = builder.get_object('title') self._artist_label = builder.get_object('artist') self._cover = builder.get_object('cover') self._pop_albums = AlbumsPopover() self._pop_albums.set_relative_to(infobox) self._pop_tunein = TuneinPopover(RadiosManager()) self._pop_tunein.set_relative_to(infobox) Lp.art.connect('cover-changed', self._update_cover) Lp.art.connect('logo-changed', self._update_logo)
class RadiosView(View): """ Init radios ui with a scrolled grid of radios widgets """ def __init__(self): View.__init__(self) self._signal = None self._radios_manager = RadiosManager() self._radios_manager.connect('playlists-changed', self._on_radios_changed) builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/RadiosView.ui') builder.connect_signals(self) widget = builder.get_object('widget') self._pop_tunein = TuneinPopover(self._radios_manager) self._pop_tunein.set_relative_to(builder.get_object('search_btn')) self._sizegroup = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.BOTH) self._radiobox = Gtk.FlowBox() self._radiobox.set_sort_func(self._sort_radios) self._radiobox.set_selection_mode(Gtk.SelectionMode.NONE) self._radiobox.connect("child-activated", self._on_album_activated) self._radiobox.set_property('column-spacing', 5) self._radiobox.set_property('row-spacing', 5) self._radiobox.set_homogeneous(True) self._radiobox.set_max_children_per_line(1000) self._radiobox.show() self._viewport.set_property("valign", Gtk.Align.START) self._viewport.set_property('margin', 5) self._viewport.add(self._radiobox) self._scrolledWindow.set_property('expand', True) self.add(widget) self.add(self._scrolledWindow) """ Populate view with tracks from playlist Thread safe """ def populate(self): radios_name = [] # Get radios name for (i, name) in self._radios_manager.get(): radios_name.append(name) GLib.idle_add(self._add_radios, radios_name) """ Connect player signal """ def do_show(self): View.do_show(self) self._signal = Lp.art.connect('logo-changed', self._on_logo_changed) """ Disconnect player signal """ def do_hide(self): View.do_hide(self) if self._signal is not None: Lp.art.disconnect(self._signal) ####################### # PRIVATE # ####################### """ Return view children @return [RadioWidget] """ def _get_children(self): children = [] for child in self._radiobox.get_children(): widget = child.get_child() children.append(widget) return children """ Sort radios @param a as Gtk.FlowBoxChild @param b as Gtk.FlowBoxChild """ def _sort_radios(self, a, b): child1 = a.get_children()[0] child2 = b.get_children()[0] return child1.get_name().lower() > child2.get_name().lower() """ Show popover for adding a new radio @param widget as Gtk.Widget """ def _on_new_clicked(self, widget): popover = RadioPopover('', self._radios_manager) popover.set_relative_to(widget) popover.show() """ Show popover for searching radios @param widget as Gtk.Widget """ def _on_search_clicked(self, widget): self._pop_tunein.populate() self._pop_tunein.show() """ Update radios @param manager as PlaylistManager """ def _on_radios_changed(self, manager): radios_name = [] currents = [] new_name = None old_widget = None old_child = None # Get radios name for (i, name) in manager.get(): radios_name.append(name) # Get currents widget less removed for child in self._radiobox.get_children(): widget = child.get_child() if widget.get_name() not in radios_name: old_widget = widget old_child = child else: currents.append(widget.get_name()) # Add the new radio for name in radios_name: if name not in currents: new_name = name break # Rename widget if new_name is not None: if old_widget is not None: old_widget.set_name(new_name) else: self._add_radios([new_name]) # Delete widget elif old_widget is not None: self._radiobox.remove(old_child) old_widget.destroy() """ Update radio logo @param player as Plyaer @param name as string """ def _on_logo_changed(self, player, name): for child in self._radiobox.get_children(): widget = child.get_child() if widget.get_name() == name: widget.update_cover() """ Pop a radio and add it to the view, repeat operation until radio list is empty @param [radio names as string] """ def _add_radios(self, radios): if radios and not self._stop: radio = radios.pop(0) widget = RadioWidget(radio, self._radios_manager) widget.show() self._sizegroup.add_widget(widget) self._radiobox.insert(widget, -1) GLib.idle_add(self._add_radios, radios) else: self._stop = False return None """ Play album @param flowbox as Gtk.Flowbox @child as Gtk.FlowboxChild """ def _on_album_activated(self, flowbox, child): name = child.get_child().get_name() uris = self._radios_manager.get_tracks(name) if len(uris) > 0: track = Track() track.set_radio(name, uris[0]) Lp.player.load(track)
class RadiosView(View): """ Show radios in a grid """ def __init__(self): """ Init view """ View.__init__(self) self._signal = None self._radios_manager = RadiosManager() self._radios_manager.connect('playlists-changed', self._on_radios_changed) builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/RadiosView.ui') builder.connect_signals(self) widget = builder.get_object('widget') self._empty = builder.get_object('empty') self._pop_tunein = TuneinPopover(self._radios_manager) self._pop_tunein.set_relative_to(builder.get_object('search_btn')) self._sizegroup = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.BOTH) self._radiobox = Gtk.FlowBox() self._radiobox.set_sort_func(self._sort_radios) self._radiobox.set_selection_mode(Gtk.SelectionMode.NONE) self._radiobox.connect("child-activated", self._on_album_activated) self._radiobox.set_property('column-spacing', 5) self._radiobox.set_property('row-spacing', 5) self._radiobox.set_homogeneous(True) self._radiobox.set_max_children_per_line(1000) self._radiobox.show() self._stack = Gtk.Stack() self._stack.set_transition_duration(500) self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) self._stack.add(self._scrolledWindow) self._stack.add(self._empty) self._stack.show() self._viewport.set_property("valign", Gtk.Align.START) self._viewport.set_property('margin', 5) self._viewport.add(self._radiobox) self._scrolledWindow.set_property('expand', True) self.add(widget) self.add(self._stack) def populate(self): """ Populate view with tracks from playlist Thread safe """ start_new_thread(self._populate, ()) def do_show(self): """ Connect player signal """ View.do_show(self) self._signal = Lp.art.connect('logo-changed', self._on_logo_changed) def do_hide(self): """ Disconnect player signal """ View.do_hide(self) if self._signal is not None: Lp.art.disconnect(self._signal) ####################### # PRIVATE # ####################### def _populate(self): """ Populate view with tracks from playlist Thread safe """ radios = [] # Get radios name for (i, name) in self._radios_manager.get(): radios.append(name) GLib.idle_add(self._show_stack, radios) def _get_children(self): """ Return view children @return [RadioWidget] """ children = [] for child in self._radiobox.get_children(): widget = child.get_child() children.append(widget) return children def _sort_radios(self, a, b): """ Sort radios @param a as Gtk.FlowBoxChild @param b as Gtk.FlowBoxChild """ child1 = a.get_children()[0] child2 = b.get_children()[0] return child1.get_name().lower() > child2.get_name().lower() def _on_new_clicked(self, widget): """ Show popover for adding a new radio @param widget as Gtk.Widget """ popover = RadioPopover('', self._radios_manager) popover.set_relative_to(widget) popover.show() def _on_search_clicked(self, widget): """ Show popover for searching radios @param widget as Gtk.Widget """ self._pop_tunein.populate() self._pop_tunein.show() def _on_radios_changed(self, manager): """ Update radios @param manager as PlaylistManager """ radios_name = [] currents = [] new_name = None old_widget = None old_child = None # Get radios name for (i, name) in manager.get(): radios_name.append(name) # Get currents widget less removed for child in self._radiobox.get_children(): widget = child.get_child() if widget.get_name() not in radios_name: old_widget = widget old_child = child else: currents.append(widget.get_name()) # Add the new radio for name in radios_name: if name not in currents: new_name = name break # Rename widget if new_name is not None: if old_widget is not None: old_widget.set_name(new_name) else: radios = [new_name] self._show_stack(radios) # Delete widget elif old_widget is not None: self._radiobox.remove(old_child) old_widget.destroy() if not self._radiobox.get_children(): self._show_stack([]) def _on_logo_changed(self, player, name): """ Update radio logo @param player as Plyaer @param name as string """ for child in self._radiobox.get_children(): widget = child.get_child() if widget.get_name() == name: widget.update_cover() def _show_stack(self, radios): """ Switch empty/radios view based on radios @param [radio names as string] """ if radios: self._stack.set_visible_child(self._scrolledWindow) self._add_radios(radios) else: self._stack.set_visible_child(self._empty) def _add_radios(self, radios): """ Pop a radio and add it to the view, repeat operation until radio list is empty @param [radio names as string] """ if radios and not self._stop: radio = radios.pop(0) widget = RadioWidget(radio, self._radios_manager) widget.show() self._sizegroup.add_widget(widget) self._radiobox.insert(widget, -1) GLib.idle_add(self._add_radios, radios) else: self._stop = False return None def _on_album_activated(self, flowbox, child): """ Play album @param flowbox as Gtk.Flowbox @child as Gtk.FlowboxChild """ name = child.get_child().get_name() uris = self._radios_manager.get_tracks(name) if len(uris) > 0: track = Track() track.set_radio(name, uris[0]) Lp.player.load(track)
class TuneinPopover(Gtk.Popover): """ Popover showing tunin radios """ def __init__(self): """ Init Popover """ Gtk.Popover.__init__(self) self._tunein = TuneIn() self._radio_manager = RadiosManager() self._current_url = None self._previous_urls = [] self._current_items = [] self._stack = Gtk.Stack() self._stack.set_property('expand', True) self._stack.show() builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/TuneinPopover.ui') builder.connect_signals(self) widget = builder.get_object('widget') widget.attach(self._stack, 0, 2, 4, 1) self._back_btn = builder.get_object('back_btn') self._home_btn = builder.get_object('home_btn') self._label = builder.get_object('label') self._view = Gtk.FlowBox() self._view.set_selection_mode(Gtk.SelectionMode.NONE) self._view.set_max_children_per_line(100) self._view.set_property('row-spacing', 10) self._view.set_property('expand', True) self._view.show() builder.get_object('viewport').add(self._view) builder.get_object('viewport').set_property('margin', 10) self._scrolled = builder.get_object('scrolled') self._spinner = builder.get_object('spinner') self._not_found = builder.get_object('notfound') self._stack.add(self._spinner) self._stack.add(self._not_found) self._stack.add(self._scrolled) self._stack.set_visible_child(self._spinner) self.add(widget) size_setting = Lp.settings.get_value('window-size') if isinstance(size_setting[1], int): self.set_size_request(700, size_setting[1]*0.7) else: self.set_size_request(700, 400) def populate(self, url=None): """ Populate views @param url as string """ if not self._view.get_children(): self._current_url = url self._clear() self._back_btn.set_sensitive(False) self._home_btn.set_sensitive(False) self._label.set_text(_("Please wait...")) t = Thread(target=self._populate, args=(url,)) t.daemon = True t.start() ####################### # PRIVATE # ####################### def _show_not_found(self): """ Show not found message """ self._label.set_text(_("Can't connect to TuneIn...")) self._stack.set_visible_child(self._not_found) self._home_btn.set_sensitive(True) def _populate(self, url): """ Same as populate() @param url as string @thread safe """ if url is None: self._current_items = self._tunein.get_items() else: self._current_items = self._tunein.get_items(url) if self._current_items: self._add_items() else: GLib.idle_add(self._show_not_found) def _add_items(self): """ Add current items @thread safe """ for item in self._current_items: GLib.idle_add(self._add_item, item) def _add_item(self, item): """ Add item @param item as TuneItem """ child = Gtk.Grid() child.set_property('halign', Gtk.Align.START) child.show() link = Gtk.LinkButton.new_with_label(item.URL, item.TEXT) link.connect('activate-link', self._on_activate_link, item) link.show() if item.TYPE == "audio": link.set_tooltip_text(_("Play")) button = Gtk.Button.new_from_icon_name('list-add-symbolic', Gtk.IconSize.MENU) button.connect('clicked', self._on_button_clicked, item) button.set_relief(Gtk.ReliefStyle.NONE) button.set_tooltip_text(_("Add")) button.show() child.add(button) else: link.set_tooltip_text('') child.add(link) self._view.add(child) # Remove spinner if exist if self._spinner == self._stack.get_visible_child(): self._stack.set_visible_child(self._scrolled) self._label.set_text(_("Browse themes and add a new radio")) if self._current_url is not None: self._back_btn.set_sensitive(True) self._home_btn.set_sensitive(True) def _clear(self): """ Clear view """ for child in self._view.get_children(): self._view.remove(child) child.destroy() def _add_radio(self, item): """ Add selected radio @param item as TuneIn Item """ # Get cover art try: cache = Art._RADIOS_PATH s = Gio.File.new_for_uri(item.LOGO) d = Gio.File.new_for_path(cache+"/%s.png" % item.TEXT.replace('/', '-')) s.copy(d, Gio.FileCopyFlags.OVERWRITE, None, None) except Exception as e: print("TuneinPopover::_add_radio: %s" % e) url = item.URL # Tune in embbed uri in ashx files, so get content if possible try: f = Gio.File.new_for_uri(url) (status, data, tag) = f.load_contents() if status: url = data.decode('utf-8') except Exception as e: print("TuneinPopover::_add_radio: %s" % e) self._radio_manager.add(item.TEXT.replace('/', '-')) self._radio_manager.add_track(item.TEXT.replace('/', '-'), url) def _on_back_btn_clicked(self, btn): """ Go to previous URL @param btn as Gtk.Button """ url = None self._current_url = None if self._previous_urls: url = self._previous_urls.pop() self._stack.set_visible_child(self._spinner) self._clear() self.populate(url) def _on_home_btn_clicked(self, btn): """ Go to root URL @param btn as Gtk.Button """ self._current_url = None self._previous_urls = [] self._stack.set_visible_child(self._spinner) self._clear() self.populate() def _on_activate_link(self, link, item): """ Update header with new link @param link as Gtk.LinkButton @param item as TuneIn Item """ if item.TYPE == "link": self._stack.set_visible_child(self._spinner) self._clear() self._scrolled.get_vadjustment().set_value(0.0) if self._current_url is not None: self._previous_urls.append(self._current_url) self.populate(item.URL) elif item.TYPE == "audio": for i in self._current_items: Lp.player.load_external(i.URL, i.TEXT) Lp.player.play_this_external(item.URL) # Only toolbar will get this one, so only create small in cache if Gio.NetworkMonitor.get_default().get_network_available(): t = Thread(target=Lp.art.copy_uri_to_cache, args=(item.LOGO, item.TEXT, ArtSize.SMALL)) t.daemon = True t.start() return True def _on_button_clicked(self, button, item): """ Play the radio @param link as Gtk.Button @param item as TuneIn Item """ t = Thread(target=self._add_radio, args=(item,)) t.daemon = True t.start() self.hide()