1 from enigma import eTimer
3 from Screens.Screen import Screen
4 from Screens.MessageBox import MessageBox
5 from Screens.ChoiceBox import ChoiceBox
6 from Components.ActionMap import ActionMap
7 from Components.Label import Label
8 from Components.ScrollLabel import ScrollLabel
9 from Components.Pixmap import Pixmap
11 from RSSList import RSSList
12 from RSSSetup import RSSSetup
14 class PictureView(Screen):
15 """Downloads a Picture, shows it and delete the temporary file"""
18 <screen position="100,100" size="460,400" title="Simple RSS Reader" >
19 <widget name="content" position="0,0" size="460,400" alphatest="on"/>
22 filename = '/tmp/simplerss_enclosure'
24 def __init__(self, session, url):
25 Screen.__init__(self, session)
29 self["actions"] = ActionMap([ "OkCancelActions" ],
35 self["content"] = Pixmap()
37 self.onLayoutFinish.append(self.fetchFile)
41 from httpclient import getFile
42 getFile(self.filename, self.url, callback=self.gotFile, errorback=self.error)
44 def gotFile(self, data = ""):
46 from Components.AVSwitch import AVSwitch
47 aspect = AVSwitch().getAspectRatioSetting()/2
50 from enigma import loadPic
51 ptr = loadPic(self.filename, 460, 400, aspect)
54 self["content"].instance.setPixmap(ptr)
56 # Remove Temporary File
63 "Error while loading Picture.",
64 type = MessageBox.TYPE_ERROR,
69 class RSSBaseView(Screen):
70 """Base Screen for all Screens used in SimpleRSS"""
72 def __init__(self, session):
73 Screen.__init__(self, session)
75 def errorPolling(self, errmsg = ""):
78 "Error while parsing Feed, this usually means there is something wrong with it.",
79 type = MessageBox.TYPE_ERROR,
83 def singleUpdate(self, feedid, errback = None):
84 # Default errorback to self.errorPolling
85 # If an empty errorback is wanted the Screen needs to provide it
87 errback = self.errorPolling
88 self.rssPoller.singlePoll(feedid, callback=True, errorback=errback)
91 "Update is being done in Background.\nContents will automatically be updated when it's done.",
92 type = MessageBox.TYPE_INFO,
96 def selectEnclosure(self, enclosures):
98 if enclosures is None:
101 count = len(enclosures)
102 # Select stream in ChoiceBox if more than one present
104 self.session.openWithCallback(
105 self.enclosureSelected,
107 "Select enclosure to play",
108 [(x[0][x[0].rfind("/")+1:].replace('%20', ' ').replace('%5F', '_').replace('%2D', '-'), x) for x in enclosures]
110 # Play if one present
112 self.enclosureSelected((None, enclosures[0]))
114 def enclosureSelected(self, enclosure):
116 (url, type) = enclosure[1]
118 print "[SimpleRSS] Trying to play back enclosure: url=%s, type=%s" % (url, type)
120 if type in ["video/mpeg", "audio/mpeg"]:
121 from enigma import eServiceReference
122 from Screens.MediaPlayer import MediaPlayer
124 mp = self.session.open(MediaPlayer)
125 ref = eServiceReference(4097, 0, url)
127 mp.switchToPlayList()
128 mp.playlist.addFile(ref)
129 mp.playlist.updateList()
131 mp.playServiceRefEntry(ref)
132 elif type in ["image/jpeg", "image/png", "image/gif", "image/bmp"]:
133 self.session.open(PictureView, url)
135 class RSSEntryView(RSSBaseView):
136 """Shows a RSS Item"""
138 <screen position="100,100" size="460,420" title="Simple RSS Reader" >
139 <widget name="info" position="0,0" size="460, 20" halign="right" font="Regular; 18" />
140 <widget name="content" position="0,20" size="460,420" font="Regular; 22" />
143 def __init__(self, session, data, feedTitle="", cur_idx=None, entries=None, nextEntryCB=None, previousEntryCB=None, nextFeedCB=None, previousFeedCB=None):
144 RSSBaseView.__init__(self, session)
147 self.feedTitle = feedTitle
148 self.nextEntryCB = nextEntryCB
149 self.previousEntryCB = previousEntryCB
150 self.nextFeedCB = nextFeedCB
151 self.previousFeedCB = previousFeedCB
152 self.cur_idx = cur_idx
153 self.entries = entries
155 if cur_idx is not None and entries is not None:
156 self["info"] = Label("Entry %s/%s" % (cur_idx+1, entries))
158 self["info"] = Label()
161 self["content"] = ScrollLabel("\n\n".join([data[0], data[2], " ".join([str(len(data[3])), "Enclosures"])]))
163 self["content"] = ScrollLabel()
165 self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "ColorActions", "DirectionActions" ],
167 "cancel": self.close,
168 "ok": self.selectEnclosure,
169 "yellow": self.selectEnclosure,
173 "left": self.previous,
174 "nextBouquet": self.nextFeed,
175 "prevBouquet": self.previousFeed,
178 self.onLayoutFinish.append(self.setConditionalTitle)
180 def setConditionalTitle(self):
181 self.setTitle(': '.join(["Simple RSS Reader", self.feedTitle]))
184 self["content"].pageUp()
187 self["content"].pageDown()
190 if self.nextEntryCB is not None:
191 (self.data, self.cur_idx, self.entries) = self.nextEntryCB()
195 if self.previousEntryCB is not None:
196 (self.data, self.cur_idx, self.entries) = self.previousEntryCB()
201 if self.nextFeedCB is not None:
202 result = self.nextFeedCB()
203 self.feedTitle = result[0]
204 self.entries = len(result[1])
207 self.data = result[1][0]
211 self.setConditionalTitle()
214 def previousFeed(self):
216 if self.previousFeedCB is not None:
217 result = self.previousFeedCB()
218 self.feedTitle = result[0]
219 self.entries = len(result[1])
222 self.data = result[1][0]
226 self.setConditionalTitle()
229 def setContent(self):
230 if self.cur_idx is not None and self.entries is not None:
231 self["info"].setText("Entry %s/%s" % (self.cur_idx+1, self.entries))
233 self["info"].setText("")
234 if self.data is not None:
235 self["content"].setText("\n\n".join([self.data[0], self.data[2], " ".join([str(len(self.data[3])), "Enclosures"])]))
237 self["content"].setText("No such Item.")
239 def selectEnclosure(self):
240 if self.data is not None:
241 RSSBaseView.selectEnclosure(self, self.data[3])
243 class RSSFeedView(RSSBaseView):
244 """Shows a RSS-Feed"""
246 <screen position="100,100" size="460,420" title="Simple RSS Reader" >
247 <widget name="info" position="0,0" size="460,20" halign="right" font="Regular; 18" />
248 <widget name="content" position="0,20" size="460,324" scrollbarMode="showOnDemand" />
249 <widget name="summary" position="0,325" size="460,95" font="Regular;16" />
252 def __init__(self, session, data, feedTitle = "", newItems=False, nextFeedCB=None, previousFeedCB=None, rssPoller=None, id = None):
253 RSSBaseView.__init__(self, session)
256 self.feedTitle = feedTitle
257 self.newItems = newItems
259 self.nextFeedCB=nextFeedCB
260 self.previousFeedCB=previousFeedCB
261 self.rssPoller=rssPoller
263 self["content"] = RSSList(data)
264 self["summary"] = Label()
265 self["info"] = Label()
268 self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "MenuActions", "ColorActions" ],
270 "ok": self.showCurrentEntry,
271 "cancel": self.close,
272 "nextBouquet": self.next,
273 "prevBouquet": self.previous,
275 "yellow": self.selectEnclosure,
277 self.onShown.append(self.__show)
278 self.onClose.append(self.__close)
280 self.timer = eTimer()
281 self.timer.timeout.get().append(self.timerTick)
282 self.onExecBegin.append(self.startTimer)
284 self["content"].connectSelChanged(self.updateInfo)
285 self.onLayoutFinish.extend([self.updateInfo, self.setConditionalTitle])
287 def startTimer(self):
288 self.timer.startLongTimer(5)
291 self.timer.timeout.get().remove(self.timerTick)
296 self.rssPoller.addCallback(self.pollCallback)
299 self.rssPoller.removeCallback(self.pollCallback)
301 def pollCallback(self, id = None):
302 print "[SimpleRSS] SimpleRSSFeed called back"
303 current_entry = self["content"].getCurrentEntry()
305 if id is not None and self.id == id+1:
306 print "[SimpleRSS] pollCallback recieved local feed", self.id
307 self.feedTitle = self.rssPoller.feeds[id].title
308 self.data = self.rssPoller.feeds[id].history
310 print "[SimpleRSS] pollCallback recieved all or non-local feed, updating active view (new_items)"
311 self.data = self.rssPoller.new_items
313 print "[SimpleRSS] pollCallback recieved all or non-local feed, updating", self.id
314 self.feedTitle = self.rssPoller.feeds[self.id-1].title
315 self.data = self.rssPoller.feeds[self-id-1].history
317 self["content"].l.setList(self.data)
318 self["content"].moveToEntry(current_entry)
320 self.setConditionalTitle()
323 def setConditionalTitle(self):
324 if not self.newItems:
325 self.setTitle(': '.join(["Simple RSS Reader", self.feedTitle]))
327 self.setTitle("Simple RSS Reader: New Items")
329 def updateInfo(self):
330 current_entry = self["content"].getCurrentEntry()
332 self["summary"].setText(current_entry[2])
334 cur_idx = self["content"].getCurrentIndex()
335 self["info"].setText("Entry %s/%s" % (cur_idx+1, len(self.data)))
337 self["summary"].setText("Feed is empty.")
338 self["info"].setText("")
342 self.singleUpdate(self.id-1)
344 def nextEntryCB(self):
345 self["content"].moveDown()
346 return (self["content"].getCurrentEntry(), self["content"].getCurrentIndex(), len(self.data))
348 def previousEntryCB(self):
349 self["content"].moveUp()
350 return (self["content"].getCurrentEntry(), self["content"].getCurrentIndex(), len(self.data))
352 # TODO: Fix moving back to previously marked entry (same goes for self.previous)
355 if self.nextFeedCB is not None:
356 result = self.nextFeedCB()
357 (self.feedTitle, self.data, self.id) = result
358 #current_entry = self["content"].getCurrentEntry()
359 self["content"].l.setList(self.data) # Update list
360 self["content"].moveToIndex(0)
361 #self["content"].moveToEntry(current_entry)
362 self.updateInfo() # In case entry is no longer in history
363 self.setConditionalTitle() # Update title
365 return (self.feedTitle, self.data, self.id)
369 if self.previousFeedCB is not None:
370 result = self.previousFeedCB()
371 (self.feedTitle, self.data, self.id) = result
372 #current_entry = self["content"].getCurrentEntry()
373 self["content"].l.setList(self.data) # Update list
374 self["content"].moveToIndex(0)
375 #self["content"].moveToEntry(current_entry)
376 self.updateInfo() # In case entry is no longer in history
377 self.setConditionalTitle() # Update title
379 return (self.feedTitle, self.data, self.id)
381 def checkEmpty(self):
382 if self.id > 0 and not len(self.data):
383 self.singleUpdate(self.id-1)
385 def showCurrentEntry(self):
386 current_entry = self["content"].getCurrentEntry()
387 if current_entry is None: # empty list
390 self.session.openWithCallback(
394 cur_idx=self["content"].getCurrentIndex(),
395 entries=len(self.data),
396 feedTitle=self.feedTitle,
397 nextEntryCB=self.nextEntryCB,
398 previousEntryCB=self.previousEntryCB,
399 nextFeedCB=self.next,
400 previousFeedCB=self.previous
403 def selectEnclosure(self):
404 current_entry = self["content"].getCurrentEntry()
405 if current_entry is None: # empty list
408 RSSBaseView.selectEnclosure(self, current_entry[3])
410 class RSSOverview(RSSBaseView):
411 """Shows an Overview over all RSS-Feeds known to rssPoller"""
413 <screen position="100,100" size="460,420" title="Simple RSS Reader" >
414 <widget name="info" position="0,0" size="460,20" halign="right" font="Regular; 18" />
415 <widget name="content" position="0,20" size="460,304" scrollbarMode="showOnDemand" />
416 <widget name="summary" position="0,325" size="460,95" font="Regular;16" />
419 def __init__(self, session, poller):
420 RSSBaseView.__init__(self, session)
422 self.rssPoller = poller
424 self["actions"] = ActionMap([ "OkCancelActions", "MenuActions", "ColorActions" ],
426 "ok": self.showCurrentEntry,
427 "cancel": self.close,
429 "yellow": self.selectEnclosure,
434 # We always have at least "New Items"-Feed
435 self["content"] = RSSList(self.feeds)
436 self["summary"] = Label(self.feeds[0][2])
437 self["info"] = Label("Feed 1/%s" % len(self.feeds))
439 self["content"].connectSelChanged(self.updateInfo)
440 self.onShown.append(self.__show)
441 self.onClose.append(self.__close)
444 self.rssPoller.addCallback(self.pollCallback)
447 self.rssPoller.removeCallback(self.pollCallback)
452 "New Items since last Auto-Update",
453 ' '.join([str(len(self.rssPoller.new_items)), "Entries"]),
454 self.rssPoller.new_items
460 ' '.join([str(len(feed.history)), "Entries"]),
463 for feed in self.rssPoller.feeds
466 def pollCallback(self, id = None):
467 print "[SimpleRSS] SimpleRSS called back"
468 current_entry = self["content"].getCurrentEntry()
471 print "[SimpleRSS] pollCallback updating feed", id
473 self.rssPoller.feeds[id].title,
474 self.rssPoller.feeds[id].description,
475 ' '.join([str(len(self.rssPoller.feeds[id].history)), "Entries"]),
476 self.rssPoller.feeds[id].history
479 print "[SimpleRSS] pollCallback updating all feeds"
482 self["content"].l.setList(self.feeds)
483 self["content"].moveToEntry(current_entry)
487 def updateInfo(self):
488 current_entry = self["content"].getCurrentEntry()
490 self["summary"].setText(current_entry[2])
491 self["info"].setText("Feed %s/%s" % (self["content"].getCurrentIndex()+1, len(self.feeds)))
492 # Should never happen
494 self["summary"].setText("")
495 self["info"].setText("")
498 cur_idx = self["content"].getCurrentIndex()
501 (_("Update Feed"), "update"),
502 (_("Setup"), "setup"),
503 (_("Close"), "close")
507 (_("Setup"), "setup"),
508 (_("Close"), "close")
510 self.session.openWithCallback(
517 def menuChoice(self, result):
519 if result[1] == "update":
520 cur_idx = self["content"].getCurrentIndex()
522 self.singleUpdate(cur_idx-1)
523 elif result[1] == "setup":
524 self.session.openWithCallback(self.refresh, RSSSetup, rssPoller=self.rssPoller)
525 elif result[1] == "close":
529 current_entry = self["content"].getCurrentEntry()
532 self["content"].l.setList(self.feeds)
534 self["content"].moveToEntry(current_entry)
537 def nextFeedCB(self):
538 self["content"].moveUp()
539 current_entry = self["content"].getCurrentEntry()
540 return (current_entry[0], current_entry[3], self["content"].getCurrentIndex())
542 def previousFeedCB(self):
543 self["content"].moveDown()
544 current_entry = self["content"].getCurrentEntry()
545 return (current_entry[0], current_entry[3], self["content"].getCurrentIndex())
547 def showCurrentEntry(self):
548 current_entry = self["content"].getCurrentEntry()
549 if current_entry is None: # empty list
552 self.session.openWithCallback(
556 feedTitle=current_entry[0],
557 nextFeedCB=self.nextFeedCB,
558 previousFeedCB=self.previousFeedCB,
559 rssPoller=self.rssPoller,
560 id=self["content"].getCurrentIndex()
563 def selectEnclosure(self):
564 current_entry = self["content"].getCurrentEntry()
565 if current_entry is None: # empty list
568 # Build a list of all enclosures in this feed
570 for entry in current_entry[3]:
571 enclosures.extend(entry[3])
572 RSSBaseView.selectEnclosure(self, enclosures)