Index: NEWS ================================================================== --- NEWS +++ NEWS @@ -1,5 +1,9 @@ +2.1.5 (unreleased) +- Rewrite, cleanup, new PYZ package. +- Plugin meta data, embedded PNGs. +- Notebook tabs now on the left per default. 2.1.4 (2015-03-25) - Fixed Internet-Radio extraction. - Added basic TuneIn channel. - Removed Dirble and MusicGoal channels. Index: PKG-INFO ================================================================== --- PKG-INFO +++ PKG-INFO @@ -1,10 +1,10 @@ Metadata-Version: 1.0 Name: streamtuner2 -Version: 2.1.4 +Version: 2.1.5 Summary: Streamtuner2 is an internet radio browser Home-page: http://fossil.include-once.org/streamtuner2/ Author: Mario Salzer Author-email: xmilky+st2@gmail.... License: Public Domain Description: Streamtuner2 lists radio directory services like Shoutcast, Xiph, Live365, MyOggRadio, Jamendo. It allows listening via any audio player, and recording of streams via streamripper. Platform: ALL Index: channels/__init__.py ================================================================== --- channels/__init__.py +++ channels/__init__.py @@ -44,34 +44,16 @@ import os.path import xml.sax.saxutils import re import copy import inspect -import pkgutil # Only export plugin classes __all__ = [ - "GenericChannel", "ChannelPlugin", "module_list" -] - - - -# Search through ./channels/ and get module basenames. -# Also order them by conf.channel_order -# -def module_list(): - - # Should list plugins within zips as well as local paths - ls = pkgutil.iter_modules([conf.share+"/channels", "channels"]) - ls = [name for loader,name,ispkg in ls] - - # resort with tab order - order = [module.strip() for module in conf.channel_order.lower().replace(".","_").replace("-","_").split(",")] - ls = [module for module in (order) if (module in ls)] + [module for module in (ls) if (module not in order)] - - return ls + "GenericChannel", "ChannelPlugin" +] # generic channel module --------------------------------------- class GenericChannel(object): @@ -128,11 +110,11 @@ #self.streams = {} self.gtk_list = None self.gtk_cat = None self.module = self.__class__.__name__ - self.meta = plugin_meta(None, inspect.getcomments(inspect.getmodule(self))) + 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["config"], self.module) @@ -554,11 +536,11 @@ # prepare label pixbuf = None if "png" in self.meta: pixbuf = uikit.pixbuf(self.meta["png"]) else: - png = pkgutil.get_data("config", "channels/" + self.module + ".png") + png = get_data("channels/" + self.module + ".png") pixbuf = uikit.pixbuf(png) if pixbuf: icon = gtk.image_new_from_pixbuf(pixbuf) else: icon = gtk.image_new_from_stock(gtk.STOCK_DIRECTORY, size=1) Index: config.py ================================================================== --- config.py +++ config.py @@ -5,16 +5,20 @@ # 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: +# to a global conf.* object, just import this module as follows: # -# from config import conf +# from config import * # # Here conf is already an instantiation of the underlying -# Config class. +# ConfigDoct class. +# +# Also provides the logging function __print__, and basic +# plugin handling code: plugin_meta() and module_list(), +# and the relative get_data() alias (files from pyzip/path). # import os import sys @@ -22,14 +26,15 @@ import gzip import platform import re import zipfile import inspect +import pkgutil # export symbols -__all__ = ["conf", "__print__", "dbg", "plugin_meta"] +__all__ = ["conf", "__print__", "dbg", "plugin_meta", "module_list", "get_data"] #-- create a stub instance of config object conf = object() @@ -37,11 +42,15 @@ netrc = None -#-- global configuration data --------------------------------------------- +# Global configuration store +# +# Autointializes itself on startup, makes conf.vars available. +# Also provides .load() and .save() for JSON data/cache files. +# class ConfigDict(dict): # start def __init__(self): @@ -232,15 +241,46 @@ for server in varhosts: if server in netrc: return netrc[server] + +# Retrieve content from install path or pyzip archive (alias for pkgutil.get_data) +# +def get_data(fn, decode=False): + try: + bin = pkgutil.get_data("config", fn) + if decode: + return bin.decode("utf-8") + else: + return str(bin) + except: + pass + + +# Search through ./channels/ and get module basenames. +# Also order them by conf.channel_order +# +def module_list(): + + # Should list plugins within zips as well as local paths + ls = pkgutil.iter_modules([conf.share+"/channels", "channels"]) + ls = [name for loader,name,ispkg in ls] + + # resort with tab order + order = [module.strip() for module in conf.channel_order.lower().replace(".","_").replace("-","_").split(",")] + ls = [module for module in (order) if (module in ls)] + [module for module in (ls) if (module not in order)] + + return ls + + # Plugin meta data extraction # # Extremely crude version for Python and streamtuner2 plugin usage. # Fetches module source, or reads from filename / out of zip package. +# def plugin_meta(fn=None, src=None, frame=1): # get source directly from caller if not src and not fn: module = inspect.getmodule(sys._getframe(frame)) Index: st2.py ================================================================== --- st2.py +++ st2.py @@ -407,11 +407,11 @@ # load plugins from /usr/share/streamtuner2/channels/ def load_plugin_channels(self): # initialize plugin modules (pre-ordered) - ls = channels.module_list() + ls = module_list() for module in ls: gui_startup(4/20.0 + 13.5/20.0 * float(ls.index(module))/len(ls), "loading module "+module) # skip module if disabled if conf.plugins.get(module, 1) == False: Index: uikit.py ================================================================== --- uikit.py +++ uikit.py @@ -19,11 +19,11 @@ # which contain current layout options for a few Widget types. Saving # and restoring must be handled elsewhere. # debug -from config import __print__, dbg, plugin_meta +from config import * # system import os.path import copy import sys @@ -30,11 +30,10 @@ import re import base64 import zlib import inspect from compat2and3 import unicode, xrange, PY3 -import pkgutil # gtk version (2=gtk2, 3=gtk3, 7=tk;) ver = 2 # if running on Python3 or with commandline flag @@ -58,11 +57,11 @@ GdkPixbuf = gtk.gdk empty_pixbuf = GdkPixbuf.Pixbuf(gtk.gdk.COLORSPACE_RGB,True,8,16,16) empty_pixbuf.fill(0xFFFFFFFF) # prepare gtkbuilder data -ui_xml = pkgutil.get_data("config", "gtk3.xml").decode("utf-8") +ui_xml = get_data("gtk3.xml", decode=True) if ver == 2: ui_xml = ui_xml.replace('version="3.0"', 'version="2.16"') @@ -613,10 +612,10 @@ def __init__(self, parent): a = gtk.AboutDialog() a.set_name(parent.meta["id"]) a.set_version(parent.meta["version"]) a.set_license(parent.meta["license"]) - a.set_authors((pkgutil.get_data("config", "CREDITS") or parent.meta["author"]).split("\n")) + a.set_authors((get_data("CREDITS") or parent.meta["author"]).split("\n")) a.set_website(parent.meta["url"]) a.connect("response", lambda a, ok: ( a.hide(), a.destroy() ) ) a.show_all()