-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathapp.py
91 lines (73 loc) · 2.97 KB
/
app.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
import json, github, io, flask_wtf, flask_wtf.file, wtforms, flask_cors
from flask import Flask, Blueprint, send_file, render_template, flash, Markup
from flask_restx import Api, Resource
from keyboard import Keyboard
app = Flask(__name__)
app.config.from_object('config')
flask_cors.CORS(app)
github_api = github.Github(app.config['API_TOKEN'])
blueprint = Blueprint('api', __name__, url_prefix='/api')
api = Api(
blueprint, version='1.0', title='KLE-Render API',
description='Prettier images of Keyboard Layout Editor designs. URLs relative to this page'
)
kle_parser = api.parser()
kle_parser.add_argument(
'data', required=True, location='json',
help='Downloaded strict JSON from Raw Data tab of Keyboard Layout Editor'
)
app.register_blueprint(blueprint)
def serve_pil_image(pil_img):
img_io = io.BytesIO()
pil_img.save(img_io, 'PNG', compress_level=3)
img_io.seek(0)
return send_file(img_io, mimetype='image/png')
@api.route('/<id>')
@api.param('id', 'Copy from keyboard-layout-editor.com/#/gists/<id>')
class FromGist(Resource):
def get(self, id):
files = github_api.get_gist(id).files
layout = next(v for k, v in files.items() if k.endswith('.kbd.json'))
img = Keyboard(json.loads(layout.content)).render()
return serve_pil_image(img)
@api.route('/')
@api.expect(kle_parser)
class FromJSON(Resource):
def post(self):
img = Keyboard(api.payload).render()
return serve_pil_image(img)
@api.errorhandler(github.GithubException)
def not_found(error):
return {'message': error.message}, 404
class InputForm(flask_wtf.FlaskForm):
url = wtforms.StringField('Copy the URL of a saved layout:')
valid = [flask_wtf.file.FileAllowed(['json'], 'Upload must be JSON')]
json = flask_wtf.file.FileField('Or upload raw JSON:', validators=valid)
def flash_errors(form):
for field, errors in form.errors.items():
for error in errors:
flash(error)
@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
def index():
form = InputForm()
if form.validate_on_submit():
if len(form.url.data) > 0:
try:
files = github_api.get_gist(form.url.data.split('gists/', 1)[1]).files
layout = next(v for k, v in files.items() if k.endswith('.kbd.json'))
img = Keyboard(json.loads(layout.content)).render()
return serve_pil_image(img)
except (IndexError, github.GithubException):
flash('Not a valid Keyboard Layout Editor gist')
elif form.json.data:
try:
content = json.loads(form.json.data.read().decode('utf-8'))
img = Keyboard(content).render()
return serve_pil_image(img)
except ValueError:
flash(Markup('Invalid JSON input - see (?) for help'))
flash_errors(form)
return render_template('index.html', form=form)
if __name__ == '__main__':
app.run(debug=True)