1 from Screens.Screen import Screen
2 from Screens.MessageBox import MessageBox
3 from Screens.ChoiceBox import ChoiceBox
4 from Components.ActionMap import ActionMap
5 from Components.Label import Label
6 from Components.ScrollLabel import ScrollLabel
7 from Components.Pixmap import Pixmap
9 from RSSList import RSSList
10 from RSSSetup import RSSSetup
12 class PictureView(Screen):
13 """Downloads a Picture, shows it and delete the temporary file"""
16 <screen position="100,100" size="460,400" title="Simple RSS Reader" >
17 <widget name="content" position="0,0" size="460,400" alphatest="on"/>
20 filename = '/tmp/simplerss_enclosure'
22 def __init__(self, session, url):
23 Screen.__init__(self, session)
27 self["actions"] = ActionMap([ "OkCancelActions" ],
33 self["content"] = Pixmap()
35 self.onLayoutFinish.append(self.fetchFile)
39 from httpclient import getFile
40 getFile(self.filename, self.url, callback=self.gotFile, errorback=self.error)
42 def gotFile(self, data = ""):
44 from Components.AVSwitch import AVSwitch
45 aspect = AVSwitch().getAspectRatioSetting()/2
48 from enigma import loadPic
49 ptr = loadPic(self.filename, 460, 400, aspect)
52 self["content"].instance.setPixmap(ptr)
54 # Remove Temporary File
61 "Error while loading Picture.",
62 type = MessageBox.TYPE_ERROR,
67 class RSSBaseView(Screen):
68 """Base Screen for all Screens used in SimpleRSS"""
70 def __init__(self, session):
71 Screen.__init__(self, session)
73 def errorPolling(self, errmsg = ""):
76 "Error while parsing Feed, this usually means there is something wrong with it.",
77 type = MessageBox.TYPE_ERROR,
81 def singleUpdate(self, feedid, errback = None):
82 # Default errorback to self.errorPolling
83 # If an empty errorback is wanted the Screen needs to provide it
85 errback = self.errorPolling
86 self.rssPoller.singlePoll(feedid, callback=True, errorback=errback)
89 "Update is being done in Background.\nContents will automatically be updated when it's done.",
90 type = MessageBox.TYPE_INFO,
94 def selectEnclosure(self, enclosures):
96 if enclosures is None:
99 count = len(enclosures)
100 # Select stream in ChoiceBox if more than one present
102 self.session.openWithCallback(
103 self.enclosureSelected,
105 "Select enclosure to play",
106 [(x[0][x[0].rfind("/")+1:].replace('%20', ' '), x) for x in enclosures]
108 # Play if one present
110 self.enclosureSelected((None, enclosures[0]))
112 def enclosureSelected(self, enclosure):
114 (url, type) = enclosure[1]
116 print "[SimpleRSS] Trying to play back enclosure: url=%s, type=%s" % (url, type)
118 if type in ["video/mpeg", "audio/mpeg"]:
119 # We should launch a Player here, but the MediaPlayer gets angry about our non-local sources
120 from enigma import eServiceReference
121 self.session.nav.playService(eServiceReference(4097, 0, url))
122 elif type in ["image/jpeg", "image/png", "image/gif", "image/bmp"]:
123 self.session.open(PictureView, url)
125 class RSSEntryView(RSSBaseView):
126 """Shows a RSS Item"""
128 <screen position="100,100" size="460,420" title="Simple RSS Reader" >
129 <widget name="info" position="0,0" size="460, 20" halign="right" font="Regular; 18" />
130 <widget name="content" position="0,20" size="460,420" font="Regular; 22" />
133 def __init__(self, session, data, feedTitle="", cur_idx=None, entries=None, nextEntryCB=None, previousEntryCB=None, nextFeedCB=None, previousFeedCB=None):
134 RSSBaseView.__init__(self, session)
137 self.feedTitle = feedTitle
138 self.nextEntryCB = nextEntryCB
139 self.previousEntryCB = previousEntryCB
140 self.nextFeedCB = nextFeedCB
141 self.previousFeedCB = previousFeedCB
142 self.cur_idx = cur_idx
143 self.entries = entries
145 if cur_idx is not None and entries is not None:
146 self["info"] = Label("Entry %s/%s" % (cur_idx+1, entries))
148 self["info"] = Label()
151 self["content"] = ScrollLabel("\n\n".join([data[0], data[2], " ".join([str(len(data[3])), "Enclosures"])]))
153 self["content"] = ScrollLabel()
155 self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "ColorActions", "DirectionActions" ],
157 "cancel": self.close,
158 "ok": self.selectEnclosure,
159 "yellow": self.selectEnclosure,
163 "left": self.previous,
164 "nextBouquet": self.nextFeed,
165 "prevBouquet": self.previousFeed,
168 self.onLayoutFinish.append(self.setConditionalTitle)
170 def setConditionalTitle(self):
171 self.setTitle(': '.join(["Simple RSS Reader", self.feedTitle]))
174 self["content"].pageUp()
177 self["content"].pageDown()
180 if self.nextEntryCB is not None:
181 (self.data, self.cur_idx, self.entries) = self.nextEntryCB()
185 if self.previousEntryCB is not None:
186 (self.data, self.cur_idx, self.entries) = self.previousEntryCB()
191 if self.nextFeedCB is not None:
192 result = self.nextFeedCB()
193 self.feedTitle = result[0]
194 self.entries = len(result[1])
197 self.data = result[1][0]
201 self.setConditionalTitle()
204 def previousFeed(self):
206 if self.previousFeedCB is not None:
207 result = self.previousFeedCB()
208 self.feedTitle = result[0]
209 self.entries = len(result[1])
212 self.data = result[1][0]
216 self.setConditionalTitle()
219 def setContent(self):
220 if self.cur_idx is not None and self.entries is not None:
221 self["info"].setText("Entry %s/%s" % (self.cur_idx+1, self.entries))
223 self["info"].setText("")
224 if self.data is not None:
225 self["content"].setText("\n\n".join([self.data[0], self.data[2], " ".join([str(len(self.data[3])), "Enclosures"])]))
227 self["content"].setText("No such Item.")
229 def selectEnclosure(self):
230 if self.data is not None:
231 RSSBaseView.selectEnclosure(self, self.data[3])
233 class RSSFeedView(RSSBaseView):
234 """Shows a RSS-Feed"""
236 <screen position="100,100" size="460,420" title="Simple RSS Reader" >
237 <widget name="info" position="0,0" size="460,20" halign="right" font="Regular; 18" />
238 <widget name="content" position="0,20" size="460,324" scrollbarMode="showOnDemand" />
239 <widget name="summary" position="0,325" size="460,95" font="Regular;16" />
242 def __init__(self, session, data, feedTitle = "", newItems=False, nextFeedCB=None, previousFeedCB=None, rssPoller=None, id = None):
243 RSSBaseView.__init__(self, session)
246 self.feedTitle = feedTitle
247 self.newItems = newItems
249 self.nextFeedCB=nextFeedCB
250 self.previousFeedCB=previousFeedCB
251 self.rssPoller=rssPoller
253 self["content"] = RSSList(data)
254 self["summary"] = Label()
255 self["info"] = Label()
258 self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "MenuActions", "ColorActions" ],
260 "ok": self.showCurrentEntry,
261 "cancel": self.close,
262 "nextBouquet": self.next,
263 "prevBouquet": self.previous,
265 "yellow": self.selectEnclosure,
267 self.onShown.append(self.__show)
268 self.onClose.append(self.__close)
270 self["content"].connectSelChanged(self.updateInfo)
271 self.onLayoutFinish.extend([self.updateInfo, self.setConditionalTitle])
274 self.rssPoller.addCallback(self.pollCallback)
277 self.rssPoller.removeCallback(self.pollCallback)
279 def pollCallback(self, id = None):
280 print "[SimpleRSS] SimpleRSSFeed called back"
281 current_entry = self["content"].getCurrentEntry()
283 if id is not None and self.id == id+1:
284 print "[SimpleRSS] pollCallback recieved local feed", self.id
285 self.feedTitle = self.rssPoller.feeds[id].title
286 self.data = self.rssPoller.feeds[id].history
288 print "[SimpleRSS] pollCallback recieved all or non-local feed, updating active view (new_items)"
289 self.data = self.rssPoller.new_items
291 print "[SimpleRSS] pollCallback recieved all or non-local feed, updating", self.id
292 self.feedTitle = self.rssPoller.feeds[self.id-1].title
293 self.data = self.rssPoller.feeds[self-id-1].history
295 self["content"].l.setList(self.data)
296 self["content"].moveToEntry(current_entry)
298 self.setConditionalTitle()
301 def setConditionalTitle(self):
302 if not self.newItems:
303 self.setTitle(': '.join(["Simple RSS Reader", self.feedTitle]))
305 self.setTitle("Simple RSS Reader: New Items")
307 def updateInfo(self):
308 current_entry = self["content"].getCurrentEntry()
310 self["summary"].setText(current_entry[2])
312 cur_idx = self["content"].getCurrentIndex()
313 self["info"].setText("Entry %s/%s" % (cur_idx+1, len(self.data)))
315 self["summary"].setText("Feed is empty.")
316 self["info"].setText("")
320 self.singleUpdate(self.id-1)
322 def nextEntryCB(self):
323 self["content"].moveDown()
324 return (self["content"].getCurrentEntry(), self["content"].getCurrentIndex(), len(self.data))
326 def previousEntryCB(self):
327 self["content"].moveUp()
328 return (self["content"].getCurrentEntry(), self["content"].getCurrentIndex(), len(self.data))
330 # TODO: Fix moving back to previously marked entry (same goes for self.previous)
333 if self.nextFeedCB is not None:
334 result = self.nextFeedCB()
335 (self.feedTitle, self.data, self.id) = result
336 #current_entry = self["content"].getCurrentEntry()
337 self["content"].l.setList(self.data) # Update list
338 self["content"].moveToIndex(0)
339 #self["content"].moveToEntry(current_entry)
340 self.updateInfo() # In case entry is no longer in history
341 self.setConditionalTitle() # Update title
343 return (self.feedTitle, self.data, self.id)
347 if self.previousFeedCB is not None:
348 result = self.previousFeedCB()
349 (self.feedTitle, self.data, self.id) = result
350 #current_entry = self["content"].getCurrentEntry()
351 self["content"].l.setList(self.data) # Update list
352 self["content"].moveToIndex(0)
353 #self["content"].moveToEntry(current_entry)
354 self.updateInfo() # In case entry is no longer in history
355 self.setConditionalTitle() # Update title
357 return (self.feedTitle, self.data, self.id)
359 def showCurrentEntry(self):
360 current_entry = self["content"].getCurrentEntry()
361 if current_entry is None: # empty list
364 self.session.openWithCallback(
368 cur_idx=self["content"].getCurrentIndex(),
369 entries=len(self.data),
370 feedTitle=self.feedTitle,
371 nextEntryCB=self.nextEntryCB,
372 previousEntryCB=self.previousEntryCB,
373 nextFeedCB=self.next,
374 previousFeedCB=self.previous
377 def selectEnclosure(self):
378 current_entry = self["content"].getCurrentEntry()
379 if current_entry is None: # empty list
382 RSSBaseView.selectEnclosure(self, current_entry[3])
384 class RSSOverview(RSSBaseView):
385 """Shows an Overview over all RSS-Feeds known to rssPoller"""
387 <screen position="100,100" size="460,420" title="Simple RSS Reader" >
388 <widget name="info" position="0,0" size="460,20" halign="right" font="Regular; 18" />
389 <widget name="content" position="0,20" size="460,304" scrollbarMode="showOnDemand" />
390 <widget name="summary" position="0,325" size="460,95" font="Regular;16" />
393 def __init__(self, session, poller):
394 RSSBaseView.__init__(self, session)
396 self.rssPoller = poller
398 self["actions"] = ActionMap([ "OkCancelActions", "MenuActions", "ColorActions" ],
400 "ok": self.showCurrentEntry,
401 "cancel": self.close,
403 "yellow": self.selectEnclosure,
408 # We always have at least "New Items"-Feed
409 self["content"] = RSSList(self.feeds)
410 self["summary"] = Label(self.feeds[0][2])
411 self["info"] = Label("Feed 1/%s" % len(self.feeds))
413 self["content"].connectSelChanged(self.updateInfo)
414 self.onShown.append(self.__show)
415 self.onClose.append(self.__close)
418 self.rssPoller.addCallback(self.pollCallback)
421 self.rssPoller.removeCallback(self.pollCallback)
426 "New Items since last Auto-Update",
427 ' '.join([str(len(self.rssPoller.new_items)), "Entries"]),
428 self.rssPoller.new_items
434 ' '.join([str(len(feed.history)), "Entries"]),
437 for feed in self.rssPoller.feeds
440 def pollCallback(self, id = None):
441 print "[SimpleRSS] SimpleRSS called back"
442 current_entry = self["content"].getCurrentEntry()
445 print "[SimpleRSS] pollCallback updating feed", id
447 self.rssPoller.feeds[id].title,
448 self.rssPoller.feeds[id].description,
449 ' '.join([str(len(self.rssPoller.feeds[id].history)), "Entries"]),
450 self.rssPoller.feeds[id].history
453 print "[SimpleRSS] pollCallback updating all feeds"
456 self["content"].l.setList(self.feeds)
457 self["content"].moveToEntry(current_entry)
461 def updateInfo(self):
462 current_entry = self["content"].getCurrentEntry()
464 self["summary"].setText(current_entry[2])
465 self["info"].setText("Feed %s/%s" % (self["content"].getCurrentIndex()+1, len(self.feeds)))
466 # Should never happen
468 self["summary"].setText("")
469 self["info"].setText("")
472 cur_idx = self["content"].getCurrentIndex()
475 (_("Update Feed"), "update"),
476 (_("Setup"), "setup"),
477 (_("Close"), "close")
481 (_("Setup"), "setup"),
482 (_("Close"), "close")
484 self.session.openWithCallback(
491 def menuChoice(self, result):
493 if result[1] == "update":
494 cur_idx = self["content"].getCurrentIndex()
496 self.singleUpdate(cur_idx-1)
497 elif result[1] == "setup":
498 self.session.openWithCallback(self.refresh, RSSSetup, rssPoller=self.rssPoller)
499 elif result[1] == "close":
503 current_entry = self["content"].getCurrentEntry()
506 self["content"].l.setList(self.feeds)
508 self["content"].moveToEntry(current_entry)
511 def nextFeedCB(self):
512 self["content"].moveUp()
513 current_entry = self["content"].getCurrentEntry()
514 return (current_entry[0], current_entry[3], self["content"].getCurrentIndex())
516 def previousFeedCB(self):
517 self["content"].moveDown()
518 current_entry = self["content"].getCurrentEntry()
519 return (current_entry[0], current_entry[3], self["content"].getCurrentIndex())
521 def showCurrentEntry(self):
522 current_entry = self["content"].getCurrentEntry()
523 if current_entry is None: # empty list
526 self.session.openWithCallback(
530 feedTitle=current_entry[0],
531 nextFeedCB=self.nextFeedCB,
532 previousFeedCB=self.previousFeedCB,
533 rssPoller=self.rssPoller,
534 id=self["content"].getCurrentIndex()
537 def selectEnclosure(self):
538 current_entry = self["content"].getCurrentEntry()
539 if current_entry is None: # empty list
542 # Build a list of all enclosures in this feed
544 for entry in current_entry[3]:
545 enclosures.extend(entry[3])
546 RSSBaseView.selectEnclosure(self, enclosures)