Remove httpclient.py and rely on twisted-web
[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 twisted.web.client 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(self.feeds[id].uri).addCallback(callback=boundFunction(self._gotSinglePage, id, callback, errorback)).addErrback(errorback)
127
128         def poll(self):
129                 # Reloading, reschedule
130                 if self.reloading:
131                         print "[SimpleRSS] timer triggered while reloading, rescheduling"
132                         self.poll_timer.start(10000, 1)
133                 # End of List
134                 elif len(self.feeds) <= self.current_feed:
135                         # New Items
136                         if len(self.new_items):
137                                 print "[SimpleRSS] got", len(self.new_items), "new items"
138                                 print "[SimpleRSS] calling back"
139                                 self.doCallback()
140                                 # Inform User
141                                 if config.plugins.simpleRSS.show_new.value:
142                                         self.session.open(RSSFeedView, self.new_items, newItems=True)
143                         # No new Items
144                         else:
145                                 print "[SimpleRSS] no new items"
146                         self.current_feed = 0
147                         self.poll_timer.startLongTimer(config.plugins.simpleRSS.interval.value*60)
148                 # It's updating-time
149                 else:
150                         # Id is 0 -> empty out new items
151                         if self.current_feed == 0:
152                                 self.new_items = [ ]
153                         # Feed supposed to autoupdate
154                         feed = self.feeds[self.current_feed]
155                         if feed.autoupdate:
156                                 getPage(feed.uri).addCallback(self._gotPage).addErrback(self.error)
157                         # Go to next feed
158                         else:
159                                 print "[SimpleRSS] passing feed"
160                                 self.next_feed()
161
162         def next_feed(self):
163                 self.current_feed += 1
164                 self.poll_timer.start(1000, 1)
165
166         def shutdown(self):
167                 self.poll_timer.timeout.get().remove(self.poll)
168                 self.poll_timer = None
169
170         def triggerReload(self):
171                 self.reloading = True
172
173                 newfeeds = []
174                 found = False
175                 for i in range(0, config.plugins.simpleRSS.feedcount.value):
176                         for feed in self.feeds:
177                                 if config.plugins.simpleRSS.feed[i].uri.value == feed.uri:
178                                         # Update possibly different autoupdate value
179                                         feed.autoupdate = config.plugins.simpleRSS.feed[i].autoupdate.value
180                                         newfeeds.append(feed) # Append to new Feeds
181                                         self.feeds.remove(feed) # Remove from old Feeds
182                                         found = True
183                                         break
184                         if not found:
185                                 newfeeds.append(
186                                         UniversalFeed(
187                                                 config.plugins.simpleRSS.feed[i].uri.value,
188                                                 config.plugins.simpleRSS.feed[i].autoupdate.value,
189                                                 self.stripper
190                                 ))
191                         found = False
192
193                 self.feeds = newfeeds
194
195                 self.reloading = False