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