Exemple #1
0
class RadioPopover(Gtk.Popover):
    """
        Popover with radio logos from the web
    """
    def __init__(self, name, radios_manager):
        """
            Init Popover
            @param name as string
            @param radios_manager as RadiosManager
        """
        Gtk.Popover.__init__(self)
        self._name = name
        self._radios_manager = radios_manager
        self._start = 0
        self._orig_pixbufs = {}

        self._stack = ViewContainer(1000)
        self._stack.show()

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/RadioPopover.ui')
        builder.connect_signals(self)

        self._view = Gtk.FlowBox()
        self._view.set_selection_mode(Gtk.SelectionMode.NONE)
        self._view.connect('child-activated', self._on_activate)
        self._view.set_max_children_per_line(100)
        self._view.set_property('row-spacing', 10)
        self._view.show()

        builder.get_object('viewport').add(self._view)

        self._widget = builder.get_object('widget')
        self._logo = builder.get_object('logo')
        self._spinner = builder.get_object('spinner')
        self._not_found = builder.get_object('notfound')
        self._name_entry = builder.get_object('name')
        self._uri_entry = builder.get_object('uri')
        self._btn_add_modify = builder.get_object('btn_add_modify')
        self._stack.add(self._spinner)
        self._stack.add(self._not_found)
        self._stack.add(self._logo)
        self._stack.add(self._widget)
        self._stack.set_visible_child(self._widget)
        self.add(self._stack)

        if self._name == '':
            builder.get_object('btn_add_modify').set_label(_("Add"))
        else:
            builder.get_object('btn_add_modify').set_label(_("Modify"))
            builder.get_object('btn_delete').show()
            self._name_entry.set_text(self._name)
            uris = self._radios_manager.get_tracks(self._name)
            if len(uris) > 0:
                self._uri_entry.set_text(uris[0])

    def do_show(self):
        """
            Resize popover and set signals callback
        """
        Gtk.Popover.do_show(self)
        self._name_entry.grab_focus()
        Lp.window.enable_global_shorcuts(False)

    def do_hide(self):
        """
            Kill thread
        """
        self._thread = False
        Gtk.Popover.do_hide(self)
        Lp.window.enable_global_shorcuts(True)

#######################
# PRIVATE             #
#######################

    def _populate_threaded(self):
        """
            Populate view
        """
        self._thread = True
        start_new_thread(self._populate, ())

    def _populate(self):
        """
            Same as _populate_threaded()
            @thread safe
        """
        self._urls = Lp.art.get_google_arts(self._name + "+logo+radio",
                                            self._start)
        if self._urls:
            self._start += GOOGLE_INC
            self._add_pixbufs()
        else:
            GLib.idle_add(self._show_not_found)

    def _add_pixbufs(self):
        """
            Add urls to the view
        """
        if self._urls:
            url = self._urls.pop()
            stream = None
            try:
                f = Gio.File.new_for_uri(url)
                (status, data, tag) = f.load_contents()
                if status:
                    stream = Gio.MemoryInputStream.new_from_data(data, None)
            except:
                if self._thread:
                    self._add_pixbufs()
            if stream:
                GLib.idle_add(self._add_pixbuf, stream)
            if self._thread:
                self._add_pixbufs()
        elif self._start < GOOGLE_MAX:
            self._populate_threaded()

    def _show_not_found(self):
        """
            Show not found message if view empty
        """
        if len(self._view.get_children()) == 0:
            self._stack.set_visible_child(self._not_found)
            self._stack.clean_old_views(self._not_found)

    def _add_pixbuf(self, stream):
        """
            Add stream to the view
        """
        try:
            pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(
                stream, ArtSize.MONSTER, ArtSize.MONSTER, True, None)
            image = Gtk.Image()
            self._orig_pixbufs[image] = pixbuf
            # Scale preserving aspect ratio
            width = pixbuf.get_width()
            height = pixbuf.get_height()
            if width > height:
                height = height * ArtSize.BIG * self.get_scale_factor() / width
                width = ArtSize.BIG * self.get_scale_factor()
            else:
                width = width * ArtSize.BIG * self.get_scale_factor() / height
                height = ArtSize.BIG * self.get_scale_factor()
            scaled_pixbuf = pixbuf.scale_simple(width, height,
                                                GdkPixbuf.InterpType.BILINEAR)
            del pixbuf
            surface = Gdk.cairo_surface_create_from_pixbuf(
                scaled_pixbuf, 0, None)
            del scaled_pixbuf
            image.set_from_surface(surface)
            del surface
            image.show()
            self._view.add(image)
        except Exception as e:
            print(e)
            pass
        # Remove spinner if exist
        if self._spinner is not None:
            self._stack.set_visible_child(self._logo)
            self._stack.clean_old_views(self._logo)
            self._spinner = None

    def _on_btn_add_modify_clicked(self, widget):
        """
            Add/Modify a radio
            @param widget as Gtk.Widget
        """
        uri = self._uri_entry.get_text()
        new_name = self._name_entry.get_text()
        rename = self._name != '' and self._name != new_name

        if uri != '' and new_name != '':
            if rename:
                self._radios_manager.rename(new_name, self._name)
            else:
                self._radios_manager.add(new_name)
            self._radios_manager.add_track(new_name, uri.lstrip().rstrip())
            self._stack.remove(self._widget)
            self._stack.set_visible_child(self._spinner)
            self._name = new_name
            self._populate_threaded()
            self.set_size_request(700, 400)

    def _on_btn_delete_clicked(self, widget):
        """
            Delete a radio
            @param widget as Gtk.Widget
        """
        if self._name != '':
            cache = Art._RADIOS_PATH
            self._radios_manager.delete(self._name)
            Lp.art.clean_radio_cache(self._name)
            if os.path.exists(cache + "/%s.png" % self._name):
                os.remove(cache + "/%s.png" % self._name)

    def _on_activate(self, flowbox, child):
        """
            Use pixbuf as cover
            Reset cache and use player object to announce cover change
        """
        pixbuf = self._orig_pixbufs[child.get_child()]
        Lp.art.save_radio_logo(pixbuf, self._name)
        Lp.art.clean_radio_cache(self._name)
        Lp.art.announce_logo_update(self._name)
        self.hide()
        self._streams = {}

    def _on_entry_changed(self, entry):
        """
            Update modify/add button
            @param entry as Gtk.Entry
        """
        uri = self._uri_entry.get_text()
        name = self._name_entry.get_text()
        if name != '' and uri.find('://') != -1:
            self._btn_add_modify.set_sensitive(True)
        else:
            self._btn_add_modify.set_sensitive(False)
Exemple #2
0
class RadioPopover(Gtk.Popover):
    """
        Popover with radio logos from the web
    """

    def __init__(self, name, radios_manager):
        """
            Init Popover
            @param name as string
            @param radios_manager as RadiosManager
        """
        Gtk.Popover.__init__(self)
        self._name = name
        self._radios_manager = radios_manager
        self._start = 0
        self._orig_pixbufs = {}

        self._stack = ViewContainer(1000)
        self._stack.show()

        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/RadioPopover.ui')
        builder.connect_signals(self)

        self._view = Gtk.FlowBox()
        self._view.set_selection_mode(Gtk.SelectionMode.NONE)
        self._view.connect('child-activated', self._on_activate)
        self._view.set_max_children_per_line(100)
        self._view.set_property('row-spacing', 10)
        self._view.show()

        builder.get_object('viewport').add(self._view)

        self._widget = builder.get_object('widget')
        self._logo = builder.get_object('logo')
        self._spinner = builder.get_object('spinner')
        self._not_found = builder.get_object('notfound')
        self._name_entry = builder.get_object('name')
        self._uri_entry = builder.get_object('uri')
        self._btn_add_modify = builder.get_object('btn_add_modify')
        self._stack.add(self._spinner)
        self._stack.add(self._not_found)
        self._stack.add(self._logo)
        self._stack.add(self._widget)
        self._stack.set_visible_child(self._widget)
        self.add(self._stack)

        if self._name == '':
            builder.get_object('btn_add_modify').set_label(_("Add"))
        else:
            builder.get_object('btn_add_modify').set_label(_("Modify"))
            builder.get_object('btn_delete').show()
            self._name_entry.set_text(self._name)
            uris = self._radios_manager.get_tracks(self._name)
            if len(uris) > 0:
                self._uri_entry.set_text(uris[0])

    def do_show(self):
        """
            Resize popover and set signals callback
        """
        Gtk.Popover.do_show(self)
        self._name_entry.grab_focus()
        Lp.window.enable_global_shorcuts(False)

    def do_hide(self):
        """
            Kill thread
        """
        self._thread = False
        Gtk.Popover.do_hide(self)
        Lp.window.enable_global_shorcuts(True)

#######################
# PRIVATE             #
#######################
    def _populate_threaded(self):
        """
            Populate view
        """
        self._thread = True
        t = Thread(target=self._populate)
        t.daemon = True
        t.start()

    def _populate(self):
        """
            Same as _populate_threaded()
            @thread safe
        """
        self._urls = Lp.art.get_google_arts(self._name+"+logo+radio",
                                            self._start)
        if self._urls:
            self._start += GOOGLE_INC
            self._add_pixbufs()
        else:
            GLib.idle_add(self._show_not_found)

    def _add_pixbufs(self):
        """
            Add urls to the view
        """
        if self._urls:
            url = self._urls.pop()
            stream = None
            try:
                f = Gio.File.new_for_uri(url)
                (status, data, tag) = f.load_contents()
                if status:
                    stream = Gio.MemoryInputStream.new_from_data(data, None)
            except:
                if self._thread:
                    self._add_pixbufs()
            if stream:
                GLib.idle_add(self._add_pixbuf, stream)
            if self._thread:
                self._add_pixbufs()
        elif self._start < GOOGLE_MAX:
            self._populate_threaded()

    def _show_not_found(self):
        """
            Show not found message if view empty
        """
        if len(self._view.get_children()) == 0:
            self._stack.set_visible_child(self._not_found)
            self._stack.clean_old_views(self._not_found)

    def _add_pixbuf(self, stream):
        """
            Add stream to the view
        """
        try:
            pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(
                stream, ArtSize.MONSTER,
                ArtSize.MONSTER,
                True,
                None)
            image = Gtk.Image()
            self._orig_pixbufs[image] = pixbuf
            # Scale preserving aspect ratio
            width = pixbuf.get_width()
            height = pixbuf.get_height()
            if width > height:
                height = height*ArtSize.BIG*self.get_scale_factor()/width
                width = ArtSize.BIG*self.get_scale_factor()
            else:
                width = width*ArtSize.BIG*self.get_scale_factor()/height
                height = ArtSize.BIG*self.get_scale_factor()
            scaled_pixbuf = pixbuf.scale_simple(width,
                                                height,
                                                GdkPixbuf.InterpType.BILINEAR)
            del pixbuf
            surface = Gdk.cairo_surface_create_from_pixbuf(scaled_pixbuf,
                                                           0,
                                                           None)
            del scaled_pixbuf
            image.set_from_surface(surface)
            del surface
            image.show()
            self._view.add(image)
        except Exception as e:
            print(e)
            pass
        # Remove spinner if exist
        if self._spinner is not None:
            self._stack.set_visible_child(self._logo)
            self._stack.clean_old_views(self._logo)
            self._spinner = None

    def _on_btn_add_modify_clicked(self, widget):
        """
            Add/Modify a radio
            @param widget as Gtk.Widget
        """
        uri = self._uri_entry.get_text()
        new_name = self._name_entry.get_text()
        rename = self._name != '' and self._name != new_name

        if uri != '' and new_name != '':
            if rename:
                self._radios_manager.rename(new_name, self._name)
            else:
                self._radios_manager.add(new_name)
            self._radios_manager.add_track(new_name,
                                           uri.lstrip().rstrip())
            self._stack.remove(self._widget)
            self._stack.set_visible_child(self._spinner)
            self._name = new_name
            self._populate_threaded()
            self.set_size_request(700, 400)

    def _on_btn_delete_clicked(self, widget):
        """
            Delete a radio
            @param widget as Gtk.Widget
        """
        if self._name != '':
            cache = Art._RADIOS_PATH
            self._radios_manager.delete(self._name)
            Lp.art.clean_radio_cache(self._name)
            if os.path.exists(cache+"/%s.png" % self._name):
                os.remove(cache+"/%s.png" % self._name)

    def _on_activate(self, flowbox, child):
        """
            Use pixbuf as cover
            Reset cache and use player object to announce cover change
        """
        pixbuf = self._orig_pixbufs[child.get_child()]
        Lp.art.save_radio_logo(pixbuf, self._name)
        Lp.art.clean_radio_cache(self._name)
        Lp.art.announce_logo_update(self._name)
        self.hide()
        self._streams = {}

    def _on_entry_changed(self, entry):
        """
            Update modify/add button
            @param entry as Gtk.Entry
        """
        uri = self._uri_entry.get_text()
        name = self._name_entry.get_text()
        if name != '' and uri.find('://') != -1:
            self._btn_add_modify.set_sensitive(True)
        else:
            self._btn_add_modify.set_sensitive(False)