-
Notifications
You must be signed in to change notification settings - Fork 51
/
resthooks.py
101 lines (86 loc) · 3.23 KB
/
resthooks.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
from flask import Flask, Markup
from flask import request, send_from_directory, render_template, render_template_string
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
def __init__(self, url_map, *items):
super(RegexConverter, self).__init__(url_map)
self.regex = items[0]
app = Flask(__name__)
app.config.from_pyfile('config.py')
app.url_map.converters['regex'] = RegexConverter
from flask_flatpages import FlatPages
pages = FlatPages(app)
import misaka
import operator
import os
import houdini
import datetime
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import HtmlFormatter
ROOT = os.path.dirname(os.path.realpath(__file__))
STATIC_URL = app.config['STATIC_URL']
POSTS_PER_PAGE = app.config['POSTS_PER_PAGE']
FLATPAGES_EXTENSION = app.config['FLATPAGES_EXTENSION']
DEBUG = app.config['DEBUG']
GLOBAL_CONTEXT = {
'STATIC_URL': STATIC_URL,
'now': datetime.datetime.now()
}
@app.route('/')
def index():
return render_template('index.html', **GLOBAL_CONTEXT)
@app.route('/favicon.ico')
def favicon():
return send_from_directory(ROOT + app.config['STATIC_URL'], 'favicon.ico')
@app.route('/<regex("[-a-zA-z0-9/]+"):slug>/')
def post(slug):
"""
Render a single post to the screen by slug `post` or 404
"""
p = pages.get(slug)
if p:
context = GLOBAL_CONTEXT.copy()
context.update(p.meta)
md = render_markdown(render_template_string(p.body, **context))
post = {
'content': md,
'meta': p.meta,
'path': p.path,
'caption': smart_truncate(md.striptags(), 120, '...'),
}
return render_template('post.html', post=post, **GLOBAL_CONTEXT)
else:
return render_template('404.html', **GLOBAL_CONTEXT)
@app.route('/static/css/pygments.css')
def pygments_css():
style = HtmlFormatter(style='monokai').get_style_defs('div.highlight')
if DEBUG:
with open('static/css/pygments.css', 'w') as f:
f.write(style)
return style, 200, {'Content-Type': 'text/css'}
def smart_truncate(content, length=100, suffix='...'):
if len(content) <= length:
return content
else:
return ' '.join(content[:length+1].split(' ')[0:-1]) + suffix
def render_markdown(md):
class CustomRenderer(misaka.HtmlRenderer, misaka.SmartyPants):
def block_code(self, text, lang):
if not lang:
return '\n<pre><code>%s</code></pre>\n' % \
houdini.escape_html(text.strip())
lexer = get_lexer_by_name(lang, stripall=True)
formatter = HtmlFormatter()
return highlight(text, lexer, formatter)
markdown = misaka.Markdown(
renderer=CustomRenderer(),
extensions=reduce(operator.or_, [misaka.EXT_FENCED_CODE,
misaka.EXT_STRIKETHROUGH,
misaka.EXT_NO_INTRA_EMPHASIS,
misaka.EXT_TABLES,
misaka.EXT_AUTOLINK,
misaka.EXT_SPACE_HEADERS]))
return Markup(markdown.render(md))
if __name__ == "__main__":
app.run(threaded=True)