| 44 __gsignals__ = { |
45 __gsignals__ = { |
| 45 'delete' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)) |
46 'delete' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_OBJECT,)) |
| 46 } |
47 } |
| 47 def __init__(self, item, parent): |
48 def __init__(self, item, parent): |
| 48 self.__gobject_init__() |
49 self.__gobject_init__() |
| 49 self.date = item['date'] |
50 try: |
| 50 self.date_parsed = item['date_parsed'] |
51 "Apparently some feed items don't have any dates in them" |
| |
52 self.date = item['date'] |
| |
53 self.date_parsed = item['date_parsed'] |
| |
54 except: |
| |
55 item['date'] = self.date = time.ctime() |
| |
56 self.date_parsed = feedparser._parse_date(self.date) |
| |
57 |
| 51 self.title = item['title'] |
58 self.title = item['title'] |
| 52 self.summary = item['summary'] |
59 self.summary = item['summary'] |
| 53 self.link = item['link'] |
60 self.link = item['link'] |
| 54 self.parent = parent |
61 self.parent = parent |
| 55 self.unread = True |
62 self.unread = True |
| 109 self.url = url # The url of the feed itself |
116 self.url = url # The url of the feed itself |
| 110 self.link = url # The web page associated with the feed |
117 self.link = url # The web page associated with the feed |
| 111 self.desc = url |
118 self.desc = url |
| 112 self.title = url |
119 self.title = url |
| 113 self.unread = 0 |
120 self.unread = 0 |
| 114 self.timer = 0 |
|
| 115 self.items = [] |
121 self.items = [] |
| 116 self.hash = {} |
122 self.hash = {} |
| |
123 self.pending = False |
| 117 |
124 |
| 118 def do_set_property(self, property, value): |
125 def do_set_property(self, property, value): |
| 119 if property.name == 'link': |
126 if property.name == 'link': |
| 120 self.link = value |
127 self.link = value |
| 121 elif property.name == 'desc': |
128 elif property.name == 'desc': |
| 124 self.title = value |
131 self.title = value |
| 125 elif property.name == 'unread': |
132 elif property.name == 'unread': |
| 126 self.unread = value |
133 self.unread = value |
| 127 pass |
134 pass |
| 128 |
135 |
| 129 def check_thread_for_death(self): |
136 def set_result(self, result): |
| 130 #if self.thread.running: |
|
| 131 # sys.stderr.write(time.ctime() + "continue") |
|
| 132 # return True |
|
| 133 # The thread has ended!! |
|
| 134 #result = self.thread.result |
|
| 135 #self.thread = None |
|
| 136 result = feedparser.parse(self.url) |
|
| 137 # XXX Look at result['bozo'] first, and emit some signal that the UI can use |
137 # XXX Look at result['bozo'] first, and emit some signal that the UI can use |
| 138 # to indicate (dim the row?) that the feed has invalid XML format or something |
138 # to indicate (dim the row?) that the feed has invalid XML format or something |
| 139 |
139 |
| 140 channel = result['channel'] |
140 try: |
| 141 self.set_property('link', channel['link']) |
141 channel = result['channel'] |
| 142 self.set_property('desc', channel['description']) |
142 self.set_property('link', channel['link']) |
| 143 self.set_property('title', channel['title']) |
143 self.set_property('desc', channel['description']) |
| 144 self.timer = 0 |
144 self.set_property('title', channel['title']) |
| 145 items = result['items'] |
145 items = result['items'] |
| |
146 except: |
| |
147 items = () |
| |
148 |
| 146 tmp = {} |
149 tmp = {} |
| 147 for item in self.items: |
150 for item in self.items: |
| 148 tmp[hash(item)] = item |
151 tmp[hash(item)] = item |
| 149 |
152 |
| 150 unread = self.unread |
153 unread = self.unread |
| 162 for hv in tmp: |
165 for hv in tmp: |
| 163 tmp[hv].remove() |
166 tmp[hv].remove() |
| 164 |
167 |
| 165 if unread != self.unread: |
168 if unread != self.unread: |
| 166 self.set_property('unread', unread) |
169 self.set_property('unread', unread) |
| |
170 self.pending = False |
| 167 return False |
171 return False |
| 168 |
172 |
| 169 def refresh(self): |
173 def refresh(self): |
| 170 #if self.thread == 0: |
174 if self.pending: |
| 171 # self.thread = FeedReader(self) |
175 return |
| 172 # self.thread.start() |
176 self.pending = True |
| 173 if self.timer == 0: |
177 FeedReader(self).run() |
| 174 self.timer = gobject.timeout_add(1000, self.check_thread_for_death) |
|
| 175 |
178 |
| 176 def mark_read(self): |
179 def mark_read(self): |
| 177 for item in self.items: |
180 for item in self.items: |
| 178 item.mark_unread(False) |
181 item.mark_unread(False) |
| 179 |
182 |
| 180 gobject.type_register(Feed) |
183 gobject.type_register(Feed) |
| 181 |
184 |
| 182 ## |
185 """ |
| 183 # A FeedReader class, which is threaded to make sure it doesn't freeze the ui |
186 The FeedReader updates a Feed. It fork()s off a child to avoid blocking. |
| 184 # (this thing doesn't quite work ... yet) |
187 """ |
| 185 ## |
188 class FeedReader: |
| 186 class FeedReader(threading.Thread): |
|
| 187 def __init__(self, feed): |
189 def __init__(self, feed): |
| 188 self.feed = feed |
190 self.feed = feed |
| 189 self.running = True |
191 |
| 190 threading.Thread.__init__(self) |
192 def reap_child(self, pid, status): |
| |
193 result = feedparser.parse(self.tmpfile.name) |
| |
194 self.tmpfile.close() |
| |
195 self.feed.set_result(result) |
| 191 |
196 |
| 192 def run(self): |
197 def run(self): |
| 193 sys.stderr.write(str(time.ctime()) + " STARTED!!!\n\n\n") |
198 self.tmpfile = tempfile.NamedTemporaryFile() |
| 194 self.running = True |
199 self.pid = os.fork() |
| 195 self.result = feedparser.parse(self.feed.url) |
200 if self.pid == 0: |
| 196 self.running = False |
201 tmp = urllib2.urlopen(self.feed.url) |
| 197 sys.stderr.write(str(time.ctime()) + " DONE!!!\n\n\n") |
202 content = tmp.read() |
| |
203 tmp.close() |
| |
204 self.tmpfile.write(content) |
| |
205 self.tmpfile.flush() |
| |
206 # Do NOT close tmpfile here |
| |
207 os._exit(os.EX_OK) |
| |
208 gobject.child_watch_add(self.pid, self.reap_child) |
| 198 |
209 |
| 199 feeds = [] |
210 feeds = [] |
| 200 urls = ("http://rss.slashdot.org/Slashdot/slashdot", |
211 urls = ("http://rss.slashdot.org/Slashdot/slashdot", |
| 201 "http://www.python.org/channews.rdf", |
212 "http://kerneltrap.org/node/feed", |
| 202 "http://kerneltrap.org/node/feed" |
213 "http://pidgin.im/rss.php", |
| |
214 "http://www.formula1.com/rss/news/latest.rss", |
| |
215 "http://www.pheedo.com/f/freshmeatnet_announcements_unix", |
| |
216 "http://www.cricinfo.com/rss/livescores.xml" |
| 203 ) |
217 ) |
| 204 |
218 |
| 205 for url in urls: |
219 for url in urls: |
| 206 feed = Feed(url) |
220 feed = Feed(url) |
| 207 feeds.append(feed) |
221 feeds.append(feed) |