Index: channels/_generic.py ================================================================== --- channels/_generic.py +++ channels/_generic.py @@ -22,18 +22,19 @@ # import gtk from mygtk import mygtk -from config import conf, __print__, dbg +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): @@ -46,10 +47,11 @@ # 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 @@ -98,10 +100,12 @@ 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) Index: config.py ================================================================== --- config.py +++ config.py @@ -1,11 +1,13 @@ # # 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 @@ -18,14 +20,17 @@ import os import sys import json import gzip import platform +import re +import zipfile +import inspect # export symbols -__all__ = ["conf", "__print__", "dbg"] +__all__ = ["conf", "__print__", "dbg", "plugin_meta"] #-- create a single instance of config object conf = object() @@ -44,12 +49,11 @@ # prepare self.defaults() self.xdg() # runtime - dirs = ["/usr/share/streamtuner2", "/usr/local/share/streamtuner2", sys.path[0], "."] - self.share = [d for d in dirs if os.path.exists(d)][0] + self.share = os.path.dirname(__file__) # settings from last session last = self.load("settings") if (last): self.update(last) @@ -203,10 +207,57 @@ 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*["']?([^,]+)(?