ADDED contrib/podspider.py Index: contrib/podspider.py ================================================================== --- contrib/podspider.py +++ contrib/podspider.py @@ -0,0 +1,205 @@ +# encoding: UTF-8 +# api: streamtuner2 +# title: PODspider +# description: lists Podcasts RSS from proprietary podspider xml database +# version: 0.0 +# depends: lxml.etree, pyquery +# url: http://www.radiograbber.de/ +# status: unsupported +# priority: separate +# +# Podspider is one part of the commercial Windows "Radiograbber" software. +# A demo version is available from http://www.surfmusik.net/downloads/download.php?pid=13 +# and runs under Wine. +# It downloads a "Podspiderpdb.xml.tmp_", which this plugin can display as +# streamtuner2 channel. The contents are a pre-classified list of PODcasts +# via RSS feeds. It needs some rework to strip out excessive duplicates, but +# it's nevertheless the largest overview. +# +# You can move the Podspiderpdb.xml.* into your ~/.config/streamtuner2/ dir +# after you have it. +# +# The current implementation is very inefficient. It reads the XML on every +# start. Caching it as JSON wouldn't be very wise, as it'd still be 20 MB. +# +# Untested. + + +import action +import http +from config import conf +from channels import * +import os, os.path +from pq import pq +import lxml.etree +import mygtk + + + +# return text entry from etree list +def get(item, tag, hint=None): + if hint != None: + if len(item) > hint: # hint tells us the usual position of the element + if item[hint].tag == tag and item[hint].text: + return item[hint].text + for e in item: # else we look at each + if e.tag==tag: + try: + if e.text: + return e.text + except: + pass + return "" # empty string if nothing found + + +# PODlist from Radiograbber +class podspider (ChannelPlugin): + + # pi info + module = "podspider" + homepage = "http://www.radiograbber.de/" + listformat = "rss" + + # data + config = [ + ] + xml = None + all = [] + streams = {} + categories = [] + + + # set up + def __init__(self, parent): + self.xml = self.find_podspider_xml() + if self.xml: + print self.xml + self.all = self.fetch() + #self.save() + else: + self.warn() + ChannelPlugin.__init__(self,parent) + + + # gtk.messagebox + def warn(self): + mygtk.msg("Podspiderpdb.xml.tmp_ couldn't be found anywhere.\nInstall Radiograbber via Wine to create it.") + + + # prevent cache file creation, as it would contain sublists and ends up being unreadable by json module + def save(self, *a): + pass + + + # get podspider.xml filename + def find_podspider_xml(self): + wine_dir = "%s/.wine/drive_c/windows/profiles/%s/Temp/RapidSolution/" % (os.environ["HOME"], os.environ["USER"]) + fn_vari = ("Podspiderpdb.xml.tmp_", "Podspiderpdb.xml.tmp", "Podspiderpdb.xml", "podspider.xml") + for dir in (conf.dir, wine_dir): + if os.path.exists(dir): + for fn in fn_vari: + if os.path.exists(dir +"/"+ fn): + return dir+fn + pass + + + # extract XML + def fetch(self, f=lambda row:1): + r = [] + + # read Podspider*.xml.* + doc = open(self.xml).read() + doc = doc.replace(' xmlns=', ' x-ign=') + + # parse to object tree + doc = lxml.etree.fromstring(doc) + # step down to + doc = doc[0] + # skip or other meta tags + while doc[0].tag != "item": + del doc[0] + + # each <item> + last_url = "" + for item in doc: + + row = { + "title": get(item, "title", hint=0), + "homepage": get(item, "link", hint=1), + "playing": str(str(get(item, "description", hint=2)).replace("\n", " "))[:512], + "favicon": get(item, "artwork", hint=4), + # "format": "application/rss+xml", + "language": get(item, "language", hint=5) or "English", + # "lang": get(item, "iso3166", hint=6), + "category": [e.get("category") for e in item if e.tag=="classification"], + "listeners": int(1000.0 * float(item.get("relevance") or 0)), + } + + if row["homepage"] != last_url and f(row): + r.append(row) + last_url = row["homepage"] + + return r + + + # loads RSS and gets first entry url + def play(self, row): + audio = "audio/mp3" + r = [] + for e in pq(http.get(row["homepage"])).find("enclosure"): + r.append(e.get("url")) + audio = e.get("type") + if r: + action.action.play(r[0], audioformat=audio, listformat="url/direct") + + + + + # look for categories + def update_categories(self): + + # collect + cat = {} + for row in self.streams["all"]: + + lang = row["language"] + if lang not in cat: + cat[lang] = [] + + for c in row["category"]: + if c and c not in cat[lang]: + cat[lang].append(c) + + # populate as two-level list + self.categories = [] + for c,sub in cat.iteritems(): + self.categories.append(c) + self.categories.append(sorted(sub)) + + + # extract + def update_streams(self, cat): + r = [] + + # ignore lang-only entries: + if cat in self.categories: + pass + + # scan through list + else: + for row in self.all: + if cat in row["category"]: + row = dict(row) #copy + row["genre"] = ", ".join(row["category"]) + del row["category"] + r.append(row) + + return r + + + + + + + +