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