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

⌈⌋ ⎇ branch:  streamtuner2


Check-in [60a80d0570]

Overview
Comment:more hooks: init, config_load, config_save
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 60a80d0570839f976882dacf64bd0287a8b286ec
User & Date: mario on 2014-05-31 23:31:34
Other Links: manifest | tags
Context
2014-05-31
23:32
More recent links, and injecting phase changed to hooks[init] check-in: fc5c5d8ae7 user: mario tags: trunk
23:31
more hooks: init, config_load, config_save check-in: 60a80d0570 user: mario tags: trunk
09:01
new iTunes Radio stations channel (via RoliSoft Radio Playlist generator API.) check-in: 72fbdf4b92 user: mario tags: trunk
Changes

Modified st2.py from [9bfb28d3f0] to [02ec24050c].

64
65
66
67
68
69
70

71
72
73
74
75
76
77



# standard modules
import sys
import os, os.path
import re


# threading or processing module
try:
    from processing import Process as Thread
except:
    from threading import Thread
    Thread.stop = lambda self: None







>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78



# standard modules
import sys
import os, os.path
import re
from collections import namedtuple

# threading or processing module
try:
    from processing import Process as Thread
except:
    from threading import Thread
    Thread.stop = lambda self: None
107
108
109
110
111
112
113



114
115
116
117
118
119
120
        widgets = {}     # non-glade widgets (the manually instantiated ones)
        channels = {}    # channel modules
        features = {}    # non-channel plugins
        working = []     # threads
        add_signals = {} # channel gtk-handler signals
        hooks = {
            "play": [favicon.download_playing],  # observers queue here



        }

        # status variables
        channel_names = ["bookmarks"]    # order of channel notebook tabs
        current_channel = "bookmarks"    # currently selected channel name (as index in self.channels{})









>
>
>







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
        widgets = {}     # non-glade widgets (the manually instantiated ones)
        channels = {}    # channel modules
        features = {}    # non-channel plugins
        working = []     # threads
        add_signals = {} # channel gtk-handler signals
        hooks = {
            "play": [favicon.download_playing],  # observers queue here
            "init": [],
            "config_load": [],
            "config_save": [],
        }

        # status variables
        channel_names = ["bookmarks"]    # order of channel notebook tabs
        current_channel = "bookmarks"    # currently selected channel name (as index in self.channels{})


149
150
151
152
153
154
155




156
157
158
159
160
161
162
163
164
                if (winstate):
                    for id in winstate.keys():
                        self.channels[id].current = winstate[id]["current"]
                        self.channels[id].shown = winlayout[id+"_list"].get("row:selected", 0)   # actually just used as boolean flag (for late loading of stream list), selection bar has been positioned before already
            except:
                pass # fails for disabled/reordered plugin channels





            # display current open channel/notebook tab
            gui_startup(17/20.0)
            self.current_channel = self.current_channel_gtk()
            try: self.channel().first_show()
            except: __print__(dbg.INIT, "main.__init__: current_channel.first_show() initialization error")

      
            # bind gtk/glade event names to functions
            gui_startup(19/20.0)







>
>
>
>

|







153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
                if (winstate):
                    for id in winstate.keys():
                        self.channels[id].current = winstate[id]["current"]
                        self.channels[id].shown = winlayout[id+"_list"].get("row:selected", 0)   # actually just used as boolean flag (for late loading of stream list), selection bar has been positioned before already
            except:
                pass # fails for disabled/reordered plugin channels

            # late plugin initializations
            gui_startup(17/20.0)
            [callback(self) for callback in self.hooks["init"]]

            # display current open channel/notebook tab
            gui_startup(18/20.0)
            self.current_channel = self.current_channel_gtk()
            try: self.channel().first_show()
            except: __print__(dbg.INIT, "main.__init__: current_channel.first_show() initialization error")

      
            # bind gtk/glade event names to functions
            gui_startup(19/20.0)
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
                "streamedit_open": streamedit.open,
                "streamedit_save": streamedit.save,
                "streamedit_new": streamedit.new,
                "streamedit_cancel": streamedit.cancel,
            }.items() ) + list( self.add_signals.items() ) ))
            
            # actually display main window
            gui_startup(99/100.0)
            self.win_streamtuner2.show()
            

          

        #-- Shortcut for glade.get_widget()
        # Allows access to widgets as direct attributes instead of using .get_widget()







|







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
                "streamedit_open": streamedit.open,
                "streamedit_save": streamedit.save,
                "streamedit_new": streamedit.new,
                "streamedit_cancel": streamedit.cancel,
            }.items() ) + list( self.add_signals.items() ) ))
            
            # actually display main window
            gui_startup(98.9/100.0)
            self.win_streamtuner2.show()
            

          

        #-- Shortcut for glade.get_widget()
        # Allows access to widgets as direct attributes instead of using .get_widget()
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
            # notebook invocation:
            else: #if type(page_num) == int:
                self.current_channel = self.channel_names[page_num]
            
            # if first selected, load current category
            try:
                __print__(dbg.PROC, "channel_switch: try .first_show", self.channel().module);
                __print__(self.channel().first_show)
                __print__(self.channel().first_show())
            except:
                __print__(dbg.INIT, "channel .first_show() initialization error")


        # convert ListStore iter to row number
        def rowno(self):
            (model, iter) = self.model_iter()







<
|







277
278
279
280
281
282
283

284
285
286
287
288
289
290
291
            # notebook invocation:
            else: #if type(page_num) == int:
                self.current_channel = self.channel_names[page_num]
            
            # if first selected, load current category
            try:
                __print__(dbg.PROC, "channel_switch: try .first_show", self.channel().module);

                self.channel().first_show()
            except:
                __print__(dbg.INIT, "channel .first_show() initialization error")


        # convert ListStore iter to row number
        def rowno(self):
            (model, iter) = self.model_iter()
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318


        # play button
        def on_play_clicked(self, widget, event=None, *args):
            row = self.row()
            if row:
                self.channel().play(row)
                [hook(row) for hook in self.hooks["play"]]


        # streamripper
        def on_record_clicked(self, widget):
            row = self.row()
            action.record(row.get("url"), row.get("format", "audio/mpeg"), "url/direct", row=row)








|







311
312
313
314
315
316
317
318
319
320
321
322
323
324
325


        # play button
        def on_play_clicked(self, widget, event=None, *args):
            row = self.row()
            if row:
                self.channel().play(row)
                [callback(row) for callback in self.hooks["play"]]


        # streamripper
        def on_record_clicked(self, widget):
            row = self.row()
            action.record(row.get("url"), row.get("format", "audio/mpeg"), "url/direct", row=row)

742
743
744
745
746
747
748

749
750
751
752
753
754
755
            if self.first_open:
                self.add_plugins()
                self.combobox_theme()
                self.first_open = 0
                self.win_config.resize(565, 625)
            self.load_config(conf.__dict__, "config_")
            self.load_config(conf.plugins, "config_plugins_")

            self.win_config.show()
        first_open = 1

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







>







749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
            if self.first_open:
                self.add_plugins()
                self.combobox_theme()
                self.first_open = 0
                self.win_config.resize(565, 625)
            self.load_config(conf.__dict__, "config_")
            self.load_config(conf.plugins, "config_plugins_")
            [callback() for callback in self.hooks["config_load"]]
            self.win_config.show()
        first_open = 1

        # Hide window
        def hide(self, *args):
            self.win_config.hide()
            return True
873
874
875
876
877
878
879

880
881
882
883
884
885
886
887
                w = mygtk.bg(w, color)
            self.plugin_options.pack_start(w)
        
        # save config
        def save(self, widget):
            self.save_config(conf.__dict__, "config_")
            self.save_config(conf.plugins, "config_plugins_")

            self.apply_theme()
            conf.save(nice=1)
            self.hide()
                  
config_dialog = config_dialog()
# instantiates itself









>
|







881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
                w = mygtk.bg(w, color)
            self.plugin_options.pack_start(w)
        
        # save config
        def save(self, widget):
            self.save_config(conf.__dict__, "config_")
            self.save_config(conf.plugins, "config_plugins_")
            [callback() for callback in main.hooks["config_save"]]
            config_dialog.apply_theme()
            conf.save(nice=1)
            self.hide()
                  
config_dialog = config_dialog()
# instantiates itself


960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977

978

979
980
981
982
983
984
985
        # this channel does not actually retrieve/parse data from anywhere
        def update_categories(self):
            pass
        def update_streams(self, cat):
            return self.streams.get(cat, [])

            
        # initial display
        def first_show(self):
            if not self.streams["favourite"]:
                self.cache()


        # all entries just come from "bookmarks.json"
        def cache(self):
            # stream list
            cache = conf.load(self.module)
            if (cache):

                self.streams = cache



        # save to cache file
        def save(self):
            conf.save(self.module, self.streams, nice=1)









|

<
|







>

>







969
970
971
972
973
974
975
976
977

978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
        # this channel does not actually retrieve/parse data from anywhere
        def update_categories(self):
            pass
        def update_streams(self, cat):
            return self.streams.get(cat, [])

            
        # streams are already loaded at instantiation
        def first_show(self):

            pass


        # all entries just come from "bookmarks.json"
        def cache(self):
            # stream list
            cache = conf.load(self.module)
            if (cache):
                __print__(dbg.PROC, "load bookmarks.json")
                self.streams = cache
            


        # save to cache file
        def save(self):
            conf.save(self.module, self.streams, nice=1)