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