mirror of
https://github.com/beetbox/beets.git
synced 2025-12-20 23:53:15 +01:00
CORS support now uses flask-cor extension
This commit is contained in:
parent
c8880de52c
commit
f47be23658
3 changed files with 12 additions and 88 deletions
|
|
@ -22,7 +22,6 @@ from flask import g
|
|||
from werkzeug.routing import BaseConverter, PathConverter
|
||||
import os
|
||||
import json
|
||||
from crossdomaindec import crossdomain, set_cors_origin
|
||||
|
||||
# Utilities.
|
||||
|
||||
|
|
@ -165,7 +164,6 @@ def before_request():
|
|||
# Items.
|
||||
|
||||
@app.route('/item/<idlist:ids>')
|
||||
@crossdomain()
|
||||
@resource('items')
|
||||
def get_item(id):
|
||||
return g.lib.get_item(id)
|
||||
|
|
@ -173,14 +171,12 @@ def get_item(id):
|
|||
|
||||
@app.route('/item/')
|
||||
@app.route('/item/query/')
|
||||
@crossdomain()
|
||||
@resource_list('items')
|
||||
def all_items():
|
||||
return g.lib.items()
|
||||
|
||||
|
||||
@app.route('/item/<int:item_id>/file')
|
||||
@crossdomain()
|
||||
def item_file(item_id):
|
||||
item = g.lib.get_item(item_id)
|
||||
response = flask.send_file(item.path, as_attachment=True,
|
||||
|
|
@ -190,7 +186,6 @@ def item_file(item_id):
|
|||
|
||||
|
||||
@app.route('/item/query/<query:queries>')
|
||||
@crossdomain()
|
||||
@resource_query('items')
|
||||
def item_query(queries):
|
||||
return g.lib.items(queries)
|
||||
|
|
@ -199,7 +194,6 @@ def item_query(queries):
|
|||
# Albums.
|
||||
|
||||
@app.route('/album/<idlist:ids>')
|
||||
@crossdomain()
|
||||
@resource('albums')
|
||||
def get_album(id):
|
||||
return g.lib.get_album(id)
|
||||
|
|
@ -207,21 +201,18 @@ def get_album(id):
|
|||
|
||||
@app.route('/album/')
|
||||
@app.route('/album/query/')
|
||||
@crossdomain()
|
||||
@resource_list('albums')
|
||||
def all_albums():
|
||||
return g.lib.albums()
|
||||
|
||||
|
||||
@app.route('/album/query/<query:queries>')
|
||||
@crossdomain()
|
||||
@resource_query('albums')
|
||||
def album_query(queries):
|
||||
return g.lib.albums(queries)
|
||||
|
||||
|
||||
@app.route('/album/<int:album_id>/art')
|
||||
@crossdomain()
|
||||
def album_art(album_id):
|
||||
album = g.lib.get_album(album_id)
|
||||
return flask.send_file(album.artpath)
|
||||
|
|
@ -230,7 +221,6 @@ def album_art(album_id):
|
|||
# Artists.
|
||||
|
||||
@app.route('/artist/')
|
||||
@crossdomain()
|
||||
def all_artists():
|
||||
with g.lib.transaction() as tx:
|
||||
rows = tx.query("SELECT DISTINCT albumartist FROM albums")
|
||||
|
|
@ -241,7 +231,6 @@ def all_artists():
|
|||
# Library information.
|
||||
|
||||
@app.route('/stats')
|
||||
@crossdomain()
|
||||
def stats():
|
||||
with g.lib.transaction() as tx:
|
||||
item_rows = tx.query("SELECT COUNT(*) FROM items")
|
||||
|
|
@ -267,7 +256,8 @@ class WebPlugin(BeetsPlugin):
|
|||
self.config.add({
|
||||
'host': u'127.0.0.1',
|
||||
'port': 8337,
|
||||
'cors_origin': 'http://127.0.0.1',
|
||||
'cors': False,
|
||||
'cors_origin': '*',
|
||||
})
|
||||
|
||||
def commands(self):
|
||||
|
|
@ -282,9 +272,16 @@ class WebPlugin(BeetsPlugin):
|
|||
if args:
|
||||
self.config['port'] = int(args.pop(0))
|
||||
|
||||
set_cors_origin(self.config['cors_origin'])
|
||||
|
||||
app.config['lib'] = lib
|
||||
|
||||
## Enable CORS if required
|
||||
if self.config['cors']:
|
||||
from flask.ext.cors import CORS
|
||||
app.config['CORS_ALLOW_HEADERS'] = "Content-Type"
|
||||
app.config['CORS_RESOURCES'] = {
|
||||
r"/*": {"origins": self.config['cors_origin'].get(str)}
|
||||
}
|
||||
cors = CORS(app)
|
||||
app.run(host=self.config['host'].get(unicode),
|
||||
port=self.config['port'].get(int),
|
||||
debug=opts.debug, threaded=True)
|
||||
|
|
|
|||
|
|
@ -1,73 +0,0 @@
|
|||
# Decorator for the HTTP Access Control
|
||||
# By Armin Ronacher
|
||||
# http://flask.pocoo.org/snippets/56/
|
||||
#
|
||||
# Cross-site HTTP requests are HTTP requests for resources from a different
|
||||
# domain than the domain of the resource making the request.
|
||||
# For instance, a resource loaded from Domain A makes a request for a resource
|
||||
# on Domain B. The way this is implemented in modern browsers is by using
|
||||
# HTTP Access Control headers
|
||||
#
|
||||
# https://developer.mozilla.org/en/HTTP_access_control
|
||||
#
|
||||
# The following view decorator implements this
|
||||
#
|
||||
# Note that some changes have been made to the original snippet
|
||||
# to allow changing the CORS origin after the decorator has been attached
|
||||
# This was done because the flask routing functions are defined before the
|
||||
# beetsplug hook is called.
|
||||
|
||||
from datetime import timedelta
|
||||
from flask import make_response, request, current_app
|
||||
from functools import update_wrapper
|
||||
|
||||
cors_origin = 'http://127.0.0.1'
|
||||
|
||||
|
||||
def set_cors_origin(origin):
|
||||
global cors_origin
|
||||
cors_origin = origin
|
||||
|
||||
|
||||
def get_cors_origin():
|
||||
return cors_origin
|
||||
|
||||
|
||||
def crossdomain(methods=None, headers=None,
|
||||
max_age=21600, attach_to_all=True,
|
||||
automatic_options=True):
|
||||
if methods is not None:
|
||||
methods = ', '.join(sorted(x.upper() for x in methods))
|
||||
if headers is not None and not isinstance(headers, basestring):
|
||||
headers = ', '.join(x.upper() for x in headers)
|
||||
if isinstance(max_age, timedelta):
|
||||
max_age = max_age.total_seconds()
|
||||
|
||||
def get_methods():
|
||||
if methods is not None:
|
||||
return methods
|
||||
|
||||
options_resp = current_app.make_default_options_response()
|
||||
return options_resp.headers['allow']
|
||||
|
||||
def decorator(f):
|
||||
def wrapped_function(*args, **kwargs):
|
||||
if automatic_options and request.method == 'OPTIONS':
|
||||
resp = current_app.make_default_options_response()
|
||||
else:
|
||||
resp = make_response(f(*args, **kwargs))
|
||||
if not attach_to_all and request.method != 'OPTIONS':
|
||||
return resp
|
||||
|
||||
h = resp.headers
|
||||
|
||||
h['Access-Control-Allow-Origin'] = get_cors_origin()
|
||||
h['Access-Control-Allow-Methods'] = get_methods()
|
||||
h['Access-Control-Max-Age'] = str(max_age)
|
||||
if headers is not None:
|
||||
h['Access-Control-Allow-Headers'] = headers
|
||||
return resp
|
||||
|
||||
f.provide_automatic_options = False
|
||||
return update_wrapper(wrapped_function, f)
|
||||
return decorator
|
||||
2
setup.py
2
setup.py
|
|
@ -102,7 +102,7 @@ setup(
|
|||
'echonest': ['pyechonest'],
|
||||
'lastgenre': ['pylast'],
|
||||
'mpdstats': ['python-mpd'],
|
||||
'web': ['flask'],
|
||||
'web': ['flask', 'flask-cors'],
|
||||
'import': ['rarfile'],
|
||||
},
|
||||
# Non-Python/non-PyPI plugin dependencies:
|
||||
|
|
|
|||
Loading…
Reference in a new issue