Index: action.py
==================================================================
--- action.py
+++ action.py
@@ -29,11 +29,11 @@
import re
import os
from ahttp import fix_url as http_fix_url, session
-from config import conf, __print__ as debug, dbg
+from config import *
import platform
import copy
import json
from datetime import datetime
from xml.sax.saxutils import escape as xmlentities, unescape as xmlunescape
@@ -111,13 +111,13 @@
# Exec wrapper
#
def run(cmd):
- debug(dbg.PROC, "Exec:", cmd)
+ log.PROC("Exec:", cmd)
try: os.system("start \"%s\"" % cmd if conf.windows else cmd + " &")
- except: debug(dbg.ERR, "Command not found:", cmd)
+ except: log.ERR("Command not found:", cmd)
# Start web browser
#
def browser(url):
@@ -207,11 +207,11 @@
# · But returns a list of [urls] after playlist extraction.
# · If repackaging as .m3u/.pls/.xspf, returns the local [fn].
#
def convert_playlist(url, source, dest, local_file=True, row={}):
urls = []
- debug(dbg.PROC, "convert_playlist(", url, source, dest, ")")
+ log.PROC("convert_playlist(", url, source, dest, ")")
# Leave alone if format matches, or if already "srv" URL, or if not http (local path, mms:/rtsp:)
if source == dest or source in ("srv", "href") or not re.match("(https?|spdy)://", url):
return [url]
@@ -227,17 +227,17 @@
ext = probe_playlist_fn_ext(url)
probe = probe_playlist_content(cnt)
# Check ambiguity (except pseudo extension)
if len(set([source, mime, probe])) > 1:
- debug(dbg.ERR, "Possible playlist format mismatch:", "listformat={}, http_mime={}, rx_probe={}, ext={}".format(source, mime, probe, ext))
+ log.ERR("Possible playlist format mismatch:", "listformat={}, http_mime={}, rx_probe={}, ext={}".format(source, mime, probe, ext))
# Extract URLs from content
for fmt in [id[0] for id in extract_playlist.extr_urls]:
if not urls and fmt in (source, mime, probe, ext, "raw"):
urls = extract_playlist(cnt).format(fmt)
- debug(dbg.DATA, "conversion from:", source, " with extractor:", fmt, "got URLs=", urls)
+ log.DATA("conversion from:", source, " with extractor:", fmt, "got URLs=", urls)
# Return original, or asis for srv targets
if not urls:
return [url]
elif dest in ("srv", "href"):
@@ -245,11 +245,11 @@
# Otherwise convert to local file
if local_file:
fn, is_unique = tmp_fn(cnt, dest)
with open(fn, "w") as f:
- debug(dbg.DATA, "exporting with format:", dest, " into filename:", fn)
+ log.DATA("exporting with format:", dest, " into filename:", fn)
f.write( save_playlist(source="srv", multiply=True).export(urls, row, dest) )
return [fn]
else:
return urls
@@ -287,11 +287,11 @@
# Map MIME to abbr type (pls, m3u, xspf)
if listfmt_t.get(mime):
mime = listfmt_t.get(mime)
# Raw content (mp3, flv)
elif mediafmt_t.get(mime):
- debug(dbg.ERR, "Got media MIME type for expected playlist", mime, " on url=", url)
+ log.ERR("Got media MIME type for expected playlist", mime, " on url=", url)
mime = mediafmt_t.get(mime)
return (mime, url)
# Rejoin body
content = "\n".join(str.decode(errors='replace') for str in r.iter_lines())
return (mime, content)
@@ -311,11 +311,11 @@
def __init__(self, text):
self.src = text
# Extract only URLs from given source type
def format(self, fmt):
- debug(dbg.DATA, "input extractor/regex:", fmt, len(self.src))
+ log.DATA("input extractor/regex:", fmt, len(self.src))
# find extractor
if fmt in dir(self):
return self.__dict__[fmt]()
@@ -411,11 +411,11 @@
# Or just allow one stream per station in a playlist entry
if not self.multiply:
break
rows = new_rows
- debug(dbg.DATA, "conversion to:", dest, " with rows=", rows)
+ log.DATA("conversion to:", dest, " with rows=", rows)
# call conversion schemes
converter = getattr(self, dest) or self.pls
return converter(rows)
Index: ahttp.py
==================================================================
--- ahttp.py
+++ ahttp.py
@@ -12,11 +12,11 @@
# simulating requests too. Hooks into mains gtk.statusbar().
# And can normalize URLs to always carry a trailing slash
# after the domain name.
-from config import conf, __print__, dbg
+from config import *
import requests
#-- hooks to progress meter and status bar in main window
feedback = None
@@ -52,11 +52,11 @@
#-- Retrieve data via HTTP
#
# Well, it says "get", but it actually does POST and AJAXish GET requests too.
#
def get(url, params={}, referer="", post=0, ajax=0, binary=0, feedback=None, content=True):
- __print__( dbg.HTTP, "GET", url, params )
+ log.HTTP("GET", url, params )
# statusbar info
progress_feedback(url)
# combine headers
@@ -74,19 +74,19 @@
if post:
r = session.post(url, params=params, headers=headers, timeout=7.5)
else:
r = session.get(url, params=params, headers=headers, timeout=9.75)
- __print__( dbg.HTTP, r.request.headers );
- __print__( dbg.HTTP, r.headers );
+ log.HTTP(r.request.headers );
+ log.HTTP(r.headers );
# finish, clean statusbar
#progress_feedback(0.9)
#progress_feedback("")
# result
- __print__( dbg.INFO, "Content-Length", len(r.content) )
+ log.INFO("Content-Length", len(r.content) )
if not content:
return r
elif binary:
return r.content
else:
Index: channels/__init__.py
==================================================================
--- channels/__init__.py
+++ channels/__init__.py
@@ -102,11 +102,11 @@
@property
def current(self):
return self.__current
@current.setter
def current(self, newcat):
- __print__(dbg.PROC, "{}.current:={} ← from {}".format(self.module, newcat, [inspect.stack()[x][3] for x in range(1,4)]))
+ log.PROC("{}.current:={} ← from {}".format(self.module, newcat, [inspect.stack()[x][3] for x in range(1,4)]))
self.__current = newcat
return self.__current
#--------------------------- initialization --------------------------------
@@ -165,11 +165,11 @@
# Statusbar stub (defers to parent/main window, if in GUI mode)
def status(self, *v):
if self.parent: self.parent.status(*v)
- else: __print__(dbg.INFO, "status():", *v)
+ else: log.INFO("status():", *v)
#--------------------- streams/model data accesss ---------------------------
@@ -245,11 +245,11 @@
print "load(None)"
return
# get data from cache or download
if force or not category in self.streams:
- __print__(dbg.PROC, "load", "update_streams")
+ log.PROC("load", "update_streams")
self.status("Updating streams...")
self.status(-0.1)
if category == "empty":
new_streams = self.empty_stub
else:
@@ -263,11 +263,11 @@
if len(set(["", None]) & set([row.get("title"), row.get("url")])):
continue
try:
modified.append( self.postprocess(row) )
except Exception as e:
- __print__(e, dbg.DATA, "Missing title or url. Postprocessing failed:", row)
+ log.DATA(e, "Missing title or url. Postprocessing failed:", row)
new_streams = modified
# don't lose forgotten streams
if conf.retain_deleted:
self.streams[category] = new_streams + self.deleted_streams(new_streams, self.streams.get(category,[]))
@@ -279,11 +279,11 @@
else:
# parse error
self.status("Category parsed empty.")
self.streams[category] = self.nothing_found
- __print__(dbg.INFO, "Oooops, parser returned nothing for category " + category)
+ log.INFO("Oooops, parser returned nothing for category " + category)
# assign to treeview model
uikit.do(lambda:uikit.columns(self.gtk_list, self.datamap, self.prepare(self.streams[category])))
# set pointer
@@ -381,35 +381,35 @@
def first_show(self):
# Already processed
if (self.shown == 55555):
return
- __print__(dbg.PROC, self.module, "→ first_show()", ", current=", self.current, ", categories=", len(self.categories))
+ log.PROC(self.module, "→ first_show()", ", current=", self.current, ", categories=", len(self.categories))
# if category tree is empty, initialize it
if not self.categories:
- __print__(dbg.PROC, self.module, "→ first_show() → reload_categories()");
+ log.PROC(self.module, "→ first_show() → reload_categories()");
try:
self.reload_categories()
except:
- __print__(dbg.ERR, "HTTP error or extraction failure.")
+ log.ERR("HTTP error or extraction failure.")
self.categories = ["empty"]
self.display_categories()
# Select first category
if not self.current:
self.current = self.str_from_struct(self.categories) or None
- __print__(dbg.STAT, self.module, "→ first_show(); use first category as current =", self.current)
+ log.STAT(self.module, "→ first_show(); use first category as current =", self.current)
self.shown = 0,
# Show current category in any case
- __print__(dbg.UI, self.module, "→ first_show(); station list → load(", self.current, ")")
+ log.UI(self.module, "→ first_show(); station list → load(", self.current, ")")
uikit.do(self.load, self.current)
# put selection/cursor on last position
if True:#self.shown != None:
- __print__(dbg.STAT, self.module+".first_show()", "select last known category treelist position =", self.shown)
+ log.STAT(self.module+".first_show()", "select last known category treelist position =", self.shown)
try:
uikit.do(lambda:self.gtk_list.get_selection().select_path(self.shown))
except:
pass
Index: channels/bookmarks.py
==================================================================
--- channels/bookmarks.py
+++ channels/bookmarks.py
@@ -73,11 +73,11 @@
# all entries just come from "bookmarks.json"
def cache(self):
# stream list
cache = conf.load(self.module)
if (cache):
- __print__(dbg.PROC, "load bookmarks.json")
+ log.PROC("load bookmarks.json")
self.streams = cache
# save to cache file
@@ -138,11 +138,11 @@
# update bookmarks from freshly loaded streams data
def heuristic_update(self, updated_channel, updated_category):
if not conf.heuristic_bookmark_update: return
- __print__(dbg.PROC, "heuristic bookmark update")
+ log.PROC("heuristic bookmark update")
save = 0
fav = self.streams["favourite"]
# First we'll generate a list of current bookmark stream urls, and then
# remove all but those from the currently UPDATED_channel + category.
Index: channels/configwin.py
==================================================================
--- channels/configwin.py
+++ channels/configwin.py
@@ -65,11 +65,11 @@
elif type(w) is gtk.ListStore:
w.clear()
for k,v in val.items():
w.append([k, v, True, self.app_bin_check(v)])
w.append(["", "", True, gtk.STOCK_NEW])
- __print__(dbg.CONF, "config load", prefix+key, val, type(w))
+ #log.CONF("config load", prefix+key, val, type(w))
# Store gtk widget valus back into conf. dict
def save_config(self, config, prefix="config_", save=0):
for key,val in config.items():
w = self.main.get_widget(prefix + key)
@@ -87,11 +87,11 @@
elif type(w) is gtk.ListStore:
config[key] = {}
for row in w:
if row[0] and row[1]:
config[key][row[0]] = row[1]
- __print__(dbg.CONF, "config save", prefix+key, val)
+ log.CONF("config save", prefix+key, val)
# Generic Gtk callback to update ListStore when entries get edited.
# (The main signal_connect() dict prepares individual lambda funcs
# for each ListStore column id.)
Index: channels/dnd.py
==================================================================
--- channels/dnd.py
+++ channels/dnd.py
@@ -4,13 +4,14 @@
# description: Copy streams/stations from and to other applications.
# depends: uikit
# version: 0.5
# type: interface
# config:
-# { name: dnd_format, type: select, value: xspf, select: "pls|m3u|xspf|jspf|asx|smil", description: "Default temporary file format for copying a station entry." }
+# { name: dnd_format, type: select, value: xspf, select: "pls|m3u|xspf|jspf|asx|smil", description: "Default temporary file format for copying a station." }
# category: ui
-# priority: experimental
+# priority: default
+# support: experimental
#
# Implements Gtk/X11 drag and drop support for station lists.
# Should allow to export either just stream URLs, or complete
# PLS, XSPF collections.
#
Index: channels/exportcat.py
==================================================================
--- channels/exportcat.py
+++ channels/exportcat.py
@@ -44,15 +44,15 @@
def savewindow(self, *w):
cn = self.parent.channel()
source = cn.listformat
streams = cn.streams[cn.current]
fn = uikit.save_file("Export category", None, "%s.%s.%s" % (cn.module, cn.current, conf.export_format))
- __print__(dbg.PROC, "Exporting category to", fn)
+ log.PROC("Exporting category to", fn)
if fn:
dest = re.findall("\.(m3u8?|pls|xspf|jspf|json|smil|asx)8?$", fn.lower())
if dest:
dest = dest[0]
else:
self.parent.status("Unsupported export playlist type (file extension).")
return
action.save_playlist(source="asis", multiply=False).file(rows=streams, fn=fn, dest=dest)
pass
Index: channels/file.py
==================================================================
--- channels/file.py
+++ channels/file.py
@@ -25,14 +25,14 @@
try:
from mutagen import File as get_meta
except:
try:
from ID3 import ID3
- __print__(dbg.INFO, "Just basic ID3 support")
+ log.INFO("Just basic ID3 support")
get_meta = lambda fn: dict([(k.lower(),v) for k,v in ID3(fn).iteritems()])
except:
- __print__(dbg.INIT, "You are out of luck in regards to mp3 browsing. No ID3 support.")
+ log.INIT("You are out of luck in regards to mp3 browsing. No ID3 support.")
get_meta = lambda *x: {}
# work around mutagens difficult interface
def mutagen_postprocess(d):
Index: channels/global_key.py
==================================================================
--- channels/global_key.py
+++ channels/global_key.py
@@ -41,11 +41,11 @@
conf.add_plugin_defaults(self.meta, self.module)
try:
for i,keyname in enumerate(conf.switch_key.split(",")): # allow multiple keys
keybinder.bind(keyname, self.switch, ((-1 if i else +1))) # forward +1 or backward -1
except:
- __print__(dbg.ERR, "plugin global_key: Key `%s` could not be registered" % conf.switch_key)
+ log.ERR("plugin global_key: Key `%s` could not be registered" % conf.switch_key)
# key event
def switch(self, num, *any):
Index: channels/icast.py
==================================================================
--- channels/icast.py
+++ channels/icast.py
@@ -33,11 +33,11 @@
# collect 200 station entries (see main options).
import re
import json
-from config import conf, dbg, __print__
+from config import *
from channels import *
import ahttp as http
# Surfmusik sharing site
@@ -89,8 +89,8 @@
if len(r) >= data["meta"]["total_count"] or len(data["stations"]) < 10:
break
else:
params["page"] = int(data["meta"]["current_page"]) + 1
self.parent.status(params["page"] * 9.5 / float(conf.max_streams))
- #__print__(dbg.DATA, data)
+ #log.DATA(data)
return r
Index: channels/internet_radio.py
==================================================================
--- channels/internet_radio.py
+++ channels/internet_radio.py
@@ -26,11 +26,11 @@
#
from channels import *
import re
-from config import conf, __print__, dbg
+from config import *
import ahttp as http
from pq import pq
@@ -82,27 +82,27 @@
if str(page+1) not in rx_pages.findall(html[-1]):
break
self.parent.status(float(page)/float(max_pages+1))
# Alternatively try regex or pyquery parsing
- #__print__(dbg.HTTP, html)
+ #log.HTTP(html)
for use_rx in [not conf.pyquery, conf.pyquery]:
try:
entries = (self.with_regex(html) if use_rx else self.with_dom(html))
if len(entries):
break
except Exception as e:
- __print__(dbg.ERR, e)
+ log.ERR(e)
continue
# fin
return entries
# Regex extraction
def with_regex(self, html):
- __print__(dbg.PROC, "internet-radio, regex")
+ log.PROC("internet-radio, regex")
r = []
html = "\n".join(html)
# Break up into
blocks before extracting bits
rx_tr = re.compile("""
]*>(.+?)
""", re.S)
@@ -116,11 +116,11 @@
.*? (\d+)\s*Kbps
""", re.S|re.X)
for div in rx_tr.findall(html):
if div.find('id="pagination"') < 0:
- #__print__(dbg.DATA, len(div))
+ #log.DATA(len(div))
uu = rx_data.search(div)
if uu:
(url, title, playing, homepage, genres, listeners, bitrate) = uu.groups()
# transform data
@@ -133,17 +133,17 @@
"bitrate": int(bitrate or 0),
"listeners": int(listeners or 0),
"format": "audio/mpeg", # there is no stream info on that, but internet-radio.org.uk doesn't seem very ogg-friendly anyway, so we assume the default here
})
else:
- __print__(dbg.DATA, "Regex couldn't decipher entry:", div)
+ log.DATA("Regex couldn't decipher entry:", div)
return r
# DOM traversing
def with_dom(self, html_list):
- __print__(dbg.PROC, "internet-radio, dom")
+ log.PROC("internet-radio, dom")
rx_numbers = re.compile("(\d+)")
r = []
for html in html_list:
# the streams are arranged in table rows
doc = pq(html)
Index: channels/itunes.py
==================================================================
--- channels/itunes.py
+++ channels/itunes.py
@@ -30,11 +30,11 @@
#
# In this module only iTunes will be queried for now.
#
import re
-from config import conf, dbg, __print__
+from config import *
from channels import *
import ahttp as http
# Surfmusik sharing site
@@ -84,11 +84,11 @@
# Just copy over stream URLs and station titles
def update_streams(self, cat):
m3u = http.get(self.base, {"category": cat.lower()})
if len(m3u) < 256:
- __print__(dbg.ERR, m3u)
+ log.ERR(m3u)
rx_m3u = re.compile(r"""
^File(\d+)\s*=\s*(http://[^\s]+)\s*$\s*
^Title\1\s*=\s*([^\r\n]+)\s*$\s*
""", re.M|re.I|re.X)
Index: channels/jamendo.py
==================================================================
--- channels/jamendo.py
+++ channels/jamendo.py
@@ -36,11 +36,11 @@
# retrieval is going to become inaccessible soon.)
import re
import ahttp as http
-from config import conf, __print__, dbg
+from config import *
from channels import *
import json
# jamendo CC music sharing site
Index: channels/live365.py
==================================================================
--- channels/live365.py
+++ channels/live365.py
@@ -24,11 +24,11 @@
# streamtuner2 modules
from config import conf
from uikit import uikit
import ahttp as http
from channels import *
-from config import __print__, dbg
+from config import *
import action
# python modules
import re
import xml.dom.minidom
Index: channels/modarchive.py
==================================================================
--- channels/modarchive.py
+++ channels/modarchive.py
@@ -27,11 +27,11 @@
import re
import ahttp as http
from config import conf
from channels import *
-from config import __print__, dbg
+from config import *
# The MOD Archive
#
# Modarchive actually provides an API
@@ -97,11 +97,11 @@
.*? >(?:Rated|Unrated)\s*(\d*)
""", re.X|re.S)
for uu in rx_mod.findall(html):
(url, id, fmt, title, file, rating) = uu
- #__print__( dbg.DATA, uu )
+ #log.DATA( uu )
entries.append({
"genre": cat,
"url": url,
"id": id,
"format": self.mime_fmt(fmt) + "+zip",
Index: channels/punkcast.py
==================================================================
--- channels/punkcast.py
+++ channels/punkcast.py
@@ -26,11 +26,11 @@
import re
import ahttp as http
from config import conf
import action
from channels import *
-from config import __print__, dbg
+from config import *
# basic.ch broadcast archive
class punkcast (ChannelPlugin):
@@ -79,13 +79,13 @@
rx_sound = re.compile("""(http://[^"<>]+[.](mp3|ogg|m3u|pls|ram))""")
html = http.get(row["homepage"])
# look up ANY audio url
for uu in rx_sound.findall(html):
- __print__( dbg.DATA, uu )
+ log.DATA( uu )
(url, fmt) = uu
action.play(url, self.mime_fmt(fmt), "srv")
return
# or just open webpage
action.browser(row["homepage"])
Index: channels/radiobrowser.py
==================================================================
--- channels/radiobrowser.py
+++ channels/radiobrowser.py
@@ -33,11 +33,11 @@
# Also has a neat JSON API, so is quite easy to support.
import re
import json
-from config import conf, dbg, __print__
+from config import *
from channels import *
import ahttp as http
# API endpoints:
Index: channels/radiotray.py
==================================================================
--- channels/radiotray.py
+++ channels/radiotray.py
@@ -101,11 +101,11 @@
row = self.parent.row()
if row:
# RadioTray doesn't have an addRadio method yet, so just fall back to play the stream URL
try:
group = self.map_group(row.get("genre"))
- __print__(dbg.PROC, "mapping genre '%s' to RT group '%s'" % (row["genre"], group))
+ log.PROC("mapping genre '%s' to RT group '%s'" % (row["genre"], group))
self.radiotray().addRadio(row["title"], row["url"], group)
except:
self.radiotray().playUrl(row["url"])
pass
Index: channels/search.py
==================================================================
--- channels/search.py
+++ channels/search.py
@@ -100,11 +100,11 @@
self.prepare_search()
entries = []
for i,cn in enumerate([self.main.channels[c] for c in self.targets]):
if cn.has_search: # "search" in cn.update_streams.func_code.co_varnames:
self.main.status("Server searching: " + cn.module)
- __print__(dbg.PROC, "has_search:", cn.module)
+ log.PROC("has_search:", cn.module)
try:
add = cn.update_streams(cat=None, search=self.q)
for row in add:
row["genre"] = cn.meta["title"] + " " + row.get("genre", "")
entries += add
Index: channels/shoutcast.py
==================================================================
--- channels/shoutcast.py
+++ channels/shoutcast.py
@@ -24,13 +24,13 @@
import ahttp as http
from json import loads as json_decode
import re
-from config import conf, __print__, dbg
+from config import *
+from channels import *
from pq import pq
-from channels import * # works everywhere but in this plugin(???!)
import channels
from compat2and3 import urllib
@@ -65,11 +65,11 @@
# Extracts the category list from www.shoutcast.com,
# stores a catmap (title => id)
def update_categories(self):
html = http.get(self.base_url)
- #__print__( dbg.DATA, html )
+ #log.DATA( html )
self.categories = []
# Genre list in sidebar
""" Adult """
rx = re.compile(r"loadStationsByGenre\( '([^']+)' [,\s]* (\d+) [,\s]* (\d+) \)", re.X)
@@ -92,11 +92,11 @@
# downloads stream list from shoutcast for given category
def update_streams(self, cat):
if (cat not in self.catmap):
- __print__( dbg.ERR, "Category not in known map.", cat )
+ log.ERR( "Category not in known map.", cat )
return []
id = self.catmap[cat]
# page
url = "http://www.shoutcast.com/Home/BrowseByGenre"
@@ -104,11 +104,11 @@
referer = None
try:
json = http.get(url, params=params, referer=referer, post=1, ajax=1)
json = json_decode(json)
except:
- __print__(dbg.ERR, "HTTP request or JSON decoding failed. Outdated python/requests perhaps.")
+ log.ERR("HTTP request or JSON decoding failed. Outdated python/requests perhaps.")
return []
self.parent.status(0.75)
# remap JSON
entries = []
@@ -123,8 +123,8 @@
"url": "http://yp.shoutcast.com/sbin/tunein-station.pls?id=%s" % e.get("ID", "0"),
"homepage": "",
"format": "audio/mpeg"
})
- #__print__(dbg.DATA, entries)
+ #log.DATA(entries)
return entries
Index: channels/somafm.py
==================================================================
--- channels/somafm.py
+++ channels/somafm.py
@@ -24,11 +24,11 @@
# Note that only 64bit AAC and 128bit MP3 are guaranteed
# to be available. Most stations offer different bitrates,
# but not all of them!
-from config import conf, dbg, __print__
+from config import *
from channels import *
import re
import ahttp
# TuneIn radio directory
Index: channels/surfmusik.py
==================================================================
--- channels/surfmusik.py
+++ channels/surfmusik.py
@@ -32,11 +32,11 @@
#
#
import re
import ahttp as http
-from config import conf, dbg, __print__
+from config import *
from channels import *
# Surfmusik sharing site
Index: channels/timer.py
==================================================================
--- channels/timer.py
+++ channels/timer.py
@@ -74,11 +74,11 @@
# prepare spool
self.sched = kronos.ThreadedScheduler()
for row in self.streams:
try: self.queue(row)
- except Exception as e: __print__(dbg.ERR, "queuing error", e)
+ except Exception as e: log.ERR("queuing error", e)
self.sched.start()
# display GUI for setting timespec
def edit_timer(self, *w):
@@ -134,11 +134,11 @@
activity, action_method = "play", self.play
# add
task = self.sched.add_daytime_task(action_method, activity, days, None, time, kronos.method.threaded, [row], {})
- #__print__( "queue", act, self.sched, (action_method, act, days, None, time, kronos.method.threaded, [row], {}), task.get_schedule_time(True) )
+ #log.QUEUE( act, self.sched, (action_method, act, days, None, time, kronos.method.threaded, [row], {}), task.get_schedule_time(True) )
# converts Mon,Tue,... into numberics 1-7
def days(self, s):
Index: channels/tunein.py
==================================================================
--- channels/tunein.py
+++ channels/tunein.py
@@ -24,11 +24,11 @@
#
import re
import json
-from config import conf, dbg, __print__
+from config import *
from channels import *
import ahttp as http
from xml.etree import ElementTree
Index: channels/ubuntuusers.py
==================================================================
--- channels/ubuntuusers.py
+++ channels/ubuntuusers.py
@@ -20,11 +20,11 @@
# but stations are grouped by country already.
#
import re
-from config import conf, dbg, __print__
+from config import *
from channels import *
import ahttp
# UU Wiki radio list
Index: channels/useragentswitcher.py
==================================================================
--- channels/useragentswitcher.py
+++ channels/useragentswitcher.py
@@ -41,9 +41,9 @@
# set new browser string in requests session
def apply(self):
ua = self.map.get(conf.useragent.lower(), self.map["default"])
if ua:
- __print__(dbg.HTTP, "UserAgentSwitcher:", ua)
+ log.HTTP("UserAgentSwitcher:", ua)
ahttp.session.headers.update({ "User-Agent": ua })
Index: channels/xiph.py
==================================================================
--- channels/xiph.py
+++ channels/xiph.py
@@ -103,18 +103,18 @@
if search:
params["search"] = search
#-- get data
data = http.get(self.json_url, params=params)
- #__print__(dbg.DATA, data)
+ #log.DATA(data)
#-- extract
l = []
- __print__( dbg.PROC, "processing api.dir.xiph.org JSON (via api.include-once.org cache)" )
+ log.PROC( "processing api.dir.xiph.org JSON (via api.include-once.org cache)" )
data = json.loads(data)
for e in data:
- #__print__(dbg.DATA, e)
+ #log.DATA(e)
bitrate = int(e["bitrate"])
if conf.xiph_min_bitrate and bitrate and bitrate >= int(conf.xiph_min_bitrate):
if not len(l) or l[-1]["title"] != e["stream_name"]:
l.append({
"title": e["stream_name"],
Index: channels/youtube.py
==================================================================
--- channels/youtube.py
+++ channels/youtube.py
@@ -241,11 +241,11 @@
params = dict( list(defaults.items()) + list(params.items()) )
# Retrieve data set
while pages > 0:
j = ahttp.get(base_url + method, params=params)
- #__print__(dbg.DATA, j)
+ #log.DATA(j)
if j:
# json decode
data = json.loads(j)
# extract items
@@ -302,11 +302,11 @@
return data
# API version 2.0s jsonified XML needs different unpacking:
def wrap2(self, row):
- #__print__(dbg.DATA, row)
+ #log.DATA(row)
return dict(
genre = row["category"][1]["term"],
title = row["title"]["$t"],
playing = row["author"][0]["name"]["$t"],
format = self.audioformat,
Index: config.py
==================================================================
--- config.py
+++ config.py
@@ -9,11 +9,11 @@
# { arg: -e, type: str, name: enable[], description: Add channel plugin. }
# { arg: --gtk3, type: boolean, name: gtk3, description: Start with Gtk3 interface. }
# { arg: -D, type: boolean, name: debug, description: Enable debug messages on console }
# { arg: action, type: str *, name: action[], description: CLI interface commands. }
# { arg: -x, type: boolean, name: exit, hidden: 1 }
-# version: 2.5
+# version: 2.6
# priority: core
#
# In the main application or module files which need access
# to a global conf.* object, just import this module as follows:
#
@@ -20,11 +20,11 @@
# from config import *
#
# Here conf is already an instantiation of the underlying
# ConfigDoct class.
#
-# Also provides the logging function __print__, and basic
+# Also provides the logging function log.TYPE(...) and basic
# plugin handling code: plugin_meta() and module_list(),
# and the relative get_data() alias (files from pyzip/path).
#
from __future__ import print_function
@@ -40,11 +40,11 @@
import inspect
import pkgutil
import argparse
# export symbols
-__all__ = ["conf", "log", "__print__", "dbg", "plugin_meta", "module_list", "get_data", "find_executable"]
+__all__ = ["conf", "log", "plugin_meta", "module_list", "get_data", "find_executable"]
#-- create a stub instance of config object
conf = object()
@@ -464,42 +464,21 @@
)
""", re.X)
-
-# wrapper for all print statements
-def __print__(*args):
- if "debug" in conf and conf.debug or args[0] == dbg.ERR:
- print(" ".join([str(a) for a in args]), file=sys.stderr)
-
-
-# error colorization
-dbg = type('obj', (object,), {
- "ERR": r"[31m[ERR][0m", # red ERROR
- "INIT": r"[31m[INIT][0m", # red INIT ERROR
- "PROC": r"[32m[PROC][0m", # green PROCESS
- "CONF": r"[33m[CONF][0m", # brown CONFIG DATA
- "UI": r"[34m[UI][0m", # blue USER INTERFACE BEHAVIOUR
- "HTTP": r"[35m[HTTP][0m", # magenta HTTP REQUEST
- "DATA": r"[36m[DATA][0m", # cyan DATA
- "INFO": r"[37m[INFO][0m", # gray INFO
- "STAT": r"[37m[STATE][0m", # gray CONFIG STATE
-})
-
-
# Simplified print wrapper: `log.err(...)`
class log_printer(object):
# Wrapper
method = None
def __getattr__(self, name):
self.method = name
- return self.__print__
+ return self.log_print
# Printer
- def __print__(self, *args, **kwargs):
+ def log_print(self, *args, **kwargs):
# debug level
method = self.method.upper()
if not method == "ERR":
if "debug" in conf and not conf.debug:
return
Index: contrib/8tracks.py
==================================================================
--- contrib/8tracks.py
+++ contrib/8tracks.py
@@ -16,11 +16,11 @@
# could work, or checking via dbus/mpris even.
#
import re
import json
-from config import conf, dbg, __print__
+from config import *
from channels import *
import ahttp as http
# Surfmusik sharing site
Index: help/action_saving.page
==================================================================
--- help/action_saving.page
+++ help/action_saving.page
@@ -17,12 +17,12 @@
The extension of the filename decides on the saved link format. Per
default a .m3u file is created, because that's what most audio players
understand.
- But you can also save in .pls or .xspf
- or .asx or .smil format. Note that the
- lower right dropdown has no effect. You have to edit the extension
- into the filename field.
+ You can also save in .pls or .xspf
+ or .asx or .smil format. In current
+ releases the file extension is automatically adapted when changing
+ the filter dropdown (bottom right corner in the file dialog).
Index: help/search.page
==================================================================
--- help/search.page
+++ help/search.page
@@ -31,18 +31,18 @@
It either will search in all channels, or just the last active
channel/service.
- Then there are two search methods. You mostly want to use
+
Then there are two search variants. You mostly want to use
the live Server search. It passes your search terms to
the actual directory services, and loads the most recent data into a
result list. This might take a few seconds. And it's not implemented
- for all channel plugins however.
+ for all channel plugins. (Some websites/APIs don't have a search.)
- With Cache find would just look up entries in your
+
While Cache find would just look up entries in your
already downloaded channel/genre lists. This is sufficient when
- you're just looking for something previously seen/listended to.
+ you're just looking for something previously seen/listened to.
Index: st2.py
==================================================================
--- st2.py
+++ st2.py
@@ -121,11 +121,11 @@
# display current open channel/notebook tab
gui_startup(18/20.0)
self.current_channel = self.current_channel_gtk()
try: self.channel().first_show()
- except: __print__(dbg.INIT, "main.__init__: current_channel.first_show() initialization error")
+ except: log.INIT("main.__init__: current_channel.first_show() initialization error")
# bind gtk/glade event names to functions
gui_startup(19.75/20.0)
self.connect_signals({
@@ -230,11 +230,11 @@
# Notebook tab has been clicked (receives numeric page_num), but *NOT* yet changed (visually).
def channel_switch(self, notebook, page, page_num=0, *args):
self.current_channel = notebook.get_menu_label_text(notebook.get_nth_page(page_num))
- __print__(dbg.UI, "main.channel_switch() :=", self.current_channel)
+ log.UI("main.channel_switch() :=", self.current_channel)
self.update_title()
# if first selected, load current category
# (run in thread, to make it look speedy on first startup)
self.thread( self.channel().first_show )
@@ -277,17 +277,17 @@
else: self.status("No homepage URL present.")
# Browse to channel homepage (double click on notebook tab)
def on_homepage_channel_clicked(self, widget, event=2):
if event == 2 or event.type == gtk.gdk._2BUTTON_PRESS:
- __print__(dbg.UI, "dblclick")
+ log.UI("dblclick")
url = self.channel().meta.get("url", "https://duckduckgo.com/?q=" + self.channel().module)
action.browser(url)
# Reload stream list in current channel-category
def on_reload_clicked(self, widget=None, reload=1):
- __print__(dbg.UI, "on_reload_clicked()", "reload=", reload, "current_channel=", self.current_channel, "c=", self.channels[self.current_channel], "cat=", self.channel().current)
+ log.UI("on_reload_clicked()", "reload=", reload, "current_channel=", self.current_channel, "c=", self.channels[self.current_channel], "cat=", self.channel().current)
category = self.channel().current
self.thread(
#@TODO: should get a wrapper, for HTTP errors, and optionalize bookamrks
lambda: ( self.channel().load(category,reload), reload and self.bookmarks.heuristic_update(self.current_channel,category) )
)
@@ -300,11 +300,11 @@
# Click in category list
def on_category_clicked(self, widget, event, *more):
category = self.channel().currentcat()
- __print__(dbg.UI, "on_category_clicked", category, self.current_channel)
+ log.UI("on_category_clicked", category, self.current_channel)
self.on_reload_clicked(None, reload=0)
pass
# Add current selection to bookmark store
def bookmark(self, widget):
@@ -389,11 +389,11 @@
if not name in conf.plugins:
conf.add_plugin_defaults(plugin_meta(module=name), name)
# skip module if disabled
if conf.plugins.get(name, 1) == False:
- __print__(dbg.STAT, "disabled plugin:", name)
+ log.STAT("disabled plugin:", name)
continue
# or if it's a built-in (already imported)
elif name in self.features or name in self.channels:
continue
@@ -410,11 +410,11 @@
# or .features{} for other plugin types
else:
self.features[name] = plugin_obj
except Exception as e:
- __print__(dbg.INIT, "load_plugin_channels: error initializing:", name, ", exception:")
+ log.INIT("load_plugin_channels: error initializing:", name, ", exception:")
traceback.print_exc()
# load application state (widget sizes, selections, etc.)
def init_app_state(self):
@@ -496,11 +496,11 @@
del conf.firstrun
# run
gtk.main()
[callback() for callback in main.hooks["quit"]]
- __print__(dbg.PROC, r"[31m gtk_main_quit [0m")
+ log.PROC(r"[31m gtk_main_quit [0m")
# invoke command-line interface
else:
import cli
cli.StreamTunerCLI(conf.args.action)
Index: uikit.py
==================================================================
--- uikit.py
+++ uikit.py
@@ -44,12 +44,12 @@
pygtk.enable()
pygtk.enable_gtk(version='3.0')
from gi.repository import Gtk as gtk
from gi.repository import GObject as gobject
from gi.repository import GdkPixbuf
- __print__(dbg.STAT, gtk)
- __print__(dbg.STAT, gobject)
+ log.STAT(gtk)
+ log.STAT(gobject)
else:
import pygtk
import gtk
import gobject
GdkPixbuf = gtk.gdk
@@ -129,11 +129,11 @@
# apply attributes
for attr,val in list(cell[3].items()):
col.add_attribute(rend, attr, val)
# next
datapos += 1
- #__print__(dbg.INFO, cell, len(cell))
+ #log.INFO(cell, len(cell))
# add column to treeview
widget.append_column(col)
# finalize widget
widget.set_search_column(5) #??
@@ -153,12 +153,12 @@
for var in xrange(2, len(desc)):
vartypes.append(desc[var][1]) # content types
rowmap.append(desc[var][0]) # dict{} column keys in entries[] list
# create gtk array storage
ls = gtk.ListStore(*vartypes) # could be a TreeStore, too
- #__print__(dbg.UI, vartypes, len(vartypes))
- #__print__(dbg.DATA, rowmap, len(rowmap))
+ #log.UI(vartypes, len(vartypes))
+ #log.DATA(rowmap, len(rowmap))
# prepare for missing values, and special variable types
defaults = {
str: "",
unicode: "",
@@ -194,11 +194,11 @@
except:
# brute-force typecast
ls.append( [va if ty==gtk.gdk.Pixbuf else ty(va) for va,ty in zip(row,vartypes)] )
#if entries:
- #__print__("[37m→[0m", row, len(row))
+ # log.ROWS(row, len(row))
# apply array to widget
widget.set_model(ls)
return ls
@@ -215,11 +215,11 @@
@staticmethod
def tree(widget, entries, title="category", icon=gtk.STOCK_DIRECTORY):
# list types
ls = gtk.TreeStore(str, str)
- #__print__(dbg.DATA, ".tree", entries)
+ #log.DATA(".tree", entries)
# add entries
for entry in entries:
if isinstance(entry, (str,unicode)):
main = ls.append(None, [str(entry), icon])