mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 17:06:17 +00:00
API: marked explicitly unsupported methods/parameters as such
This commit is contained in:
parent
adb4e7e89b
commit
a6b894c586
82
docs/api.md
82
docs/api.md
@ -69,15 +69,15 @@ or with version 1.8.0.
|
||||
| [`getCaptions`](#getcaptions) | 1.15.0 | 🔴 |
|
||||
| [`getCoverArt`](#getcoverart) | | ✔️ |
|
||||
| [`getLyrics`](#getlyrics) | | ✔️ |
|
||||
| [`getAvatar`](#getavatar) | | 🔴 |
|
||||
| [`getAvatar`](#getavatar) | | ❌ |
|
||||
| [`star`](#star) | | ✔️ |
|
||||
| [`unstar`](#unstar) | | ✔️ |
|
||||
| [`setRating`](#setrating) | | ✔️ |
|
||||
| [`scrobble`](#scrobble) | | ✔️ |
|
||||
| [`getShares`](#getshares) | | 🔴 |
|
||||
| [`createShare`](#createshare) | | 🔴 |
|
||||
| [`updateShare`](#updateshare) | | 🔴 |
|
||||
| [`deleteShare`](#deleteshare) | | 🔴 |
|
||||
| [`getShares`](#getshares) | | ❌ |
|
||||
| [`createShare`](#createshare) | | ❌ |
|
||||
| [`updateShare`](#updateshare) | | ❌ |
|
||||
| [`deleteShare`](#deleteshare) | | ❌ |
|
||||
| [`getPodcasts`](#getpodcasts) | | ❔ |
|
||||
| [`getNewestPodcasts`](#getnewestpodcasts) | 1.14.0 | ❔ |
|
||||
| [`refreshPodcasts`](#refreshpodcasts) | 1.9.0 | ❔ |
|
||||
@ -432,8 +432,8 @@ No parameter
|
||||
| `id` | | ✔️ |
|
||||
| `maxBitRate` | | ✔️ |
|
||||
| `format` | | ✔️ |
|
||||
| `timeOffset` | | 🔴 |
|
||||
| `size` | | 🔴 |
|
||||
| `timeOffset` | | ❌ |
|
||||
| `size` | | ❌ |
|
||||
| `estimateContentLength` | | 📅 |
|
||||
| `converted` | 1.15.0 | 🔴 |
|
||||
|
||||
@ -478,11 +478,11 @@ No parameter
|
||||
| `title` | | ✔️ |
|
||||
|
||||
#### `getAvatar`
|
||||
🔴
|
||||
❌
|
||||
|
||||
| Parameter | Vers. | |
|
||||
|------------|-------|---|
|
||||
| `username` | | 🔴 |
|
||||
| `username` | | ❌ |
|
||||
|
||||
### Media annotation
|
||||
|
||||
@ -524,33 +524,33 @@ No parameter
|
||||
### Sharing
|
||||
|
||||
#### `getShares`
|
||||
🔴
|
||||
❌
|
||||
No parameter
|
||||
|
||||
#### `createShare`
|
||||
🔴
|
||||
❌
|
||||
|
||||
| Parameter | Vers. | |
|
||||
|---------------|-------|---|
|
||||
| `id` | | 🔴 |
|
||||
| `description` | | 🔴 |
|
||||
| `expires` | | 🔴 |
|
||||
| `id` | | ❌ |
|
||||
| `description` | | ❌ |
|
||||
| `expires` | | ❌ |
|
||||
|
||||
#### `updateShare`
|
||||
🔴
|
||||
❌
|
||||
|
||||
| Parameter | Vers. | |
|
||||
|---------------|-------|---|
|
||||
| `id` | | 🔴 |
|
||||
| `description` | | 🔴 |
|
||||
| `expires` | | 🔴 |
|
||||
| `id` | | ❌ |
|
||||
| `description` | | ❌ |
|
||||
| `expires` | | ❌ |
|
||||
|
||||
#### `deleteShare`
|
||||
🔴
|
||||
❌
|
||||
|
||||
| Parameter | Vers. | |
|
||||
|-----------|-------|---|
|
||||
| `id` | | 🔴 |
|
||||
| `id` | | ❌ |
|
||||
|
||||
### Podcast
|
||||
|
||||
@ -687,19 +687,19 @@ No parameter
|
||||
| `username` | | ✔️ |
|
||||
| `password` | | ✔️ |
|
||||
| `email` | | ✔️ |
|
||||
| `ldapAuthenticated` | | ❔ |
|
||||
| `ldapAuthenticated` | | |
|
||||
| `adminRole` | | ✔️ |
|
||||
| `settingsRole` | | ❔ |
|
||||
| `streamRole` | | ❔ |
|
||||
| `settingsRole` | | |
|
||||
| `streamRole` | | |
|
||||
| `jukeboxRole` | | 📅 |
|
||||
| `downloadRole` | | ❔ |
|
||||
| `uploadRole` | | ❔ |
|
||||
| `playlistRole` | | ❔ |
|
||||
| `coverArtRole` | | ❔ |
|
||||
| `commentRole` | | ❔ |
|
||||
| `podcastRole` | | ❔ |
|
||||
| `shareRole` | | 🔴 |
|
||||
| `videoConversionRole` | 1.14.0 | 🔴 |
|
||||
| `downloadRole` | | |
|
||||
| `uploadRole` | | |
|
||||
| `playlistRole` | | |
|
||||
| `coverArtRole` | | |
|
||||
| `commentRole` | | |
|
||||
| `podcastRole` | | |
|
||||
| `shareRole` | | |
|
||||
| `videoConversionRole` | 1.14.0 | |
|
||||
| `musicFolderId` | 1.12.0 | 📅 |
|
||||
|
||||
#### `updateUser`
|
||||
@ -710,18 +710,18 @@ No parameter
|
||||
| `username` | 1.10.2 | 📅 |
|
||||
| `password` | 1.10.2 | 📅 |
|
||||
| `email` | 1.10.2 | 📅 |
|
||||
| `ldapAuthenticated` | 1.10.2 | ❔ |
|
||||
| `ldapAuthenticated` | 1.10.2 | |
|
||||
| `adminRole` | 1.10.2 | 📅 |
|
||||
| `settingsRole` | 1.10.2 | ❔ |
|
||||
| `streamRole` | 1.10.2 | ❔ |
|
||||
| `settingsRole` | 1.10.2 | |
|
||||
| `streamRole` | 1.10.2 | |
|
||||
| `jukeboxRole` | 1.10.2 | 📅 |
|
||||
| `downloadRole` | 1.10.2 | ❔ |
|
||||
| `uploadRole` | 1.10.2 | ❔ |
|
||||
| `coverArtRole` | 1.10.2 | ❔ |
|
||||
| `commentRole` | 1.10.2 | ❔ |
|
||||
| `podcastRole` | 1.10.2 | ❔ |
|
||||
| `shareRole` | 1.10.2 | 🔴 |
|
||||
| `videoConversionRole` | 1.14.0 | 🔴 |
|
||||
| `downloadRole` | 1.10.2 | |
|
||||
| `uploadRole` | 1.10.2 | |
|
||||
| `coverArtRole` | 1.10.2 | |
|
||||
| `commentRole` | 1.10.2 | |
|
||||
| `podcastRole` | 1.10.2 | |
|
||||
| `shareRole` | 1.10.2 | |
|
||||
| `videoConversionRole` | 1.14.0 | |
|
||||
| `musicFolderId` | 1.12.0 | 📅 |
|
||||
| `maxBitRate` | 1.13.0 | 📅 |
|
||||
|
||||
|
@ -88,4 +88,5 @@ from .annotation import *
|
||||
from .chat import *
|
||||
from .search import *
|
||||
from .playlists import *
|
||||
from .unsupported import *
|
||||
|
||||
|
@ -139,7 +139,3 @@ def track_info():
|
||||
res = get_entity(Track)
|
||||
return request.formatter('song', res.as_subsonic_child(request.user, request.client))
|
||||
|
||||
@api.route('/getVideos.view', methods = [ 'GET', 'POST' ])
|
||||
def list_videos():
|
||||
return request.formatter.error(0, 'Video streaming not supported'), 501
|
||||
|
||||
|
@ -38,5 +38,5 @@ def generic_error(e): # pragma: nocover
|
||||
#@api.errorhandler(404)
|
||||
@api.route('/<path:invalid>', methods = [ 'GET', 'POST' ]) # blueprint 404 workaround
|
||||
def not_found(*args, **kwargs):
|
||||
return GenericError('Not implemented'), 501
|
||||
return GenericError('Unknown method'), 404
|
||||
|
||||
|
@ -34,6 +34,11 @@ class GenericError(SubsonicAPIException):
|
||||
class ServerError(GenericError):
|
||||
code = 500
|
||||
|
||||
class UnsupportedParameter(GenericError):
|
||||
def __init__(self, parameter, *args, **kwargs):
|
||||
message = "Unsupported parameter '{}'".format(parameter)
|
||||
super(UnsupportedParameter, self).__init__(message, *args, **kwargs)
|
||||
|
||||
class MissingParameter(SubsonicAPIException):
|
||||
api_code = 10
|
||||
|
||||
|
@ -23,7 +23,7 @@ from ..db import Track, Album, Artist, Folder, User, ClientPrefs, now
|
||||
from ..py23 import dict
|
||||
|
||||
from . import api, get_entity
|
||||
from .exceptions import GenericError, MissingParameter, NotFound, ServerError
|
||||
from .exceptions import GenericError, MissingParameter, NotFound, ServerError, UnsupportedParameter
|
||||
|
||||
def prepare_transcoding_cmdline(base_cmdline, input_file, input_format, output_format, output_bitrate):
|
||||
if not base_cmdline:
|
||||
@ -39,7 +39,12 @@ def prepare_transcoding_cmdline(base_cmdline, input_file, input_format, output_f
|
||||
def stream_media():
|
||||
res = get_entity(Track)
|
||||
|
||||
maxBitRate, format, timeOffset, size, estimateContentLength = map(request.values.get, [ 'maxBitRate', 'format', 'timeOffset', 'size', 'estimateContentLength' ])
|
||||
if 'timeOffset' in request.values:
|
||||
raise UnsupportedParameter('timeOffset')
|
||||
if 'size' in request.values:
|
||||
raise UnsupportedParameter('size')
|
||||
|
||||
maxBitRate, format, estimateContentLength = map(request.values.get, [ 'maxBitRate', 'format', 'estimateContentLength' ])
|
||||
if format:
|
||||
format = format.lower()
|
||||
|
||||
@ -94,7 +99,7 @@ def stream_media():
|
||||
if not data:
|
||||
break
|
||||
yield data
|
||||
except:
|
||||
except: # pragma: nocover
|
||||
if dec_proc != None:
|
||||
dec_proc.terminate()
|
||||
proc.terminate()
|
||||
@ -184,10 +189,10 @@ def lyrics():
|
||||
title = root.find('cl:LyricSong', namespaces = ns).text,
|
||||
_value_ = root.find('cl:Lyric', namespaces = ns).text
|
||||
))
|
||||
except requests.exceptions.RequestException as e:
|
||||
except requests.exceptions.RequestException as e: # pragma: nocover
|
||||
current_app.logger.warning('Error while requesting the ChartLyrics API: ' + str(e))
|
||||
|
||||
return request.formatter('lyrics', dict())
|
||||
return request.formatter('lyrics', dict()) # pragma: nocover
|
||||
|
||||
def read_file_as_unicode(path):
|
||||
""" Opens a file trying with different encodings and returns the contents as a unicode string """
|
||||
|
22
supysonic/api/unsupported.py
Normal file
22
supysonic/api/unsupported.py
Normal file
@ -0,0 +1,22 @@
|
||||
# coding: utf-8
|
||||
#
|
||||
# This file is part of Supysonic.
|
||||
# Supysonic is a Python implementation of the Subsonic server API.
|
||||
#
|
||||
# Copyright (C) 2018 Alban 'spl0k' Féron
|
||||
#
|
||||
# Distributed under terms of the GNU AGPLv3 license.
|
||||
|
||||
from . import api
|
||||
from .exceptions import GenericError
|
||||
|
||||
methods = (
|
||||
'getVideos', 'getAvatar', 'getShares', 'createShare', 'updateShare', 'deleteShare',
|
||||
)
|
||||
|
||||
def unsupported():
|
||||
return GenericError('Not supported by Supysonic'), 501
|
||||
|
||||
for m in methods:
|
||||
api.add_url_rule('/{}.view'.format(m), 'unsupported', unsupported, methods = [ 'GET', 'POST' ])
|
||||
|
@ -128,13 +128,23 @@ class ApiSetupTestCase(TestBase):
|
||||
self.assertIn('license', json['subsonic-response'])
|
||||
|
||||
def test_not_implemented(self):
|
||||
# Access to not implemented endpoint
|
||||
rv = self.client.get('/rest/not-implemented', query_string = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests' })
|
||||
# Access to not implemented/unknown endpoint
|
||||
rv = self.client.get('/rest/unknown', query_string = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests' })
|
||||
self.assertEqual(rv.status_code, 404)
|
||||
self.assertIn('status="failed"', rv.data)
|
||||
self.assertIn('code="0"', rv.data)
|
||||
|
||||
rv = self.client.post('/rest/unknown', data = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests' })
|
||||
self.assertEqual(rv.status_code, 404)
|
||||
self.assertIn('status="failed"', rv.data)
|
||||
self.assertIn('code="0"', rv.data)
|
||||
|
||||
rv = self.client.get('/rest/getVideos.view', query_string = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests' })
|
||||
self.assertEqual(rv.status_code, 501)
|
||||
self.assertIn('status="failed"', rv.data)
|
||||
self.assertIn('code="0"', rv.data)
|
||||
|
||||
rv = self.client.post('/rest/not-implemented', data = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests' })
|
||||
rv = self.client.post('/rest/getVideos.view', data = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests' })
|
||||
self.assertEqual(rv.status_code, 501)
|
||||
self.assertIn('status="failed"', rv.data)
|
||||
self.assertIn('code="0"', rv.data)
|
||||
|
@ -57,6 +57,8 @@ class MediaTestCase(ApiTestBase):
|
||||
self._make_request('stream', { 'id': str(uuid.uuid4()) }, error = 70)
|
||||
self._make_request('stream', { 'id': str(self.folderid) }, error = 70)
|
||||
self._make_request('stream', { 'id': str(self.trackid), 'maxBitRate': 'string' }, error = 0)
|
||||
self._make_request('stream', { 'id': str(self.trackid), 'timeOffset': 2 }, error = 0)
|
||||
self._make_request('stream', { 'id': str(self.trackid), 'size': '640x480' }, error = 0)
|
||||
|
||||
rv = self.client.get('/rest/stream.view', query_string = { 'u': 'alice', 'p': 'Alic3', 'c': 'tests', 'id': str(self.trackid) })
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
|
Loading…
Reference in New Issue
Block a user