Internet radio browser GUI for music/video streams from various directory services.

⌈⌋ ⎇ branch:  streamtuner2


Diff

Differences From Artifact [7776cafb92]:

To Artifact [6bfb3a77f9]:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python
# encoding: UTF-8
# api: python
# type: application
# title: streamtuner2
# description: directory browser for internet radio / audio streams
# depends: pygtk | pygi, threading, pyquery, kronos, requests
# version: 2.1.0
# author: mario salzer
# license: public domain
# url: http://freshmeat.net/projects/streamtuner2
# config: <env name="http_proxy" value="" description="proxy for HTTP access" />  <env name="XDG_CONFIG_HOME" description="relocates user .config subdirectory" />
# category: multimedia
# 
#







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python
# encoding: UTF-8
# api: python
# type: application
# title: streamtuner2
# description: directory browser for internet radio / audio streams
# depends: pygtk | pygi, threading, pyquery, kronos, requests
# version: 2.1.1
# author: mario salzer
# license: public domain
# url: http://freshmeat.net/projects/streamtuner2
# config: <env name="http_proxy" value="" description="proxy for HTTP access" />  <env name="XDG_CONFIG_HOME" description="relocates user .config subdirectory" />
# category: multimedia
# 
#
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91

92
93
94
95
96
97
98
    from processing import Process as Thread
except:
    from threading import Thread
    Thread.stop = lambda self: None

# add library path
sys.path.insert(0, "/usr/share/streamtuner2")   # pre-defined directory for modules
sys.path.insert(0, "/usr/share/streamtuner2/bundle")   # external libraries
sys.path.insert(0, ".")   # development module path

# gtk modules
from mygtk import pygtk, gtk, gobject, ui_file, mygtk, ver as GTK_VER

# custom modules
from config import conf   # initializes itself, so all conf.vars are available right away
from config import __print__, dbg
import ahttp
import action  # needs workaround... (action.main=main)

from channels import *
import favicon


__version__ = "2.1.0"









|










>







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
    from processing import Process as Thread
except:
    from threading import Thread
    Thread.stop = lambda self: None

# add library path
sys.path.insert(0, "/usr/share/streamtuner2")   # pre-defined directory for modules
sys.path.append(   "/usr/share/streamtuner2/bundle")   # external libraries
sys.path.insert(0, ".")   # development module path

# gtk modules
from mygtk import pygtk, gtk, gobject, ui_file, mygtk, ver as GTK_VER

# custom modules
from config import conf   # initializes itself, so all conf.vars are available right away
from config import __print__, dbg
import ahttp
import action  # needs workaround... (action.main=main)
import channels
from channels import *
import favicon


__version__ = "2.1.0"


438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
                mygtk.do(lambda:self.statusbar.push(sbar_cid, text))
            pass


        # load plugins from /usr/share/streamtuner2/channels/
        def load_plugin_channels(self):

            # find plugin files
            ls = os.listdir(conf.share + "/channels/")
            ls = [fn[:-3] for fn in ls if re.match("^[a-z][\w\d_]+\.py$", fn)]
            
            # resort with tab order
            order = [module.strip() for module in conf.channel_order.lower().replace(".","_").replace("-","_").split(",")]
            ls = [module for module in (order) if (module in ls)] + [module for module in (ls) if (module not in order)]

            # step through
            for module in ls:
                gui_startup(2/10.0 + 7/10.0 * float(ls.index(module))/len(ls), "loading module "+module)
                                
                # skip module if disabled
                if conf.plugins.get(module, 1) == False:







|
<
<
|
<
<
<







439
440
441
442
443
444
445
446


447



448
449
450
451
452
453
454
                mygtk.do(lambda:self.statusbar.push(sbar_cid, text))
            pass


        # load plugins from /usr/share/streamtuner2/channels/
        def load_plugin_channels(self):

            # find and order plugin files


            ls = channels.module_list()




            # step through
            for module in ls:
                gui_startup(2/10.0 + 7/10.0 * float(ls.index(module))/len(ls), "loading module "+module)
                                
                # skip module if disabled
                if conf.plugins.get(module, 1) == False:
749
750
751
752
753
754
755

756
757
758
759


760

761
762
763
764
765
766
767

# aux win: settings UI
class config_dialog (auxiliary_window):


        # display win_config, pre-fill text fields from global conf. object
        def open(self, widget):

            self.add_plugins()
            self.apply(conf.__dict__, "config_", 0)
            #self.win_config.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#443399'))
            self.combobox_theme()


            self.win_config.show()



        def hide(self, *args):
            self.win_config.hide()
            return True

        







>
|
<
<
|
>
>

>







745
746
747
748
749
750
751
752
753


754
755
756
757
758
759
760
761
762
763
764
765

# aux win: settings UI
class config_dialog (auxiliary_window):


        # display win_config, pre-fill text fields from global conf. object
        def open(self, widget):
            if self.first_open:
                self.add_plugins()


                self.combobox_theme()
                self.first_open = 0
            self.apply(conf.__dict__, "config_", 0)
            self.win_config.show()
        first_open = 1


        def hide(self, *args):
            self.win_config.hide()
            return True

        
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831

832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859






860
861
862
863



864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
        def apply_theme(self):
            if self.theme.get_active() >= 0:
                conf.theme = self.theme.get_model()[ self.theme.get_active()][0]
                main.load_theme()


        # add configuration setting definitions from plugins
        once = 0
        def add_plugins(self):
            if self.once:
                return

            for name,enabled in conf.plugins.items():

                # add plugin load entry
                if name:
                    label = ("enable ⎗ %s channel" if self.channels.get(name) else "use ⎗ %s plugin")
                    cb =  gtk.ToggleButton(label=label % name)

                    self.add_( "config_plugins_"+name, cb )#, label=None, color="#ddd" )

                # look up individual plugin options, if loaded
                if self.channels.get(name) or self.features.get(name):
                    c = self.channels.get(name) or self.features.get(name)
                    for opt in c.config:

                        # default values are already in conf[] dict (now done in conf.add_plugin_defaults)
                            
                        # display checkbox or text entry
                        if opt["type"] == "boolean":
                            cb = gtk.CheckButton(opt["description"])
                            #cb.set_line_wrap(True)
                            self.add_( "config_"+opt["name"], cb )
                        else:
                            self.add_( "config_"+opt["name"], gtk.Entry(), opt["description"] )

                # spacer 
                self.add_( "filler_pl_"+name, gtk.HSeparator() )
            self.once = 1


        # put gtk widgets into config dialog notebook
        def add_(self, id, w, label=None, color=""):
            w.set_property("visible", True)
            main.widgets[id] = w
            if label:
                w.set_width_chars(10)






                label = gtk.Label(label)
                label.set_property("visible", True)
                label.set_line_wrap(True) 
                label.set_size_request(250, -1)



                vbox = gtk.HBox(homogeneous=False, spacing=10)
                vbox.set_property("visible", True)
                vbox.pack_start(w, expand=False, fill=False)
                vbox.pack_start(label, expand=True, fill=True)
                w = vbox
            if color:
                w = mygtk.bg(w, color)
            self.plugin_options.pack_start(w)

        
        # save config
        def save(self, widget):
            self.apply(conf.__dict__, "config_", 1)
            self.apply_theme()
            conf.save(nice=1)







<

<
<

|



<
|
>
|


















<








>
>
>
>
>
>
|
|
|
|
>
>
>
|
|
|
|
|
<
<
<







812
813
814
815
816
817
818

819


820
821
822
823
824

825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845

846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871



872
873
874
875
876
877
878
        def apply_theme(self):
            if self.theme.get_active() >= 0:
                conf.theme = self.theme.get_model()[ self.theme.get_active()][0]
                main.load_theme()


        # add configuration setting definitions from plugins

        def add_plugins(self):



            for name,meta in channels.module_meta().items():

                # add plugin load entry
                if name:

                    cb = gtk.CheckButton(name)
                    cb.child.set_markup("<b>%s</b> <i>(%s)</i> %s\n<small>%s</small>" % (meta["title"], meta["type"], meta.get("version", ""), meta["description"]))
                    self.add_( "config_plugins_"+name, cb )

                # look up individual plugin options, if loaded
                if self.channels.get(name) or self.features.get(name):
                    c = self.channels.get(name) or self.features.get(name)
                    for opt in c.config:

                        # default values are already in conf[] dict (now done in conf.add_plugin_defaults)
                            
                        # display checkbox or text entry
                        if opt["type"] == "boolean":
                            cb = gtk.CheckButton(opt["description"])
                            #cb.set_line_wrap(True)
                            self.add_( "config_"+opt["name"], cb )
                        else:
                            self.add_( "config_"+opt["name"], gtk.Entry(), opt["description"] )

                # spacer 
                self.add_( "filler_pl_"+name, gtk.HSeparator() )



        # put gtk widgets into config dialog notebook
        def add_(self, id, w, label=None, color=""):
            w.set_property("visible", True)
            main.widgets[id] = w
            if label:
                w.set_width_chars(10)
                w = self.hbox(w, self.label(label))
            if color:
                w = mygtk.bg(w, color)
            self.plugin_options.pack_start(w)

        def label(self, label):
            label = gtk.Label(label)
            label.set_property("visible", True)
            label.set_line_wrap(True) 
            label.set_size_request(250, -1)
            return label

        def hbox(self, w1, w2):
            vbox = gtk.HBox(homogeneous=False, spacing=10)
            vbox.set_property("visible", True)
            vbox.pack_start(w1, expand=False, fill=False)
            vbox.pack_start(w2, expand=True, fill=True)
            return vbox




        
        # save config
        def save(self, widget):
            self.apply(conf.__dict__, "config_", 1)
            self.apply_theme()
            conf.save(nice=1)