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

⌈⌋ ⎇ branch:  streamtuner2


Check-in [41405a6488]

Overview
Comment:fixed channels/timer gtk signal_connect handling, st2main now provides an amendable slot dict
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 41405a6488758582e7ee2afcdffa4101dcce95f2
User & Date: mario on 2014-01-05 03:30:44
Original Comment: (no comment)
Other Links: manifest | tags
Context
2014-01-06
22:45
prepare for gtk3 check-in: c0702405f8 user: mario tags: trunk
2014-01-05
03:30
fixed channels/timer gtk signal_connect handling, st2main now provides an amendable slot dict check-in: 41405a6488 user: mario tags: trunk
01:23
fix Pixbuf has_alpha bug due to redundant typecast prior liststore appending check-in: caee086b9c user: mario tags: trunk, 2.0.9
Changes

Modified _pack from [b488883eba] to [b33b7021fe].

11
12
13
14
15
16
17

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35





36
37
38
39
40
41
42


43
pax -wvJf streamtuner2-$VERSION.src.txz \
	streamtuner2/*.py streamtuner2/*.xml streamtuner2/channels/*.{py,png} \
	streamtuner2/*.png streamtuner2/*.svg streamtuner2/*.desktop \
	streamtuner2/README streamtuner2/help/* streamtuner2/contrib/* \
	streamtuner2/PKG-INFO streamtuner2/version streamtuner2/_pack streamtuner2/*.epm
# streamtuner2/scripts
cd -



echo "-------------------- .deb -----------------------"
fakeroot epm -vvv -n -a all -f deb DEP=deb streamtuner2 _package.epm


echo "------------------ slackware --------------------"
epm -vvv -n -a all -f slackware streamtuner2 _package.epm


echo "-------------- .tar.gz installer  ---------------"
epm -vvv -n -a all -f portable -s streamtuner2.png streamtuner2 _package.epm


echo "-------------------- .rpm -----------------------"
epm -vvv -n -a all -f rpm streamtuner2 _package.epm
/usr/bin/rpmbuild -bb --buildroot "/home/mario/projects/streamtuner2/linux-3.0-all/buildroot" --target all linux-3.0-all/streamtuner2.spec
mv linux-3.0-all/RPMS/all/*.rpm linux-3.0-all







echo "-------------------- win32 -----------------------"
for pkg in "win32"
do
  epm-win32sfx -v streamtuner2 _package.epm
done










>

















|
>
>
>
>
>







>
>

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
pax -wvJf streamtuner2-$VERSION.src.txz \
	streamtuner2/*.py streamtuner2/*.xml streamtuner2/channels/*.{py,png} \
	streamtuner2/*.png streamtuner2/*.svg streamtuner2/*.desktop \
	streamtuner2/README streamtuner2/help/* streamtuner2/contrib/* \
	streamtuner2/PKG-INFO streamtuner2/version streamtuner2/_pack streamtuner2/*.epm
# streamtuner2/scripts
cd -
mv ../streamtuner2-*.txz linux-3.0-all/


echo "-------------------- .deb -----------------------"
fakeroot epm -vvv -n -a all -f deb DEP=deb streamtuner2 _package.epm


echo "------------------ slackware --------------------"
epm -vvv -n -a all -f slackware streamtuner2 _package.epm


echo "-------------- .tar.gz installer  ---------------"
epm -vvv -n -a all -f portable -s streamtuner2.png streamtuner2 _package.epm


echo "-------------------- .rpm -----------------------"
epm -vvv -n -a all -f rpm streamtuner2 _package.epm
/usr/bin/rpmbuild -bb --buildroot "/home/mario/projects/streamtuner2/linux-3.0-all/buildroot" --target all linux-3.0-all/streamtuner2.spec
mv linux-3.0-all/RPMS/all/*.rpm linux-3.0-all/streamtuner2-$VERSION.rpm
rm -r linux-3.0-all/RPMS
rm -r linux-3.0-all/rpms
rm -r linux-3.0-all/buildroot
rmdir linux-3.0-all/streamtuner2-$VERSION
rm linux-3.0-all/streamtuner2.spec


echo "-------------------- win32 -----------------------"
for pkg in "win32"
do
  epm-win32sfx -v streamtuner2 _package.epm
done
mv win32/*exe linux-3.0-all/
rmdir win32

Modified channels/shoutcast.py from [20027a66d7] to [59a1f308de].

119
120
121
122
123
124
125


126
127
128
129
130
131
132
            # loop
            entries = []
            next = 0
            max = int(conf.max_streams)
            count = max
            rx_stream = None
            rx_next = re.compile("""onclick="showMoreGenre""")


            while (next < max):

               # page
               url = "http://www.shoutcast.com/genre-ajax/" + ucat
	       referer = url.replace("/genre-ajax", "/radio")
	       params = { "strIndex":"0", "count":str(count), "ajax":"true", "mode":"listeners", "order":"desc" }
               html = http.ajax(url, params, referer)   #,feedback=self.parent.status)







>
>







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
            # loop
            entries = []
            next = 0
            max = int(conf.max_streams)
            count = max
            rx_stream = None
            rx_next = re.compile("""onclick="showMoreGenre""")

            try:
            while (next < max):

               # page
               url = "http://www.shoutcast.com/genre-ajax/" + ucat
	       referer = url.replace("/genre-ajax", "/radio")
	       params = { "strIndex":"0", "count":str(count), "ajax":"true", "mode":"listeners", "order":"desc" }
               html = http.ajax(url, params, referer)   #,feedback=self.parent.status)
197
198
199
200
201
202
203



204
205
206
207
208
               
               # more pages to load?
               if (re.search(rx_next, html)):
                  next += count
               else:
                  next = 99999
            



            #fin
            __print__(entries)
            return entries









>
>
>





199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
               
               # more pages to load?
               if (re.search(rx_next, html)):
                  next += count
               else:
                  next = 99999
            
            except:
               return entries
            
            #fin
            __print__(entries)
            return entries


Modified channels/timer.py from [c3eb5a36c2] to [c50adafaed].

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Okay, while programming this, I missed the broadcast I wanted to hear. Again(!)
# But still this is a useful extension, as it allows recording and playing specific
# stations at a programmed time and interval. It accepts a natural language time
# string when registering a stream. (Via streams menu > extension > add timer)
#
# Programmed events are visible in "timer" under the "bookmarks" channel. Times
# are stored in the description field, and can thus be edited. However, after editing
# times manuall, streamtuner2 must be restarted for the changes to take effect.
#


from channels import *
import kronos
from mygtk import mygtk
from action import action







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Okay, while programming this, I missed the broadcast I wanted to hear. Again(!)
# But still this is a useful extension, as it allows recording and playing specific
# stations at a programmed time and interval. It accepts a natural language time
# string when registering a stream. (Via streams menu > extension > add timer)
#
# Programmed events are visible in "timer" under the "bookmarks" channel. Times
# are stored in the description field, and can thus be edited. However, after editing
# times manually, streamtuner2 must be restarted for the changes to take effect.
#


from channels import *
import kronos
from mygtk import mygtk
from action import action
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
        # target channel
        if not self.bookmarks.streams.get("timer"):
            self.bookmarks.streams["timer"] = [{"title":"--- timer events ---"}]
        self.bookmarks.add_category("timer")
        self.streams = self.bookmarks.streams["timer"]
        
        # widgets
        parent.signal_autoconnect({
            "timer_ok": self.add_timer,
            "timer_cancel": lambda w,*a: self.parent.timer_dialog.hide() or 1,
        })
        
        # prepare spool
        self.sched = kronos.ThreadedScheduler()
        for row in self.streams:







|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
        # target channel
        if not self.bookmarks.streams.get("timer"):
            self.bookmarks.streams["timer"] = [{"title":"--- timer events ---"}]
        self.bookmarks.add_category("timer")
        self.streams = self.bookmarks.streams["timer"]
        
        # widgets
        parent.add_signals.update({
            "timer_ok": self.add_timer,
            "timer_cancel": lambda w,*a: self.parent.timer_dialog.hide() or 1,
        })
        
        # prepare spool
        self.sched = kronos.ThreadedScheduler()
        for row in self.streams:

Modified st2.py from [2dd481062a] to [26d82d3fb9].

118
119
120
121
122
123
124

125
126
127
128
129
130
131


        # object containers
        widgets = {}     # non-glade widgets (the manually instantiated ones)
        channels = {}    # channel modules
        features = {}    # non-channel plugins
        working = []     # threads


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


        # constructor







>







118
119
120
121
122
123
124
125
126
127
128
129
130
131
132


        # object containers
        widgets = {}     # non-glade widgets (the manually instantiated ones)
        channels = {}    # channel modules
        features = {}    # non-channel plugins
        working = []     # threads
        add_signals = {} # channel gtk-handler signals

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


        # constructor
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
            self.current_channel = self.current_channel_gtk()
            try: self.channel().first_show()
            except: print("channel .first_show() initialization error")

      
            # bind gtk/glade event names to functions
            gui_startup(0.95)
            self.connect_signals({
                "gtk_main_quit" : self.gtk_main_quit,                # close window
                # treeviews / notebook
                "on_stream_row_activated" : self.on_play_clicked,    # double click in a streams list
                "on_category_clicked": self.on_category_clicked,     # new selection in category list
                "on_notebook_channels_switch_page": self.channel_switch,   # channel notebook tab changed
                "station_context_menu": lambda tv,ev: station_context_menu(tv,ev),
                # toolbar







|







170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
            self.current_channel = self.current_channel_gtk()
            try: self.channel().first_show()
            except: print("channel .first_show() initialization error")

      
            # bind gtk/glade event names to functions
            gui_startup(0.95)
            self.connect_signals(dict( {
                "gtk_main_quit" : self.gtk_main_quit,                # close window
                # treeviews / notebook
                "on_stream_row_activated" : self.on_play_clicked,    # double click in a streams list
                "on_category_clicked": self.on_category_clicked,     # new selection in category list
                "on_notebook_channels_switch_page": self.channel_switch,   # channel notebook tab changed
                "station_context_menu": lambda tv,ev: station_context_menu(tv,ev),
                # toolbar
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
                "search_google": search.google,
                "search_cancel": search.cancel,
                "true": lambda w,*args: True,
                "streamedit_open": streamedit.open,
                "streamedit_save": streamedit.save,
                "streamedit_new": streamedit.new,
                "streamedit_cancel": streamedit.cancel,
            })
            
            # actually display main window
            gui_startup(0.99)
            self.win_streamtuner2.show()
            
            # WHY DON'T YOU WANT TO WORK?!
            #self.shoutcast.gtk_list.set_enable_search(True)







|







220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
                "search_google": search.google,
                "search_cancel": search.cancel,
                "true": lambda w,*args: True,
                "streamedit_open": streamedit.open,
                "streamedit_save": streamedit.save,
                "streamedit_new": streamedit.new,
                "streamedit_cancel": streamedit.cancel,
            }.items() + self.add_signals.items() ))
            
            # actually display main window
            gui_startup(0.99)
            self.win_streamtuner2.show()
            
            # WHY DON'T YOU WANT TO WORK?!
            #self.shoutcast.gtk_list.set_enable_search(True)
468
469
470
471
472
473
474
475

476
477
478
479
480
481
482
483
                        if module not in self.channel_names:  # skip (glade) built-in channels
                            self.channel_names.append(module)
                    # other plugin types
                    else:
                        self.features[module] = plugin_class(parent=self)
                    
                except Exception, e:
                    print("error initializing:", module)

                    print(e)

            # default plugins
            conf.add_plugin_defaults(self.channels["bookmarks"].config, "bookmarks")
            #conf.add_plugin_defaults(self.channels["shoutcast"].config, "shoutcast")

        # store window/widget states (sizes, selections, etc.)
        def app_state(self, widget):







|
>
|







469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
                        if module not in self.channel_names:  # skip (glade) built-in channels
                            self.channel_names.append(module)
                    # other plugin types
                    else:
                        self.features[module] = plugin_class(parent=self)
                    
                except Exception, e:
                    print("error initializing:", module, ", exception:")
                    import traceback
                    traceback.print_exc()

            # default plugins
            conf.add_plugin_defaults(self.channels["bookmarks"].config, "bookmarks")
            #conf.add_plugin_defaults(self.channels["shoutcast"].config, "shoutcast")

        # store window/widget states (sizes, selections, etc.)
        def app_state(self, widget):