comparison finch/libgnt/pygnt/example/rss/gntrss.py @ 18728:3db31505e42f

Use pseudo-nonblocking stuff to update the feeds.
author Sadrul Habib Chowdhury <imadil@gmail.com>
date Tue, 31 Jul 2007 04:33:53 +0000
parents 778f4fc8cbcc
children 6976a6dae441
comparison
equal deleted inserted replaced
18727:778f4fc8cbcc 18728:3db31505e42f
23 23
24 """ 24 """
25 This file deals with the rss parsing part (feedparser) of the application 25 This file deals with the rss parsing part (feedparser) of the application
26 """ 26 """
27 27
28 import threading 28 import os
29 import tempfile, urllib2
29 import feedparser 30 import feedparser
30 import gobject 31 import gobject
31 import sys 32 import sys
32 import time 33 import time
33 34
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)