1 # warning, this is work in progress.
2 # plus, the "global_session" stuff is of course very lame.
3 # plus, the error handling sucks.
4 from Screens.Screen import Screen
5 from Screens.MessageBox import MessageBox
6 from Components.ActionMap import ActionMap
7 from Components.GUIComponent import GUIComponent
8 from Components.MultiContent import MultiContentEntryText
9 from Plugins.Plugin import PluginDescriptor
10 from enigma import eListboxPythonMultiContent, eListbox, gFont, RT_HALIGN_LEFT, RT_WRAP
12 from twisted.web.client import getPage
13 import xml.dom.minidom
15 from Tools.XMLTools import mergeText, elementsWithTag
17 from enigma import eTimer
20 my_global_session = None
22 urls = ["http://www.heise.de/newsticker/heise.rdf", "http://rss.slashdot.org/Slashdot/slashdot/to"]
24 from Components.config import config, ConfigSubsection, ConfigSelection, getConfigListEntry
25 from Components.ConfigList import ConfigListScreen
26 config.simpleRSS = ConfigSubsection()
27 config.simpleRSS.hostname = ConfigSelection(choices = urls)
29 class SimpleRSS(ConfigListScreen, Screen):
31 <screen position="100,100" size="550,400" title="Simple RSS Reader" >
32 <widget name="config" position="20,10" size="460,350" scrollbarMode="showOnDemand" />
35 def __init__(self, session, args = None):
37 Screen.__init__(self, session)
38 self.skin = SimpleRSS.skin
40 self.onClose.append(self.abort)
42 # nun erzeugen wir eine liste von elementen fuer die menu liste.
44 self.list.append(getConfigListEntry(_("RSS Feed URI"), config.simpleRSS.hostname))
47 ConfigListScreen.__init__(self, self.list)
49 self["actions"] = ActionMap([ "OkCancelActions" ],
52 # "cancel": self.close,
55 self["setupActions"] = ActionMap(["SetupActions"],
65 for x in self["config"].list:
70 for x in self["config"].list:
74 class RSSList(GUIComponent):
75 def __init__(self, entries):
76 GUIComponent.__init__(self)
77 self.l = eListboxPythonMultiContent()
78 self.l.setFont(0, gFont("Regular", 22))
79 self.l.setFont(1, gFont("Regular", 18))
80 self.list = [self.buildListboxEntry(x) for x in entries]
81 self.l.setList(self.list)
85 def postWidgetCreate(self, instance):
86 instance.setContent(self.l)
87 instance.setItemHeight(100)
89 def buildListboxEntry(self, rss_entry):
91 res.append(MultiContentEntryText(pos=(0, 0), size=(460, 75), font=0, flags = RT_HALIGN_LEFT|RT_WRAP, text = rss_entry[0]))
92 res.append(MultiContentEntryText(pos=(0, 75), size=(460, 20), font=1, flags = RT_HALIGN_LEFT, text = rss_entry[1]))
96 def getCurrentEntry(self):
97 return self.l.getCurrentSelection()
99 class RSSDisplay(Screen):
101 <screen position="100,100" size="460,400" title="Simple RSS Reader" >
102 <widget name="content" position="0,0" size="460,400" />
105 def __init__(self, session, data, interactive = False):
106 Screen.__init__(self, session)
107 self.skin = RSSDisplay.skin
110 self["actions"] = ActionMap([ "OkCancelActions" ],
112 "ok": self.showCurrentEntry,
113 "cancel": self.close,
116 self["content"] = RSSList(data)
118 def showCurrentEntry(self):
119 current_entry = self["content"].getCurrentEntry()
120 if current_entry is None: # empty list
123 (title, link, enclosure) = current_entry[0]
126 (url, type) = enclosure[0] # TODO: currently, we used the first enclosure. there can be multiple.
128 print "enclosure: url=%s, type=%s" % (url, type)
130 if type in ["video/mpeg", "audio/mpeg"]:
131 from enigma import eServiceReference
132 # we should better launch a player or so...
133 self.session.nav.playService(eServiceReference(4097, 0, url))
137 MAX_HISTORY_ELEMENTS = 100
140 self.poll_timer = eTimer()
141 self.poll_timer.timeout.get().append(self.poll)
142 self.poll_timer.start(0, 1)
143 self.last_links = Set()
147 def error(self, error):
148 if not my_global_session:
149 print "error polling"
151 my_global_session.open(MessageBox, "Sorry, failed to fetch feed.\n" + error)
153 def _gotPage(self, data):
154 # workaround: exceptions in gotPage-callback were ignored
158 import traceback, sys
159 traceback.print_exc(file=sys.stdout)
162 def gotPage(self, data):
167 dom = xml.dom.minidom.parseString(data)
168 for r in elementsWithTag(dom.childNodes, "rss"):
174 for item in elementsWithTag(r.childNodes, "item"):
178 for channel in elementsWithTag(r.childNodes, "channel"):
179 for item in elementsWithTag(channel.childNodes, "item"):
189 for s in elementsWithTag(item.childNodes, lambda x: x in ["title", "link", "enclosure"]):
190 if s.tagName == "title":
191 title = mergeText(s.childNodes)
192 elif s.tagName == "link":
193 link = mergeText(s.childNodes)
194 elif s.tagName == "enclosure":
195 enclosure.append((s.getAttribute("url").encode("UTF-8"), s.getAttribute("type").encode("UTF-8")))
197 print title, link, enclosure
201 rss_entry = (title.encode("UTF-8"), link.encode("UTF-8"), enclosure)
203 self.history.insert(0, rss_entry)
205 if link not in self.last_links:
206 self.last_links.add(link)
207 new_items.append(rss_entry)
208 print "NEW", rss_entry[0], rss_entry[1]
210 self.history = self.history[:self.MAX_HISTORY_ELEMENTS]
213 self.dialog = my_global_session.instantiateDialog(RSSDisplay, new_items)
215 self.poll_timer.start(5000, 1)
217 self.poll_timer.start(60000, 1)
224 self.poll_timer.start(60000, 1)
225 elif not my_global_session:
226 print "no session yet."
227 self.poll_timer.start(10000, 1)
229 print "yes, session ok. starting"
230 self.d = getPage(config.simpleRSS.hostname.value).addCallback(self._gotPage).addErrback(self.error)
233 self.poll_timer.timeout.get().remove(self.poll)
234 self.poll_timer = None
238 session.open(SimpleRSS)
243 def autostart(reason, **kwargs):
248 # ouch, this is a hack
249 if kwargs.has_key("session"):
250 global my_global_session
251 print "session now available"
252 my_global_session = kwargs["session"]
257 rssPoller = RSSPoller()
262 def showCurrent(session, **kwargs):
264 if rssPoller is None:
266 session.open(RSSDisplay, rssPoller.history, interactive = True)
268 def Plugins(**kwargs):
269 return [ PluginDescriptor(name="RSS Reader", description="A (really) simple RSS reader", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=main),
270 PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart),
271 PluginDescriptor(name="View RSS", description="Let's you view current RSS entries", where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=showCurrent) ]