1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-09-20 03:11:04 +00:00

API as blueprint

Ref #76
This commit is contained in:
spl0k 2018-01-28 22:50:21 +01:00
parent aedda4f642
commit 0de87e64b0
11 changed files with 79 additions and 82 deletions

View File

@ -24,7 +24,7 @@ import binascii
import uuid import uuid
from flask import request from flask import request
from flask import current_app as app from flask import Blueprint
from pony.orm import db_session, ObjectNotFound from pony.orm import db_session, ObjectNotFound
from ..managers.user import UserManager from ..managers.user import UserManager
@ -33,11 +33,10 @@ from ..py23 import dict
from .formatters import make_json_response, make_jsonp_response, make_xml_response from .formatters import make_json_response, make_jsonp_response, make_xml_response
from .formatters import make_error_response_func from .formatters import make_error_response_func
@app.before_request api = Blueprint('api', __name__)
def set_formatter():
if not request.path.startswith('/rest/'):
return
@api.before_request
def set_formatter():
"""Return a function to create the response.""" """Return a function to create the response."""
f, callback = map(request.values.get, ['f', 'callback']) f, callback = map(request.values.get, ['f', 'callback'])
if f == 'jsonp': if f == 'jsonp':
@ -58,11 +57,8 @@ def decode_password(password):
except: except:
return password return password
@app.before_request @api.before_request
def authorize(): def authorize():
if not request.path.startswith('/rest/'):
return
error = request.error_formatter(40, 'Unauthorized'), 401 error = request.error_formatter(40, 'Unauthorized'), 401
if request.authorization: if request.authorization:
@ -84,11 +80,8 @@ def authorize():
request.username = username request.username = username
request.user = user request.user = user
@app.before_request @api.before_request
def get_client_prefs(): def get_client_prefs():
if not request.path.startswith('/rest/'):
return
if 'c' not in request.values: if 'c' not in request.values:
return request.error_formatter(10, 'Missing required parameter') return request.error_formatter(10, 'Missing required parameter')
@ -101,11 +94,9 @@ def get_client_prefs():
request.client = client request.client = client
@app.errorhandler(404) #@api.errorhandler(404)
def not_found(error): @api.route('/<path:invalid>', methods = [ 'GET', 'POST' ]) # blueprint 404 workaround
if not request.path.startswith('/rest/'): def not_found(*args, **kwargs):
return error
return request.error_formatter(0, 'Not implemented'), 501 return request.error_formatter(0, 'Not implemented'), 501
def get_entity(req, cls, param = 'id'): def get_entity(req, cls, param = 'id'):

View File

@ -22,14 +22,15 @@ import random
import uuid import uuid
from datetime import timedelta from datetime import timedelta
from flask import request, current_app as app from flask import request
from pony.orm import db_session, select, desc, avg, max, min, count from pony.orm import db_session, select, desc, avg, max, min, count
from ..db import Folder, Artist, Album, Track, RatingFolder, StarredFolder, StarredArtist, StarredAlbum, StarredTrack, User from ..db import Folder, Artist, Album, Track, RatingFolder, StarredFolder, StarredArtist, StarredAlbum, StarredTrack, User
from ..db import now from ..db import now
from ..py23 import dict from ..py23 import dict
from . import api
@app.route('/rest/getRandomSongs.view', methods = [ 'GET', 'POST' ]) @api.route('/getRandomSongs.view', methods = [ 'GET', 'POST' ])
def rand_songs(): def rand_songs():
size = request.values.get('size', '10') size = request.values.get('size', '10')
genre, fromYear, toYear, musicFolderId = map(request.values.get, [ 'genre', 'fromYear', 'toYear', 'musicFolderId' ]) genre, fromYear, toYear, musicFolderId = map(request.values.get, [ 'genre', 'fromYear', 'toYear', 'musicFolderId' ])
@ -63,7 +64,7 @@ def rand_songs():
) )
)) ))
@app.route('/rest/getAlbumList.view', methods = [ 'GET', 'POST' ]) @api.route('/getAlbumList.view', methods = [ 'GET', 'POST' ])
def album_list(): def album_list():
ltype, size, offset = map(request.values.get, [ 'type', 'size', 'offset' ]) ltype, size, offset = map(request.values.get, [ 'type', 'size', 'offset' ])
if not ltype: if not ltype:
@ -106,7 +107,7 @@ def album_list():
) )
)) ))
@app.route('/rest/getAlbumList2.view', methods = [ 'GET', 'POST' ]) @api.route('/getAlbumList2.view', methods = [ 'GET', 'POST' ])
def album_list_id3(): def album_list_id3():
ltype, size, offset = map(request.values.get, [ 'type', 'size', 'offset' ]) ltype, size, offset = map(request.values.get, [ 'type', 'size', 'offset' ])
if not ltype: if not ltype:
@ -147,7 +148,7 @@ def album_list_id3():
) )
)) ))
@app.route('/rest/getNowPlaying.view', methods = [ 'GET', 'POST' ]) @api.route('/getNowPlaying.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def now_playing(): def now_playing():
query = User.select(lambda u: u.last_play is not None and u.last_play_date + timedelta(minutes = 3) > now()) query = User.select(lambda u: u.last_play is not None and u.last_play_date + timedelta(minutes = 3) > now())
@ -161,7 +162,7 @@ def now_playing():
) )
)) ))
@app.route('/rest/getStarred.view', methods = [ 'GET', 'POST' ]) @api.route('/getStarred.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def get_starred(): def get_starred():
folders = select(s.starred for s in StarredFolder if s.user.id == request.user.id) folders = select(s.starred for s in StarredFolder if s.user.id == request.user.id)
@ -174,7 +175,7 @@ def get_starred():
) )
)) ))
@app.route('/rest/getStarred2.view', methods = [ 'GET', 'POST' ]) @api.route('/getStarred2.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def get_starred_id3(): def get_starred_id3():
return request.formatter(dict( return request.formatter(dict(

View File

@ -21,7 +21,7 @@
import time import time
import uuid import uuid
from flask import request, current_app as app from flask import current_app, request
from pony.orm import db_session, delete from pony.orm import db_session, delete
from pony.orm import ObjectNotFound from pony.orm import ObjectNotFound
@ -31,7 +31,7 @@ from ..db import RatingTrack, RatingFolder
from ..lastfm import LastFm from ..lastfm import LastFm
from ..py23 import dict from ..py23 import dict
from . import get_entity from . import api, get_entity
@db_session @db_session
def try_star(cls, starred_cls, eid): def try_star(cls, starred_cls, eid):
@ -88,7 +88,7 @@ def merge_errors(errors):
return error return error
@app.route('/rest/star.view', methods = [ 'GET', 'POST' ]) @api.route('/star.view', methods = [ 'GET', 'POST' ])
def star(): def star():
id, albumId, artistId = map(request.values.getlist, [ 'id', 'albumId', 'artistId' ]) id, albumId, artistId = map(request.values.getlist, [ 'id', 'albumId', 'artistId' ])
@ -111,7 +111,7 @@ def star():
error = merge_errors(errors) error = merge_errors(errors)
return request.formatter(dict(error = error), error = True) if error else request.formatter(dict()) return request.formatter(dict(error = error), error = True) if error else request.formatter(dict())
@app.route('/rest/unstar.view', methods = [ 'GET', 'POST' ]) @api.route('/unstar.view', methods = [ 'GET', 'POST' ])
def unstar(): def unstar():
id, albumId, artistId = map(request.values.getlist, [ 'id', 'albumId', 'artistId' ]) id, albumId, artistId = map(request.values.getlist, [ 'id', 'albumId', 'artistId' ])
@ -134,7 +134,7 @@ def unstar():
error = merge_errors(errors) error = merge_errors(errors)
return request.formatter(dict(error = error), error = True) if error else request.formatter(dict()) return request.formatter(dict(error = error), error = True) if error else request.formatter(dict())
@app.route('/rest/setRating.view', methods = [ 'GET', 'POST' ]) @api.route('/setRating.view', methods = [ 'GET', 'POST' ])
def rate(): def rate():
id, rating = map(request.values.get, [ 'id', 'rating' ]) id, rating = map(request.values.get, [ 'id', 'rating' ])
if not id or not rating: if not id or not rating:
@ -172,7 +172,7 @@ def rate():
return request.formatter(dict()) return request.formatter(dict())
@app.route('/rest/scrobble.view', methods = [ 'GET', 'POST' ]) @api.route('/scrobble.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def scrobble(): def scrobble():
status, res = get_entity(request, Track) status, res = get_entity(request, Track)
@ -189,7 +189,7 @@ def scrobble():
else: else:
t = int(time.time()) t = int(time.time())
lfm = LastFm(app.config['LASTFM'], User[request.user.id], app.logger) lfm = LastFm(current_app.config['LASTFM'], User[request.user.id], current_app.logger)
if submission in (None, '', True, 'true', 'True', 1, '1'): if submission in (None, '', True, 'true', 'True', 1, '1'):
lfm.scrobble(res, t) lfm.scrobble(res, t)

View File

@ -21,16 +21,16 @@
import string import string
import uuid import uuid
from flask import request, current_app as app from flask import request
from pony.orm import db_session from pony.orm import db_session
from pony.orm import ObjectNotFound from pony.orm import ObjectNotFound
from ..db import Folder, Artist, Album, Track from ..db import Folder, Artist, Album, Track
from ..py23 import dict from ..py23 import dict
from . import get_entity from . import api, get_entity
@app.route('/rest/getMusicFolders.view', methods = [ 'GET', 'POST' ]) @api.route('/getMusicFolders.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def list_folders(): def list_folders():
return request.formatter(dict( return request.formatter(dict(
@ -42,7 +42,7 @@ def list_folders():
) )
)) ))
@app.route('/rest/getIndexes.view', methods = [ 'GET', 'POST' ]) @api.route('/getIndexes.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def list_indexes(): def list_indexes():
musicFolderId = request.values.get('musicFolderId') musicFolderId = request.values.get('musicFolderId')
@ -105,7 +105,7 @@ def list_indexes():
) )
)) ))
@app.route('/rest/getMusicDirectory.view', methods = [ 'GET', 'POST' ]) @api.route('/getMusicDirectory.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def show_directory(): def show_directory():
status, res = get_entity(request, Folder) status, res = get_entity(request, Folder)
@ -122,7 +122,7 @@ def show_directory():
return request.formatter(dict(directory = directory)) return request.formatter(dict(directory = directory))
@app.route('/rest/getArtists.view', methods = [ 'GET', 'POST' ]) @api.route('/getArtists.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def list_artists(): def list_artists():
# According to the API page, there are no parameters? # According to the API page, there are no parameters?
@ -148,7 +148,7 @@ def list_artists():
) )
)) ))
@app.route('/rest/getArtist.view', methods = [ 'GET', 'POST' ]) @api.route('/getArtist.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def artist_info(): def artist_info():
status, res = get_entity(request, Artist) status, res = get_entity(request, Artist)
@ -162,7 +162,7 @@ def artist_info():
return request.formatter(dict(artist = info)) return request.formatter(dict(artist = info))
@app.route('/rest/getAlbum.view', methods = [ 'GET', 'POST' ]) @api.route('/getAlbum.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def album_info(): def album_info():
status, res = get_entity(request, Album) status, res = get_entity(request, Album)
@ -174,7 +174,7 @@ def album_info():
return request.formatter(dict(album = info)) return request.formatter(dict(album = info))
@app.route('/rest/getSong.view', methods = [ 'GET', 'POST' ]) @api.route('/getSong.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def track_info(): def track_info():
status, res = get_entity(request, Track) status, res = get_entity(request, Track)
@ -183,7 +183,7 @@ def track_info():
return request.formatter(dict(song = res.as_subsonic_child(request.user, request.client))) return request.formatter(dict(song = res.as_subsonic_child(request.user, request.client)))
@app.route('/rest/getVideos.view', methods = [ 'GET', 'POST' ]) @api.route('/getVideos.view', methods = [ 'GET', 'POST' ])
def list_videos(): def list_videos():
return request.error_formatter(0, 'Video streaming not supported') return request.error_formatter(0, 'Video streaming not supported')

View File

@ -18,13 +18,14 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from flask import request, current_app as app from flask import request
from pony.orm import db_session from pony.orm import db_session
from ..db import ChatMessage, User from ..db import ChatMessage, User
from ..py23 import dict from ..py23 import dict
from . import api
@app.route('/rest/getChatMessages.view', methods = [ 'GET', 'POST' ]) @api.route('/getChatMessages.view', methods = [ 'GET', 'POST' ])
def get_chat(): def get_chat():
since = request.values.get('since') since = request.values.get('since')
try: try:
@ -39,7 +40,7 @@ def get_chat():
return request.formatter(dict(chatMessages = dict(chatMessage = [ msg.responsize() for msg in query ] ))) return request.formatter(dict(chatMessages = dict(chatMessage = [ msg.responsize() for msg in query ] )))
@app.route('/rest/addChatMessage.view', methods = [ 'GET', 'POST' ]) @api.route('/addChatMessage.view', methods = [ 'GET', 'POST' ])
def add_chat_message(): def add_chat_message():
msg = request.values.get('message') msg = request.values.get('message')
if not msg: if not msg:

View File

@ -24,7 +24,8 @@ import os.path
import requests import requests
import subprocess import subprocess
from flask import request, send_file, Response, current_app as app from flask import request, Response, send_file
from flask import current_app
from PIL import Image from PIL import Image
from pony.orm import db_session from pony.orm import db_session
from xml.etree import ElementTree from xml.etree import ElementTree
@ -33,7 +34,7 @@ from .. import scanner
from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now
from ..py23 import dict from ..py23 import dict
from . import get_entity from . import api, get_entity
def prepare_transcoding_cmdline(base_cmdline, input_file, input_format, output_format, output_bitrate): def prepare_transcoding_cmdline(base_cmdline, input_file, input_format, output_format, output_bitrate):
if not base_cmdline: if not base_cmdline:
@ -45,7 +46,7 @@ def prepare_transcoding_cmdline(base_cmdline, input_file, input_format, output_f
] ]
return ret return ret
@app.route('/rest/stream.view', methods = [ 'GET', 'POST' ]) @api.route('/stream.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def stream_media(): def stream_media():
status, res = get_entity(request, Track) status, res = get_entity(request, Track)
@ -81,7 +82,7 @@ def stream_media():
dst_mimetype = mimetypes.guess_type('dummyname.' + dst_suffix, False)[0] or 'application/octet-stream' dst_mimetype = mimetypes.guess_type('dummyname.' + dst_suffix, False)[0] or 'application/octet-stream'
if format != 'raw' and (dst_suffix != src_suffix or dst_bitrate != res.bitrate): if format != 'raw' and (dst_suffix != src_suffix or dst_bitrate != res.bitrate):
config = app.config['TRANSCODING'] config = current_app.config['TRANSCODING']
transcoder = config.get('transcoder_{}_{}'.format(src_suffix, dst_suffix)) transcoder = config.get('transcoder_{}_{}'.format(src_suffix, dst_suffix))
decoder = config.get('decoder_' + src_suffix) or config.get('decoder') decoder = config.get('decoder_' + src_suffix) or config.get('decoder')
encoder = config.get('encoder_' + dst_suffix) or config.get('encoder') encoder = config.get('encoder_' + dst_suffix) or config.get('encoder')
@ -89,7 +90,7 @@ def stream_media():
transcoder = config.get('transcoder') transcoder = config.get('transcoder')
if not transcoder: if not transcoder:
message = 'No way to transcode from {} to {}'.format(src_suffix, dst_suffix) message = 'No way to transcode from {} to {}'.format(src_suffix, dst_suffix)
app.logger.info(message) current_app.logger.info(message)
return request.error_formatter(0, message) return request.error_formatter(0, message)
transcoder, decoder, encoder = map(lambda x: prepare_transcoding_cmdline(x, res.path, src_suffix, dst_suffix, dst_bitrate), [ transcoder, decoder, encoder ]) transcoder, decoder, encoder = map(lambda x: prepare_transcoding_cmdline(x, res.path, src_suffix, dst_suffix, dst_bitrate), [ transcoder, decoder, encoder ])
@ -119,7 +120,7 @@ def stream_media():
dec_proc.wait() dec_proc.wait()
proc.wait() proc.wait()
app.logger.info('Transcoding track {0.id} for user {1.id}. Source: {2} at {0.bitrate}kbps. Dest: {3} at {4}kbps'.format(res, request.user, src_suffix, dst_suffix, dst_bitrate)) current_app.logger.info('Transcoding track {0.id} for user {1.id}. Source: {2} at {0.bitrate}kbps. Dest: {3} at {4}kbps'.format(res, request.user, src_suffix, dst_suffix, dst_bitrate))
response = Response(transcode(), mimetype = dst_mimetype) response = Response(transcode(), mimetype = dst_mimetype)
else: else:
response = send_file(res.path, mimetype = dst_mimetype, conditional=True) response = send_file(res.path, mimetype = dst_mimetype, conditional=True)
@ -132,7 +133,7 @@ def stream_media():
return response return response
@app.route('/rest/download.view', methods = [ 'GET', 'POST' ]) @api.route('/download.view', methods = [ 'GET', 'POST' ])
def download_media(): def download_media():
with db_session: with db_session:
status, res = get_entity(request, Track) status, res = get_entity(request, Track)
@ -141,7 +142,7 @@ def download_media():
return send_file(res.path, mimetype = res.content_type, conditional=True) return send_file(res.path, mimetype = res.content_type, conditional=True)
@app.route('/rest/getCoverArt.view', methods = [ 'GET', 'POST' ]) @api.route('/getCoverArt.view', methods = [ 'GET', 'POST' ])
def cover_art(): def cover_art():
with db_session: with db_session:
status, res = get_entity(request, Folder) status, res = get_entity(request, Folder)
@ -164,7 +165,7 @@ def cover_art():
if size > im.size[0] and size > im.size[1]: if size > im.size[0] and size > im.size[1]:
return send_file(os.path.join(res.path, 'cover.jpg')) return send_file(os.path.join(res.path, 'cover.jpg'))
size_path = os.path.join(app.config['WEBAPP']['cache_dir'], str(size)) size_path = os.path.join(current_app.config['WEBAPP']['cache_dir'], str(size))
path = os.path.abspath(os.path.join(size_path, str(res.id))) path = os.path.abspath(os.path.join(size_path, str(res.id)))
if os.path.exists(path): if os.path.exists(path):
return send_file(path, mimetype = 'image/jpeg') return send_file(path, mimetype = 'image/jpeg')
@ -175,7 +176,7 @@ def cover_art():
im.save(path, 'JPEG') im.save(path, 'JPEG')
return send_file(path, mimetype = 'image/jpeg') return send_file(path, mimetype = 'image/jpeg')
@app.route('/rest/getLyrics.view', methods = [ 'GET', 'POST' ]) @api.route('/getLyrics.view', methods = [ 'GET', 'POST' ])
def lyrics(): def lyrics():
artist, title = map(request.values.get, [ 'artist', 'title' ]) artist, title = map(request.values.get, [ 'artist', 'title' ])
if not artist: if not artist:
@ -188,14 +189,14 @@ def lyrics():
for track in query: for track in query:
lyrics_path = os.path.splitext(track.path)[0] + '.txt' lyrics_path = os.path.splitext(track.path)[0] + '.txt'
if os.path.exists(lyrics_path): if os.path.exists(lyrics_path):
app.logger.debug('Found lyrics file: ' + lyrics_path) current_app.logger.debug('Found lyrics file: ' + lyrics_path)
try: try:
lyrics = read_file_as_unicode(lyrics_path) lyrics = read_file_as_unicode(lyrics_path)
except UnicodeError: except UnicodeError:
# Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or # Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or
# return no lyrics. Log it anyway. # return no lyrics. Log it anyway.
app.logger.warning('Unsupported encoding for lyrics file ' + lyrics_path) current_app.logger.warning('Unsupported encoding for lyrics file ' + lyrics_path)
continue continue
return request.formatter(dict(lyrics = dict( return request.formatter(dict(lyrics = dict(
@ -216,7 +217,7 @@ def lyrics():
_value_ = root.find('cl:Lyric', namespaces = ns).text _value_ = root.find('cl:Lyric', namespaces = ns).text
))) )))
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
app.logger.warning('Error while requesting the ChartLyrics API: ' + str(e)) current_app.logger.warning('Error while requesting the ChartLyrics API: ' + str(e))
return request.formatter(dict(lyrics = dict())) return request.formatter(dict(lyrics = dict()))
@ -228,13 +229,13 @@ def read_file_as_unicode(path):
for enc in encodings: for enc in encodings:
try: try:
contents = codecs.open(path, 'r', encoding = enc).read() contents = codecs.open(path, 'r', encoding = enc).read()
app.logger.debug('Read file {} with {} encoding'.format(path, enc)) current_app.logger.debug('Read file {} with {} encoding'.format(path, enc))
# Maybe save the encoding somewhere to prevent going through this loop each time for the same file # Maybe save the encoding somewhere to prevent going through this loop each time for the same file
return contents return contents
except UnicodeError: except UnicodeError:
pass pass
# Fallback to ASCII # Fallback to ASCII
app.logger.debug('Reading file {} with ascii encoding'.format(path)) current_app.logger.debug('Reading file {} with ascii encoding'.format(path))
return unicode(open(path, 'r').read()) return unicode(open(path, 'r').read())

View File

@ -20,16 +20,16 @@
import uuid import uuid
from flask import request, current_app as app from flask import request
from pony.orm import db_session, rollback from pony.orm import db_session, rollback
from pony.orm import ObjectNotFound from pony.orm import ObjectNotFound
from ..db import Playlist, User, Track from ..db import Playlist, User, Track
from ..py23 import dict from ..py23 import dict
from . import get_entity from . import api, get_entity
@app.route('/rest/getPlaylists.view', methods = [ 'GET', 'POST' ]) @api.route('/getPlaylists.view', methods = [ 'GET', 'POST' ])
def list_playlists(): def list_playlists():
query = Playlist.select(lambda p: p.user.id == request.user.id or p.public).order_by(Playlist.name) query = Playlist.select(lambda p: p.user.id == request.user.id or p.public).order_by(Playlist.name)
@ -48,7 +48,7 @@ def list_playlists():
with db_session: with db_session:
return request.formatter(dict(playlists = dict(playlist = [ p.as_subsonic_playlist(request.user) for p in query ] ))) return request.formatter(dict(playlists = dict(playlist = [ p.as_subsonic_playlist(request.user) for p in query ] )))
@app.route('/rest/getPlaylist.view', methods = [ 'GET', 'POST' ]) @api.route('/getPlaylist.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def show_playlist(): def show_playlist():
status, res = get_entity(request, Playlist) status, res = get_entity(request, Playlist)
@ -62,7 +62,7 @@ def show_playlist():
info['entry'] = [ t.as_subsonic_child(request.user, request.client) for t in res.get_tracks() ] info['entry'] = [ t.as_subsonic_child(request.user, request.client) for t in res.get_tracks() ]
return request.formatter(dict(playlist = info)) return request.formatter(dict(playlist = info))
@app.route('/rest/createPlaylist.view', methods = [ 'GET', 'POST' ]) @api.route('/createPlaylist.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def create_playlist(): def create_playlist():
playlist_id, name = map(request.values.get, [ 'playlistId', 'name' ]) playlist_id, name = map(request.values.get, [ 'playlistId', 'name' ])
@ -104,7 +104,7 @@ def create_playlist():
return request.formatter(dict()) return request.formatter(dict())
@app.route('/rest/deletePlaylist.view', methods = [ 'GET', 'POST' ]) @api.route('/deletePlaylist.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def delete_playlist(): def delete_playlist():
status, res = get_entity(request, Playlist) status, res = get_entity(request, Playlist)
@ -117,7 +117,7 @@ def delete_playlist():
res.delete() res.delete()
return request.formatter(dict()) return request.formatter(dict())
@app.route('/rest/updatePlaylist.view', methods = [ 'GET', 'POST' ]) @api.route('/updatePlaylist.view', methods = [ 'GET', 'POST' ])
@db_session @db_session
def update_playlist(): def update_playlist():
status, res = get_entity(request, Playlist, 'playlistId') status, res = get_entity(request, Playlist, 'playlistId')

View File

@ -20,13 +20,14 @@
from collections import OrderedDict from collections import OrderedDict
from datetime import datetime from datetime import datetime
from flask import request, current_app as app from flask import request
from pony.orm import db_session, select from pony.orm import db_session, select
from ..db import Folder, Track, Artist, Album from ..db import Folder, Track, Artist, Album
from ..py23 import dict from ..py23 import dict
from . import api
@app.route('/rest/search.view', methods = [ 'GET', 'POST' ]) @api.route('/search.view', methods = [ 'GET', 'POST' ])
def old_search(): def old_search():
artist, album, title, anyf, count, offset, newer_than = map(request.values.get, [ 'artist', 'album', 'title', 'any', 'count', 'offset', 'newerThan' ]) artist, album, title, anyf, count, offset, newer_than = map(request.values.get, [ 'artist', 'album', 'title', 'any', 'count', 'offset', 'newerThan' ])
try: try:
@ -70,7 +71,7 @@ def old_search():
match = [ r.as_subsonic_child(request.user) if isinstance(r, Folder) else r.as_subsonic_child(request.user, request.client) for r in query[offset : offset + count] ] match = [ r.as_subsonic_child(request.user) if isinstance(r, Folder) else r.as_subsonic_child(request.user, request.client) for r in query[offset : offset + count] ]
))) )))
@app.route('/rest/search2.view', methods = [ 'GET', 'POST' ]) @api.route('/search2.view', methods = [ 'GET', 'POST' ])
def new_search(): def new_search():
query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map( query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
request.values.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ]) request.values.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ])
@ -99,7 +100,7 @@ def new_search():
('song', [ t.as_subsonic_child(request.user, request.client) for t in songs ]) ('song', [ t.as_subsonic_child(request.user, request.client) for t in songs ])
)))) ))))
@app.route('/rest/search3.view', methods = [ 'GET', 'POST' ]) @api.route('/search3.view', methods = [ 'GET', 'POST' ])
def search_id3(): def search_id3():
query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map( query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
request.values.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ]) request.values.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ])

View File

@ -18,15 +18,16 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from flask import request, current_app as app from flask import request
from ..py23 import dict from ..py23 import dict
from . import api
@app.route('/rest/ping.view', methods = [ 'GET', 'POST' ]) @api.route('/ping.view', methods = [ 'GET', 'POST' ])
def ping(): def ping():
return request.formatter(dict()) return request.formatter(dict())
@app.route('/rest/getLicense.view', methods = [ 'GET', 'POST' ]) @api.route('/getLicense.view', methods = [ 'GET', 'POST' ])
def license(): def license():
return request.formatter(dict(license = dict(valid = True ))) return request.formatter(dict(license = dict(valid = True )))

View File

@ -18,16 +18,16 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from flask import request, current_app as app from flask import request
from pony.orm import db_session from pony.orm import db_session
from ..db import User from ..db import User
from ..managers.user import UserManager from ..managers.user import UserManager
from ..py23 import dict from ..py23 import dict
from . import decode_password from . import api, decode_password
@app.route('/rest/getUser.view', methods = [ 'GET', 'POST' ]) @api.route('/getUser.view', methods = [ 'GET', 'POST' ])
def user_info(): def user_info():
username = request.values.get('username') username = request.values.get('username')
if username is None: if username is None:
@ -43,7 +43,7 @@ def user_info():
return request.formatter(dict(user = user.as_subsonic_user())) return request.formatter(dict(user = user.as_subsonic_user()))
@app.route('/rest/getUsers.view', methods = [ 'GET', 'POST' ]) @api.route('/getUsers.view', methods = [ 'GET', 'POST' ])
def users_info(): def users_info():
if not request.user.admin: if not request.user.admin:
return request.error_formatter(50, 'Admin restricted') return request.error_formatter(50, 'Admin restricted')
@ -51,7 +51,7 @@ def users_info():
with db_session: with db_session:
return request.formatter(dict(users = dict(user = [ u.as_subsonic_user() for u in User.select() ] ))) return request.formatter(dict(users = dict(user = [ u.as_subsonic_user() for u in User.select() ] )))
@app.route('/rest/createUser.view', methods = [ 'GET', 'POST' ]) @api.route('/createUser.view', methods = [ 'GET', 'POST' ])
def user_add(): def user_add():
if not request.user.admin: if not request.user.admin:
return request.error_formatter(50, 'Admin restricted') return request.error_formatter(50, 'Admin restricted')
@ -68,7 +68,7 @@ def user_add():
return request.formatter(dict()) return request.formatter(dict())
@app.route('/rest/deleteUser.view', methods = [ 'GET', 'POST' ]) @api.route('/deleteUser.view', methods = [ 'GET', 'POST' ])
def user_del(): def user_del():
if not request.user.admin: if not request.user.admin:
return request.error_formatter(50, 'Admin restricted') return request.error_formatter(50, 'Admin restricted')
@ -88,7 +88,7 @@ def user_del():
return request.formatter(dict()) return request.formatter(dict())
@app.route('/rest/changePassword.view', methods = [ 'GET', 'POST' ]) @api.route('/changePassword.view', methods = [ 'GET', 'POST' ])
def user_changepass(): def user_changepass():
username, password = map(request.values.get, [ 'username', 'password' ]) username, password = map(request.values.get, [ 'username', 'password' ])
if not username or not password: if not username or not password:

View File

@ -65,7 +65,8 @@ def create_application(config = None):
if app.config['WEBAPP']['mount_webui']: if app.config['WEBAPP']['mount_webui']:
from . import frontend from . import frontend
if app.config['WEBAPP']['mount_api']: if app.config['WEBAPP']['mount_api']:
from . import api from .api import api
app.register_blueprint(api, url_prefix = '/rest')
return app return app