Add a TagStripper to replace german umlauts and strip html-tags,
[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 SimpleRSSScreens import SimpleRSSFeed
6 from TagStrip import TagStrip
7 from Feed import Feed
8
9 from httpclient import getPage
10 from urlparse import urlsplit
11 from xml.dom.minidom import parseString as minidom_parseString
12
13 class RSSPoller:
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                 for i in range(0, config.plugins.simpleRSS.feedcount.value):
28                         self.feeds.append(Feed(config.plugins.simpleRSS.feed[i].uri.value, config.plugins.simpleRSS.feed[i].autoupdate.value, self.stripper))
29                 self.new_items = [ ]
30                 self.current_feed = 0
31
32         def addCallback(self, callback):
33                 if callback not in self.update_callbacks:
34                         self.update_callbacks.append(callback)
35
36         def removeCallback(self, callback):
37                 if callback in self.update_callbacks:
38                         self.update_callbacks.remove(callback)
39
40         def doCallback(self, id = None):
41                 for callback in self.update_callbacks:
42                         try:
43                                 callback(id)
44                         except:
45                                 pass
46
47         # Wrap boundFunction over real function
48         def _gotSinglePage(self, id, callback, errorback, data):
49                 self._gotPage(data, id, callback, errorback)
50
51         def error(self, error = ""):
52                 if not self.session:
53                         print "[SimpleRSS] error polling"
54                 else:
55                         self.session.open(MessageBox, "Sorry, failed to fetch feed.\n" + error, type = MessageBox.TYPE_INFO, timeout = 5)
56                         # Assume its just a temporary failure and jump over to next feed                          
57                         self.current_feed += 1                     
58                         self.poll_timer.start(1000, 1)
59
60         def _gotPage(self, data, id = None, callback = False, errorback = None):
61                 # workaround: exceptions in gotPage-callback were ignored
62                 try:
63                         self.gotPage(data, id)
64                         if callback:
65                                 self.doCallback(id)
66                 except NotImplementedError, errmsg:
67                         # TODO: Annoying with Multifeed?
68                         self.session.open(MessageBox, "Sorry, this type of feed is unsupported.\n"+ str(errmsg), type = MessageBox.TYPE_INFO, timeout = 5)
69                 except:
70                         import traceback, sys
71                         traceback.print_exc(file=sys.stdout)
72                         # Errorback given, call it (asumme we don't need do restart timer!)
73                         if errorback is not None:
74                                 errorback()
75                                 return
76                         # Assume its just a temporary failure and jump over to next feed                          
77                         self.current_feed += 1                     
78                         self.poll_timer.start(1000, 1)
79         
80         def gotPage(self, data, id = None):
81                 print "[SimpleRSS] parsing.."
82
83                 # sometimes activates spinner :-/
84                 dom = minidom_parseString(data)
85
86                 print "[SimpleRSS] xml parsed.."
87
88                 # For Single-Polling
89                 if id is not None:
90                         self.feeds[id].gotDom(dom)
91                         print "[SimpleRSS] single feed parsed.."
92                         return
93                 else:
94                         new_items = self.feeds[self.current_feed].gotDom(dom)
95
96                 print "[SimpleRSS] feed parsed.."
97
98                 # Append new items to locally bound ones
99                 self.new_items.extend(new_items)
100
101                 # Start Timer so we can either fetch next feed or show new_items
102                 self.current_feed += 1
103                 self.poll_timer.start(1000, 1)
104
105         def singlePoll(self, id, callback = False, errorback = None):
106                 from Tools.BoundFunction import boundFunction
107                 remote = urlsplit(self.feeds[id].uri)
108                 print "[SimpleRSS] updating", remote.geturl()
109                 hostname = remote.hostname
110                 port = remote.port or 80
111                 path = '?'.join([remote.path, remote.query])
112                 print "[SimpleRSS] hostname:", hostname, ", port:", port, ", path:", path
113                 getPage(hostname, port, path, callback=boundFunction(self._gotSinglePage, id, callback, errorback), errorback=errorback)
114
115         def poll(self):
116                 # Reloading, reschedule
117                 if self.reloading:
118                         print "[SimpleRSS] timer triggered while reloading, rescheduling"
119                         self.poll_timer.start(10000, 1)
120                 # Dialog shown, hide
121                 elif self.dialog:
122                         print "[SimpleRSS] hiding"
123                         self.dialog.hide()
124                         self.dialog = None
125                         self.new_items = [ ]
126                         self.current_feed = 0
127                         self.poll_timer.startLongTimer(config.plugins.simpleRSS.interval.value*60)
128                 # End of List
129                 elif len(self.feeds) <= self.current_feed:
130                         # New Items
131                         if len(self.new_items):
132                                 print "[SimpleRSS] got", len(self.new_items), "new items"
133                                 print "[SimpleRSS] calling back"
134                                 self.doCallback()
135                                 # Inform User
136                                 if config.plugins.simpleRSS.show_new.value:
137                                         self.dialog = self.session.instantiateDialog(SimpleRSSFeed, self.new_items, newItems=True)
138                                         self.dialog.show()
139                                         self.poll_timer.startLongTimer(5)
140                         # No new Items
141                         else:
142                                 print "[SimpleRSS] no new items"
143                                 self.new_items = [ ]
144                                 self.current_feed = 0
145                                 self.poll_timer.startLongTimer(config.plugins.simpleRSS.interval.value*60)
146                 # Feed is supposed to auto-update
147                 elif self.feeds[self.current_feed].autoupdate:
148                         remote = urlsplit(self.feeds[self.current_feed].uri)
149                         hostname = remote.hostname
150                         port = remote.port or 80
151                         path = '?'.join([remote.path, remote.query])
152                         print "[SimpleRSS] hostname:", hostname, ", port:", port, ", path:", path
153                         self.d = getPage(hostname, port, path, callback=self._gotPage, errorback=self.error)
154                 # Go to next feed in 100ms
155                 else:
156                         print "[SimpleRSS] passing feed"
157                         self.current_feed += 1
158                         self.poll_timer.start(100, 1)
159
160         def shutdown(self):
161                 self.poll_timer.timeout.get().remove(self.poll)
162                 self.poll_timer = None
163
164         def triggerReload(self):
165                 self.reloading = True
166
167                 # TODO: Fix this evil way of updating feeds
168                 newfeeds = []
169                 for i in range(0, config.plugins.simpleRSS.feedcount.value):
170                         newfeeds.append(Feed(config.plugins.simpleRSS.feed[i].uri.value, config.plugins.simpleRSS.feed[i].autoupdate.value, self.stripper))
171
172                 self.feeds = newfeeds
173
174                 self.reloading = False