Exemple #1
0
 def __init__(self):
     self.__client = Client()
Exemple #2
0
    def __init__(self, client=None):
        super(MainWindow, self).__init__()

        if client is None:
            client = Client()

        def channel_compare_cb(model, a, b):
            a, = model.get(a, 0)
            b, = model.get(b, 0)

            return cmp(a.title, b.title) or cmp(a.tags, b.tags) or cmp(a.station.title, b.station.title)

        channels = gtk.ListStore(object)
        channels.set_sort_func(0, channel_compare_cb)
        channels.set_sort_column_id(0, gtk.SORT_ASCENDING)

        tag_completion = TagsCompletion(client.get_tags())
        self.__current_title = None

        def read_wishlist():
            filename = get_config_filename("wishlist")
            wishlist = []

            try:
                text = file(filename).read().strip()
                wishlist = text and text.split("\n") or []

            except IOError:
                pass

            return dict(zip(wishlist, range(len(wishlist))))

        self.__wishlist = read_wishlist()

        def channel_added_cb(client, channel):
            tree_iter = channels.insert(-1, (channel,))
            tag_completion.add(channel.tags)

            if channel == client.current_channel or (
                channel.uri == self.__config.channel_uri and client.current_channel is None
            ):

                model = tree_view.get_model()
                tree_iter = model.convert_child_iter_to_iter(tree_iter)
                tree_view.get_selection().select_iter(tree_iter)

        def state_changed_cb(client):
            if client.is_playing:
                self.__config.channel_uri = client.current_channel.uri
                self.__play_button.set_active(True)
                stream_tags_changed_cb(client)

            else:
                self.__pause_button.set_active(True)
                self.__stream_info.hide()

            tree_view.queue_draw()

        def stream_tags_changed_cb(client):
            self.__current_title = client.stream_tags.get("title").strip() or None
            org = client.stream_tags.get("organization").strip() or None
            markup = []

            if self.__current_title:
                markup.append("<b>%s</b>" % glib.markup_escape_text(self.__current_title))
            if org:
                markup.append("<small>%s</small>" % glib.markup_escape_text(org))

            if markup:
                self.__stream_info.set_markup(" - ".join(markup))
                self.__stream_info.set_tooltip_markup("\n".join(markup))
                self.__stream_info.show()

            else:
                self.__stream_info.set_markup("")
                self.__stream_info.hide()

            self.__favorite_button.set_sensitive(bool(self.__current_title))
            self.__favorite_button.set_active(self.__current_title in self.__wishlist)

        self.__client = client
        self.__client.connect("channel-added", channel_added_cb)
        self.__client.connect("state-changed", state_changed_cb)
        self.__client.connect("stream-tags-changed", stream_tags_changed_cb)
        self.__client.wait(Client.STATE_STATIONS_LOADED)

        self.__filter_timeout = 0
        self.__current_tags = []
        self.__config = Configuration()

        def channel_visible_cb(model, iter):
            channel, = model.get(iter, 0)
            return channel.matches(self.__current_tags)

        matching_channels = gtk.TreeModel.filter_new(channels)
        matching_channels.set_visible_func(channel_visible_cb)

        self.set_title("WebRadio")
        self.set_default_size(500, 400)
        self.set_icon_name("rhythmbox")
        self.connect("destroy", gtk.main_quit)

        vbox = gtk.VBox()
        self.add(vbox)

        toolbar = gtk.Toolbar()
        toolbar.set_show_arrow(False)
        vbox.pack_start(toolbar, expand=False)

        def play_button_clicked_cb(button):
            if not button.get_active():
                self.__client.pause()
                return

            model, tree_iter = tree_view.get_selection().get_selected()
            channel = None

            if model and tree_iter:
                channel, = model.get(tree_iter, 0)

            if channel is not None:
                if channel == self.__client.current_channel:
                    self.__client.resume()

                else:
                    self.__client.play(channel)

        def favorite_button_clicked_cb(button):
            if not self.__current_title:
                return

            if button.get_active():
                self.__wishlist[self.__current_title] = True

            else:
                self.__wishlist.pop(self.__current_title, False)

            wishlist_text = "\n".join(self.__wishlist.keys()) + "\n"
            filename = get_config_filename("wishlist")
            file(filename, "w").write(wishlist_text)

        self.__play_button = gtk.RadioToolButton(None, gtk.STOCK_MEDIA_PLAY)
        self.__play_button.connect("clicked", play_button_clicked_cb)
        self.__play_button.set_is_important(True)
        toolbar.insert(self.__play_button, -1)

        self.__pause_button = gtk.RadioToolButton(self.__play_button, gtk.STOCK_MEDIA_PAUSE)
        toolbar.insert(self.__pause_button, -1)

        self.__favorite_button = gtk.ToggleToolButton(gtk.STOCK_ABOUT)
        self.__favorite_button.connect("clicked", favorite_button_clicked_cb)
        toolbar.insert(self.__favorite_button, -1)

        item = gtk.SeparatorToolItem()
        item.set_expand(True)
        item.set_draw(False)
        toolbar.insert(item, -1)

        item = gtk.ToolItem()
        toolbar.insert(item, -1)

        def filter_timeout_cb(entry):
            self.__current_tags = filter(None, entry.get_text().split(" "))
            matching_channels.refilter()

            self.__filter_timeout = 0
            return False

        def filter_entry_changed_cb(entry, *args):
            if self.__filter_timeout:
                glib.source_remove(self.__filter_timeout)

            self.__filter_timeout = glib.timeout_add(200, filter_timeout_cb, entry)

        self.__filter_entry = gtk.Entry()
        self.__filter_entry.set_width_chars(40)
        self.__filter_entry.set_completion(tag_completion)
        self.__filter_entry.connect("changed", filter_entry_changed_cb)
        item.add(self.__filter_entry)

        scrolled = gtk.ScrolledWindow()
        scrolled.set_shadow_type(gtk.SHADOW_IN)
        scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        vbox.pack_start(scrolled, expand=True)

        def row_activated_cb(view, path, column):
            model = view.get_model()
            channel, = model.get(model.get_iter(path), 0)
            self.__client.play(channel)

        tree_view = gtk.TreeView(matching_channels)
        tree_view.set_headers_visible(False)
        tree_view.connect("row-activated", row_activated_cb)
        scrolled.add(tree_view)

        def adjustment_cb(adjustment):
            model, tree_iter = tree_view.get_selection().get_selected()

            if model and tree_iter:
                path = model.get_path(tree_iter)
                tree_view.scroll_to_cell(path, None, True, 0.5, 0.5)

        tree_view.get_vadjustment().connect("changed", adjustment_cb)

        def icon_cell_data_cb(column, cell, model, iter):
            channel, = model.get(iter, 0)

            if channel != self.__client.current_channel:
                cell.set_property("stock-id", None)

            elif self.__client.is_playing:
                cell.set_property("stock-id", gtk.STOCK_MEDIA_PLAY)

            else:
                cell.set_property("stock-id", gtk.STOCK_MEDIA_PAUSE)

        def text_cell_data_cb(column, cell, model, iter):
            channel, = model.get(iter, 0)

            title, tags = channel.title, channel.tags
            tags = [channel.station.id] + list(tags)

            details = title, " ".join(tags), channel.station.title
            details = tuple(map(glib.markup_escape_text, details))

            markup = "<b>%s</b>\n<small>%s - %s</small>" % details
            cell.set_property("markup", markup)

        cell = gtk.CellRendererPixbuf()
        cell.set_properties(stock_size=gtk.ICON_SIZE_MENU)
        column = gtk.TreeViewColumn("Icon", cell)
        column.set_cell_data_func(cell, icon_cell_data_cb)
        column.set_expand(False)
        tree_view.insert_column(column, -1)

        cell = gtk.CellRendererText()
        cell.set_properties(ellipsize=pango.ELLIPSIZE_END)
        column = gtk.TreeViewColumn(None, cell)
        column.set_cell_data_func(cell, text_cell_data_cb)
        tree_view.insert_column(column, -1)

        self.__stream_info = MarqueLabel()
        self.__stream_info.set_no_show_all(True)
        vbox.pack_start(self.__stream_info, expand=False)

        stream_tags_changed_cb(self.__client)
        state_changed_cb(self.__client)

        tags = (self.__config.tags or "").strip()

        self.__filter_entry.grab_focus()
        self.__filter_entry.set_text(tags + " ")
        self.__filter_entry.set_position(-1)

        for station in self.__client.get_stations():
            for channel in station.channels:
                channel_added_cb(self.__client, channel)

        self.get_child().show_all()
Exemple #3
0
class CommandLineClient(object):
    def __init__(self):
        self.__client = Client()

    @staticmethod
    def list_channels(channels):
        stations = dict()

        for c in channels:
            l = stations.get(c.station, []) + [c]
            stations[c.station] = l

        for s, l in stations.items():
            print '\n - '.join(
                ['%s: %s' % (s.id, s.title)] +
                ['%s [%s]' % (c.title, ' '.join(c.tags)) for c in l])

    @command
    def list(self, args):
        '''List matching stations'''

        self.__client.wait(Client.STATE_CHANNELS_LOADED)
        channels = self.__client.find_channels(args[2:])
        self.list_channels(channels)

    @command
    def status(self, args=None):
        '''Print service status'''

        state = self.__client.is_playing and 'playing' or 'paused'
        channel = self.__client.current_channel

        if channel is not None:
            state += (': "%s" from "%s" [%s]' % (
                channel.title, channel.station.title,
                ' '.join(channel.tags)))

        print state

    @command
    def equalizer(self, args):
        '''Select equalizer profile'''

        if 3 == len(args):
            self.__client.equalizer_profile = args[2]

        else:
            profiles = self.__client.get_equalizer_profiles()
            profiles = ' '.join(profiles)

            print 'Supported profiles: %s' % profiles

    @command
    def play(self, args):
        '''Play music from matching station'''

        query = args[2:]
        self.__client.wait(Client.STATE_CHANNELS_LOADED)
        channels = self.__client.find_channels(query)
        channels = list(channels)

        if not channels:
            print 'No matching channels found'
            return

        self.list_channels(channels)

        if 1 == len(channels):
            self.__client.play(channels[0])

    @command
    def pause(self, args):
        '''Pause music player'''
        self.__client.pause()

    @command
    def resume(self, args):
        '''Resume music player'''
        self.__client.resume()

    @command
    def tags(self, args):
        '''Lists known tags'''

        self.__client.wait(Client.STATE_STATIONS_LOADED)
        for tag in self.__client.get_tags():
            print tag

    @command
    def ui(self, args):
        '''Run user interface'''
        MainWindow(self.__client).run()

    @command
    def help(self, args):
        '''Show usage information'''

        commands = [(f.__name__, f.__doc__) for f in __commands__]
        length = max([len(name) for name, desc in commands])

        print 'Usage: %s COMMAND [ARGS]' % args[0]
        print
        print 'Commands:'
        print

        for name, desc in commands:
            print '  %-*s - %s' % (length, name, desc)

        print

    @command
    def quit(self, args):
        '''Stop the background service'''

        self.__client.quit()

    def run(self, args):
        command_name = len(args) > 1 and args[1]
        command_table = dict([(f.__name__, f) for f in __commands__])
        command_table.get(command_name, CommandLineClient.help)(self, args)
Exemple #4
0
    def __init__(self, client=None):
        super(MainWindow, self).__init__()

        if client is None:
            client = Client()

        def channel_compare_cb(model, a, b):
            a, = model.get(a, 0)
            b, = model.get(b, 0)

            return (cmp(a.title, b.title) or cmp(a.tags, b.tags)
                    or cmp(a.station.title, b.station.title))

        channels = gtk.ListStore(object)
        channels.set_sort_func(0, channel_compare_cb)
        channels.set_sort_column_id(0, gtk.SORT_ASCENDING)

        tag_completion = TagsCompletion(client.get_tags())
        self.__current_title = None

        def read_wishlist():
            filename = get_config_filename('wishlist')
            wishlist = []

            try:
                text = file(filename).read().strip()
                wishlist = text and text.split('\n') or []

            except IOError:
                pass

            return dict(zip(wishlist, range(len(wishlist))))

        self.__wishlist = read_wishlist()

        def channel_added_cb(client, channel):
            tree_iter = channels.insert(-1, (channel, ))
            tag_completion.add(channel.tags)

            if (channel == client.current_channel
                    or (channel.uri == self.__config.channel_uri
                        and client.current_channel is None)):

                model = tree_view.get_model()
                tree_iter = model.convert_child_iter_to_iter(tree_iter)
                tree_view.get_selection().select_iter(tree_iter)

        def state_changed_cb(client):
            if client.is_playing:
                self.__config.channel_uri = client.current_channel.uri
                self.__play_button.set_active(True)
                stream_tags_changed_cb(client)

            else:
                self.__pause_button.set_active(True)
                self.__stream_info.hide()

            tree_view.queue_draw()

        def stream_tags_changed_cb(client):
            self.__current_title = client.stream_tags.get(
                'title').strip() or None
            org = client.stream_tags.get('organization').strip() or None
            markup = []

            if self.__current_title:
                markup.append('<b>%s</b>' %
                              glib.markup_escape_text(self.__current_title))
            if org:
                markup.append('<small>%s</small>' %
                              glib.markup_escape_text(org))

            if markup:
                self.__stream_info.set_markup(' - '.join(markup))
                self.__stream_info.set_tooltip_markup('\n'.join(markup))
                self.__stream_info.show()

            else:
                self.__stream_info.set_markup('')
                self.__stream_info.hide()

            self.__favorite_button.set_sensitive(bool(self.__current_title))
            self.__favorite_button.set_active(
                self.__current_title in self.__wishlist)

        self.__client = client
        self.__client.connect('channel-added', channel_added_cb)
        self.__client.connect('state-changed', state_changed_cb)
        self.__client.connect('stream-tags-changed', stream_tags_changed_cb)
        self.__client.wait(Client.STATE_STATIONS_LOADED)

        self.__filter_timeout = 0
        self.__current_tags = []
        self.__config = Configuration()

        def channel_visible_cb(model, iter):
            channel, = model.get(iter, 0)
            return channel.matches(self.__current_tags)

        matching_channels = gtk.TreeModel.filter_new(channels)
        matching_channels.set_visible_func(channel_visible_cb)

        self.set_title('WebRadio')
        self.set_default_size(500, 400)
        self.set_icon_name('rhythmbox')
        self.connect('destroy', gtk.main_quit)

        vbox = gtk.VBox()
        self.add(vbox)

        toolbar = gtk.Toolbar()
        toolbar.set_show_arrow(False)
        vbox.pack_start(toolbar, expand=False)

        def play_button_clicked_cb(button):
            if not button.get_active():
                self.__client.pause()
                return

            model, tree_iter = tree_view.get_selection().get_selected()
            channel = None

            if model and tree_iter:
                channel, = model.get(tree_iter, 0)

            if channel is not None:
                if channel == self.__client.current_channel:
                    self.__client.resume()

                else:
                    self.__client.play(channel)

        def favorite_button_clicked_cb(button):
            if not self.__current_title:
                return

            if button.get_active():
                self.__wishlist[self.__current_title] = True

            else:
                self.__wishlist.pop(self.__current_title, False)

            wishlist_text = '\n'.join(self.__wishlist.keys()) + '\n'
            filename = get_config_filename('wishlist')
            file(filename, 'w').write(wishlist_text)

        self.__play_button = gtk.RadioToolButton(None, gtk.STOCK_MEDIA_PLAY)
        self.__play_button.connect('clicked', play_button_clicked_cb)
        self.__play_button.set_is_important(True)
        toolbar.insert(self.__play_button, -1)

        self.__pause_button = gtk.RadioToolButton(self.__play_button,
                                                  gtk.STOCK_MEDIA_PAUSE)
        toolbar.insert(self.__pause_button, -1)

        self.__favorite_button = gtk.ToggleToolButton(gtk.STOCK_ABOUT)
        self.__favorite_button.connect('clicked', favorite_button_clicked_cb)
        toolbar.insert(self.__favorite_button, -1)

        item = gtk.SeparatorToolItem()
        item.set_expand(True)
        item.set_draw(False)
        toolbar.insert(item, -1)

        item = gtk.ToolItem()
        toolbar.insert(item, -1)

        def filter_timeout_cb(entry):
            self.__current_tags = filter(None, entry.get_text().split(' '))
            matching_channels.refilter()

            self.__filter_timeout = 0
            return False

        def filter_entry_changed_cb(entry, *args):
            if self.__filter_timeout:
                glib.source_remove(self.__filter_timeout)

            self.__filter_timeout = glib.timeout_add(200, filter_timeout_cb,
                                                     entry)

        self.__filter_entry = gtk.Entry()
        self.__filter_entry.set_width_chars(40)
        self.__filter_entry.set_completion(tag_completion)
        self.__filter_entry.connect('changed', filter_entry_changed_cb)
        item.add(self.__filter_entry)

        scrolled = gtk.ScrolledWindow()
        scrolled.set_shadow_type(gtk.SHADOW_IN)
        scrolled.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
        vbox.pack_start(scrolled, expand=True)

        def row_activated_cb(view, path, column):
            model = view.get_model()
            channel, = model.get(model.get_iter(path), 0)
            self.__client.play(channel)

        tree_view = gtk.TreeView(matching_channels)
        tree_view.set_headers_visible(False)
        tree_view.connect('row-activated', row_activated_cb)
        scrolled.add(tree_view)

        def adjustment_cb(adjustment):
            model, tree_iter = tree_view.get_selection().get_selected()

            if model and tree_iter:
                path = model.get_path(tree_iter)
                tree_view.scroll_to_cell(path, None, True, 0.5, 0.5)

        tree_view.get_vadjustment().connect('changed', adjustment_cb)

        def icon_cell_data_cb(column, cell, model, iter):
            channel, = model.get(iter, 0)

            if channel != self.__client.current_channel:
                cell.set_property('stock-id', None)

            elif self.__client.is_playing:
                cell.set_property('stock-id', gtk.STOCK_MEDIA_PLAY)

            else:
                cell.set_property('stock-id', gtk.STOCK_MEDIA_PAUSE)

        def text_cell_data_cb(column, cell, model, iter):
            channel, = model.get(iter, 0)

            title, tags = channel.title, channel.tags
            tags = [channel.station.id] + list(tags)

            details = title, ' '.join(tags), channel.station.title
            details = tuple(map(glib.markup_escape_text, details))

            markup = '<b>%s</b>\n<small>%s - %s</small>' % details
            cell.set_property('markup', markup)

        cell = gtk.CellRendererPixbuf()
        cell.set_properties(stock_size=gtk.ICON_SIZE_MENU)
        column = gtk.TreeViewColumn('Icon', cell)
        column.set_cell_data_func(cell, icon_cell_data_cb)
        column.set_expand(False)
        tree_view.insert_column(column, -1)

        cell = gtk.CellRendererText()
        cell.set_properties(ellipsize=pango.ELLIPSIZE_END)
        column = gtk.TreeViewColumn(None, cell)
        column.set_cell_data_func(cell, text_cell_data_cb)
        tree_view.insert_column(column, -1)

        self.__stream_info = MarqueLabel()
        self.__stream_info.set_no_show_all(True)
        vbox.pack_start(self.__stream_info, expand=False)

        stream_tags_changed_cb(self.__client)
        state_changed_cb(self.__client)

        tags = (self.__config.tags or '').strip()

        self.__filter_entry.grab_focus()
        self.__filter_entry.set_text(tags + ' ')
        self.__filter_entry.set_position(-1)

        for station in self.__client.get_stations():
            for channel in station.channels:
                channel_added_cb(self.__client, channel)

        self.get_child().show_all()