1 # Copyright (C) 2006 by Aiwota Programmer
2 # aiwotaprog@tetteke.tk
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 from http_sub import HTTPRedirectHandler302, HTTPDebugHandler
32 BOARD_DATA_INVALID_VALUE = 0
37 def __init__(self, bbs_type):
38 self.bbs_type = bbs_type
40 def set_status(self, text):
43 def _merge_new_thread(self, datalist, id, title, res, num, lastmod):
51 # avoid the Last-Modified time of subject.txt and
52 # the build time of thread is equal (zero division)
57 average = round(res * 60 * 60 * 24.0 / dur, 2)
62 # already exists in datalist and num is not 0, then this thread
63 # is duplicate in subject.txt.
70 item["average"] = average
72 datalist[id] = {"id": id, "num": num, "title": title,
73 "res": res, "lineCount": BOARD_DATA_INVALID_VALUE,
74 "lastModified": "", "average": average}
76 def merge_local_subjecttxt(self, datalist):
77 f = lambda id, title, res, num, lastmod: \
78 self._merge_new_thread(datalist, id, title, res, num, lastmod)
79 self._load_subjecttxt(f)
81 def merge_remote_subjecttxt(self, datalist):
82 f = lambda id, title, res, num, lastmod: \
83 self._merge_new_thread(datalist, id, title, res, num, lastmod)
84 self._get_subjecttxt(f)
86 def _init_extra_data(self, dic):
92 def load_idxfiles(self):
95 def on_load_record(id, metadata_dic):
96 datalist[id] = self._init_extra_data(metadata_dic)
99 cachefile.load_cache(self.bbs_type, on_load_record)
101 self._load_modified_idxfiles(datalist)
103 cachefile.save_cache(self.bbs_type, datalist)
107 def _load_modified_idxfiles(self, datalist):
108 basedir = misc.get_thread_idx_dir_path(self.bbs_type)
110 exist_key_set = set()
111 if os.path.isdir(basedir):
112 for idxfile_path in glob.glob(os.path.join(basedir, "*"+ext)):
113 basename = os.path.basename(idxfile_path)
114 thread_id = basename[:len(ext)*-1]
116 idxlastModified = os.path.getmtime(idxfile_path)
119 exist_key_set.add(thread_id)
120 if thread_id not in datalist:
121 print "new", thread_id
122 bbs_type_for_thread = self.bbs_type.clone_with_thread(
124 dic = idxfile.load_idx(bbs_type_for_thread)
125 dic["id"] = thread_id
126 dic["idxlastModified"] = idxlastModified
127 dic = self._init_extra_data(dic)
128 datalist[thread_id] = dic
129 elif idxlastModified > datalist[thread_id]["idxlastModified"]:
130 print "modified", thread_id
131 bbs_type_for_thread = self.bbs_type.clone_with_thread(
133 datalist[thread_id]["idxlastModified"] = idxlastModified
134 dic = idxfile.load_idx(bbs_type_for_thread)
135 for key, value in dic.iteritems():
136 datalist[thread_id][key] = value
138 # delete from datalist if idx file does not exist.
139 for key in datalist.keys():
140 if key not in exist_key_set:
144 def _split_record(self, line_encoded):
145 line = line_encoded.decode(self.bbs_type.encoding, "replace")
146 m = self.bbs_type.subject_reg.match(line)
149 title = m.group("title")
151 res = int(m.group("res"))
154 return id, title, res
157 def _load_subjecttxt(self, func):
158 lastmod = self.load_board_idx()
160 lastmod = misc.httpdate_to_secs(lastmod)
164 subjecttxt_path = misc.get_board_subjecttxt_path(self.bbs_type)
166 for num, line_encoded \
167 in itertools.izip(itertools.count(1),
168 file(subjecttxt_path)):
169 result = self._split_record(line_encoded)
171 id, title, res = result
173 func(id, title, res, num, lastmod)
175 traceback.print_exc()
177 traceback.print_exc()
179 def _get_subjecttxt(self, func):
183 opener = urllib2.build_opener(HTTPRedirectHandler302, HTTPDebugHandler)
184 request = urllib2.Request(self.bbs_type.get_subject_txt_uri())
185 request.add_header("User-agent", config.User_Agent)
187 response = opener.open(request)
188 except urllib2.HTTPError, e:
189 gobject.idle_add(self.set_status, "%d %s" % (e.code, e.msg))
190 print "switch to local"
191 self._load_subjecttxt(func)
192 except urllib2.URLError, e:
194 gobject.idle_add(self.set_status, str(e))
195 print "switch to local"
196 self._load_subjecttxt(func)
198 status = "%d %s" % (response.code, response.msg)
199 gobject.idle_add(self.set_status, status)
200 info = response.info()
203 if "Last-Modified" in info:
204 _lastmod = info["Last-Modified"]
205 self.save_board_idx(_lastmod)
207 lastmod = misc.httpdate_to_secs(_lastmod)
211 subjecttxt_path = misc.get_board_subjecttxt_path(self.bbs_type)
212 basedir = os.path.dirname(subjecttxt_path)
213 if not os.path.isdir(basedir):
217 f = file(subjecttxt_path, "w")
219 traceback.print_exc()
222 for num, line_encoded in itertools.izip(itertools.count(1),
226 f.write(line_encoded)
228 traceback.print_exc()
229 result = self._split_record(line_encoded)
231 id, title, res = result
233 func(id, title, res, num, lastmod)
235 traceback.print_exc()
237 traceback.print_exc()
243 def load_board_idx(self):
245 boardidxfile = misc.get_board_idx_path(self.bbs_type)
247 for line in file(boardidxfile):
248 if line.startswith("lastModified="):
249 lastmod = line[len("lastModified="):].rstrip("\n")
252 traceback.print_exc()
255 def save_board_idx(self, lastmod):
259 boardidx_path = misc.get_board_idx_path(self.bbs_type)
260 basedir = os.path.dirname(boardidx_path)
261 if not os.path.isdir(basedir):
264 f = file(boardidx_path, "w")
265 f.write("lastModified=" + lastmod + "\n")