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"]
23 urls = ["http://mastermaq.podcastspot.com/episodes/rss/mpg1"]
25 from Components.config import config, ConfigSubsection, ConfigSelection, getConfigListEntry
26 from Components.ConfigList import ConfigListScreen
27 config.simpleRSS = ConfigSubsection()
28 config.simpleRSS.hostname = ConfigSelection(choices = urls)
30 class SimpleRSS(ConfigListScreen, Screen):
32 <screen position="100,100" size="550,400" title="Simple RSS Reader" >
33 <widget name="config" position="20,10" size="460,350" scrollbarMode="showOnDemand" />
36 def __init__(self, session, args = None):
38 Screen.__init__(self, session)
39 self.skin = SimpleRSS.skin
41 self.onClose.append(self.abort)
43 # nun erzeugen wir eine liste von elementen fuer die menu liste.
45 self.list.append(getConfigListEntry(_("RSS Feed URI"), config.simpleRSS.hostname))
48 ConfigListScreen.__init__(self, self.list)
50 self["actions"] = ActionMap([ "OkCancelActions" ],
53 # "cancel": self.close,
56 self["setupActions"] = ActionMap(["SetupActions"],
66 for x in self["config"].list:
71 for x in self["config"].list:
75 class RSSList(GUIComponent):
76 def __init__(self, entries):
77 GUIComponent.__init__(self)
78 self.l = eListboxPythonMultiContent()
79 self.l.setFont(0, gFont("Regular", 22))
80 self.l.setFont(1, gFont("Regular", 18))
81 self.list = [self.buildListboxEntry(x) for x in entries]
82 self.l.setList(self.list)
86 def postWidgetCreate(self, instance):
87 instance.setContent(self.l)
88 instance.setItemHeight(100)
90 def buildListboxEntry(self, rss_entry):
92 res.append(MultiContentEntryText(pos=(0, 0), size=(460, 75), font=0, flags = RT_HALIGN_LEFT|RT_WRAP, text = rss_entry[0]))
93 res.append(MultiContentEntryText(pos=(0, 75), size=(460, 20), font=1, flags = RT_HALIGN_LEFT, text = rss_entry[1]))
97 def getCurrentEntry(self):
98 return self.l.getCurrentSelection()
100 class RSSDisplay(Screen):
102 <screen position="100,100" size="460,400" title="Simple RSS Reader" >
103 <widget name="content" position="0,0" size="460,400" />
106 def __init__(self, session, data, interactive = False):
107 Screen.__init__(self, session)
108 self.skin = RSSDisplay.skin
111 self["actions"] = ActionMap([ "OkCancelActions" ],
113 "ok": self.showCurrentEntry,
114 "cancel": self.close,
117 self["content"] = RSSList(data)
119 def showCurrentEntry(self):
120 current_entry = self["content"].getCurrentEntry()
121 if current_entry is None: # empty list
124 (title, link, enclosure) = current_entry[0]
127 (url, type) = enclosure[0] # TODO: currently, we used the first enclosure. there can be multiple.
129 print "enclosure: url=%s, type=%s" % (url, type)
131 if type in ["video/mpeg", "audio/mpeg"]:
132 from enigma import eServiceReference
133 # we should better launch a player or so...
134 self.session.nav.playService(eServiceReference(4097, 0, url))
138 MAX_HISTORY_ELEMENTS = 100
141 self.poll_timer = eTimer()
142 self.poll_timer.callback.append(self.poll)
143 self.poll_timer.start(0, 1)
144 self.last_links = Set()
148 def error(self, error):
149 if not my_global_session:
150 print "error polling"
152 my_global_session.open(MessageBox, "Sorry, failed to fetch feed.\n" + error)
154 def _gotPage(self, data):
155 # workaround: exceptions in gotPage-callback were ignored
159 import traceback, sys
160 traceback.print_exc(file=sys.stdout)
163 def gotPage(self, data):
168 dom = xml.dom.minidom.parseString(data)
169 for r in elementsWithTag(dom.childNodes, "rss"):
175 for item in elementsWithTag(r.childNodes, "item"):
179 for channel in elementsWithTag(r.childNodes, "channel"):
180 for item in elementsWithTag(channel.childNodes, "item"):
190 for s in elementsWithTag(item.childNodes, lambda x: x in ["title", "link", "enclosure"]):
191 if s.tagName == "title":
192 title = mergeText(s.childNodes)
193 elif s.tagName == "link":
194 link = mergeText(s.childNodes)
195 elif s.tagName == "enclosure":
196 enclosure.append((s.getAttribute("url").encode("UTF-8"), s.getAttribute("type").encode("UTF-8")))
198 print title, link, enclosure
202 rss_entry = (title.encode("UTF-8"), link.encode("UTF-8"), enclosure)
204 self.history.insert(0, rss_entry)
206 if link not in self.last_links:
207 self.last_links.add(link)
208 new_items.append(rss_entry)
209 print "NEW", rss_entry[0], rss_entry[1]
211 self.history = self.history[:self.MAX_HISTORY_ELEMENTS]
214 self.dialog = my_global_session.instantiateDialog(RSSDisplay, new_items)
216 self.poll_timer.start(5000, 1)
218 self.poll_timer.start(60000, 1)
225 self.poll_timer.start(60000, 1)
226 elif not my_global_session:
227 print "no session yet."
228 self.poll_timer.start(10000, 1)
230 print "yes, session ok. starting"
231 self.d = getPage(config.simpleRSS.hostname.value).addCallback(self._gotPage).addErrback(self.error)
234 self.poll_timer.callback.remove(self.poll)
235 self.poll_timer = None
237 def main(session, **kwargs):
239 session.open(SimpleRSS)
244 def autostart(reason, **kwargs):
249 # ouch, this is a hack
250 if kwargs.has_key("session"):
251 global my_global_session
252 print "session now available"
253 my_global_session = kwargs["session"]
258 rssPoller = RSSPoller()
263 def showCurrent(session, **kwargs):
265 if rssPoller is None:
267 session.open(RSSDisplay, rssPoller.history, interactive = True)
269 def Plugins(**kwargs):
270 return [ PluginDescriptor(name="RSS Reader", description="A (really) simple RSS reader", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=main),
271 PluginDescriptor(where = [PluginDescriptor.WHERE_SESSIONSTART, PluginDescriptor.WHERE_AUTOSTART], fnc = autostart),
272 PluginDescriptor(name="View RSS", description="Lets you view current RSS entries", where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=showCurrent) ]