Check-in [acaea4439d]
Overview
| Comment: | Implement plugin meta data extraction in config.plugin_meta() instead of channels.__init__ |
|---|---|
| Downloads: | Tarball | ZIP archive | SQL archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
acaea4439df7b4577156aaf10d79af18 |
| User & Date: | mario on 2015-03-28 07:26:35 |
| Other Links: | manifest | tags |
Context
|
2015-03-28
| ||
| 07:27 | Move bookmarks channel out of main, add proper plugin description. (Can't be disabled, is still a core plugin, and manually imported anyway.) check-in: b9dc5e172c user: mario tags: trunk | |
| 07:26 | Implement plugin meta data extraction in config.plugin_meta() instead of channels.__init__ check-in: acaea4439d user: mario tags: trunk | |
| 07:25 | Disable some debugging, move gui_startup() to mygtk collection, allow markup for mygtk.label() text. check-in: 164043075d user: mario tags: trunk | |
Changes
Modified channels/_generic.py from [e9222413a9] to [d7e715823c].
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | # file. They derive from the ChannelPlugins class instead, which # adds the required gtk Widgets manually. # import gtk from mygtk import mygtk | | > > | 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 52 53 54 55 56 57 58 59 |
# file. They derive from the ChannelPlugins class instead, which
# adds the required gtk Widgets manually.
#
import gtk
from mygtk import mygtk
from config import *
import ahttp as http
import action
import favicon
import os.path
import xml.sax.saxutils
import re
import copy
import inspect
# dict==object
class struct(dict):
def __init__(self, *xargs, **kwargs):
self.__dict__ = self
self.update(kwargs)
[self.update(x) for x in xargs]
pass
# generic channel module ---------------------------------------
class GenericChannel(object):
# desc
module = "generic"
meta = {}
title = "GenericChannel"
homepage = "http://fossil.include-once.org/streamtuner2/"
base_url = ""
listformat = "audio/x-scpls"
audioformat = "audio/mpeg" # fallback value
config = []
has_search = False
|
| ︙ | ︙ | |||
96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# constructor
def __init__(self, parent=None):
#self.streams = {}
self.gtk_list = None
self.gtk_cat = None
# only if streamtuner2 is run in graphical mode
if (parent):
self.cache()
self.gui(parent)
pass
| > > | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# constructor
def __init__(self, parent=None):
#self.streams = {}
self.gtk_list = None
self.gtk_cat = None
self.meta = plugin_meta(inspect.getsourcefile(inspect.getmodule(self)))
self.config = self.meta["config"]
# only if streamtuner2 is run in graphical mode
if (parent):
self.cache()
self.gui(parent)
pass
|
| ︙ | ︙ |
Modified config.py from [59ff23a453] to [cb67ede034].
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 | # # encoding: UTF-8 # api: streamtuner2 # type: class # title: global config object # description: reads ~/.config/streamtuner/*.json files # # In the main application or module files which need access # to a global conf object, just import this module as follows: # # from config import conf # # Here conf is already an instantiation of the underlying # Config class. # import os import sys import json import gzip import platform # export symbols | > > > > > | | 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 |
#
# encoding: UTF-8
# api: streamtuner2
# .2
# type: class
# title: global config object
# description: reads ~/.config/streamtuner/*.json files
# config: {type:var, name:z, description:v}
#
# In the main application or module files which need access
# to a global conf object, just import this module as follows:
#
# from config import conf
#
# Here conf is already an instantiation of the underlying
# Config class.
#
import os
import sys
import json
import gzip
import platform
import re
import zipfile
import inspect
# export symbols
__all__ = ["conf", "__print__", "dbg", "plugin_meta"]
#-- create a single instance of config object
conf = object()
|
| ︙ | ︙ | |||
42 43 44 45 46 47 48 |
self.__dict__ = self # let's pray this won't leak memory due to recursion issues
# prepare
self.defaults()
self.xdg()
# runtime
| < | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
self.__dict__ = self # let's pray this won't leak memory due to recursion issues
# prepare
self.defaults()
self.xdg()
# runtime
self.share = os.path.dirname(__file__)
# settings from last session
last = self.load("settings")
if (last):
self.update(last)
self.migrate()
# store defaults in file
|
| ︙ | ︙ | |||
201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
def find_in_dirs(self, dirs, file):
for d in dirs:
if os.path.exists(d+"/"+file):
return d+"/"+file
# wrapper for all print statements
def __print__(*args):
if conf.debug:
print(" ".join([str(a) for a in args]))
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
def find_in_dirs(self, dirs, file):
for d in dirs:
if os.path.exists(d+"/"+file):
return d+"/"+file
# Plugin meta data extraction
#
# Extremely crude version for Python and streamtuner2 plugin usage.
# Doesn't check top-level comment coherency.
# But supports plugins within python zip archives.
#
rx_zipfn = re.compile(r"""^(.+\.(?:zip|pyz|pyzw|pyzip)(?:\.py)?)/(\w.*)$""")
rx_meta = re.compile(r"""^ {0,4}# *([\w-]+): *(.+(\n *# +(?![\w-]+:).+)*)$""", re.M) # Python comments only
rx_lines = re.compile(r"""\n *# """) # strip multi-line prefixes
rx_config = re.compile(r"""[\{\<](.+?)[\}\>]""") # extract only from JSOL/YAML scheme
rx_fields = re.compile(r"""["']?(\w+)["']?\s*[:=]\s*["']?([^,]+)(?<!["'])""") # simple key: value entries
#
def plugin_meta(fn=None, frame=1, src=""):
# filename of caller
if not fn:
fn = inspect.getfile(sys._getframe(frame))
# within zip archive?
zip = rx_zipfn.match(fn)
if zip and zipfile.is_zipfile(zip.group(1)):
src = zipfile.ZipFile(zip.group(1), "r").read(zip.group(2))
else:
src = open(fn).read(4096)
# defaults
meta = {
"fn": fn,
"id": os.path.basename(fn).replace(".py", "")
}
# extraction
for field in rx_meta.findall(src):
meta[field[0]] = rx_lines.sub("", field[1])
# unpack config: structures
meta["config"] = [
dict([field for field in rx_fields.findall(entry)])
for entry in rx_config.findall(meta.get("config", ""))
]
return meta
# wrapper for all print statements
def __print__(*args):
if conf.debug:
print(" ".join([str(a) for a in args]))
|
| ︙ | ︙ | |||
227 228 229 230 231 232 233 234 |
#-- actually fill global conf instance
conf = ConfigDict()
if conf:
__print__(dbg.PROC, "ConfigDict() initialized")
| < < < | 278 279 280 281 282 283 284 285 |
#-- actually fill global conf instance
conf = ConfigDict()
if conf:
__print__(dbg.PROC, "ConfigDict() initialized")
|