RSSPoller.py: some compatibility code for new e2
[enigma2-plugins.git] / simplerss / src / RSSPoller.py
1 from __future__ import print_function
2
3 # for localized messages
4 from . import _
5
6 from Components.config import config
7 from enigma import eTimer
8
9 from Tools.Notifications import AddPopup
10 from Screens.MessageBox import MessageBox
11
12 from RSSFeed import BaseFeed, UniversalFeed
13
14 from twisted.web.client import getPage
15 from xml.etree.cElementTree import fromstring as cElementTree_fromstring
16
17 from GoogleReader import GoogleReader
18
19 NOTIFICATIONID = 'SimpleRSSUpdateNotification'
20
21 update_callbacks = []
22
23 class RSSPoller:
24         """Keeps all Feed and takes care of (automatic) updates"""
25
26         def __init__(self, poll = True):
27                 # Timer
28                 self.poll_timer = eTimer()
29                 self.poll_timer.callback.append(self.poll)
30                 self.do_poll = poll
31
32                 # this indicates we're reloading the list of feeds
33                 self.reloading = False
34
35                 self.newItemFeed = BaseFeed(
36                         "",
37                         _("New Items"),
38                         _("New Items since last Auto-Update"),
39                 )
40
41                 # Generate Feeds
42                 self.feeds = [
43                         UniversalFeed(
44                                 x.uri.value,
45                                 x.autoupdate.value
46                         )
47                                 for x in config.plugins.simpleRSS.feed
48                 ]
49
50                 if not config.plugins.simpleRSS.enable_google_reader.value:
51                         if poll:
52                                 self.poll_timer.start(0, 1)
53                 else:
54                         self.googleReader = GoogleReader(config.plugins.simpleRSS.google_username.value, config.plugins.simpleRSS.google_password.value)
55                         self.googleReader.login().addCallback(self.googleLoggedIn).addErrback(self.googleLoginFailed)
56
57                 # Initialize Vars
58                 self.current_feed = 0
59
60         def googleLoggedIn(self, sid = None):
61                 self.googleReader.getSubscriptionList().addCallback(self.googleSubscriptionList).addErrback(self.googleSubscriptionFailed)
62
63         def googleLoginFailed(self, res = None):
64                 AddPopup(
65                         _("Failed to login to Google Reader."),
66                         MessageBox.TYPE_ERROR,
67                         5,
68                 )
69
70                 self.reloading = False
71                 if self.do_poll:
72                         self.poll_timer.start(0, 1)
73
74         def googleSubscriptionList(self, subscriptions = None):
75                 self.feeds.extend(subscriptions)
76
77                 self.reloading = False
78                 if self.do_poll:
79                         self.doCallback()
80                         self.poll_timer.start(0, 1)
81
82         def googleSubscriptionFailed(self, res = None):
83                 AddPopup(
84                         _("Failed to get subscriptions from Google Reader."),
85                         MessageBox.TYPE_ERROR,
86                         5,
87                 )
88
89                 self.reloading = False
90                 if self.do_poll:
91                         self.poll_timer.start(0, 1)
92
93         def addCallback(self, callback):
94                 if callback not in update_callbacks:
95                         update_callbacks.append(callback)
96
97         def removeCallback(self, callback):
98                 if callback in update_callbacks:
99                         update_callbacks.remove(callback)
100
101         def doCallback(self, id = None):
102                 for callback in update_callbacks:
103                         try:
104                                 callback(id)
105                         except Exception:
106                                 pass
107
108         def error(self, error = ""):
109                 print("[SimpleRSS] failed to fetch feed:", error)
110
111                 # Assume its just a temporary failure and jump over to next feed
112                 self.next_feed()
113
114         def _gotPage(self, data, id = None, callback = False, errorback = None):
115                 # workaround: exceptions in gotPage-callback were ignored
116                 try:
117                         self.gotPage(data, id)
118                         if callback:
119                                 self.doCallback(id)
120                 except NotImplementedError as errmsg:
121                         # Don't show this error when updating in background
122                         if id is not None:
123                                 AddPopup(
124                                         _("Sorry, this type of feed is unsupported:\n%s") % (str(errmsg)),
125                                         MessageBox.TYPE_INFO,
126                                         5,
127                                 )
128                         else:
129                                 # We don't want to stop updating just because one feed is broken
130                                 self.next_feed()
131                 except Exception:
132                         import traceback, sys
133                         traceback.print_exc(file=sys.stdout)
134                         # Errorback given, call it (asumme we don't need do restart timer!)
135                         if errorback is not None:
136                                 errorback()
137                                 return
138                         # Assume its just a temporary failure and jump over to next feed
139                         self.next_feed()
140
141         def gotPage(self, data, id = None):
142                 feed = cElementTree_fromstring(data)
143
144                 # For Single-Polling
145                 if id is not None:
146                         self.feeds[id].gotFeed(feed)
147                         print("[SimpleRSS] single feed parsed...")
148                         return
149
150                 new_items = self.feeds[self.current_feed].gotFeed(feed)
151
152                 print("[SimpleRSS] feed parsed...")
153
154                 # Append new items to locally bound ones
155                 if new_items is not None:
156                         self.newItemFeed.history.extend(new_items)
157
158                 # Start Timer so we can either fetch next feed or show new_items
159                 self.next_feed()
160
161         def singlePoll(self, id, callback = False, errorback = None):
162                 getPage(self.feeds[id].uri).addCallback(self._gotPage, id, callback, errorback).addErrback(errorback)
163
164         def poll(self):
165                 # Reloading, reschedule
166                 if self.reloading:
167                         print("[SimpleRSS] timer triggered while reloading, rescheduling")
168                         self.poll_timer.start(10000, 1)
169                 # End of List
170                 elif len(self.feeds) <= self.current_feed:
171                         # New Items
172                         if self.newItemFeed.history:
173                                 print("[SimpleRSS] got new items, calling back")
174                                 self.doCallback()
175
176                                 # Inform User
177                                 update_notification_value = config.plugins.simpleRSS.update_notification.value
178                                 if update_notification_value == "preview":
179                                         from RSSScreens import RSSFeedView
180
181                                         from Tools.Notifications import AddNotificationWithID, RemovePopup
182
183                                         RemovePopup(NOTIFICATIONID)
184
185                                         AddNotificationWithID(
186                                                 NOTIFICATIONID,
187                                                 RSSFeedView,
188                                                 self.newItemFeed,
189                                                 newItems = True
190                                         )
191                                 elif update_notification_value == "notification":
192                                         AddPopup(
193                                                 _("Received %d new news item(s).") % (len(self.newItemFeed.history)),
194                                                 MessageBox.TYPE_INFO,
195                                                 5,
196                                                 NOTIFICATIONID
197                                         )
198                                 elif update_notification_value == "ticker":
199                                         from RSSTickerView import tickerView
200                                         if not tickerView:
201                                                 print("[SimpleRSS] missing ticker instance, something with my code is wrong :-/")
202                                         else:
203                                                 tickerView.display(self.newItemFeed)
204                         # No new Items
205                         else:
206                                 print("[SimpleRSS] no new items")
207
208                         self.current_feed = 0
209                         self.poll_timer.startLongTimer(config.plugins.simpleRSS.interval.value*60)
210                 # It's updating-time
211                 else:
212                         # Assume we're cleaning history if current feed is 0
213                         clearHistory = self.current_feed == 0
214                         if config.plugins.simpleRSS.update_notification.value != "none":
215                                 from Tools import Notifications
216                                 if hasattr(Notifications, 'notificationQueue'):
217                                         notifications = Notifications.notificationQueue.queue
218                                         current_notifications = Notifications.notificationQueue.current
219                                         handler = lambda note: (note.fnc, note.screen, note.args, note.kwargs, note.id)
220                                         handler_current = lambda note_tup: (note[0].id,)
221                                 else:
222                                         notifications = Notifications.notifications
223                                         current_notifications = Notifications.current_notifications
224                                         handler_current = handler = lambda note: note
225
226                                 for x in current_notifications:
227                                         if handler_current(x)[0] == NOTIFICATIONID:
228                                                 print("[SimpleRSS] timer triggered while preview on screen, rescheduling")
229                                                 self.poll_timer.start(10000, 1)
230                                                 return
231
232                                 if clearHistory:
233                                         for x in notifications:
234                                                 if handler(x)[4] == NOTIFICATIONID:
235                                                         print("[SimpleRSS] wont wipe history because it was never read")
236                                                         clearHistory = False
237                                                         break
238
239                         if clearHistory:
240                                 del self.newItemFeed.history[:]
241
242                         # Feed supposed to autoupdate
243                         feed = self.feeds[self.current_feed]
244
245                         if feed.autoupdate:
246                                 getPage(feed.uri).addCallback(self._gotPage).addErrback(self.error)
247                         # Go to next feed
248                         else:
249                                 print("[SimpleRSS] passing feed")
250                                 self.next_feed()
251
252         def next_feed(self):
253                 self.current_feed += 1
254                 self.poll_timer.start(1000, 1)
255
256         def shutdown(self):
257                 self.poll_timer.callback.remove(self.poll)
258                 self.poll_timer = None
259                 self.do_poll = False
260
261         def triggerReload(self):
262                 self.reloading = True
263
264                 newfeeds = []
265                 oldfeeds = self.feeds
266                 found = False
267                 for x in config.plugins.simpleRSS.feed:
268                         for feed in oldfeeds:
269                                 if x.uri.value == feed.uri:
270                                         # Update possibly different autoupdate value
271                                         feed.autoupdate = x.autoupdate.value
272                                         newfeeds.append(feed) # Append to new Feeds
273                                         oldfeeds.remove(feed) # Remove from old Feeds
274                                         found = True
275                                         break
276                         if not found:
277                                 newfeeds.append(
278                                         UniversalFeed(
279                                                 x.uri.value,
280                                                 x.autoupdate.value
281                                 ))
282                         found = False
283
284                 self.feeds = newfeeds
285
286                 if config.plugins.simpleRSS.enable_google_reader.value:
287                         self.googleReader = GoogleReader(config.plugins.simpleRSS.google_username.value, config.plugins.simpleRSS.google_password.value)
288                         self.googleReader.login().addCallback(self.googleLoggedIn).addErrback(self.googleLoginFailed)
289                 else:
290                         self.reloading = False
291