#!/usr/bin/python import calendar, os, re, time from urllib import quote_plus from config import service, __dict__ as config from Cheetah.Template import Template from urlparse import urljoin from entry import post splitExcerpt=re.compile('(?:
(?:(.*?)
)?\s*)?(.*)',re.S) unique_ids = [] def resize(svg, scale=0.0625, feed=False): height = width = viewBox = None decl = svg[1:svg.find('>')+1] split = re.split(r''' width=["'](\d+)["']''', decl, 1) if len(split)==3: split = re.split(r''' width=["'](\d+)["']''', svg, 1) width,svg = int(split[1]), split[0]+split[2] split = re.split(r''' height=["'](\d+)["']''', decl, 1) if len(split)==3: split = re.split(r''' height=["'](\d+)["']''', svg, 1) height,svg = int(split[1]), split[0]+split[2] split = re.split(r''' viewBox=['"]([-\d\s\.]*?)["']''', svg) if len(split)==3: viewBox,svg = [eval(n) for n in split[1].split()], split[0]+split[2] elif width and height: viewBox = [0,0,width,height] if viewBox: svg = re.sub(' style="float: ?right"','',svg) i = svg.find('>') dsvg = ('
' + '%s viewBox="%d %d %d %d"%s
') % tuple( [(width or viewBox[2])*scale, (height or viewBox[3])*scale, svg[:i].strip()] + viewBox + [svg[i:]]) xsvg = ('' + '%s viewBox="%d %d %d %d"%s') % tuple( [(width or viewBox[2])*scale*16, (height or viewBox[3])*scale*16, svg[:i].strip()] + viewBox + [svg[i:]]) svg = ('%s width="%d" height="%d" viewBox="%d %d %d %d"%s') % tuple( [svg[:i].strip(), (width or viewBox[2])*scale*16, (height or viewBox[3])*scale*16] + viewBox + [svg[i:]]) if not feed: # ensure ids are unique global unique_ids for id in re.findall(''' id=["'](.*?)["']''', svg): if id in unique_ids: i = 2 while id+'_'+str(i) in unique_ids: i+=1 svg = re.sub('''([('"]#?%s)([)'"])'''%id, r'\1_%d\2'%i, svg) id = id+'_'+str(i) unique_ids.append(id) return svg def format(path, query=''): blogdir = os.listdir('.') basepath=path ####################################################################### # Defaults # ####################################################################### # select all files def fileFilter(name): return True # limit the number of files displayed numEntries = 20 # What files are we looking for? filterExt= '.txt' # What files should we return links to? linkExt= '.html' # Which template should we use? flavor= 'html' # Order to sort items: -1=reverse chronological, +1=chronological sortOrder= -1 # Parent item (if any) to a list of comments parent = {} ####################################################################### # Make adjustments based on path # ####################################################################### redirect = False archivedir = '' if isinstance(path, str): path = path.split('/') if path[-1]=='': path[-1]='index.'+flavor if path[0]=='': del path[0] if len(path)>0 and path[0]=='archives': archivedir = '/'.join(path[0:-1]) + '/' # archives page if path[-1]=='index.html': path[-1]='index.bymonth' del path[0] if len(path)<3: path = map(str,time.localtime()[0:3-len(path)]) + path if len(path)==1 and path[0].startswith('index.'): # Front page flavor = path[-1].split('.',1)[1] # if flavor <> 'html': numEntries = 5 def fileFilter(name): return name.endswith('.txt') elif len(path)==1 and path[0].startswith('comments.'): # Comments flavor = path[-1].split('.',1)[1] filterExt = '.cmt' config['channel'].title = config['channel'].cmttitle config['channel'].alternate = config['channel'].cmtalt filterLast=int(time.time()) - 86400*7 cmt_re = re.compile('\d+-(\d+)\.cmt$') def fileFilter(name): if name.startswith('test'): return False mtime=cmt_re.findall(name) or [os.stat(name).st_mtime] return (int(mtime[0]) > filterLast) elif len(path)==1 and path[0].startswith('all.'): # All flavor = path[-1].split('.',1)[1] filterExt = None config['channel'].title = config['channel'].cmttitle config['channel'].alternate = config['channel'].cmtalt filterLast=int(time.time()) - 86400*7 cmt_re = re.compile('\d+-(\d+)\.cmt$') def fileFilter(name): mtime=cmt_re.findall(name) or [os.stat(name).st_mtime] return (int(mtime[0]) > filterLast) elif len(path)==1: # Individual blog entry if path[0].find('.')>=0: (entry, flavor) = path[0].split('.',1) else: (entry, flavor) = (path[0],'html') filterPrefix = entry + '-' filterExt = '.cmt' sortOrder = +1 def fileFilter(name): return name.find(filterPrefix)==0 try: entry = post(entry, linkExt.split('.')[-1]) thrcount, thrupdated = comments(entry.id(), blogdir) # make svg resizable body = entry.body() if body and body.startswith('')>0: svg=resize(body[:body.find('')+6]) if body.find('

')<0: svg=svg.replace('div>','span>') if body.find('

')<0: svg=svg.replace('')+6:] parent = { 'entry': entry.id(), 'filename': entry.filepath(), 'title': entry.title(), 'link': entry.link(), 'guid': 'tag:intertwingly.net,2004:%s' % entry.id(), 'id': entry.id(), 'mtime': time.gmtime(entry.modified()), 'description': body, 'content': body, 'comments': thrcount, 'lastcomment': thrupdated } entry = entry.id() except IOError: flavor = 404 numEntries = 2000 elif re.match('\d+$',path[0]): # Year / Month / Day page if path[-1][:6]=='index.': flavor = path[-1].split('.',1)[1] del path[-1] if path[-1].find('.')>=0: (path[-1],flavor) = path[-1].split('.',1) months=list(calendar.month_abbr) if len(path)>1 and path[1] in months: path[1]=str(months.index(path[1])) if len(path)>0 and (len(path)>3 or not path[-1].isdigit()): slug=path[-1].lower() del path[-1] if basepath.endswith('/index.html'): redirect = True else: slug=None redirect = True first = [0000, 01, 01, 00, 00, 00, 0,0,0] last = [0000, 01, 01, 00, 00, 00, 0,0,0] for i in range(0,len(path)): try: first[i]=last[i]=int(path[i]) except ValueError: flavor = 404 break else: last[len(path)-1] += 1 try: filterFirst=time.mktime(first)-3600 filterLast=time.mktime(last) except: filterFirst=firstLast=time.time() flavor = 404 numEntries = 200 def fileFilter(name): mtime=os.stat(name).st_mtime if (mtime < filterFirst) or (mtime > filterLast): return False return (not slug) or (slug == post(name.split('.')[0]).slug().lower()) else: flavor = 404 ####################################################################### # Select the list of files to be displayed # ####################################################################### if query: from search import search if filterExt=='.txt': searchList=map(lambda x: x.replace('-','_')+'.txt', search(query)) else: base = search(query) searchList=[name for name in blogdir if name.split('-')[0] in base] else: searchList=blogdir filelist=[] extList = filterExt and [filterExt] or ['.cmt','.txt'] for name in searchList: if name[-4:] in extList: if fileFilter(name): try: filelist.append((os.stat(name).st_mtime,name)) except: pass if not parent and not filelist: flavor=404 filelist.sort() if sortOrder == -1: filelist.reverse() if flavor=='xhtml': linkExt = '.xhtml' if parent: parent['link'] = entry + linkExt flavor = 'html' if not parent and len(filelist)==1 and flavor<>'bymonth': entry = filelist[0][1].split('.')[0] if redirect: from config import urlpath url = config['urlpath'].cache + "/" + post(entry).link() return "Status: 301 Redirect\r\nLocation: %s\r\n\r\n" % url else: return format(entry+"."+str(flavor)) ####################################################################### # Retrieve each selected file # ####################################################################### children=[] tbfrom=re.compile(r'\[more\]

Trackback from') urlbase=config['channel'].link for mtime, filename in filelist[:numEntries]: entry = filename[:-4].split('-')[0] # read the blog entry itself file = open(filename) title = file.readline().strip() (updated,excerpt,body)=splitExcerpt.match(file.read()).groups() file.close() # backtrack those that are trackbacks, filter those that are not from tbrss more=None # tbfrom.findall(body) if more: body=body.replace('>[more]', '>[more][back]' % (service.backtrack, quote_plus(more[0]))) else: if flavor=="tbrss": continue if linkExt=='.html': try: etime = os.stat(entry+".txt").st_mtime except: pass link = post(entry).link() else: link = entry + linkExt # determine the anchor to use for this entry on the page if filename.find('-')>0: id = 'c'+ str(int(mtime)) link = link + '#' + id guid = entry + linkExt + "#" + id guid = 'tag:intertwingly.net,2004:%s-%s' % (entry,id[1:]) else : id = 'x' + entry guid = entry + linkExt guid = 'tag:intertwingly.net,2004:%s' % entry # make svg resizable if body.startswith('')>0: svg=resize(body[:body.find('')+6]) if body.find('

')<0: svg=svg.replace('div>','span>').replace('')+6:] if excerpt and excerpt.find('')<0: svg=svg.replace('div>','span>').replace('')<0: excerpt+=' ...' % urljoin(urlbase,link) else: excerpt+='\n

...

' % urljoin(urlbase,link) if not parent and not query and str(flavor).startswith('html'): if not children: excerpt=body thrcount, thrupdated = comments(entry, blogdir) # add to the list of items children.append({ 'entry': entry, 'title': title, 'link': link, 'guid': guid, 'id': id, 'filename': filename, 'mtime': time.gmtime(mtime), 'description': excerpt or body, 'content': body, 'comments': thrcount, 'lastcomment': thrupdated }) ####################################################################### # Apply the template # ####################################################################### if parent and flavor=='html': flavor='comment' if flavor=='tb': flavor='tbform' if flavor=='atomapi': flavor='atom' if 'entry' in parent: Items = [parent]+children else: Items = children maxtime = time.mktime(max([item['mtime'] for item in Items] or [[0]*9])) age = int(time.time() - maxtime) / 86400 import template data={'Items':Items, 'children':children, 'parent':parent, 'path':path, 'age':age, 'archive': archivedir} return template.apply(flavor, [data, config]) ######################################################################### # Count the number of comments # ######################################################################### def comments(entry, blogdir): thr_count = 0 thr_when = 0 try: cmtPattern = re.compile(entry+"-.*\.cmt") for name in blogdir: if cmtPattern.match(name): thr_count += 1 thr_when = max(thr_when, os.stat(name).st_mtime) except: pass return thr_count, thr_when if __name__ == '__main__': import os,sys from config import directory os.chdir(directory.data) if directory.codebase not in sys.path: sys.path.insert(0, directory.codebase) os.environ["REQUEST_URI"]="REQUEST_URI" os.environ["SERVER_NAME"]="SERVER_NAME" os.environ["SERVER_PORT"]="SERVER_PORT" os.environ["SERVER_SOFTWARE"]="SERVER_SOFTWARE" for path in sys.argv[1:]: print format(path)