class LiqOutput(gtk.VBox):
    def delete_event(self, widget, event, data=None):
        return False

    def destroy(self, widget, data=None):
        gtk.main_quit()

    def __init__(self, host='localhost', port=1234, op='root'):
        gtk.VBox.__init__(self)

        # Connect to liquidsoap
        self.op = op
        self.tel = LiqClient(host, port)

        # Fast metadata view: short metadata, right click to see more (TODO)
        a = self.tel.metadata(self.op + ".metadata")
        self.list = View(
            [
                ['rid', 40],
                ['artist', '120'],
                ['title', '120'],
                # Right-align URI because the end is more informative
                # than the beginning
                ['initial_uri', '300', {
                    'xalign': 1.0
                }],
                ['on_air', '50']
            ],
            a)
        scroll = gtk.ScrolledWindow()
        scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scroll.add(self.list)
        scroll.show()
        self.pack_start(scroll, padding=10)

        # an hbox containing : remaining / start-stop / skip
        self.hbox = gtk.HBox()
        self.pack_start(self.hbox, False, False)

        self.remaining = gtk.Label("...")
        self.hbox.pack_start(self.remaining)
        gobject.timeout_add(1000, self.update)

        self.skip = gtk.Button("skip")
        self.skip.connect("clicked", self.do_skip, None)
        self.hbox.pack_start(self.skip, False, False)

        self.onoff = gtk.ToggleButton("on/off")
        self.onoff.set_active(self.tel.command(self.op + ".status") == "on")
        self.onoff.connect("clicked", self.do_onoff, None)
        self.hbox.pack_start(self.onoff, False, False)

        # Show everything...
        self.list.show()
        self.remaining.show()
        self.onoff.show()
        self.skip.show()
        self.show()
        self.hbox.show()

    def update(self):
        remaining = self.tel.command(self.op + ".remaining")
        if remaining != "(undef)":
            remaining = float(remaining)
            self.remaining.set_label("Remaining: %02d:%02d" %
                                     (remaining / 60, remaining % 60))
        else:
            self.remaining.set_label("Remaining: (undef)")
        self.list.setModel(self.tel.metadata(self.op + ".metadata"))
        if self.tel.command(self.op + ".status") == "on":
            if not self.onoff.get_active():
                self.onoff.set_active(True)
        else:
            if self.onoff.get_active():
                self.onoff.set_active(False)
        return 1

    def do_skip(self, widget, data=None):
        self.tel.command(self.op + ".skip")

    def do_onoff(self, widget, data=None):
        # The state we get is the one *after* the click
        if self.onoff.get_active():
            self.tel.command(self.op + ".start")
        else:
            self.tel.command(self.op + ".stop")

    def main(self):
        gtk.main()
Exemplo n.º 2
0
class LiqOutput(gtk.VBox):

  def delete_event(self, widget, event, data=None):
    return False

  def destroy(self, widget, data=None):
    gtk.main_quit()

  def __init__(self,host='localhost',port=1234,op='root'):
    gtk.VBox.__init__(self)

    # Connect to liquidsoap
    self.op = op
    self.tel = LiqClient(host,port)

    # Fast metadata view: short metadata, right click to see more (TODO)
    a=self.tel.metadata(self.op+".metadata")
    self.list = View([['rid'        , 40],
                      ['artist'     ,'120'],
                      ['title'      ,'120'],
                      # Right-align URI because the end is more informative
                      # than the beginning
                      ['initial_uri','300', {'xalign':1.0}],
                      ['on_air','50']], a)
    scroll = gtk.ScrolledWindow()
    scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
    scroll.add(self.list)
    scroll.show()
    self.pack_start(scroll,padding=10)

    # an hbox containing : remaining / start-stop / skip
    self.hbox = gtk.HBox()
    self.pack_start(self.hbox,False,False)

    self.remaining = gtk.Label("...")
    self.hbox.pack_start(self.remaining)
    gobject.timeout_add(1000,self.update)

    self.skip = gtk.Button("skip")
    self.skip.connect("clicked", self.do_skip, None)
    self.hbox.pack_start(self.skip,False,False)

    self.onoff = gtk.ToggleButton("on/off")
    self.onoff.set_active(self.tel.command(self.op+".status")=="on")
    self.onoff.connect("clicked", self.do_onoff, None)
    self.hbox.pack_start(self.onoff,False,False)

    # Show everything...
    self.list.show()
    self.remaining.show()
    self.onoff.show()
    self.skip.show()
    self.show()
    self.hbox.show()

  def update(self):
    remaining = self.tel.command(self.op+".remaining")
    if remaining!="(undef)":
      remaining=float(remaining)
      self.remaining.set_label("Remaining: %02d:%02d" %
                               (remaining/60,remaining%60))
    else:
      self.remaining.set_label("Remaining: (undef)")
    self.list.setModel(self.tel.metadata(self.op+".metadata"))
    if self.tel.command(self.op+".status")=="on":
      if not self.onoff.get_active():
        self.onoff.set_active(True)
    else:
      if self.onoff.get_active():
        self.onoff.set_active(False)
    return 1

  def do_skip(self,widget,data=None):
    self.tel.command(self.op+".skip")

  def do_onoff(self,widget,data=None):
    # The state we get is the one *after* the click
    if self.onoff.get_active():
      self.tel.command(self.op+".start")
    else:
      self.tel.command(self.op+".stop")

  def main(self):
    gtk.main()
Exemplo n.º 3
0
class LiqQueue(gtk.VPaned):

  def __init__(self,host='localhost',port=1234,op='request'):
    gtk.VPaned.__init__(self)
    self.show()

    # Connect to liquidsoap
    self.op = op
    self.tel = LiqClient(host,port)

    # Fast metadata view: short metadata, right click to see more (TODO)
    self.list = View([['rid'        , 40],
                      ['2nd_queue_pos', 80],
                      ['skip'       , False],
                      ['artist'     ,'120'],
                      ['title'      ,'120'],
                      # Right-align URI because the end is more informative
                      # than the beginning
                      ['initial_uri','250', {'xalign':1.0}]],
                      self.queue())
    self.list.drag_dest_set(gtk.DEST_DEFAULT_ALL,
                            [('text/uri-list',0,0)],
                            gtk.gdk.ACTION_COPY)
    self.list.connect("drag_data_received",self.drag)
    self.list.connect("row_activated",self.row_activated)
    scroll = gtk.ScrolledWindow()
    scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
    scroll.add(self.list)

    # The list is ready, pack it to the top region
    # together with a help label
    box = gtk.VBox()
    lbl = gtk.Label()
    lbl.set_markup("\
<b>Enqueue</b> files by drag-n-dropping from your file manager or \
using the file chooser below.\n\
<b>Remove/restore</b> scheduled files by double-clicking.")
    box.pack_start(scroll,fill=True,expand=True)
    box.pack_start(lbl,fill=True,expand=False)
    self.pack1(box,resize=True)
    lbl.show()
    self.list.show()
    scroll.show()
    box.show()

    fsel = gtk.FileChooserWidget()
    fsel.connect("file_activated", lambda s: self.selected(s))
    exp = gtk.Expander("File chooser")
    exp.add(fsel)
    self.pack2(exp,resize=False)
    fsel.show()
    exp.show()

    gobject.timeout_add(1000,self.update)

  def selected(self,file):
    self.tel.command(self.op+".push "+file.get_filename())

  def drag(self,w,context,x,y,data,info,time):
    if data and data.format == 8:
      for e in data.data.split('\r\n')[:-1]:
        self.tel.command(self.op+".push "+urllib.unquote(e))
        context.finish(gtk.TRUE, gtk.FALSE, time)

  def row_activated(self,view,path,column):
    rid = view.get_model().get_value(view.get_model().get_iter(path),0)
    skip = view.get_model().get_value(view.get_model().get_iter(path),2)
    if skip:
      self.tel.command(self.op+".consider "+str(rid))
    else:
      self.tel.command(self.op+".ignore "+str(rid))

  def queue(self):
    a = filter(lambda x: x!='',
          re.compile('(\d+)\s*').split(self.tel.command(self.op+".queue")))
    a = [ self.tel.metadata('request.metadata '+e)[0] for e in a ]
    return a

  def update(self):
    self.list.setModel(self.queue())
    return 1
class LiqQueue(gtk.VPaned):
    def __init__(self, host='localhost', port=1234, op='request'):
        gtk.VPaned.__init__(self)
        self.show()

        # Connect to liquidsoap
        self.op = op
        self.tel = LiqClient(host, port)

        # Fast metadata view: short metadata, right click to see more (TODO)
        self.list = View(
            [
                ['rid', 40],
                ['2nd_queue_pos', 80],
                ['skip', False],
                ['artist', '120'],
                ['title', '120'],
                # Right-align URI because the end is more informative
                # than the beginning
                ['initial_uri', '250', {
                    'xalign': 1.0
                }]
            ],
            self.queue())
        self.list.drag_dest_set(gtk.DEST_DEFAULT_ALL,
                                [('text/uri-list', 0, 0)], gtk.gdk.ACTION_COPY)
        self.list.connect("drag_data_received", self.drag)
        self.list.connect("row_activated", self.row_activated)
        scroll = gtk.ScrolledWindow()
        scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scroll.add(self.list)

        # The list is ready, pack it to the top region
        # together with a help label
        box = gtk.VBox()
        lbl = gtk.Label()
        lbl.set_markup("\
<b>Enqueue</b> files by drag-n-dropping from your file manager or \
using the file chooser below.\n\
<b>Remove/restore</b> scheduled files by double-clicking.")
        box.pack_start(scroll, fill=True, expand=True)
        box.pack_start(lbl, fill=True, expand=False)
        self.pack1(box, resize=True)
        lbl.show()
        self.list.show()
        scroll.show()
        box.show()

        fsel = gtk.FileChooserWidget()
        fsel.connect("file_activated", lambda s: self.selected(s))
        exp = gtk.Expander("File chooser")
        exp.add(fsel)
        self.pack2(exp, resize=False)
        fsel.show()
        exp.show()

        gobject.timeout_add(1000, self.update)

    def selected(self, file):
        self.tel.command(self.op + ".push " + file.get_filename())

    def drag(self, w, context, x, y, data, info, time):
        if data and data.format == 8:
            for e in data.data.split('\r\n')[:-1]:
                self.tel.command(self.op + ".push " + urllib.unquote(e))
                context.finish(gtk.TRUE, gtk.FALSE, time)

    def row_activated(self, view, path, column):
        rid = view.get_model().get_value(view.get_model().get_iter(path), 0)
        skip = view.get_model().get_value(view.get_model().get_iter(path), 2)
        if skip:
            self.tel.command(self.op + ".consider " + str(rid))
        else:
            self.tel.command(self.op + ".ignore " + str(rid))

    def queue(self):
        a = filter(
            lambda x: x != '',
            re.compile('(\d+)\s*').split(self.tel.command(self.op + ".queue")))
        a = [self.tel.metadata('request.metadata ' + e)[0] for e in a]
        return a

    def update(self):
        self.list.setModel(self.queue())
        return 1
Exemplo n.º 5
0
class LiqEditable(gtk.VPaned):

  def __init__(self,host='localhost',port=1234,op='request'):
    gtk.VPaned.__init__(self)
    self.show()

    # Connect to liquidsoap
    self.op = op
    self.tel = LiqClient(host,port)

    self.list = View([['rid'        , 40],
                      ['status'     ,'70'],
                      ['artist'     ,'120'],
                      ['title'      ,'120'],
                      # Right-align URI because the end is more informative
                      # than the beginning
                      ['initial_uri','300', {'xalign':1.0}]], [])
    self.update()

    # Popup menu for requests
    menu = gtk.Menu()
    item = gtk.ImageMenuItem(gtk.STOCK_REMOVE)
    def remove_request(item):
      model,path = self.list.get_selection().get_selected()
      self.tel.command(self.op+'.remove '+str(model.get_value(path,0)))
    item.connect('activate',remove_request)
    item.show()
    menu.append(item)
    def popup(w,event):
      if event.button==3:
        menu.popup(None,None,None,event.button,event.time)
    self.list.connect('button_press_event',popup)

    # Receive drag-n-drops
    self.list.enable_model_drag_dest(
        [('text/uri-list',0,0),ridformat],
        gtk.gdk.ACTION_DEFAULT)

    def dnd_receive(w,context,x,y,data,info,time):
      if data and (data.format != 8 and data.format != ridformat[2]):
        print "DnD received: Unknown data format! (%d)" % data.format
        return
      row = w.get_dest_row_at_pos(x,y)
      if row:
        # This is an insertion
        path, pos = row
        # Remove the number of resolv(ed|ing) requests to get the pos
        # in the pending queue
        pos = path[0]-(len(w.get_model())-self.plen)
        if pos<0:
          print "Cannot move outside pending queue!"
          return
        if pos >= self.plen-1:
          pos = -1
        if data and data.format == ridformat[2]:
          rid = int(data.data)
          self.tel.command('%s.move %d %d' % (self.op,rid,pos))
        if data and data.format == 8:
          for e in data.data.split('\r\n')[:-1]:
            self.tel.command(self.op+'.insert '+str(pos)+' '+e)
      else:
        # This is a push
        if data and data.format == ridformat[2]:
          rid = int(data.data)
          self.tel.command('%s.move %d %d' % (self.op,rid,-1))
        if data and data.format == 8:
          for e in data.data.split('\r\n')[:-1]:
            self.tel.command(self.op+".push "+urllib.unquote(e))
            context.finish(True, False, time)

    self.list.connect("drag_data_received",dnd_receive)

    # Emit drag-n-drops
    self.list.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,[ridformat],
        gtk.DEST_DEFAULT_ALL)
    def dnd_emit(w,context,sel,info,time):
      # Check that format is RID
      if info==ridformat[2]:
        model,iter = w.get_selection().get_selected()
        if iter:
          sel.set(sel.target,info,str(model.get_value(iter,0)))
    self.list.connect("drag_data_get",dnd_emit)

    # Put the list in a scroll
    scroll = gtk.ScrolledWindow()
    scroll.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
    scroll.add(self.list)
    scroll.show()
    self.list.show()

    # Pack this to self, with a doc label
    box = gtk.VBox()
    lbl = gtk.Label()
    lbl.set_markup("\
<b>Enqueue</b> files by drag-n-dropping from your file manager or \
using the file chooser below.\n\
<b>Re-order</b> the queue by drag-n-dropping.\n\
<b>Remove</b> scheduled requests by right-clicking.")
    box.pack_start(scroll,fill=True,expand=True)
    box.pack_start(lbl,fill=True,expand=False)
    self.pack1(box,resize=True)
    lbl.show()
    box.show()

    # A file selector in the other side of the pane
    fsel = gtk.FileChooserWidget()
    fsel.connect("file_activated", lambda s: self.selected(s))
    exp = gtk.Expander("File chooser")
    exp.add(fsel)
    self.pack2(exp,resize=False)
    fsel.show()
    exp.show()

    # And the update callback
    gobject.timeout_add(1000,self.update)

  def selected(self,file):
    self.tel.command(self.op+".push "+file.get_filename())

  def queue(self):
    a = filter(lambda x: x!='',
          re.compile('(\d+)\s*').split(self.tel.command(self.op+".queue")))
    a = [ self.tel.metadata('request.metadata '+e)[0] for e in a ]
    return a

  def update(self):
    newq = self.queue()
    if newq != self.list.getModel():
      # The test is useless for setModel but needed for plen update
      self.list.setModel(newq)
      plen = int(self.tel.command(self.op+'.pending_length'))
      self.plen = plen
    return 1
class LiqEditable(gtk.VPaned):
    def __init__(self, host='localhost', port=1234, op='request'):
        gtk.VPaned.__init__(self)
        self.show()

        # Connect to liquidsoap
        self.op = op
        self.tel = LiqClient(host, port)

        self.list = View(
            [
                ['rid', 40],
                ['status', '70'],
                ['artist', '120'],
                ['title', '120'],
                # Right-align URI because the end is more informative
                # than the beginning
                ['initial_uri', '300', {
                    'xalign': 1.0
                }]
            ],
            [])
        self.update()

        # Popup menu for requests
        menu = gtk.Menu()
        item = gtk.ImageMenuItem(gtk.STOCK_REMOVE)

        def remove_request(item):
            model, path = self.list.get_selection().get_selected()
            self.tel.command(self.op + '.remove ' +
                             str(model.get_value(path, 0)))

        item.connect('activate', remove_request)
        item.show()
        menu.append(item)

        def popup(w, event):
            if event.button == 3:
                menu.popup(None, None, None, event.button, event.time)

        self.list.connect('button_press_event', popup)

        # Receive drag-n-drops
        self.list.enable_model_drag_dest([('text/uri-list', 0, 0), ridformat],
                                         gtk.gdk.ACTION_DEFAULT)

        def dnd_receive(w, context, x, y, data, info, time):
            if data and (data.format != 8 and data.format != ridformat[2]):
                print "DnD received: Unknown data format! (%d)" % data.format
                return
            row = w.get_dest_row_at_pos(x, y)
            if row:
                # This is an insertion
                path, pos = row
                # Remove the number of resolv(ed|ing) requests to get the pos
                # in the pending queue
                pos = path[0] - (len(w.get_model()) - self.plen)
                if pos < 0:
                    print "Cannot move outside pending queue!"
                    return
                if pos >= self.plen - 1:
                    pos = -1
                if data and data.format == ridformat[2]:
                    rid = int(data.data)
                    self.tel.command('%s.move %d %d' % (self.op, rid, pos))
                if data and data.format == 8:
                    for e in data.data.split('\r\n')[:-1]:
                        self.tel.command(self.op + '.insert ' + str(pos) +
                                         ' ' + e)
            else:
                # This is a push
                if data and data.format == ridformat[2]:
                    rid = int(data.data)
                    self.tel.command('%s.move %d %d' % (self.op, rid, -1))
                if data and data.format == 8:
                    for e in data.data.split('\r\n')[:-1]:
                        self.tel.command(self.op + ".push " +
                                         urllib.unquote(e))
                        context.finish(True, False, time)

        self.list.connect("drag_data_received", dnd_receive)

        # Emit drag-n-drops
        self.list.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, [ridformat],
                                           gtk.DEST_DEFAULT_ALL)

        def dnd_emit(w, context, sel, info, time):
            # Check that format is RID
            if info == ridformat[2]:
                model, iter = w.get_selection().get_selected()
                if iter:
                    sel.set(sel.target, info, str(model.get_value(iter, 0)))

        self.list.connect("drag_data_get", dnd_emit)

        # Put the list in a scroll
        scroll = gtk.ScrolledWindow()
        scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        scroll.add(self.list)
        scroll.show()
        self.list.show()

        # Pack this to self, with a doc label
        box = gtk.VBox()
        lbl = gtk.Label()
        lbl.set_markup("\
<b>Enqueue</b> files by drag-n-dropping from your file manager or \
using the file chooser below.\n\
<b>Re-order</b> the queue by drag-n-dropping.\n\
<b>Remove</b> scheduled requests by right-clicking.")
        box.pack_start(scroll, fill=True, expand=True)
        box.pack_start(lbl, fill=True, expand=False)
        self.pack1(box, resize=True)
        lbl.show()
        box.show()

        # A file selector in the other side of the pane
        fsel = gtk.FileChooserWidget()
        fsel.connect("file_activated", lambda s: self.selected(s))
        exp = gtk.Expander("File chooser")
        exp.add(fsel)
        self.pack2(exp, resize=False)
        fsel.show()
        exp.show()

        # And the update callback
        gobject.timeout_add(1000, self.update)

    def selected(self, file):
        self.tel.command(self.op + ".push " + file.get_filename())

    def queue(self):
        a = filter(
            lambda x: x != '',
            re.compile('(\d+)\s*').split(self.tel.command(self.op + ".queue")))
        a = [self.tel.metadata('request.metadata ' + e)[0] for e in a]
        return a

    def update(self):
        newq = self.queue()
        if newq != self.list.getModel():
            # The test is useless for setModel but needed for plen update
            self.list.setModel(newq)
            plen = int(self.tel.command(self.op + '.pending_length'))
            self.plen = plen
        return 1