mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 17:06:17 +00:00
Subsonic API 1.10.2
Except for changes required to comply to the XSD specification, this does not include any feature this version brings Closes #194
This commit is contained in:
parent
8e3cd5ef4d
commit
1be526b8d2
@ -4,7 +4,7 @@ This page lists all the API methods and their parameters up to the version
|
|||||||
1.16.0 (Subsonic 6.1.2). Here you'll find details about which API features
|
1.16.0 (Subsonic 6.1.2). Here you'll find details about which API features
|
||||||
_Supysonic_ support, plan on supporting, or won't.
|
_Supysonic_ support, plan on supporting, or won't.
|
||||||
|
|
||||||
At the moment, the current target API version is 1.9.0.
|
At the moment, the current target API version is 1.10.2.
|
||||||
|
|
||||||
The following information was gathered by _diff_-ing various snapshots of the
|
The following information was gathered by _diff_-ing various snapshots of the
|
||||||
[Subsonic API page](http://www.subsonic.org/pages/api.jsp).
|
[Subsonic API page](http://www.subsonic.org/pages/api.jsp).
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
# coding: utf-8
|
|
||||||
#
|
|
||||||
# This file is part of Supysonic.
|
# This file is part of Supysonic.
|
||||||
# Supysonic is a Python implementation of the Subsonic server API.
|
# Supysonic is a Python implementation of the Subsonic server API.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2013-2018 Alban 'spl0k' Féron
|
# Copyright (C) 2013-2020 Alban 'spl0k' Féron
|
||||||
#
|
#
|
||||||
# Distributed under terms of the GNU AGPLv3 license.
|
# Distributed under terms of the GNU AGPLv3 license.
|
||||||
|
|
||||||
API_VERSION = "1.9.0"
|
API_VERSION = "1.10.2"
|
||||||
|
|
||||||
import binascii
|
import binascii
|
||||||
import uuid
|
import uuid
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
# This file is part of Supysonic.
|
# This file is part of Supysonic.
|
||||||
# Supysonic is a Python implementation of the Subsonic server API.
|
# Supysonic is a Python implementation of the Subsonic server API.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2013-2018 Alban 'spl0k' Féron
|
# Copyright (C) 2013-2020 Alban 'spl0k' Féron
|
||||||
#
|
#
|
||||||
# Distributed under terms of the GNU AGPLv3 license.
|
# Distributed under terms of the GNU AGPLv3 license.
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ import string
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
from flask import request
|
from flask import request
|
||||||
from pony.orm import ObjectNotFound, select
|
from pony.orm import ObjectNotFound, select, count
|
||||||
|
|
||||||
from ..db import Folder, Artist, Album, Track
|
from ..db import Folder, Artist, Album, Track
|
||||||
|
|
||||||
@ -50,7 +50,9 @@ def list_indexes():
|
|||||||
|
|
||||||
last_modif = max(map(lambda f: f.last_scan, folders))
|
last_modif = max(map(lambda f: f.last_scan, folders))
|
||||||
if ifModifiedSince is not None and last_modif < ifModifiedSince:
|
if ifModifiedSince is not None and last_modif < ifModifiedSince:
|
||||||
return request.formatter("indexes", dict(lastModified=last_modif * 1000))
|
return request.formatter(
|
||||||
|
"indexes", dict(lastModified=last_modif * 1000, ignoredArticles="")
|
||||||
|
)
|
||||||
|
|
||||||
# The XSD lies, we don't return artists but a directory structure
|
# The XSD lies, we don't return artists but a directory structure
|
||||||
artists = []
|
artists = []
|
||||||
@ -76,6 +78,7 @@ def list_indexes():
|
|||||||
"indexes",
|
"indexes",
|
||||||
dict(
|
dict(
|
||||||
lastModified=last_modif * 1000,
|
lastModified=last_modif * 1000,
|
||||||
|
ignoredArticles="",
|
||||||
index=[
|
index=[
|
||||||
dict(
|
dict(
|
||||||
name=k,
|
name=k,
|
||||||
@ -121,7 +124,10 @@ def list_genres():
|
|||||||
"genres",
|
"genres",
|
||||||
dict(
|
dict(
|
||||||
genre=[
|
genre=[
|
||||||
dict(value=genre) for genre in select(t.genre for t in Track if t.genre)
|
dict(value=genre, songCount=sc, albumCount=ac)
|
||||||
|
for genre, sc, ac in select(
|
||||||
|
(t.genre, count(), count(t.album)) for t in Track if t.genre
|
||||||
|
)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -146,6 +152,7 @@ def list_artists():
|
|||||||
return request.formatter(
|
return request.formatter(
|
||||||
"artists",
|
"artists",
|
||||||
dict(
|
dict(
|
||||||
|
ignoredArticles="",
|
||||||
index=[
|
index=[
|
||||||
dict(
|
dict(
|
||||||
name=k,
|
name=k,
|
||||||
@ -155,7 +162,7 @@ def list_artists():
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
for k, v in sorted(indexes.items())
|
for k, v in sorted(indexes.items())
|
||||||
]
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class ApiTestBase(TestBase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(ApiTestBase, self).setUp()
|
super(ApiTestBase, self).setUp()
|
||||||
|
|
||||||
xsd = etree.parse("tests/assets/subsonic-rest-api-1.9.0.xsd")
|
xsd = etree.parse("tests/assets/subsonic-rest-api-1.10.2.xsd")
|
||||||
self.schema = etree.XMLSchema(xsd)
|
self.schema = etree.XMLSchema(xsd)
|
||||||
|
|
||||||
def _find(self, xml, path):
|
def _find(self, xml, path):
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# coding: utf-8
|
|
||||||
#
|
#
|
||||||
# This file is part of Supysonic.
|
# This file is part of Supysonic.
|
||||||
# Supysonic is a Python implementation of the Subsonic server API.
|
# Supysonic is a Python implementation of the Subsonic server API.
|
||||||
#
|
#
|
||||||
# Copyright (C) 2017 Alban 'spl0k' Féron
|
# Copyright (C) 2017-2020 Alban 'spl0k' Féron
|
||||||
#
|
#
|
||||||
# Distributed under terms of the GNU AGPLv3 license.
|
# Distributed under terms of the GNU AGPLv3 license.
|
||||||
|
|
||||||
@ -53,6 +52,7 @@ class BrowseTestCase(ApiTestBase):
|
|||||||
duration=2,
|
duration=2,
|
||||||
album=album,
|
album=album,
|
||||||
artist=artist,
|
artist=artist,
|
||||||
|
genre="Music!",
|
||||||
bitrate=320,
|
bitrate=320,
|
||||||
path="tests/assets/{0}rtist/{0}{1}lbum/{2}".format(
|
path="tests/assets/{0}rtist/{0}{1}lbum/{2}".format(
|
||||||
letter, lether, song
|
letter, lether, song
|
||||||
@ -201,6 +201,13 @@ class BrowseTestCase(ApiTestBase):
|
|||||||
def test_get_videos(self):
|
def test_get_videos(self):
|
||||||
self._make_request("getVideos", error=0)
|
self._make_request("getVideos", error=0)
|
||||||
|
|
||||||
|
def test_genres(self):
|
||||||
|
rv, child = self._make_request("getGenres", tag="genres")
|
||||||
|
self.assertEqual(len(child), 1)
|
||||||
|
self.assertEqual(child[0].text, "Music!")
|
||||||
|
self.assertEqual(child[0].get("songCount"), "18")
|
||||||
|
self.assertEqual(child[0].get("albumCount"), "6")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
targetNamespace="http://subsonic.org/restapi"
|
targetNamespace="http://subsonic.org/restapi"
|
||||||
attributeFormDefault="unqualified"
|
attributeFormDefault="unqualified"
|
||||||
elementFormDefault="qualified"
|
elementFormDefault="qualified"
|
||||||
version="1.9.0">
|
version="1.10.2">
|
||||||
|
|
||||||
<xs:element name="subsonic-response" type="sub:Response"/>
|
<xs:element name="subsonic-response" type="sub:Response"/>
|
||||||
|
|
||||||
@ -68,8 +68,8 @@
|
|||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="MusicFolder">
|
<xs:complexType name="MusicFolder">
|
||||||
<xs:attribute name="id" type="xs:int" use="required"/>
|
<xs:attribute name="id" type="xs:int" use="required"/>
|
||||||
<xs:attribute name="name" type="xs:string" use="optional"/>
|
<xs:attribute name="name" type="xs:string" use="optional"/>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="Indexes">
|
<xs:complexType name="Indexes">
|
||||||
@ -79,6 +79,7 @@
|
|||||||
<xs:element name="child" type="sub:Child" minOccurs="0" maxOccurs="unbounded"/> <!-- Added in 1.7.0 -->
|
<xs:element name="child" type="sub:Child" minOccurs="0" maxOccurs="unbounded"/> <!-- Added in 1.7.0 -->
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
<xs:attribute name="lastModified" type="xs:long" use="required"/>
|
<xs:attribute name="lastModified" type="xs:long" use="required"/>
|
||||||
|
<xs:attribute name="ignoredArticles" type="xs:string" use="required"/> <!-- Added in 1.10.0 -->
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="Index">
|
<xs:complexType name="Index">
|
||||||
@ -91,18 +92,25 @@
|
|||||||
<xs:complexType name="Artist">
|
<xs:complexType name="Artist">
|
||||||
<xs:attribute name="id" type="xs:string" use="required"/>
|
<xs:attribute name="id" type="xs:string" use="required"/>
|
||||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||||
|
<xs:attribute name="starred" type="xs:dateTime" use="optional"/> <!-- Added in 1.10.1 -->
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="Genres">
|
<xs:complexType name="Genres">
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="genre" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
|
<xs:element name="genre" type="sub:Genre" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
|
<xs:complexType name="Genre" mixed="true">
|
||||||
|
<xs:attribute name="songCount" type="xs:int" use="required"/> <!-- Added in 1.10.2 -->
|
||||||
|
<xs:attribute name="albumCount" type="xs:int" use="required"/> <!-- Added in 1.10.2 -->
|
||||||
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="ArtistsID3">
|
<xs:complexType name="ArtistsID3">
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="index" type="sub:IndexID3" minOccurs="0" maxOccurs="unbounded"/>
|
<xs:element name="index" type="sub:IndexID3" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
|
<xs:attribute name="ignoredArticles" type="xs:string" use="required"/> <!-- Added in 1.10.0 -->
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="IndexID3">
|
<xs:complexType name="IndexID3">
|
||||||
@ -140,6 +148,8 @@
|
|||||||
<xs:attribute name="duration" type="xs:int" use="required"/>
|
<xs:attribute name="duration" type="xs:int" use="required"/>
|
||||||
<xs:attribute name="created" type="xs:dateTime" use="required"/>
|
<xs:attribute name="created" type="xs:dateTime" use="required"/>
|
||||||
<xs:attribute name="starred" type="xs:dateTime" use="optional"/>
|
<xs:attribute name="starred" type="xs:dateTime" use="optional"/>
|
||||||
|
<xs:attribute name="year" type="xs:int" use="optional"/> <!-- Added in 1.10.1 -->
|
||||||
|
<xs:attribute name="genre" type="xs:string" use="optional"/> <!-- Added in 1.10.1 -->
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="AlbumWithSongsID3">
|
<xs:complexType name="AlbumWithSongsID3">
|
||||||
@ -165,6 +175,7 @@
|
|||||||
<xs:attribute name="id" type="xs:string" use="required"/>
|
<xs:attribute name="id" type="xs:string" use="required"/>
|
||||||
<xs:attribute name="parent" type="xs:string" use="optional"/>
|
<xs:attribute name="parent" type="xs:string" use="optional"/>
|
||||||
<xs:attribute name="name" type="xs:string" use="required"/>
|
<xs:attribute name="name" type="xs:string" use="required"/>
|
||||||
|
<xs:attribute name="starred" type="xs:dateTime" use="optional"/> <!-- Added in 1.10.1 -->
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="Child">
|
<xs:complexType name="Child">
|
||||||
@ -195,6 +206,7 @@
|
|||||||
<xs:attribute name="albumId" type="xs:string" use="optional"/> <!-- Added in 1.8.0 -->
|
<xs:attribute name="albumId" type="xs:string" use="optional"/> <!-- Added in 1.8.0 -->
|
||||||
<xs:attribute name="artistId" type="xs:string" use="optional"/> <!-- Added in 1.8.0 -->
|
<xs:attribute name="artistId" type="xs:string" use="optional"/> <!-- Added in 1.8.0 -->
|
||||||
<xs:attribute name="type" type="sub:MediaType" use="optional"/> <!-- Added in 1.8.0 -->
|
<xs:attribute name="type" type="sub:MediaType" use="optional"/> <!-- Added in 1.8.0 -->
|
||||||
|
<xs:attribute name="bookmarkPosition" type="xs:long" use="optional"/> <!-- In millis. Added in 1.10.1 -->
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:simpleType name="MediaType">
|
<xs:simpleType name="MediaType">
|
Loading…
Reference in New Issue
Block a user