Check-in [ea924e3c27]
Overview
| Comment: | Introduce FeaturePlugin as new base class for channels and all other plugins. Pre-defines the meta, module attributes and calls init2(). |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
ea924e3c27911b844b8b6159392ce90b |
| User & Date: | mario on 2017-01-05 21:23:23 |
| Other Links: | manifest | tags |
Context
|
2017-01-05
| ||
| 21:33 | Fix `links` plugin format: attribute; make it understood by channel.play() that a homepage-only row triggers the web browser. check-in: f48ad79aa1 user: mario tags: trunk | |
| 21:23 | Introduce FeaturePlugin as new base class for channels and all other plugins. Pre-defines the meta, module attributes and calls init2(). check-in: ea924e3c27 user: mario tags: trunk | |
| 21:22 | Detect more absent variables/login, introduce UI delay on submission. check-in: 9eeccf1f29 user: mario tags: trunk | |
Changes
Modified channels/__init__.py from [c58402c723] to [4a4e01489e].
1 2 3 4 5 6 | # encoding: UTF-8 # api: streamtuner2 # type: class # category: ui # title: Channel plugins # description: Base implementation for channels and feature plugins | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # encoding: UTF-8 # api: streamtuner2 # type: class # category: ui # title: Channel plugins # description: Base implementation for channels and feature plugins # version: 1.7 # license: public domain # author: mario # url: http://fossil.include-once.org/streamtuner2/ # pack: # *.py # config: - # priority: core |
| ︙ | ︙ | |||
34 35 36 37 38 39 40 | import re import copy import inspect # Only export plugin classes and a few utility functions __all__ = [ | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 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 104 105 106 |
import re
import copy
import inspect
# Only export plugin classes and a few utility functions
__all__ = [
"FeaturePlugin", "GenericChannel", "ChannelPlugin", "use_rx", "mime_fmt",
"stub_parent", "entity_decode", "strip_tags", "nl", "unhtml", "to_int"
]
__path__.insert(0, conf.dir + "/plugins")
# Base class for plugins (features or channels)
class FeaturePlugin(object):
# plugin meta and object references
module = ""
meta = { "config": [] }
parent = None # main window
# minimum setup for ChannelPlugins and feature hooks
def __init__(self, parent, *k, **kw):
# set up meta infos
self.parent = parent
self.module = self.__class__.__name__
self.meta = plugin_meta(src = inspect.getcomments(inspect.getmodule(self)))
self.config = self.meta.get("config", [])
self.title = self.meta.get("title", self.module)
# add default options values to config.conf.* dict
conf.add_plugin_defaults(self.meta, self.module)
# implicit action handler registration
if hasattr(self, "resolve_urn"):
action.handler["urn:%s" % self.module] = self.resolve_urn
# secondary init function
self.init2(parent)
# optionally to be overriden by plugins (run after base __init__)
def init2(self, parent, *k, **kw):
pass
# Statusbar stub (defers to parent/main window, if in GUI mode)
def status(self, *args, **kw):
if self.parent:
self.parent.status(*args, **kw)
else:
log.INFO("status():", *v)
# Statusbar with highlighting and default icon
def warn(self, text, *args, **kw):
if isinstance(text, (str, unicode)) and "status_color" in conf:
text = "<span background='%s'>%s</span>" % (conf.status_color, text)
kw["markup"] = 1
if not "icon" in kw:
kw["icon"] = "gtk-dialog-warning"
self.status(text, *args, **kw)
# Generic channel module
class GenericChannel(FeaturePlugin):
# control attributes
meta = { "config": [] }
base_url = ""
listformat = "pls"
audioformat = "audio/mpeg" # fallback value
has_search = False
|
| ︙ | ︙ | |||
67 68 69 70 71 72 73 |
gtk_list = None # Gtk widget for station treeview
gtk_cat = None # Gtk widget for category columns
ls = None # ListStore for station treeview
rowmap = None # Preserve streams-datamap
pix_entry = None # ListStore entry that contains favicon
img_resize = None # Rescale `img` references to icon size
fixed_size = [24,24] # Default height+width for favicons
| < | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
gtk_list = None # Gtk widget for station treeview
gtk_cat = None # Gtk widget for category columns
ls = None # ListStore for station treeview
rowmap = None # Preserve streams-datamap
pix_entry = None # ListStore entry that contains favicon
img_resize = None # Rescale `img` references to icon size
fixed_size = [24,24] # Default height+width for favicons
# mapping of stream{} data into gtk treeview/treestore representation
datamap = [
# coltitle width [ datasrc key, type, renderer, attrs ] [cellrenderer2], ...
["", 20, ["state", str, "pixbuf", {}], ],
["Genre", 65, ['genre', str, "t", {}], ],
["Station Title",275, ["title", str, "text", {"strikethrough":11, "cell-background":12, "cell-background-set":13}], ["favicon", gtk.gdk.Pixbuf, "pixbuf", {}], ],
|
| ︙ | ︙ | |||
124 125 126 127 128 129 130 |
# constructor
def __init__(self, parent=None):
#self.streams = {}
self.gtk_list = None
self.gtk_cat = None
| < < < < | < < | < < | < < | 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# constructor
def __init__(self, parent=None):
#self.streams = {}
self.gtk_list = None
self.gtk_cat = None
# base init (meta infos, parent reference, init2)
FeaturePlugin.__init__(self, parent)
# Only if streamtuner2 is run in graphical mode
if (parent):
# Update/display stream processors
if not self.prepare_filters:
self.prepare_filters += [
self.prepare_filter_icons,
|
| ︙ | ︙ | |||
190 191 192 193 194 195 196 |
def columns(self, entries=None):
self.ls, self.rowmap, self.pix_entry = uikit.columns(
self.gtk_list, self.datamap, entries,
show_favicons=True, fixed_size=self.fixed_size
)
# no longer using `conf.show_favicons`
| < < < < < < < < | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
def columns(self, entries=None):
self.ls, self.rowmap, self.pix_entry = uikit.columns(
self.gtk_list, self.datamap, entries,
show_favicons=True, fixed_size=self.fixed_size
)
# no longer using `conf.show_favicons`
#--------------------- streams/model data accesss ---------------------------
# Traverse category TreeModel to set current, expand parent nodes
def select_current(self, name):
|
| ︙ | ︙ | |||
585 586 587 588 589 590 591 |
listformat = row.get("listformat", self.listformat)
action.record(row, audioformat, listformat)
return row
| < < < < < < < < < | 616 617 618 619 620 621 622 623 624 625 626 627 628 629 |
listformat = row.get("listformat", self.listformat)
action.record(row, audioformat, listformat)
return row
# channel plugin without glade-pre-defined notebook tab
#
class ChannelPlugin(GenericChannel):
module = "abstract"
|
| ︙ | ︙ | |||
678 679 680 681 682 683 684 685 686 687 688 689 690 691 |
# try to initialize superclass now, before adding to channel tabs
GenericChannel.gui(self, parent)
# add notebook tab
tab = parent.notebook_channels.insert_page_menu(vbox, ev_label, plain_label, -1)
parent.notebook_channels.set_tab_reorderable(vbox, True)
# WORKAROUND for direct channel module imports,
# eases instantiations without GUI a little,
# reducing module dependencies (conf. / ahttp. / channels. / parent.) would be better
def stub_parent(object):
| > > | 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 |
# try to initialize superclass now, before adding to channel tabs
GenericChannel.gui(self, parent)
# add notebook tab
tab = parent.notebook_channels.insert_page_menu(vbox, ev_label, plain_label, -1)
parent.notebook_channels.set_tab_reorderable(vbox, True)
# WORKAROUND for direct channel module imports,
# eases instantiations without GUI a little,
# reducing module dependencies (conf. / ahttp. / channels. / parent.) would be better
def stub_parent(object):
|
| ︙ | ︙ |
Modified channels/jamendo.py from [0db1a39017] to [d440527930].
| ︙ | ︙ | |||
320 321 322 323 324 325 326 |
#"url": "http://api.jamendo.com/get2/stream/track/xspf/?album_id=%s&streamencoding=ogg2&n=all&from=app-%s" % (e["id"], self.cid),
#"format": "audio/ogg",
#"listformat": "xspf",
"url": "http://api.jamendo.com/v3.0/tracks?client_id={}&audioformat={}&album_id={}".format(self.cid, fmt, e["id"]),
"listformat": "jamj",
"format": fmt_mime,
})
| | | 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 |
#"url": "http://api.jamendo.com/get2/stream/track/xspf/?album_id=%s&streamencoding=ogg2&n=all&from=app-%s" % (e["id"], self.cid),
#"format": "audio/ogg",
#"listformat": "xspf",
"url": "http://api.jamendo.com/v3.0/tracks?client_id={}&audioformat={}&album_id={}".format(self.cid, fmt, e["id"]),
"listformat": "jamj",
"format": fmt_mime,
})
# Feeds (News)
elif cat == "feeds":
for e in self.api(method="feeds", order="date_start_desc", target="notlogged"):
if e.get("joinid") and e.get("subtitle"):
entries.append({
"genre": e["type"],
"title": e["title"]["en"],
|
| ︙ | ︙ |