-
Notifications
You must be signed in to change notification settings - Fork 4
/
xkcd2.py
112 lines (80 loc) · 2.91 KB
/
xkcd2.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
102
103
104
105
106
107
108
109
110
111
112
# coding=utf-8
import httplib2
import json
import re
from flask import Flask, render_template, redirect, url_for
from path import path
from typogrify import filters as jinja2_filters
try:
import cPickle as pickle
except ImportError:
import pickle
__author__ = 'tyler@tylerbutler.com'
app = Flask(__name__)
app.debug = True
class InvalidComicException(Exception):
pass
@app.route('/')
def home():
"""Retrieves the current comic on the xkcd.com homepage and displays it on xkcd2.com."""
return render_template('base.html', **get_comic())
@app.route('/<int:comic_id>/')
def comic(comic_id):
""""
Retrieves the comic specified by comic_id from xkcd.com and displays it on xkcd2.com.
If the comic is not found, redirects to the home page.
"""
try:
return render_template('base.html', **get_comic(comic_id))
except InvalidComicException:
return redirect(url_for('home'))
_regex = re.compile(r'^http://(?P<domain>.*)/(?P<comic>.*)/$')
@app.route('/random/')
def random():
"""Loads a random comic from xkcd.com."""
h = httplib2.Http('_cache')
resp, content = h.request('http://dynamic.xkcd.com/random/comic/', 'GET')
url = resp['content-location']
comic_id = re.match(_regex, url).group('comic')
return redirect(url_for('comic', comic_id=comic_id))
@app.route('/about/')
def about():
return redirect('http://tylerbutler.com/projects/xkcd2/')
def get_comic(comic_id=None):
"""Retrieves a comic with a specific ID from xkcd.com and returns relevant metadata."""
if comic_id is not None:
url = 'http://xkcd.com/%s/info.0.json' % comic_id
else:
url = 'http://xkcd.com/info.0.json'
# get the comic page using httplib2, which handles most of the caching for us <3
h = httplib2.Http('_cache')
resp, content = h.request(url, 'GET')
if resp['status'] in ('404', '500', '401'):
raise InvalidComicException('Invalid comic id %s' % comic_id)
content = unicode(content, encoding='utf8')
cache_file = path(__file__).dirname() / ('_cache/%s.xkcd' % comic_id)
if resp.fromcache and cache_file.exists(): # check if httplib2 loaded the page from its own cache
with open(cache_file, mode='rb') as f:
cache = pickle.load(f)
else:
doc = json.loads(content.strip())
comic_title = doc['safe_title']
comic_src = doc['img']
comic_img_title = doc['alt']
# parse out the comic_id if we need to...
if comic_id is None:
comic_id = doc['num']
cache = {
'comic_title': comic_title,
'comic_src': comic_src,
'comic_img_title': comic_img_title,
'comic_id': comic_id,
}
with open(cache_file, mode='wb') as f:
pickle.dump(cache, f)
return cache
@app.template_filter()
def typogrify(s):
return jinja2_filters.typogrify(s)
if __name__ == "__main__":
app.run()