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