diff --git a/supysonic/api/__init__.py b/supysonic/api/__init__.py index fdeebf1..1b441cc 100644 --- a/supysonic/api/__init__.py +++ b/supysonic/api/__init__.py @@ -1,7 +1,7 @@ # This file is part of Supysonic. # Supysonic is a Python implementation of the Subsonic server API. # -# Copyright (C) 2013-2023 Alban 'spl0k' Féron +# Copyright (C) 2013-2024 Alban 'spl0k' Féron # # Distributed under terms of the GNU AGPLv3 license. @@ -152,3 +152,4 @@ from .jukebox import * from .radio import * from .unsupported import * from .scan import * +from .extensions import * diff --git a/supysonic/api/extensions.py b/supysonic/api/extensions.py new file mode 100644 index 0000000..4b1f505 --- /dev/null +++ b/supysonic/api/extensions.py @@ -0,0 +1,16 @@ +# +# This file is part of Supysonic. +# Supysonic is a Python implementation of the Subsonic server API. +# +# Copyright (C) 2024 Alban 'spl0k' Féron +# +# Distributed under terms of the GNU AGPLv3 license. + +from flask import request + +from . import api_routing + + +@api_routing("/getOpenSubsonicExtensions") +def extensions(): + return request.formatter("openSubsonicExtensions", []) diff --git a/supysonic/api/formatters.py b/supysonic/api/formatters.py index a30de9c..7ac5073 100644 --- a/supysonic/api/formatters.py +++ b/supysonic/api/formatters.py @@ -1,7 +1,7 @@ # This file is part of Supysonic. # Supysonic is a Python implementation of the Subsonic server API. # -# Copyright (C) 2018 Alban 'spl0k' Féron +# Copyright (C) 2018-2024 Alban 'spl0k' Féron # # Distributed under terms of the GNU AGPLv3 license. @@ -9,6 +9,7 @@ from flask import json, jsonify, make_response from xml.etree import ElementTree from . import API_VERSION +from .. import NAME, VERSION class BaseFormatter: @@ -59,7 +60,13 @@ class JSONBaseFormatter(BaseFormatter): if (elem is None) != (data is None): raise ValueError("Expecting both elem and data or neither of them") - rv = {"status": "failed" if elem == "error" else "ok", "version": API_VERSION} + rv = { + "status": "failed" if elem == "error" else "ok", + "version": API_VERSION, + "type": NAME, + "serverVersion": VERSION, + "openSubsonic": True, + } if data: rv[elem] = self.__remove_empty_lists(data) @@ -138,6 +145,9 @@ class XMLFormatter(BaseFormatter): "status": "failed" if elem == "error" else "ok", "version": API_VERSION, "xmlns": "http://subsonic.org/restapi", + "type": NAME, + "serverVersion": VERSION, + "openSubsonic": True, } if elem: response[elem] = data diff --git a/tests/api/apitestbase.py b/tests/api/apitestbase.py index 3531efe..c257cda 100644 --- a/tests/api/apitestbase.py +++ b/tests/api/apitestbase.py @@ -25,7 +25,7 @@ class ApiTestBase(TestBase): super().setUp() logging.getLogger("supysonic.api").addHandler(logging.NullHandler()) self.apiVersion = apiVersion - xsd = etree.parse(f"tests/assets/subsonic-rest-api-{self.apiVersion}.xsd") + xsd = etree.parse(f"tests/assets/subsonic-rest-api-{self.apiVersion}-os.xsd") self.schema = etree.XMLSchema(xsd) def _find(self, xml, path): diff --git a/tests/api/test_response_helper.py b/tests/api/test_response_helper.py index 695b480..74e2626 100644 --- a/tests/api/test_response_helper.py +++ b/tests/api/test_response_helper.py @@ -1,7 +1,7 @@ # This file is part of Supysonic. # Supysonic is a Python implementation of the Subsonic server API. # -# Copyright (C) 2017-2018 Alban 'spl0k' Féron +# Copyright (C) 2017-2024 Alban 'spl0k' Féron # # Distributed under terms of the GNU AGPLv3 license. @@ -44,9 +44,12 @@ class ResponseHelperJsonTestCase(TestBase, UnwrapperMixin.create_from(JSONFormat self.assertIsInstance(empty["subsonic-response"], dict) resp = empty["subsonic-response"] - self.assertEqual(len(resp), 2) + self.assertEqual(len(resp), 5) self.assertIn("status", resp) self.assertIn("version", resp) + self.assertIn("type", resp) + self.assertIn("serverVersion", resp) + self.assertIn("openSubsonic", resp) self.assertEqual(resp["status"], "ok") resp = self.error(0, "message")["subsonic-response"] @@ -137,6 +140,9 @@ class ResponseHelperXMLTestCase(TestBase, UnwrapperMixin.create_from(XMLFormatte empty = self.empty self.assertIsNotNone(empty.find(".[@version]")) self.assertIsNotNone(empty.find(".[@status='ok']")) + self.assertIsNotNone(empty.find(".[@type]")) + self.assertIsNotNone(empty.find(".[@serverVersion]")) + self.assertIsNotNone(empty.find(".[@openSubsonic='true']")) resp = self.error(0, "message") self.assertIsNotNone(resp.find(".[@status='failed']")) diff --git a/tests/assets/subsonic-rest-api-1.12.0-os.xsd b/tests/assets/subsonic-rest-api-1.12.0-os.xsd new file mode 100644 index 0000000..3994d24 --- /dev/null +++ b/tests/assets/subsonic-rest-api-1.12.0-os.xsd @@ -0,0 +1,566 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/assets/subsonic-rest-api-1.16.0-os.xsd b/tests/assets/subsonic-rest-api-1.16.0-os.xsd new file mode 100644 index 0000000..433e64d --- /dev/null +++ b/tests/assets/subsonic-rest-api-1.16.0-os.xsd @@ -0,0 +1,641 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file