blog.py (3063B) - raw
1 2 # vim:fileencoding=utf-8 3 4 import os 5 import re 6 import email 7 from datetime import datetime 8 import genshi.template 9 import lxml.etree 10 11 import constance 12 import viewutils 13 14 template_loader = genshi.template.TemplateLoader( 15 os.path.join(os.path.realpath(os.path.dirname(__file__)), 'templates', 'blog'), 16 variable_lookup='strict') 17 18 def cleanup_metadata(header_items): 19 cleaned = {} 20 for k, v in header_items: 21 k = k.lower() 22 if k.endswith('date'): 23 v = datetime.strptime(v, '%Y-%m-%d %H:%M:%S') 24 else: 25 v = v.decode('utf8') # XXX encoding 26 cleaned[k] = v 27 return cleaned 28 29 class BlogEntry(object): 30 31 def __init__(self, dir, name): 32 content_filename = os.path.join(dir, name + '.txt') 33 self.id = name.decode('utf8') 34 35 # not really a MIME document, but parse it like one 36 msg = email.message_from_file(open(content_filename, 'r')) 37 self.metadata = cleanup_metadata(msg.items()) 38 self.body = viewutils.markdown(msg.get_payload().decode('utf8')) 39 self.title = viewutils.mini_markdown(self.metadata['title']) 40 41 raw_tags = self.metadata.get('tags', '').strip() 42 if raw_tags: 43 self.tags = frozenset(tag.strip() for tag in raw_tags.split(',')) 44 else: 45 self.tags = frozenset() 46 47 self.modified_date = datetime.fromtimestamp(os.path.getmtime(content_filename)) 48 self.publication_date = self.metadata.get('publication-date', None) or self.modified_date 49 self.guid = self.metadata['guid'] 50 self.language = self.metadata.get('language', None) 51 52 def generate_atom(self, config): 53 return template_loader.load('entry.atom').generate(item=self, 54 config=config) 55 56 class BlogEntrySet(object): 57 58 def __init__(self, dir): 59 self.dir = dir 60 self.entries = [] 61 for filename in os.listdir(dir): 62 m = re.match(r'([^.].*)\.txt$', filename) 63 if m: 64 self.entries.append(BlogEntry(dir, m.group(1))) 65 66 def __iter__(self): 67 return iter(self.entries) 68 69 def __len__(self): 70 return len(self.entries) 71 72 def generate(dir, xslt, config): 73 entries = BlogEntrySet(dir) 74 75 for entry in entries: 76 rendered = template_loader.load('entry.html').generate(item=entry, 77 config=config).render('xhtml', encoding='utf8') 78 transformed = str(xslt(lxml.etree.fromstring(rendered))) 79 constance.output(os.path.join(dir, entry.id.encode('utf8') + '.html'), transformed) 80 81 # index 82 rendered = template_loader.load('index.html').generate(items=entries, 83 config=config).render('xhtml', encoding='utf8') 84 transformed = str(xslt(lxml.etree.fromstring(rendered))) 85 constance.output(os.path.join(dir, 'index.html'), transformed) 86 87 # feed 88 rendered = template_loader.load('index.atom').generate(items=entries, 89 config=config).render('xml', encoding='utf8') 90 constance.output(os.path.join(dir, 'index.atom'), rendered) 91 92 return entries