︙ | | | ︙ | |
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
# url: http://freshcode.club/projects/streamtuner2
# config:
# { type: env, name: http_proxy, description: proxy for HTTP access }
# { type: env, name: XDG_CONFIG_HOME, description: relocates user .config subdirectory }
# category: sound
# depends: pygtk | gi, threading, requests, pyquery, lxml
# id: streamtuner2
# pack: *.py, gtk3.xml.zlib, bin, channels/__init__.py, bundle/*.py, CREDITS, help/index.page,
# streamtuner2.desktop, README, help/streamtuner2.1=/usr/share/man/man1/,
# NEWS.gz=/usr/share/doc/streamtuner2/changelog.gz, logo.png=/usr/share/pixmaps/streamtuner2.png
# architecture: all
#
# Streamtuner2 is a GUI for browsing internet radio directories, music
# collections, and video services - grouped by genres or categories.
# It runs your preferred audio player, and streamripper for recording.
#
# It's an independent rewrite of streamtuner1. Being written in Python,
|
|
|
|
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
# url: http://freshcode.club/projects/streamtuner2
# config:
# { type: env, name: http_proxy, description: proxy for HTTP access }
# { type: env, name: XDG_CONFIG_HOME, description: relocates user .config subdirectory }
# category: sound
# depends: pygtk | gi, threading, requests, pyquery, lxml
# id: streamtuner2
# pack: *.py, gtk3.xml.gz, bin, channels/__init__.py, bundle/*.py, CREDITS, help/index.page,
# streamtuner2.desktop, README, help/streamtuner2.1=/usr/share/man/man1/,
# NEWS.gz=/usr/share/doc/streamtuner2/changelog.gz, icon.png=/usr/share/pixmaps/streamtuner2.png
# architecture: all
#
# Streamtuner2 is a GUI for browsing internet radio directories, music
# collections, and video services - grouped by genres or categories.
# It runs your preferred audio player, and streamripper for recording.
#
# It's an independent rewrite of streamtuner1. Being written in Python,
|
︙ | | | ︙ | |
70
71
72
73
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
100
101
102
103
|
class StreamTunerTwo(gtk.Builder):
# 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
hooks = {
"play": [favicon.download_playing], # observers queue here
"init": [],
"config_load": [],
"config_save": [],
}
meta = plugin_meta()
# status variables
current_channel = "bookmarks" # currently selected channel name (as index in self.channels{})
# constructor
def __init__(self):
# Load stylesheet, instantiate GtkBuilder in self, menu and logo hooks
gui_startup(1/20.0), gtk.Builder.__init__(self)
gui_startup(1/20.0), gtk.Builder.add_from_string(self, ui_xml)
gui_startup(3/20.0), self.img_logo.set_from_pixbuf(uikit.pixbuf(logo.png))
# initialize built-in plugins
self.channels = {
"bookmarks": channels.bookmarks.bookmarks(parent=self), # this the remaining built-in channel
}
# dialogs that are connected to main
self.features = {
|
<
|
|
70
71
72
73
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
100
101
102
|
class StreamTunerTwo(gtk.Builder):
# object containers
widgets = {} # non-glade widgets (the manually instantiated ones)
channels = {} # channel modules
features = {} # non-channel plugins
working = [] # threads
hooks = {
"play": [favicon.download_playing], # observers queue here
"init": [],
"config_load": [],
"config_save": [],
}
meta = plugin_meta()
# status variables
current_channel = "bookmarks" # currently selected channel name (as index in self.channels{})
# constructor
def __init__(self):
# Load stylesheet, instantiate GtkBuilder in self, menu and logo hooks
gui_startup(1/20.0), gtk.Builder.__init__(self)
gui_startup(1/20.0), gtk.Builder.add_from_string(self, ui_xml)
gui_startup(3/20.0), self.img_logo.set_from_pixbuf(uikit.pixbuf(logo.png, decode=1, fmt="png"))
# initialize built-in plugins
self.channels = {
"bookmarks": channels.bookmarks.bookmarks(parent=self), # this the remaining built-in channel
}
# dialogs that are connected to main
self.features = {
|
︙ | | | ︙ | |
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
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.75/20.0)
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: self.station_context_menu(tv,ev),
# toolbar
|
|
|
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
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.75/20.0)
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: self.station_context_menu(tv,ev),
# toolbar
|
︙ | | | ︙ | |
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
"search_cancel": self.search.cancel,
"true": lambda w,*args: True,
# win_streamedit
"streamedit_open": self.streamedit.open,
"streamedit_save": self.streamedit.save,
"streamedit_new": self.streamedit.new,
"streamedit_cancel": self.streamedit.cancel,
}, **self.add_signals))
# actually display main window
self.win_streamtuner2.show_all()
gui_startup(100.0)
#-- Shortcut for glade.get_widget()
# Allows access to widgets as direct attributes instead of using .get_widget()
# Also looks in self.channels[] for the named channel plugins
|
|
>
|
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
"search_cancel": self.search.cancel,
"true": lambda w,*args: True,
# win_streamedit
"streamedit_open": self.streamedit.open,
"streamedit_save": self.streamedit.save,
"streamedit_new": self.streamedit.new,
"streamedit_cancel": self.streamedit.cancel,
})
# actually display main window
self.update_title()
self.win_streamtuner2.show_all()
gui_startup(100.0)
#-- Shortcut for glade.get_widget()
# Allows access to widgets as direct attributes instead of using .get_widget()
# Also looks in self.channels[] for the named channel plugins
|
︙ | | | ︙ | |
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
return self.channel_names[self.notebook_channels.get_current_page()]
# Notebook tab has been clicked (receives numeric page_num), but *NOT* yet changed (visually).
def channel_switch(self, notebook, page, page_num=0, *args):
self.current_channel = notebook.get_menu_label_text(notebook.get_nth_page(page_num))
__print__(dbg.UI, "main.channel_switch():", "set current_channel :=", self.current_channel)
# if first selected, load current category
__print__(dbg.STAT, "TRY", "main.channel_switch(): ", self.current_channel + ".first_show()")
try: self.channel().first_show()
except: __print__(dbg.INIT, ".first_show() initialization error")
# Invoked from the menu instead, uses module name instead of numeric tab id
def channel_switch_by_name(self, name):
self.notebook_channels.set_current_page(self.channel_names.index(name))
# Convert ListStore iter to row number
def rowno(self):
(model, iter) = self.model_iter()
return model.get_path(iter)[0]
# Currently selected entry in stations list, return complete data dict
|
>
>
>
>
>
|
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
|
return self.channel_names[self.notebook_channels.get_current_page()]
# Notebook tab has been clicked (receives numeric page_num), but *NOT* yet changed (visually).
def channel_switch(self, notebook, page, page_num=0, *args):
self.current_channel = notebook.get_menu_label_text(notebook.get_nth_page(page_num))
__print__(dbg.UI, "main.channel_switch():", "set current_channel :=", self.current_channel)
self.update_title()
# if first selected, load current category
__print__(dbg.STAT, "TRY", "main.channel_switch(): ", self.current_channel + ".first_show()")
try: self.channel().first_show()
except: __print__(dbg.INIT, ".first_show() initialization error")
# Invoked from the menu instead, uses module name instead of numeric tab id
def channel_switch_by_name(self, name):
self.notebook_channels.set_current_page(self.channel_names.index(name))
# Mirror selected channel tab into main window title
def update_title(self):
self.win_streamtuner2.set_title("Streamtuner2 - %s" % self.channel().meta.get("title"))
# Convert ListStore iter to row number
def rowno(self):
(model, iter) = self.model_iter()
return model.get_path(iter)[0]
# Currently selected entry in stations list, return complete data dict
|
︙ | | | ︙ | |