Improve readability,
[enigma2-plugins.git] / simplerss / src / RSSPoller.py
1 from Screens.MessageBox import MessageBox
2 from Components.config import config
3 from enigma import eTimer
4
5 from RSSScreens import RSSFeedView
6 from TagStrip import TagStrip
7 from RSSFeed import UniversalFeed
8
9 from httpclient import getPage
10 from xml.dom.minidom import parseString as minidom_parseString
11
12 class RSSPoller:
13         """Keeps all Feed and takes care of (automatic) updates"""
14         def __init__(self, session):
15                 # Timer
16                 self.poll_timer = eTimer()
17                 self.poll_timer.timeout.get().append(self.poll)
18                 self.poll_timer.start(0, 1)
19
20                 # Stripper
21                 self.stripper = TagStrip()
22
23                 # Functions to call when updates happened
24                 self.update_callbacks = [ ]
25
26                 # Save Session, Initialize Var to identify triggered Reload
27                 self.session = session
28                 self.reloading = False
29
30                 # Generate Feeds
31                 self.feeds = [
32                         UniversalFeed(
33                                 config.plugins.simpleRSS.feed[i].uri.value,
34                                 config.plugins.simpleRSS.feed[i].autoupdate.value,
35                                 self.stripper
36                         )
37                                 for i in range(0, config.plugins.simpleRSS.feedcount.value)
38                 ]
39
40                 # Initialize Vars
41                 self.new_items = [ ]
42                 self.current_feed = 0
43
44         def addCallback(self, callback):
45                 if callback not in self.update_callbacks:
46                         self.update_callbacks.append(callback)
47
48         def removeCallback(self, callback):
49                 if callback in self.update_callbacks:
50                         self.update_callbacks.remove(callback)
51
52         def doCallback(self, id = None):
53                 for callback in self.update_callbacks:
54                         try:
55                                 callback(id)
56                         except:
57                                 pass
58
59         # Wrap boundFunction over real function
60         def _gotSinglePage(self, id, callback, errorback, data):
61                 self._gotPage(data, id, callback, errorback)
62
63         def error(self, error = ""):
64                 if not self.session:
65                         print "[SimpleRSS] error polling"
66                 else:
67                         self.session.open(
68                                 MessageBox,
69                                 "Sorry, failed to fetch feed.\n" + error,
70                                 type = MessageBox.TYPE_INFO,
71                                 timeout = 5
72                         )
73                         # Assume its just a temporary failure and jump over to next feed                          
74                         self.next_feed()
75
76         def _gotPage(self, data, id = None, callback = False, errorback = None):
77                 # workaround: exceptions in gotPage-callback were ignored
78                 try:
79                         self.gotPage(data, id)
80                         if callback:
81                                 self.doCallback(id)
82                 except NotImplementedError, errmsg:
83                         # TODO: Annoying with Multifeed?
84                         self.session.open(
85                                 MessageBox,
86                                 "Sorry, this type of feed is unsupported.\n"+ str(errmsg),
87                                 type = MessageBox.TYPE_INFO,
88                                 timeout = 5
89                         )
90                 except:
91                         import traceback, sys
92                         traceback.print_exc(file=sys.stdout)
93                         # Errorback given, call it (asumme we don't need do restart timer!)
94                         if errorback is not None:
95                                 errorback()
96                                 return
97                         # Assume its just a temporary failure and jump over to next feed                          
98                         self.next_feed()
99         
100         def gotPage(self, data, id = None):
101                 print "[SimpleRSS] parsing.."
102
103                 # sometimes activates spinner :-/
104                 dom = minidom_parseString(data)
105
106                 print "[SimpleRSS] xml parsed.."
107
108                 # For Single-Polling
109                 if id is not None:
110                         self.feeds[id].gotDom(dom)
111                         print "[SimpleRSS] single feed parsed.."
112                         return
113
114                 new_items = self.feeds[self.current_feed].gotDom(dom)
115
116                 print "[SimpleRSS] feed parsed.."
117
118                 # Append new items to locally bound ones
119                 self.new_items.extend(new_items)
120
121                 # Start Timer so we can either fetch next feed or show new_items
122                 self.next_feed()
123
124         def singlePoll(self, id, callback = False, errorback = None):
125                 from Tools.BoundFunction import boundFunction
126                 getPage(
127                         self.feeds[id].hostname,
128                         self.feeds[id].port,
129                         self.feeds[id].path,
130                         callback=boundFunction(self._gotSinglePage, id, callback, errorback),
131                         errorback=errorback
132                 )
133
134         def poll(self):
135                 # Reloading, reschedule
136                 if self.reloading:
137                         print "[SimpleRSS] timer triggered while reloading, rescheduling"
138                         self.poll_timer.start(10000, 1)
139                 # End of List
140                 elif len(self.feeds) <= self.current_feed:
141                         # New Items
142                         if len(self.new_items):
143                                 print "[SimpleRSS] got", len(self.new_items), "new items"
144                                 print "[SimpleRSS] calling back"
145                                 self.doCallback()
146                                 # Inform User
147                                 if config.plugins.simpleRSS.show_new.value:
148                                         self.session.open(RSSFeedView, self.new_items, newItems=True)
149                         # No new Items
150                         else:
151                                 print "[SimpleRSS] no new items"
152                         self.current_feed = 0
153                         self.poll_timer.startLongTimer(config.plugins.simpleRSS.interval.value*60)
154                 # It's updating-time
155                 else:
156                         # Id is 0 -> empty out new items
157                         if self.current_feed == 0:
158                                 self.new_items = [ ]
159                         # Feed supposed to autoupdate
160                         feed = self.feeds[self.current_feed]
161                         if feed.autoupdate:
162                                 getPage(
163                                         feed.hostname,
164                                         feed.port,
165                                         feed.path,
166                                         callback=self._gotPage,
167                                         errorback=self.error
168                                 )
169                         # Go to next feed
170                         else:
171                                 print "[SimpleRSS] passing feed"
172                                 self.next_feed()
173
174         def next_feed(self):
175                 self.current_feed += 1
176                 self.poll_timer.start(1000, 1)
177
178         def shutdown(self):
179                 self.poll_timer.timeout.get().remove(self.poll)
180                 self.poll_timer = None
181
182         def triggerReload(self):
183                 self.reloading = True
184
185                 newfeeds = []
186                 found = False
187                 for i in range(0, config.plugins.simpleRSS.feedcount.value):
188                         for feed in self.feeds:
189                                 if config.plugins.simpleRSS.feed[i].uri.value == feed.uri:
190                                         # Update possibly different autoupdate value
191                                         feed.autoupdate = config.plugins.simpleRSS.feed[i].autoupdate.value
192                                         newfeeds.append(feed) # Append to new Feeds
193                                         self.feeds.remove(feed) # Remove from old Feeds
194                                         found = True
195                                         break
196                         if not found:
197                                 newfeeds.append(
198                                         UniversalFeed(
199                                                 config.plugins.simpleRSS.feed[i].uri.value,
200                                                 config.plugins.simpleRSS.feed[i].autoupdate.value,
201                                                 self.stripper
202                                 ))
203                         found = False
204
205                 self.feeds = newfeeds
206
207                 self.reloading = False