1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-22 17:06:17 +00:00

Porting supysonic.api.browse

This commit is contained in:
Alban Féron 2022-12-18 18:03:51 +01:00
parent 7401b4dec9
commit 95f77cc170
No known key found for this signature in database
GPG Key ID: 8CE0313646D16165
4 changed files with 112 additions and 117 deletions

View File

@ -96,8 +96,7 @@ def get_entity(cls, param="id"):
eid = int(eid) eid = int(eid)
else: else:
eid = uuid.UUID(eid) eid = uuid.UUID(eid)
entity = cls[eid] return cls[eid]
return entity
def get_entity_id(cls, eid): def get_entity_id(cls, eid):
@ -107,12 +106,12 @@ def get_entity_id(cls, eid):
raise GenericError("Invalid ID") raise GenericError("Invalid ID")
try: try:
return int(eid) return int(eid)
except ValueError: except ValueError as e:
raise GenericError("Invalid ID") raise GenericError("Invalid ID") from e
try: try:
return uuid.UUID(eid) return uuid.UUID(eid)
except (AttributeError, ValueError): except (AttributeError, ValueError) as e:
raise GenericError("Invalid ID") raise GenericError("Invalid ID") from e
def get_root_folder(id): def get_root_folder(id):
@ -121,14 +120,13 @@ def get_root_folder(id):
try: try:
fid = int(id) fid = int(id)
except ValueError: except ValueError as e:
raise ValueError("Invalid folder ID") raise ValueError("Invalid folder ID") from e
folder = Folder.get(id=fid, root=True) try:
if folder is None: return Folder.get(id=fid, root=True)
raise NotFound("Folder") except Folder.DoesNotExist as e:
raise NotFound("Folder") from e
return folder
from .errors import * from .errors import *

View File

@ -9,6 +9,7 @@ import re
import string import string
from flask import current_app, request from flask import current_app, request
from peewee import fn
from ..db import Folder, Artist, Album, Track from ..db import Folder, Artist, Album, Track
@ -22,7 +23,7 @@ def list_folders():
{ {
"musicFolder": [ "musicFolder": [
{"id": str(f.id), "name": f.name} {"id": str(f.id), "name": f.name}
for f in Folder.select(lambda f: f.root).order_by(Folder.name) for f in Folder.select().where(Folder.root).order_by(Folder.name)
] ]
}, },
) )
@ -77,7 +78,7 @@ def list_indexes():
ifModifiedSince = int(ifModifiedSince) / 1000 ifModifiedSince = int(ifModifiedSince) / 1000
if musicFolderId is None: if musicFolderId is None:
folders = Folder.select(lambda f: f.root)[:] folders = Folder.select().where(Folder.root)[:]
else: else:
folders = [get_root_folder(musicFolderId)] folders = [get_root_folder(musicFolderId)]
@ -95,8 +96,8 @@ def list_indexes():
artists = [] artists = []
children = [] children = []
for f in folders: for f in folders:
artists += f.children.select()[:] artists += f.children[:]
children += f.tracks.select()[:] children += f.tracks[:]
indexes = build_indexes(artists) indexes = build_indexes(artists)
return request.formatter( return request.formatter(
@ -137,9 +138,11 @@ def list_genres():
{ {
"genre": [ "genre": [
{"value": genre, "songCount": sc, "albumCount": ac} {"value": genre, "songCount": sc, "albumCount": ac}
for genre, sc, ac in select( for genre, sc, ac in Track.select(
(t.genre, count(), count(t.album)) for t in Track if t.genre Track.genre, fn.count(), fn.count(Track.album.distinct())
) )
.group_by(Track.genre)
.tuples()
] ]
}, },
) )
@ -152,7 +155,7 @@ def list_artists():
query = Artist.select() query = Artist.select()
if mfid is not None: if mfid is not None:
folder = get_root_folder(mfid) folder = get_root_folder(mfid)
query = Artist.select(lambda a: folder in a.tracks.root_folder) query = Artist.select().join(Track).where(Track.root_folder == folder)
indexes = build_indexes(query) indexes = build_indexes(query)
return request.formatter( return request.formatter(

View File

@ -150,7 +150,7 @@ class Folder(PathMixin, db.Model):
"name": self.name, "name": self.name,
"child": [ "child": [
f.as_subsonic_child(user) f.as_subsonic_child(user)
for f in self.children.order_by(lambda c: c.name.lower()) for f in self.children.order_by(fn.lower(Folder.name))
] ]
+ [ + [
t.as_subsonic_child(user, client) t.as_subsonic_child(user, client)

View File

@ -9,8 +9,6 @@ import time
import unittest import unittest
import uuid import uuid
from pony.orm import db_session
from supysonic.db import Folder, Artist, Album, Track from supysonic.db import Folder, Artist, Album, Track
from .apitestbase import ApiTestBase from .apitestbase import ApiTestBase
@ -20,51 +18,52 @@ class BrowseTestCase(ApiTestBase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
with db_session: self.empty_root = Folder.create(root=True, name="Empty root", path="/tmp")
self.empty_root = Folder(root=True, name="Empty root", path="/tmp") self.root = Folder.create(root=True, name="Root folder", path="tests/assets")
self.root = Folder(root=True, name="Root folder", path="tests/assets")
for letter in "ABC": for letter in "ABC":
folder = Folder( folder = Folder.create(
name=letter + "rtist", name=letter + "rtist",
path="tests/assets/{}rtist".format(letter), path="tests/assets/{}rtist".format(letter),
parent=self.root, root=False,
parent=self.root,
)
artist = Artist.create(name=letter + "rtist")
for lether in "AB":
afolder = Folder.create(
name=letter + lether + "lbum",
path="tests/assets/{0}rtist/{0}{1}lbum".format(letter, lether),
root=False,
parent=folder,
) )
artist = Artist(name=letter + "rtist") album = Album.create(name=letter + lether + "lbum", artist=artist)
for lether in "AB": for num, song in enumerate(["One", "Two", "Three"]):
afolder = Folder( Track.create(
name=letter + lether + "lbum", disc=1,
path="tests/assets/{0}rtist/{0}{1}lbum".format(letter, lether), number=num,
parent=folder, title=song,
duration=2,
album=album,
artist=artist,
genre="Music!",
bitrate=320,
path="tests/assets/{0}rtist/{0}{1}lbum/{2}".format(
letter, lether, song
),
last_modification=0,
root_folder=self.root,
folder=afolder,
) )
album = Album(name=letter + lether + "lbum", artist=artist) self.assertEqual(Folder.select().count(), 11)
self.assertEqual(Folder.select().where(Folder.root).count(), 2)
for num, song in enumerate(["One", "Two", "Three"]): self.assertEqual(Artist.select().count(), 3)
Track( self.assertEqual(Album.select().count(), 6)
disc=1, self.assertEqual(Track.select().count(), 18)
number=num,
title=song,
duration=2,
album=album,
artist=artist,
genre="Music!",
bitrate=320,
path="tests/assets/{0}rtist/{0}{1}lbum/{2}".format(
letter, lether, song
),
last_modification=0,
root_folder=self.root,
folder=afolder,
)
self.assertEqual(Folder.select().count(), 11)
self.assertEqual(Folder.select(lambda f: f.root).count(), 2)
self.assertEqual(Artist.select().count(), 3)
self.assertEqual(Album.select().count(), 6)
self.assertEqual(Track.select().count(), 18)
def test_get_music_folders(self): def test_get_music_folders(self):
rv, child = self._make_request("getMusicFolders", tag="musicFolders") rv, child = self._make_request("getMusicFolders", tag="musicFolders")
@ -86,8 +85,7 @@ class BrowseTestCase(ApiTestBase):
) )
self.assertEqual(len(child), 0) self.assertEqual(len(child), 0)
with db_session: fid = Folder.get(name="Empty root").id
fid = Folder.get(name="Empty root").id
rv, child = self._make_request( rv, child = self._make_request(
"getIndexes", {"musicFolderId": str(fid)}, tag="indexes" "getIndexes", {"musicFolderId": str(fid)}, tag="indexes"
) )
@ -106,27 +104,26 @@ class BrowseTestCase(ApiTestBase):
self._make_request("getMusicDirectory", {"id": 1234567890}, error=70) self._make_request("getMusicDirectory", {"id": 1234567890}, error=70)
# should test with folders with both children folders and tracks. this code would break in that case # should test with folders with both children folders and tracks. this code would break in that case
with db_session: for f in Folder.select():
for f in Folder.select(): rv, child = self._make_request(
rv, child = self._make_request( "getMusicDirectory", {"id": str(f.id)}, tag="directory"
"getMusicDirectory", {"id": str(f.id)}, tag="directory" )
) self.assertEqual(child.get("id"), str(f.id))
self.assertEqual(child.get("id"), str(f.id)) self.assertEqual(child.get("name"), f.name)
self.assertEqual(child.get("name"), f.name) self.assertEqual(len(child), f.children.count() + f.tracks.count())
self.assertEqual(len(child), f.children.count() + f.tracks.count()) for dbc, xmlc in zip(
for dbc, xmlc in zip( sorted(f.children, key=lambda c: c.name),
sorted(f.children, key=lambda c: c.name), sorted(child, key=lambda c: c.get("title")),
sorted(child, key=lambda c: c.get("title")), ):
): self.assertEqual(dbc.name, xmlc.get("title"))
self.assertEqual(dbc.name, xmlc.get("title")) self.assertEqual(xmlc.get("artist"), f.name)
self.assertEqual(xmlc.get("artist"), f.name) self.assertEqual(xmlc.get("parent"), str(f.id))
self.assertEqual(xmlc.get("parent"), str(f.id)) for t, xmlc in zip(
for t, xmlc in zip( sorted(f.tracks, key=lambda t: t.title),
sorted(f.tracks, key=lambda t: t.title), sorted(child, key=lambda c: c.get("title")),
sorted(child, key=lambda c: c.get("title")), ):
): self.assertEqual(t.title, xmlc.get("title"))
self.assertEqual(t.title, xmlc.get("title")) self.assertEqual(xmlc.get("parent"), str(f.id))
self.assertEqual(xmlc.get("parent"), str(f.id))
def test_get_artists(self): def test_get_artists(self):
# same as getIndexes standard case # same as getIndexes standard case
@ -158,51 +155,48 @@ class BrowseTestCase(ApiTestBase):
self._make_request("getArtist", {"id": "artist"}, error=0) self._make_request("getArtist", {"id": "artist"}, error=0)
self._make_request("getArtist", {"id": str(uuid.uuid4())}, error=70) self._make_request("getArtist", {"id": str(uuid.uuid4())}, error=70)
with db_session: for ar in Artist.select():
for ar in Artist.select(): rv, child = self._make_request(
rv, child = self._make_request( "getArtist", {"id": str(ar.id)}, tag="artist"
"getArtist", {"id": str(ar.id)}, tag="artist" )
) self.assertEqual(child.get("id"), str(ar.id))
self.assertEqual(child.get("id"), str(ar.id)) self.assertEqual(child.get("albumCount"), str(len(child)))
self.assertEqual(child.get("albumCount"), str(len(child))) self.assertEqual(len(child), ar.albums.count())
self.assertEqual(len(child), ar.albums.count()) for dal, xal in zip(
for dal, xal in zip( sorted(ar.albums, key=lambda a: a.name),
sorted(ar.albums, key=lambda a: a.name), sorted(child, key=lambda c: c.get("name")),
sorted(child, key=lambda c: c.get("name")), ):
): self.assertEqual(dal.name, xal.get("name"))
self.assertEqual(dal.name, xal.get("name")) self.assertEqual(
self.assertEqual( xal.get("artist"), ar.name
xal.get("artist"), ar.name ) # could break with a better dataset
) # could break with a better dataset self.assertEqual(xal.get("artistId"), str(ar.id)) # see above
self.assertEqual(xal.get("artistId"), str(ar.id)) # see above
def test_get_album(self): def test_get_album(self):
self._make_request("getAlbum", error=10) self._make_request("getAlbum", error=10)
self._make_request("getAlbum", {"id": "nastynasty"}, error=0) self._make_request("getAlbum", {"id": "nastynasty"}, error=0)
self._make_request("getAlbum", {"id": str(uuid.uuid4())}, error=70) self._make_request("getAlbum", {"id": str(uuid.uuid4())}, error=70)
with db_session: a = Album.select().first()
a = Album.select().first() rv, child = self._make_request("getAlbum", {"id": str(a.id)}, tag="album")
rv, child = self._make_request("getAlbum", {"id": str(a.id)}, tag="album") self.assertEqual(child.get("id"), str(a.id))
self.assertEqual(child.get("id"), str(a.id)) self.assertEqual(child.get("songCount"), str(len(child)))
self.assertEqual(child.get("songCount"), str(len(child)))
self.assertEqual(len(child), a.tracks.count()) self.assertEqual(len(child), a.tracks.count())
for dal, xal in zip( for dal, xal in zip(
sorted(a.tracks, key=lambda t: t.title), sorted(a.tracks, key=lambda t: t.title),
sorted(child, key=lambda c: c.get("title")), sorted(child, key=lambda c: c.get("title")),
): ):
self.assertEqual(dal.title, xal.get("title")) self.assertEqual(dal.title, xal.get("title"))
self.assertEqual(xal.get("album"), a.name) self.assertEqual(xal.get("album"), a.name)
self.assertEqual(xal.get("albumId"), str(a.id)) self.assertEqual(xal.get("albumId"), str(a.id))
def test_get_song(self): def test_get_song(self):
self._make_request("getSong", error=10) self._make_request("getSong", error=10)
self._make_request("getSong", {"id": "nastynasty"}, error=0) self._make_request("getSong", {"id": "nastynasty"}, error=0)
self._make_request("getSong", {"id": str(uuid.uuid4())}, error=70) self._make_request("getSong", {"id": str(uuid.uuid4())}, error=70)
with db_session: s = Track.select().first()
s = Track.select().first()
self._make_request("getSong", {"id": str(s.id)}, tag="song") self._make_request("getSong", {"id": str(s.id)}, tag="song")
def test_get_videos(self): def test_get_videos(self):