plugin.py split up,\nfeed overview and single feed view in different screens,\nyellow...
[enigma2-plugins.git] / simplerss / src / SimpleRSSScreens.py
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
8 from RSSList import RSSList
9 from SimpleRSSSetup import SimpleRSSSetup
10
11 class SimpleRSSBase(Screen):
12         def __init__(self, session):
13                 Screen.__init__(self, session)
14
15         def selectEnclosure(self, enclosures):
16                 if enclosures is None: # empty list
17                         return
18
19                 # Select stream in ChoiceBox if more than one present
20                 if len(enclosures) > 1:
21                         # TODO: beautify
22                         self.session.openWithCallback(self.enclosureSelected, ChoiceBox, "Select enclosure to play", [(x[0][x[0].rfind("/")+1:], x) for x in enclosures])
23                 # Play if one present
24                 elif len(enclosures):
25                         self.enclosureSelected((None, enclosures[0]))
26                 # Nothing if none present
27
28         def enclosureSelected(self, enclosure):
29                 if enclosure:
30                         (url, type) = enclosure[1]
31
32                         print "[SimpleRSS] Trying to play back enclosure: url=%s, type=%s" % (url, type)
33
34                         # TODO: other types? (showing images wouldn't be hard if the source was local)
35                         if type in ["video/mpeg", "audio/mpeg"]:
36                                 # We should launch a Player here, but the MediaPlayer gets angry about our non-local sources
37                                 from enigma import eServiceReference
38                                 self.session.nav.playService(eServiceReference(4097, 0, url))
39
40 class SimpleRSSEntry(SimpleRSSBase):
41         skin = """
42                 <screen position="100,100" size="460,400" title="Simple RSS Reader" >
43                         <widget name="content" position="0,0" size="460,400" font="Regular; 22" />
44                 </screen>"""
45
46         def __init__(self, session, data, feedTitle="", nextEntryCB=None, previousEntryCB=None, nextFeedCB=None, previousFeedCB=None):
47                 SimpleRSSBase.__init__(self, session)
48
49                 self.data = data
50                 self.feedTitle = feedTitle
51                 self.nextEntryCB = nextEntryCB
52                 self.previousEntryCB = previousEntryCB
53                 self.nextFeedCB = nextFeedCB
54                 self.previousFeedCB = previousFeedCB
55
56                 if data is not None:
57                         self["content"] = ScrollLabel("\n\n".join([data[0], data[2], " ".join([str(len(data[3])), "Enclosures"])]))
58                 else:
59                         self["content"] = ScrollLabel()
60
61                 self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "ColorActions", "DirectionActions" ],
62                 {
63                         "cancel": self.close,
64                         "ok": self.selectEnclosure,
65                         "yellow": self.selectEnclosure,
66                         "up": self.up,
67                         "down": self.down,
68                         "right": self.next,
69                         "left": self.previous,
70                         "nextBouquet": self.nextFeed,
71                         "prevBouquet": self.previousFeed,
72                 })
73
74                 self.onLayoutFinish.append(self.setConditionalTitle)
75
76         def setConditionalTitle(self):
77                 self.setTitle(': '.join(["Simple RSS Reader", self.feedTitle]))
78
79         def up(self):
80                 self["content"].pageUp()
81
82         def down(self):
83                 self["content"].pageDown()
84
85         def next(self):
86                 if self.nextEntryCB is not None:
87                         self.data = self.nextEntryCB()
88                         self.setContent()
89
90         def previous(self):
91                 if self.previousEntryCB is not None:
92                         self.data = self.previousEntryCB()
93                         self.setContent()
94
95         def nextFeed(self):
96                 # Show next Feed
97                 if self.nextFeedCB is not None:
98                         result = self.nextFeedCB()
99                         self.feedTitle = result[0]
100                         if len(result[1]):
101                                 self.data = result[1][0]
102                         else:
103                                 self.data = None
104                         self.setConditionalTitle()
105                         self.setContent()
106
107         def previousFeed(self):
108                 # Show previous Feed
109                 if self.previousFeedCB is not None:
110                         result = self.previousFeedCB()
111                         self.feedTitle = result[0]
112                         if len(result[1]):
113                                 self.data = result[1][0]
114                         else:
115                                 self.data = None
116                         self.setConditionalTitle()
117                         self.setContent()
118
119         def setContent(self):
120                 if self.data is not None:
121                         self["content"].setText("\n\n".join([self.data[0], self.data[2], " ".join([str(len(self.data[3])), "Enclosures"])]))
122                 else:
123                         self["content"].setText("No such Item.")
124
125         def selectEnclosure(self):
126                 if self.data is not None:
127                         SimpleRSSBase.selectEnclosure(self, self.data[3])
128
129 class SimpleRSSFeed(SimpleRSSBase):
130         skin = """
131                 <screen position="100,100" size="460,400" title="Simple RSS Reader" >
132                         <widget name="content" position="0,0" size="460,304" scrollbarMode="showOnDemand" />
133                         <widget name="summary" position="0,305" size="460,95" font="Regular;16" />
134                 </screen>"""
135
136         def __init__(self, session, data, feedTitle = "", newItems=False, nextFeedCB=None, previousFeedCB=None, rssPoller=None, id = None):
137                 SimpleRSSBase.__init__(self, session)
138
139                 self.data = data
140                 self.feedTitle = feedTitle
141                 self.newItems = newItems
142                 self.id = id
143                 self.nextFeedCB=nextFeedCB
144                 self.previousFeedCB=previousFeedCB
145                 self.rssPoller=rssPoller
146
147                 if len(data):
148                         self["content"] = RSSList(data)
149                         self["summary"] = Label(data[0][2])
150                 else:
151                         self["content"] = RSSList([])
152                         self["summary"] = Label("Feed is empty.")
153
154                 if not newItems:
155                         self["actions"] = ActionMap([ "OkCancelActions", "ChannelSelectBaseActions", "MenuActions", "ColorActions" ], 
156                         {
157                                 "ok": self.showCurrentEntry,
158                                 "cancel": self.close,
159                                 "nextBouquet": self.next,
160                                 "prevBouquet": self.previous,
161                                 "menu": self.menu,
162                                 "yellow": self.selectEnclosure,
163                         })
164                         self.onShown.append(self.__show)
165                         self.onClose.append(self.__close)
166                 
167                 self["content"].connectSelChanged(self.updateSummary)
168                 self.onLayoutFinish.append(self.setConditionalTitle)
169
170         def __show(self):
171                 self.rssPoller.addCallback(self.pollCallback)
172
173         def __close(self):
174                 self.rssPoller.removeCallback(self.pollCallback)
175
176         def pollCallback(self, id = None):
177                 print "[SimpleRSS] SimpleRSSFeed called back"
178                 current_entry = self["content"].getCurrentEntry()
179
180                 if id is not None and self.id == id:
181                         print "[SimpleRSS] pollCallback recieved local feed", self.id
182                         self.feedTitle = self.rssPoller.feeds[id].title
183                         self.data = self.rssPoller.feeds[id].history
184                 else:
185                         print "[SimpleRSS] pollCallback recieved all feeds, updating", self.id
186                         self.feedTitle = self.rssPoller.feeds[id].title
187                         self.data = self.rssPoller.feeds[id].history
188
189                 self["content"].l.setList(self.data)
190                 self["content"].moveToEntry(current_entry)
191
192                 self.setConditionalTitle()
193                 self.updateSummary()
194
195         def setConditionalTitle(self):
196                 if not self.newItems:
197                         self.setTitle(': '.join(["Simple RSS Reader", self.feedTitle]))
198                 else:
199                         self.setTitle("Simple RSS Reader: New Items")
200
201         def updateSummary(self):
202                 current_entry = self["content"].getCurrentEntry()
203                 if current_entry:
204                         self["summary"].setText(current_entry[2])
205                 else:
206                         self["summary"].setText("Feed is empty.")
207
208         def errorPolling(self):
209                 self.session.open(MessageBox, "Error while parsing Feed, this usually means there is something wrong with it.", type = MessageBox.TYPE_ERROR, timeout = 5)
210
211         def menu(self):
212                 self.rssPoller.singlePoll(self.id, callback=True, errorback=self.errorPolling)
213                 self.session.open(MessageBox, "Update is being done in Background.\nContents will automatically be updated when it's done.", type = MessageBox.TYPE_INFO, timeout = 5)
214
215         def nextEntryCB(self):
216                 self["content"].moveDown()
217                 return self["content"].getCurrentEntry()
218
219         def previousEntryCB(self):
220                 self["content"].moveUp()
221                 return self["content"].getCurrentEntry()
222
223         def next(self):
224                 # Show next Feed
225                 if self.nextFeedCB is not None:
226                         result = self.nextFeedCB()
227                         (self.feedTitle, self.data, self.id) = result
228                         current_entry = self["content"].getCurrentEntry()
229                         self["content"].l.setList(self.data) # Update list
230                         self["content"].moveToEntry(current_entry)
231                         self.updateSummary() # In case entry is no longer in history
232                         self.setConditionalTitle() # Update title
233                         return result
234                 return (self.feedTitle, self.data, self.id)
235
236         def previous(self):
237                 # Show previous Feed
238                 if self.previousFeedCB is not None:
239                         result = self.previousFeedCB()
240                         (self.feedTitle, self.data, self.id) = result
241                         current_entry = self["content"].getCurrentEntry()
242                         self["content"].l.setList(self.data) # Update list
243                         self["content"].moveToEntry(current_entry)
244                         self.updateSummary() # In case entry is no longer in history
245                         self.setConditionalTitle() # Update title
246                         return result
247                 return (self.feedTitle, self.data, self.id)
248
249         def showCurrentEntry(self):
250                 current_entry = self["content"].getCurrentEntry()
251                 if current_entry is None: # empty list
252                         return
253
254                 self.session.openWithCallback(self.updateSummary, SimpleRSSEntry, current_entry, feedTitle=self.feedTitle, nextEntryCB=self.nextEntryCB, previousEntryCB=self.previousEntryCB, nextFeedCB=self.next, previousFeedCB=self.previous)
255
256         def selectEnclosure(self):
257                 current_entry = self["content"].getCurrentEntry()
258                 if current_entry is None: # empty list
259                         return
260
261                 SimpleRSSBase.selectEnclosure(self, current_entry[3])
262
263 class SimpleRSS(SimpleRSSBase):
264         skin = """
265                 <screen position="100,100" size="460,400" title="Simple RSS Reader" >
266                         <widget name="content" position="0,0" size="460,304" scrollbarMode="showOnDemand" />
267                         <widget name="summary" position="0,305" size="460,95" font="Regular;16" />
268                 </screen>"""
269
270         def __init__(self, session, poller):
271                 SimpleRSSBase.__init__(self, session)
272
273                 self.rssPoller = poller
274                 
275                 self["actions"] = ActionMap([ "OkCancelActions", "MenuActions", "ColorActions" ], 
276                 {
277                         "ok": self.showCurrentEntry,
278                         "cancel": self.close,
279                         "menu": self.menu,
280                         "yellow": self.selectEnclosure,
281                 })
282
283                 self.feeds = ([(feed.title, feed.description, ' '.join([str(len(feed.history)), "Entries"]), feed.history) for feed in self.rssPoller.feeds])
284                 if len(self.feeds):
285                         self["content"] = RSSList(self.feeds)
286                         self["summary"] = Label(self.feeds[0][2])
287                 else:
288                         self["content"] = RSSList(self.feeds)
289                         self["summary"] = Label("")
290
291                 self["content"].connectSelChanged(self.updateSummary)
292                 self.onShown.append(self.__show)
293                 self.onClose.append(self.__close)
294
295         def __show(self):
296                 self.rssPoller.addCallback(self.pollCallback)
297
298         def __close(self):
299                 self.rssPoller.removeCallback(self.pollCallback)
300
301         def pollCallback(self, id = None):
302                 print "[SimpleRSS] SimpleRSS called back"
303                 current_entry = self["content"].getCurrentEntry()
304
305                 if id is not None:
306                         print "[SimpleRSS] pollCallback updating feed", id
307                         self.feeds[id] = (self.rssPoller.feeds[id].title, self.rssPoller.feeds[id].description, ' '.join([str(len(self.rssPoller.feeds[id].history)), "Entries"]), self.rssPoller.feeds[id].history)
308                 else:
309                         print "[SimpleRSS] pollCallback updating all feeds"
310                         self.feeds = ([(feed.title, feed.description, ' '.join([str(len(feed.history)), "Entries"]), feed.history) for feed in self.rssPoller.feeds])
311
312                 self["content"].l.setList(self.feeds)
313                 self["content"].moveToEntry(current_entry)
314
315                 self.updateSummary()
316
317         def updateSummary(self):
318                 current_entry = self["content"].getCurrentEntry()
319                 if current_entry:
320                         self["summary"].setText(current_entry[2])
321                 else:
322                         self["summary"].setText("")
323
324         def errorPolling(self):
325                 self.session.open(MessageBox, "Error while parsing Feed, this usually means there is something wrong with it.", type = MessageBox.TYPE_ERROR, timeout = 5)
326
327         def menu(self):
328                 self.session.openWithCallback(self.menuChoice, ChoiceBox, "What to do?", [(_("Update Feed"), "update"), (_("Setup"), "setup"), (_("Close"), "close")])
329
330         def menuChoice(self, result):
331                 if result:
332                         if result[1] == "update":
333                                 self.rssPoller.singlePoll(self["content"].getCurrentIndex(), callback=True, errorback=self.errorPolling)
334                                 self.session.open(MessageBox, "Update is being done in Background.\nContents will automatically be updated when it's done.", type = MessageBox.TYPE_INFO, timeout = 5)
335                         elif result[1] == "setup":
336                                 self.session.openWithCallback(self.menuClosed, SimpleRSSSetup, rssPoller=self.rssPoller)
337                         elif result[1] == "close":
338                                 self.close()
339
340         def menuClosed(self):
341                 current_entry = self["content"].getCurrentEntry()
342
343                 self.rssPoller.triggerReload()
344
345                 self.feeds = ([(feed.title, feed.description, ' '.join([str(len(feed.history)), " Entries"]), feed.history) for feed in self.rssPoller.feeds])
346                 self["content"].l.setList(self.feeds)
347
348                 self["content"].moveToEntry(current_entry)
349         
350         # Same as menuClosed but without triggering a reload
351         def refresh(self):
352                 current_entry = self["content"].getCurrentEntry()
353
354                 self.feeds = ([(feed.title, feed.description, ' '.join([str(len(feed.history)), " Entries"]), feed.history) for feed in self.rssPoller.feeds])
355                 self["content"].l.setList(self.feeds)
356
357                 self["content"].moveToEntry(current_entry)
358
359         def nextFeedCB(self):
360                 self["content"].moveUp()
361                 current_entry = self["content"].getCurrentEntry()
362                 return (current_entry[0], current_entry[3], self["content"].getCurrentIndex())
363
364         def previousFeedCB(self):
365                 self["content"].moveDown()
366                 current_entry = self["content"].getCurrentEntry()
367                 return (current_entry[0], current_entry[3], self["content"].getCurrentIndex())
368
369         def showCurrentEntry(self):
370                 current_entry = self["content"].getCurrentEntry()
371                 if current_entry is None: # empty list
372                         return
373
374                 self.session.openWithCallback(self.refresh, SimpleRSSFeed, current_entry[3], feedTitle=current_entry[0], nextFeedCB=self.nextFeedCB, previousFeedCB=self.previousFeedCB, rssPoller=self.rssPoller, id=self["content"].getCurrentIndex())
375
376         def selectEnclosure(self):
377                 current_entry = self["content"].getCurrentEntry()
378                 if current_entry is None: # empty list
379                         return
380
381                 # Build a list of all enclosures in this feed
382                 enclosures = []
383                 for entry in current_entry[3]:
384                                 enclosures.extend(entry[3])
385                 SimpleRSSBase.selectEnclosure(self, enclosures)