1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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: gtk, pygtk, xml.dom.minidom, threading, lxml, pyquery, kronos
# version: 2.1.0
# version: 2.0.9.5
# 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
#
#
|
︙ | | |
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
-
+
-
+
-
+
-
+
-
+
|
current_channel = "bookmarks" # currently selected channel name (as index in self.channels{})
# constructor
def __init__(self):
# gtkrc stylesheet
self.load_theme(), gui_startup(0.05)
self.load_theme(), gui_startup(1/20)
# instantiate gtk/glade widgets in current object
gtk.Builder.__init__(self)
gtk.Builder.add_from_file(self, conf.find_in_dirs([".", conf.share], ui_file)), gui_startup(0.10)
gtk.Builder.add_from_file(self, conf.find_in_dirs([".", conf.share], ui_file)), gui_startup(2/20)
# manual gtk operations
self.extensionsCTM.set_submenu(self.extensions) # duplicates Station>Extension menu into stream context menu
# initialize channels
self.channels = {
"bookmarks": bookmarks(parent=self), # this the remaining built-in channel
"shoutcast": None,#shoutcast(parent=self),
}
gui_startup(0.15)
gui_startup(3/20)
self.load_plugin_channels() # append other channel modules / plugins
# load application state (widget sizes, selections, etc.)
try:
winlayout = conf.load("window")
if (winlayout):
mygtk.app_restore(self, winlayout)
# selection values
winstate = conf.load("state")
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(0.90)
gui_startup(17/20)
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)
gui_startup(19/20)
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),
|
︙ | | |
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
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() + self.add_signals.items() ))
# actually display main window
gui_startup(0.99)
gui_startup(99/100)
self.win_streamtuner2.show()
# WHY DON'T YOU WANT TO WORK?!
#self.shoutcast.gtk_list.set_enable_search(True)
#self.shoutcast.gtk_list.set_search_column(4)
|
︙ | | |
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
|
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
|
-
+
-
+
|
sbar_cid = self.get_widget("statusbar").get_context_id("messages")
# remove text
while ((not text) and (type(text)==str) and len(sbar_msg)):
sbar_msg.pop()
mygtk.do(lambda:self.statusbar.pop(sbar_cid))
# progressbar
if (type(text)==float):
if (text >= 1.0): # completed
if (text >= 999/1000): # completed
mygtk.do(lambda:self.progress.hide())
else: # show percentage
mygtk.do(lambda:self.progress.show() or self.progress.set_fraction(text))
if (text <= 0.0): # unknown state
if (text <= 0): # unknown state
mygtk.do(lambda:self.progress.pulse())
# add text
elif (type(text)==str):
sbar_msg.append(1)
mygtk.do(lambda:self.statusbar.push(sbar_cid, text))
pass
|
︙ | | |
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
|
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
|
-
+
|
# 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(0.2 + 0.7 * float(ls.index(module))/len(ls), "loading module "+module)
gui_startup(2/10 + 7/10 * float(ls.index(module))/len(ls), "loading module "+module)
# skip module if disabled
if conf.plugins.get(module, 1) == False:
__print__("disabled plugin:", module)
continue
# load plugin
|
︙ | | |
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
|
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
|
-
+
|
self.channels[module] = plugin_class(parent=self)
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:
except Exception as 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")
|
︙ | | |
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
|
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
|
-
+
|
conf.save("state", channelopts, nice=1)
# apply gtkrc stylesheet
def load_theme(self):
if conf.get("theme"):
for dir in (conf.dir, conf.share, "/usr/share"):
f = dir + "/themes/" + conf.theme + "/gtk-2.0/gtkrc"
f = dir + "/themes/" + conf.theme + "/gtk-2"+".0/gtkrc"
if os.path.exists(f):
gtk.rc_parse(f)
pass
# end application and gtk+ main loop
def gtk_main_quit(self, widget, *x):
|
︙ | | |
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
|
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
|
-
+
-
+
|
# auxiliary window: about dialog
class AboutStreamtuner2:
# about us
def __init__(self):
a = gtk.AboutDialog()
a.set_version("2.0.9")
a.set_version("2.0.9.5")
a.set_name("streamtuner2")
a.set_license("Public Domain\n\nNo Strings Attached.\nUnrestricted distribution,\nmodification, use.")
a.set_authors(["Mario Salzer <http://mario.include-once.org/>\n\nConcept based on streamtuner 0.99.99 from\nJean-Yves Lefort, of which some code remains\nin the Google stations plugin.\n<http://www.nongnu.org/streamtuner/>\n\nMyOggRadio plugin based on cooperation\nwith Christian Ehm. <http://ehm-edv.de/>"])
a.set_authors(["Mario Salzer <http://mario.include-once.org/>\n\nConcept based on streamtuner 0."+"99."+"99 from\nJean-Yves Lefort, of which some code remains\nin the Google stations plugin.\n<http://www.nongnu.org/streamtuner/>\n\nMyOggRadio plugin based on cooperation\nwith Christian Ehm. <http://ehm-edv.de/>"])
a.set_website("http://milki.include-once.org/streamtuner2/")
a.connect("response", lambda a, ok: ( a.hide(), a.destroy() ) )
a.show()
# right click in streams/stations TreeView
|
︙ | | |
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
|
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
|
-
+
|
class bookmarks(GenericChannel):
# desc
api = "streamtuner2"
module = "bookmarks"
title = "bookmarks"
version = 0.4
version = 4/10
base_url = "file:.config/streamtuner2/bookmarks.json"
listformat = "*/*"
# i like this
config = [
{"name":"like_my_bookmarks", "type":"boolean", "value":0, "description":"I like my bookmarks"},
|
︙ | | |
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
|
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
|
-
+
|
#-- startup progress bar
progresswin, progressbar = 0, 0
def gui_startup(p=0.0, msg="streamtuner2 is starting"):
def gui_startup(p=0/100, msg="streamtuner2 is starting"):
global progresswin,progressbar
if not progresswin:
# GtkWindow "progresswin"
progresswin = gtk.Window()
progresswin.set_property("title", "streamtuner2")
|
︙ | | |
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
|
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
|
-
+
-
+
|
# graphical
if len(sys.argv) < 2:
# prepare for threading in Gtk+ callbacks
gobject.threads_init()
gui_startup(0.05)
gui_startup(1/100)
# prepare main window
main = StreamTunerTwo()
# module coupling
action.main = main # action (play/record) module needs a reference to main window for gtk interaction and some URL/URI callbacks
action = action.action # shorter name
http.feedback = main.status # http module gives status feedbacks too
# first invocation
if (conf.get("firstrun")):
config_dialog.open(None)
del conf.firstrun
# run
gui_startup(1.00)
gui_startup(100/100)
gtk.main()
# invoke command-line interface
else:
import cli
cli.StreamTunerCLI()
|
︙ | | |