Check-in [9de894c13c]
Overview
| Comment: | Moved `bookmarks` channel into plugin. Implemented plugin .meta data consumption to replace .config = [] builtins. (Still need to rescan disabled channel/feature plugins later..) |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
9de894c13cd468a1d06805b2dd68801a |
| User & Date: | mario on 2015-03-28 07:32:19 |
| Other Links: | manifest | tags |
Context
|
2015-03-28
| ||
| 07:33 | Basic rewrites to transition to fully plugin meta data capable implementation. check-in: 21d6d1cf4b user: mario tags: trunk | |
| 07:32 | Moved `bookmarks` channel into plugin. Implemented plugin .meta data consumption to replace .config = [] builtins. (Still need to rescan disabled channel/feature plugins later..) check-in: 9de894c13c user: mario tags: trunk | |
| 07:30 | Add .deb package $DEPS. check-in: 58df0e920e user: mario tags: trunk | |
Changes
Modified st2.py from [5bccd0fbcd] to [083dc8256e].
1 2 3 4 5 6 | #!/usr/bin/env python # encoding: UTF-8 # api: python # type: application # title: streamtuner2 # description: Directory browser for internet radio / audio streams | > | > > | < < | < < | < | < | < < | < | | | | > | 1 2 3 4 5 6 7 8 9 10 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 |
#!/usr/bin/env python
#
# encoding: UTF-8
# api: python
# type: application
# title: streamtuner2
# description: Directory browser for internet radio / audio streams
# depends: pygtk | gi, threading, requests, pyquery, lxml, deb:python-pyquery, deb:python-requests, deb:python-gtk2
# version: 2.1.4
# author: Mario Salzer <milky@users.sf.net>
# license: public domain
# 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
# id: streamtuner2
# pack: *.py, gtk*.xml, st2.py=/usr/bin/streamtuner2, channels/__init__.py, bundle/*.py,
# streamtuner2.desktop=/usr/share/applications/, README=/usr/share/doc/streamtuner2/,
# NEWS.gz=/usr/share/doc/streamtuner2/changelog.gz, help/streamtuner2.1=/usr/share/man/man1/,
# help/*page=/usr/share/doc/streamtuner2/help/, help/img/*=/usr/share/doc/streamtuner2/help/img/,
# streamtuner2.png, logo.png=/usr/share/pixmaps/streamtuner2.png,
# architecture: all
#
# Streamtuner2 is a GUI browser for internet radio directories. Various
# providers can be added, and streaming stations are usually grouped into
# music genres or categories. It starts external audio players for stream
# playing, and defaults to streamripper for recording broadcasts.
#
# It's an independent rewrite of streamtuner1. Being written in Python,
# can be more easily extended and fixed. The mix of JSON APIs, regex
# or PyQuery extraction makes list generation simpler and more robust.
#
# Primarily radio stations are displayed, some channels however are music
# collections. Commercial and sign-up services are not the target purpose.
#
""" project status """
#
# The application runs mostly stable. The GUI interfaces are workable.
# It's supposed to run on Gtk2 and Gtk3. Python3 support is still WIP.
# There haven't been any optimizations regarding memory usage and
# performance. The current internal API is vastly undocumented.
|
| ︙ | ︙ | |||
89 90 91 92 93 94 95 | # add library path sys.path.insert(0, "/usr/share/streamtuner2") # pre-defined directory for modules sys.path.append( "/usr/share/streamtuner2/bundle") # external libraries sys.path.insert(0, ".") # development module path # gtk modules | | | | 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | # add library path sys.path.insert(0, "/usr/share/streamtuner2") # pre-defined directory for modules sys.path.append( "/usr/share/streamtuner2/bundle") # external libraries sys.path.insert(0, ".") # development module path # gtk modules from mygtk import pygtk, gtk, gobject, ui_file, mygtk, ver as GTK_VER, ComboBoxText, gui_startup # custom modules from config import conf # initializes itself, so all conf.vars are available right away from config import __print__, dbg import ahttp import action # needs workaround... (action.main=main) import channels from channels import * import favicon import channels.bookmarks __version__ = "2.1.4" # this represents the main window # and also contains most application behaviour main = None |
| ︙ | ︙ | |||
142 143 144 145 146 147 148 |
gtk.Builder.__init__(self)
gtk.Builder.add_from_file(self, conf.find_in_dirs([".", conf.share], ui_file)), gui_startup(2/20.0)
# manual gtk operations
self.extensionsCTM.set_submenu(self.extensions) # duplicates Station>Extension menu into stream context menu
# initialize channels
self.channels = {
| | | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
gtk.Builder.__init__(self)
gtk.Builder.add_from_file(self, conf.find_in_dirs([".", conf.share], ui_file)), gui_startup(2/20.0)
# manual gtk operations
self.extensionsCTM.set_submenu(self.extensions) # duplicates Station>Extension menu into stream context menu
# initialize channels
self.channels = {
"bookmarks": channels.bookmarks.bookmarks(parent=self), # this the remaining built-in channel
#"shoutcast": None,#shoutcast(parent=self),
}
gui_startup(3/20.0)
self.load_plugin_channels() # append other channel modules / plugins
# load application state (widget sizes, selections, etc.)
|
| ︙ | ︙ | |||
453 454 455 456 457 458 459 |
__print__(dbg.STAT, "disabled plugin:", module)
continue
# load plugin
try:
plugin = __import__("channels."+module, None, None, [""])
plugin_class = plugin.__dict__[module]
| > | | | | | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
__print__(dbg.STAT, "disabled plugin:", module)
continue
# load plugin
try:
plugin = __import__("channels."+module, None, None, [""])
plugin_class = plugin.__dict__[module]
plugin_obj = plugin_class(parent=self)
# load .config settings from plugin
conf.add_plugin_defaults(plugin_obj.meta["config"], module)
# add and initialize channel
if issubclass(plugin_class, GenericChannel):
self.channels[module] = plugin_obj
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_obj
except Exception as e:
__print__(dbg.INIT, "load_plugin_channels: error initializing:", module, ", exception:")
import traceback
traceback.print_exc()
# default plugins
|
| ︙ | ︙ | |||
828 829 830 831 832 833 834 |
# retrieve currently selected value
def apply_theme(self):
conf.theme = self.theme.get_active_text()
main.load_theme()
| | | > > | > > > | < | | | < < < < < | > | < | | | | | | | | | | | | | | 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 |
# retrieve currently selected value
def apply_theme(self):
conf.theme = self.theme.get_active_text()
main.load_theme()
# iterate over channel and feature plugins
def add_plugins(self):
for name,plugin in main.channels.iteritems():
self.add_plg(name, plugin, plugin.meta)
self.plugin_options.pack_start(mygtk.label("\n<b>Feature</b> plugins add categories, submenu entries, or other extensions.\n", 500, 1))
for name,plugin in main.features.iteritems():
self.add_plg(name, plugin, plugin.meta)
# add configuration setting definitions from plugins
def add_plg(self, name, c, meta):
# add plugin load entry
cb = gtk.CheckButton(name)
cb.get_children()[0].set_markup("<b>%s</b> <i>(%s)</i> %s\n<small>%s</small>" % (meta["title"], meta["type"], meta.get("version", ""), meta["description"]))
self.add_( "config_plugins_"+name, cb )
# default values are already in conf[] dict (now done in conf.add_plugin_defaults)
for opt in meta["config"]:
color = opt.get("color", None)
# display checkbox
if opt["type"] == "boolean":
cb = gtk.CheckButton(opt["description"])
self.add_( "config_"+opt["name"], cb, color=color )
# drop down list
elif opt["type"] == "select":
cb = ComboBoxText(ComboBoxText.parse_options(opt["select"])) # custom mygtk widget
self.add_( "config_"+opt["name"], cb, opt["description"], color )
# text entry
else:
self.add_( "config_"+opt["name"], gtk.Entry(), opt["description"], color )
# spacer
self.add_( "filler_pl_"+name, gtk.HSeparator() )
# Put config widgets into config dialog notebook
def add_(self, id, w, label=None, color=""):
w.set_property("visible", True)
main.widgets[id] = w
if label:
|
| ︙ | ︙ | |||
888 889 890 891 892 893 894 |
conf.save(nice=1)
self.hide()
config_dialog = config_dialog()
# instantiates itself
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 883 884 885 886 887 888 889 890 891 892 893 894 895 896 |
conf.save(nice=1)
self.hide()
config_dialog = config_dialog()
# instantiates itself
#-- run main ---------------------------------------------
if __name__ == "__main__":
|
| ︙ | ︙ |