# warning, this is work in progress. # plus, the "global_session" stuff is of course very lame. # plus, the error handling sucks. from Screens.Screen import Screen from Screens.MessageBox import MessageBox from Components.ActionMap import ActionMap from Components.GUIComponent import GUIComponent from Components.MultiContent import MultiContentEntryText from Plugins.Plugin import PluginDescriptor from enigma import eListboxPythonMultiContent, eListbox, gFont, RT_HALIGN_LEFT, RT_WRAP from twisted.web.client import getPage import xml.dom.minidom from Tools.XMLTools import mergeText, elementsWithTag from enigma import eTimer from sets import Set my_global_session = None #urls = ["http://www.heise.de/newsticker/heise.rdf", "http://rss.slashdot.org/Slashdot/slashdot/to"] urls = ["http://mastermaq.podcastspot.com/episodes/rss/mpg1"] from Components.config import config, ConfigSubsection, ConfigSelection, getConfigListEntry from Components.ConfigList import ConfigListScreen config.simpleRSS = ConfigSubsection() config.simpleRSS.hostname = ConfigSelection(choices = urls) class SimpleRSS(ConfigListScreen, Screen): skin = """ """ def __init__(self, session, args = None): print "screen init" Screen.__init__(self, session) self.skin = SimpleRSS.skin self.onClose.append(self.abort) # nun erzeugen wir eine liste von elementen fuer die menu liste. self.list = [ ] self.list.append(getConfigListEntry(_("RSS Feed URI"), config.simpleRSS.hostname)) # die liste selbst ConfigListScreen.__init__(self, self.list) self["actions"] = ActionMap([ "OkCancelActions" ], { "ok": self.close, # "cancel": self.close, }) self["setupActions"] = ActionMap(["SetupActions"], { "save": self.save, "cancel": self.close }, -1) def abort(self): print "aborting" def save(self): for x in self["config"].list: x[1].save() self.close() def cancel(self): for x in self["config"].list: x[1].cancel() self.close() class RSSList(GUIComponent): def __init__(self, entries): GUIComponent.__init__(self) self.l = eListboxPythonMultiContent() self.l.setFont(0, gFont("Regular", 22)) self.l.setFont(1, gFont("Regular", 18)) self.list = [self.buildListboxEntry(x) for x in entries] self.l.setList(self.list) GUI_WIDGET = eListbox def postWidgetCreate(self, instance): instance.setContent(self.l) instance.setItemHeight(100) def buildListboxEntry(self, rss_entry): res = [ rss_entry ] res.append(MultiContentEntryText(pos=(0, 0), size=(460, 75), font=0, flags = RT_HALIGN_LEFT|RT_WRAP, text = rss_entry[0])) res.append(MultiContentEntryText(pos=(0, 75), size=(460, 20), font=1, flags = RT_HALIGN_LEFT, text = rss_entry[1])) return res def getCurrentEntry(self): return self.l.getCurrentSelection() class RSSDisplay(Screen): skin = """ """ def __init__(self, session, data, interactive = False): Screen.__init__(self, session) self.skin = RSSDisplay.skin if interactive: self["actions"] = ActionMap([ "OkCancelActions" ], { "ok": self.showCurrentEntry, "cancel": self.close, }) self["content"] = RSSList(data) def showCurrentEntry(self): current_entry = self["content"].getCurrentEntry() if current_entry is None: # empty list return (title, link, enclosure) = current_entry[0] if len(enclosure): (url, type) = enclosure[0] # TODO: currently, we used the first enclosure. there can be multiple. print "enclosure: url=%s, type=%s" % (url, type) if type in ["video/mpeg", "audio/mpeg"]: from enigma import eServiceReference # we should better launch a player or so... self.session.nav.playService(eServiceReference(4097, 0, url)) class RSSPoller: MAX_HISTORY_ELEMENTS = 100 def __init__(self): self.poll_timer = eTimer() self.poll_timer.callback.append(self.poll) self.poll_timer.start(0, 1) self.last_links = Set() self.dialog = None self.history = [ ] def error(self, error): if not my_global_session: print "error polling" else: my_global_session.open(MessageBox, "Sorry, failed to fetch feed.\n" + error) def _gotPage(self, data): # workaround: exceptions in gotPage-callback were ignored try: self.gotPage(data) except: import traceback, sys traceback.print_exc(file=sys.stdout) raise e def gotPage(self, data): print "parsing.." new_items = [ ] dom = xml.dom.minidom.parseString(data) for r in elementsWithTag(dom.childNodes, "rss"): rss = r items = [ ] # RSS 1.0 for item in elementsWithTag(r.childNodes, "item"): items.append(item) # RSS 2.0 for channel in elementsWithTag(r.childNodes, "channel"): for item in elementsWithTag(channel.childNodes, "item"): items.append(item) for item in items: title = None link = "" enclosure = [ ] print "got item" for s in elementsWithTag(item.childNodes, lambda x: x in ["title", "link", "enclosure"]): if s.tagName == "title": title = mergeText(s.childNodes) elif s.tagName == "link": link = mergeText(s.childNodes) elif s.tagName == "enclosure": enclosure.append((s.getAttribute("url").encode("UTF-8"), s.getAttribute("type").encode("UTF-8"))) print title, link, enclosure if title is None: continue rss_entry = (title.encode("UTF-8"), link.encode("UTF-8"), enclosure) self.history.insert(0, rss_entry) if link not in self.last_links: self.last_links.add(link) new_items.append(rss_entry) print "NEW", rss_entry[0], rss_entry[1] self.history = self.history[:self.MAX_HISTORY_ELEMENTS] if len(new_items): self.dialog = my_global_session.instantiateDialog(RSSDisplay, new_items) self.dialog.show() self.poll_timer.start(5000, 1) else: self.poll_timer.start(60000, 1) def poll(self): if self.dialog: print "hiding" self.dialog.hide() self.dialog = None self.poll_timer.start(60000, 1) elif not my_global_session: print "no session yet." self.poll_timer.start(10000, 1) else: print "yes, session ok. starting" self.d = getPage(config.simpleRSS.hostname.value).addCallback(self._gotPage).addErrback(self.error) def shutdown(self): self.poll_timer.callback.remove(self.poll) self.poll_timer = None def main(session, **kwargs): print "session.open" session.open(SimpleRSS) print "done" rssPoller = None def autostart(reason, **kwargs): global rssPoller print "autostart" # ouch, this is a hack if kwargs.has_key("session"): global my_global_session print "session now available" my_global_session = kwargs["session"] return print "autostart" if reason == 0: rssPoller = RSSPoller() elif reason == 1: rssPoller.shutdown() rssPoller = None def showCurrent(session, **kwargs): global rssPoller if rssPoller is None: return session.open(RSSDisplay, rssPoller.history, interactive = True) def Plugins(**kwargs): return [ PluginDescriptor(name="RSS Reader", description="A (really) simple RSS reader", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=main), PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart), PluginDescriptor(name="View RSS", description="Lets you view current RSS entries", where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=showCurrent) ]