diff --git a/supysonic/api/albums_songs.py b/supysonic/api/albums_songs.py index 774988d..086e736 100644 --- a/supysonic/api/albums_songs.py +++ b/supysonic/api/albums_songs.py @@ -1,9 +1,7 @@ -# coding: utf-8 -# # This file is part of Supysonic. # 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. @@ -205,7 +203,7 @@ def get_starred(): "starred", dict( artist=[ - dict(id=str(sf.id), name=sf.name) + sf.as_subsonic_artist(request.user) for sf in folders.filter(lambda f: count(f.tracks) == 0) ], album=[ diff --git a/supysonic/api/browse.py b/supysonic/api/browse.py index a3cdebd..f0d976b 100644 --- a/supysonic/api/browse.py +++ b/supysonic/api/browse.py @@ -1,5 +1,3 @@ -# coding: utf-8 -# # This file is part of Supysonic. # Supysonic is a Python implementation of the Subsonic server API. # @@ -83,7 +81,7 @@ def list_indexes(): dict( name=k, artist=[ - dict(id=str(a.id), name=a.name) + a.as_subsonic_artist(request.user) for a in sorted(v, key=lambda a: a.name.lower()) ], ) @@ -100,22 +98,9 @@ def list_indexes(): @api.route("/getMusicDirectory.view", methods=["GET", "POST"]) def show_directory(): res = get_entity(Folder) - directory = dict( - id=str(res.id), - name=res.name, - child=[ - f.as_subsonic_child(request.user) - for f in res.children.order_by(lambda c: c.name.lower()) - ] - + [ - t.as_subsonic_child(request.user, request.client) - for t in sorted(res.tracks, key=lambda t: t.sort_key()) - ], + return request.formatter( + "directory", res.as_subsonic_directory(request.user, request.client) ) - if not res.root: - directory["parent"] = str(res.parent.id) - - return request.formatter("directory", directory) @api.route("/getGenres.view", methods=["GET", "POST"]) diff --git a/supysonic/api/search.py b/supysonic/api/search.py index a1d7524..1e67524 100644 --- a/supysonic/api/search.py +++ b/supysonic/api/search.py @@ -1,9 +1,7 @@ -# coding: utf-8 -# # This file is part of Supysonic. # 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. @@ -119,7 +117,7 @@ def new_search(): "searchResult2", OrderedDict( ( - ("artist", [dict(id=str(a.id), name=a.name) for a in artists]), + ("artist", [a.as_subsonic_artist(request.user) for a in artists]), ("album", [f.as_subsonic_child(request.user) for f in albums]), ( "song", diff --git a/supysonic/db.py b/supysonic/db.py index a2712a8..77e1c73 100755 --- a/supysonic/db.py +++ b/supysonic/db.py @@ -1,5 +1,3 @@ -# coding: utf-8 -# # This file is part of Supysonic. # Supysonic is a Python implementation of the Subsonic server API. # @@ -18,7 +16,7 @@ from hashlib import sha1 from pony.orm import Database, Required, Optional, Set, PrimaryKey, LongStr from pony.orm import ObjectNotFound, DatabaseError from pony.orm import buffer -from pony.orm import min, max, avg, sum, exists +from pony.orm import min, max, avg, sum, count, exists from pony.orm import db_session from urllib.parse import urlparse, parse_qsl from uuid import UUID, uuid4 @@ -130,6 +128,35 @@ class Folder(PathMixin, db.Entity): return info + def as_subsonic_artist(self, user): # "Artist" type in XSD + info = dict(id=str(self.id), name=self.name) + + try: + starred = StarredFolder[user.id, self.id] + info["starred"] = starred.date.isoformat() + except ObjectNotFound: + pass + + return info + + def as_subsonic_directory(self, user, client): # "Directory" type in XSD + info = dict( + id=str(self.id), + name=self.name, + child=[ + f.as_subsonic_child(user) + for f in self.children.order_by(lambda c: c.name.lower()) + ] + + [ + t.as_subsonic_child(user, client) + for t in sorted(self.tracks, key=lambda t: t.sort_key()) + ], + ) + if not self.root: + info["parent"] = str(self.parent.id) + + return info + @classmethod def prune(cls): query = cls.select( @@ -189,7 +216,7 @@ class Album(db.Entity): stars = Set(lambda: StarredAlbum) - def as_subsonic_album(self, user): + def as_subsonic_album(self, user): # "AlbumID3" type in XSD info = dict( id=str(self.id), name=self.name, @@ -210,6 +237,13 @@ class Album(db.Entity): if track_with_cover is not None: info["coverArt"] = str(track_with_cover.id) + if count(self.tracks.year) > 0: + info["year"] = min(self.tracks.year) + + genre = ", ".join(self.tracks.genre) + if genre: + info["genre"] = genre + try: starred = StarredAlbum[user.id, self.id] info["starred"] = starred.date.isoformat()