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
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
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
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(17/20.0)
            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
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(99/100.0)
            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
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);
                __print__(self.channel().first_show)
                __print__(self.channel().first_show())
                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
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)
                [hook(row) for hook in self.hooks["play"]]
                [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
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
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"]]
            self.apply_theme()
            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
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, [])

            
        # initial display
        # streams are already loaded at instantiation
        def first_show(self):
            if not self.streams["favourite"]:
                self.cache()
            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)