See #75 more subsonic api endpoints (star, unstar, search...)
This commit is contained in:
parent
40cde0cd92
commit
e31099ef33
|
@ -0,0 +1,23 @@
|
||||||
|
from django_filters import rest_framework as filters
|
||||||
|
|
||||||
|
from funkwhale_api.music import models as music_models
|
||||||
|
|
||||||
|
|
||||||
|
class AlbumList2FilterSet(filters.FilterSet):
|
||||||
|
type = filters.CharFilter(name='_', method='filter_type')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = music_models.Album
|
||||||
|
fields = ['type']
|
||||||
|
|
||||||
|
def filter_type(self, queryset, name, value):
|
||||||
|
ORDERING = {
|
||||||
|
'random': '?',
|
||||||
|
'newest': '-creation_date',
|
||||||
|
'alphabeticalByArtist': 'artist__name',
|
||||||
|
'alphabeticalByName': 'title',
|
||||||
|
}
|
||||||
|
if value not in ORDERING:
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
return queryset.order_by(ORDERING[value])
|
|
@ -4,6 +4,16 @@ from django.db.models import functions, Count
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from funkwhale_api.music import models as music_models
|
||||||
|
|
||||||
|
|
||||||
|
def get_artist_data(artist_values):
|
||||||
|
return {
|
||||||
|
'id': artist_values['id'],
|
||||||
|
'name': artist_values['name'],
|
||||||
|
'albumCount': artist_values['_albums_count']
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class GetArtistsSerializer(serializers.Serializer):
|
class GetArtistsSerializer(serializers.Serializer):
|
||||||
def to_representation(self, queryset):
|
def to_representation(self, queryset):
|
||||||
|
@ -11,7 +21,7 @@ class GetArtistsSerializer(serializers.Serializer):
|
||||||
'ignoredArticles': '',
|
'ignoredArticles': '',
|
||||||
'index': []
|
'index': []
|
||||||
}
|
}
|
||||||
queryset = queryset.annotate(_albums_count=Count('albums'))
|
queryset = queryset.with_albums_count()
|
||||||
queryset = queryset.order_by(functions.Lower('name'))
|
queryset = queryset.order_by(functions.Lower('name'))
|
||||||
values = queryset.values('id', '_albums_count', 'name')
|
values = queryset.values('id', '_albums_count', 'name')
|
||||||
|
|
||||||
|
@ -23,11 +33,7 @@ class GetArtistsSerializer(serializers.Serializer):
|
||||||
letter_data = {
|
letter_data = {
|
||||||
'name': letter,
|
'name': letter,
|
||||||
'artist': [
|
'artist': [
|
||||||
{
|
get_artist_data(v)
|
||||||
'id': v['id'],
|
|
||||||
'name': v['name'],
|
|
||||||
'albumCount': v['_albums_count']
|
|
||||||
}
|
|
||||||
for v in artists
|
for v in artists
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -59,42 +65,88 @@ class GetArtistSerializer(serializers.Serializer):
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
||||||
class GetAlbumSerializer(serializers.Serializer):
|
def get_track_data(album, track, tf):
|
||||||
def to_representation(self, album):
|
data = {
|
||||||
tracks = album.tracks.prefetch_related('files')
|
|
||||||
payload = {
|
|
||||||
'id': album.id,
|
|
||||||
'artistId': album.artist.id,
|
|
||||||
'name': album.title,
|
|
||||||
'artist': album.artist.name,
|
|
||||||
'created': album.creation_date,
|
|
||||||
'songCount': len(tracks),
|
|
||||||
'song': [],
|
|
||||||
}
|
|
||||||
if album.release_date:
|
|
||||||
payload['year'] = album.release_date.year
|
|
||||||
|
|
||||||
for track in tracks:
|
|
||||||
try:
|
|
||||||
tf = [tf for tf in track.files.all()][0]
|
|
||||||
except IndexError:
|
|
||||||
continue
|
|
||||||
track_data = {
|
|
||||||
'id': track.pk,
|
'id': track.pk,
|
||||||
'isDir': False,
|
'isDir': 'false',
|
||||||
'title': track.title,
|
'title': track.title,
|
||||||
'album': album.title,
|
'album': album.title,
|
||||||
'artist': album.artist.name,
|
'artist': album.artist.name,
|
||||||
'track': track.position,
|
'track': track.position,
|
||||||
'contentType': tf.mimetype,
|
'contentType': tf.mimetype,
|
||||||
'suffix': tf.extension,
|
'suffix': tf.extension or '',
|
||||||
'duration': tf.duration,
|
'duration': tf.duration or 0,
|
||||||
'created': track.creation_date,
|
'created': track.creation_date,
|
||||||
'albumId': album.pk,
|
'albumId': album.pk,
|
||||||
'artistId': album.artist.pk,
|
'artistId': album.artist.pk,
|
||||||
'type': 'music',
|
'type': 'music',
|
||||||
}
|
}
|
||||||
if album.release_date:
|
if album.release_date:
|
||||||
track_data['year'] = album.release_date.year
|
data['year'] = album.release_date.year
|
||||||
payload['song'].append(track_data)
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def get_album2_data(album):
|
||||||
|
payload = {
|
||||||
|
'id': album.id,
|
||||||
|
'artistId': album.artist.id,
|
||||||
|
'name': album.title,
|
||||||
|
'artist': album.artist.name,
|
||||||
|
'created': album.creation_date,
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
payload['songCount'] = album._tracks_count
|
||||||
|
except AttributeError:
|
||||||
|
payload['songCount'] = len(album.tracks.prefetch_related('files'))
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def get_song_list_data(tracks):
|
||||||
|
songs = []
|
||||||
|
for track in tracks:
|
||||||
|
try:
|
||||||
|
tf = [tf for tf in track.files.all()][0]
|
||||||
|
except IndexError:
|
||||||
|
continue
|
||||||
|
track_data = get_track_data(track.album, track, tf)
|
||||||
|
songs.append(track_data)
|
||||||
|
return songs
|
||||||
|
|
||||||
|
|
||||||
|
class GetAlbumSerializer(serializers.Serializer):
|
||||||
|
def to_representation(self, album):
|
||||||
|
tracks = album.tracks.prefetch_related('files').select_related('album')
|
||||||
|
payload = get_album2_data(album)
|
||||||
|
if album.release_date:
|
||||||
|
payload['year'] = album.release_date.year
|
||||||
|
|
||||||
|
payload['song'] = get_song_list_data(tracks)
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def get_starred_tracks_data(favorites):
|
||||||
|
by_track_id = {
|
||||||
|
f.track_id: f
|
||||||
|
for f in favorites
|
||||||
|
}
|
||||||
|
tracks = music_models.Track.objects.filter(
|
||||||
|
pk__in=by_track_id.keys()
|
||||||
|
).select_related('album__artist').prefetch_related('files')
|
||||||
|
tracks = tracks.order_by('-creation_date')
|
||||||
|
data = []
|
||||||
|
for t in tracks:
|
||||||
|
try:
|
||||||
|
tf = [tf for tf in t.files.all()][0]
|
||||||
|
except IndexError:
|
||||||
|
continue
|
||||||
|
td = get_track_data(t.album, t, tf)
|
||||||
|
td['starred'] = by_track_id[t.pk].creation_date
|
||||||
|
data.append(td)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def get_album_list2_data(albums):
|
||||||
|
return [
|
||||||
|
get_album2_data(a)
|
||||||
|
for a in albums
|
||||||
|
]
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
from rest_framework import exceptions
|
from rest_framework import exceptions
|
||||||
from rest_framework import permissions as rest_permissions
|
from rest_framework import permissions as rest_permissions
|
||||||
from rest_framework import response
|
from rest_framework import response
|
||||||
|
@ -5,10 +9,13 @@ from rest_framework import viewsets
|
||||||
from rest_framework.decorators import list_route
|
from rest_framework.decorators import list_route
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
|
|
||||||
|
from funkwhale_api.favorites.models import TrackFavorite
|
||||||
from funkwhale_api.music import models as music_models
|
from funkwhale_api.music import models as music_models
|
||||||
|
from funkwhale_api.music import utils
|
||||||
from funkwhale_api.music import views as music_views
|
from funkwhale_api.music import views as music_views
|
||||||
|
|
||||||
from . import authentication
|
from . import authentication
|
||||||
|
from . import filters
|
||||||
from . import negotiation
|
from . import negotiation
|
||||||
from . import serializers
|
from . import serializers
|
||||||
|
|
||||||
|
@ -83,6 +90,24 @@ class SubsonicViewSet(viewsets.GenericViewSet):
|
||||||
}
|
}
|
||||||
return response.Response(data, status=200)
|
return response.Response(data, status=200)
|
||||||
|
|
||||||
|
@list_route(
|
||||||
|
methods=['get', 'post'],
|
||||||
|
url_name='get_license',
|
||||||
|
permissions_classes=[],
|
||||||
|
url_path='getLicense')
|
||||||
|
def get_license(self, request, *args, **kwargs):
|
||||||
|
now = timezone.now()
|
||||||
|
data = {
|
||||||
|
'status': 'ok',
|
||||||
|
'version': '1.16.0',
|
||||||
|
'license': {
|
||||||
|
'valid': 'true',
|
||||||
|
'email': 'valid@valid.license',
|
||||||
|
'licenseExpires': now + datetime.timedelta(days=365)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response.Response(data, status=200)
|
||||||
|
|
||||||
@list_route(
|
@list_route(
|
||||||
methods=['get', 'post'],
|
methods=['get', 'post'],
|
||||||
url_name='get_artists',
|
url_name='get_artists',
|
||||||
|
@ -110,6 +135,19 @@ class SubsonicViewSet(viewsets.GenericViewSet):
|
||||||
|
|
||||||
return response.Response(payload, status=200)
|
return response.Response(payload, status=200)
|
||||||
|
|
||||||
|
@list_route(
|
||||||
|
methods=['get', 'post'],
|
||||||
|
url_name='get_artist_info2',
|
||||||
|
url_path='getArtistInfo2')
|
||||||
|
@find_object(music_models.Artist.objects.all())
|
||||||
|
def get_artist_info2(self, request, *args, **kwargs):
|
||||||
|
artist = kwargs.pop('obj')
|
||||||
|
payload = {
|
||||||
|
'artist-info2': {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Response(payload, status=200)
|
||||||
|
|
||||||
@list_route(
|
@list_route(
|
||||||
methods=['get', 'post'],
|
methods=['get', 'post'],
|
||||||
url_name='get_album',
|
url_name='get_album',
|
||||||
|
@ -139,5 +177,134 @@ class SubsonicViewSet(viewsets.GenericViewSet):
|
||||||
)
|
)
|
||||||
track_file = queryset.first()
|
track_file = queryset.first()
|
||||||
if not track_file:
|
if not track_file:
|
||||||
return Response(status=404)
|
return response.Response(status=404)
|
||||||
return music_views.handle_serve(track_file)
|
return music_views.handle_serve(track_file)
|
||||||
|
|
||||||
|
@list_route(
|
||||||
|
methods=['get', 'post'],
|
||||||
|
url_name='star',
|
||||||
|
url_path='star')
|
||||||
|
@find_object(
|
||||||
|
music_models.Track.objects.all())
|
||||||
|
def star(self, request, *args, **kwargs):
|
||||||
|
track = kwargs.pop('obj')
|
||||||
|
TrackFavorite.add(user=request.user, track=track)
|
||||||
|
return response.Response({'status': 'ok'})
|
||||||
|
|
||||||
|
@list_route(
|
||||||
|
methods=['get', 'post'],
|
||||||
|
url_name='unstar',
|
||||||
|
url_path='unstar')
|
||||||
|
@find_object(
|
||||||
|
music_models.Track.objects.all())
|
||||||
|
def unstar(self, request, *args, **kwargs):
|
||||||
|
track = kwargs.pop('obj')
|
||||||
|
request.user.track_favorites.filter(track=track).delete()
|
||||||
|
return response.Response({'status': 'ok'})
|
||||||
|
|
||||||
|
@list_route(
|
||||||
|
methods=['get', 'post'],
|
||||||
|
url_name='get_starred2',
|
||||||
|
url_path='getStarred2')
|
||||||
|
def get_starred2(self, request, *args, **kwargs):
|
||||||
|
favorites = request.user.track_favorites.all()
|
||||||
|
data = {
|
||||||
|
'song': serializers.get_starred_tracks_data(favorites)
|
||||||
|
}
|
||||||
|
return response.Response(data)
|
||||||
|
|
||||||
|
@list_route(
|
||||||
|
methods=['get', 'post'],
|
||||||
|
url_name='get_album_list2',
|
||||||
|
url_path='getAlbumList2')
|
||||||
|
def get_album_list2(self, request, *args, **kwargs):
|
||||||
|
queryset = music_models.Album.objects.with_tracks_count()
|
||||||
|
data = request.GET or request.POST
|
||||||
|
filterset = filters.AlbumList2FilterSet(data, queryset=queryset)
|
||||||
|
queryset = filterset.qs
|
||||||
|
try:
|
||||||
|
offset = int(data['offset'])
|
||||||
|
except (TypeError, KeyError, ValueError):
|
||||||
|
offset = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
size = int(data['size'])
|
||||||
|
except (TypeError, KeyError, ValueError):
|
||||||
|
size = 50
|
||||||
|
|
||||||
|
size = min(size, 500)
|
||||||
|
queryset = queryset[offset:size]
|
||||||
|
data = {
|
||||||
|
'albumList2': {
|
||||||
|
'album': serializers.get_album_list2_data(queryset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response.Response(data)
|
||||||
|
|
||||||
|
|
||||||
|
@list_route(
|
||||||
|
methods=['get', 'post'],
|
||||||
|
url_name='search3',
|
||||||
|
url_path='search3')
|
||||||
|
def search3(self, request, *args, **kwargs):
|
||||||
|
data = request.GET or request.POST
|
||||||
|
query = str(data.get('query', '')).replace('*', '')
|
||||||
|
conf = [
|
||||||
|
{
|
||||||
|
'subsonic': 'artist',
|
||||||
|
'search_fields': ['name'],
|
||||||
|
'queryset': (
|
||||||
|
music_models.Artist.objects
|
||||||
|
.with_albums_count()
|
||||||
|
.values('id', '_albums_count', 'name')
|
||||||
|
),
|
||||||
|
'serializer': lambda qs: [
|
||||||
|
serializers.get_artist_data(a) for a in qs
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'subsonic': 'album',
|
||||||
|
'search_fields': ['title'],
|
||||||
|
'queryset': (
|
||||||
|
music_models.Album.objects
|
||||||
|
.with_tracks_count()
|
||||||
|
.select_related('artist')
|
||||||
|
),
|
||||||
|
'serializer': serializers.get_album_list2_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'subsonic': 'song',
|
||||||
|
'search_fields': ['title'],
|
||||||
|
'queryset': (
|
||||||
|
music_models.Track.objects
|
||||||
|
.prefetch_related('files')
|
||||||
|
.select_related('album__artist')
|
||||||
|
),
|
||||||
|
'serializer': serializers.get_song_list_data,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
payload = {
|
||||||
|
'searchResult3': {}
|
||||||
|
}
|
||||||
|
for c in conf:
|
||||||
|
offsetKey = '{}Offset'.format(c['subsonic'])
|
||||||
|
countKey = '{}Count'.format(c['subsonic'])
|
||||||
|
try:
|
||||||
|
offset = int(data[offsetKey])
|
||||||
|
except (TypeError, KeyError, ValueError):
|
||||||
|
offset = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
size = int(data[countKey])
|
||||||
|
except (TypeError, KeyError, ValueError):
|
||||||
|
size = 20
|
||||||
|
|
||||||
|
size = min(size, 100)
|
||||||
|
queryset = c['queryset']
|
||||||
|
if query:
|
||||||
|
queryset = c['queryset'].filter(
|
||||||
|
utils.get_query(query, c['search_fields'])
|
||||||
|
)
|
||||||
|
queryset = queryset[offset:size]
|
||||||
|
payload['searchResult3'][c['subsonic']] = c['serializer'](queryset)
|
||||||
|
return response.Response(payload)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from funkwhale_api.music import models as music_models
|
||||||
from funkwhale_api.subsonic import serializers
|
from funkwhale_api.subsonic import serializers
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,15 +90,15 @@ def test_get_album_serializer(factories):
|
||||||
'song': [
|
'song': [
|
||||||
{
|
{
|
||||||
'id': track.pk,
|
'id': track.pk,
|
||||||
'isDir': False,
|
'isDir': 'false',
|
||||||
'title': track.title,
|
'title': track.title,
|
||||||
'album': album.title,
|
'album': album.title,
|
||||||
'artist': artist.name,
|
'artist': artist.name,
|
||||||
'track': track.position,
|
'track': track.position,
|
||||||
'year': track.album.release_date.year,
|
'year': track.album.release_date.year,
|
||||||
'contentType': tf.mimetype,
|
'contentType': tf.mimetype,
|
||||||
'suffix': tf.extension,
|
'suffix': tf.extension or '',
|
||||||
'duration': tf.duration,
|
'duration': tf.duration or 0,
|
||||||
'created': track.creation_date,
|
'created': track.creation_date,
|
||||||
'albumId': album.pk,
|
'albumId': album.pk,
|
||||||
'artistId': artist.pk,
|
'artistId': artist.pk,
|
||||||
|
@ -107,3 +108,28 @@ def test_get_album_serializer(factories):
|
||||||
}
|
}
|
||||||
|
|
||||||
assert serializers.GetAlbumSerializer(album).data == expected
|
assert serializers.GetAlbumSerializer(album).data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_starred_tracks2_serializer(factories):
|
||||||
|
artist = factories['music.Artist']()
|
||||||
|
album = factories['music.Album'](artist=artist)
|
||||||
|
track = factories['music.Track'](album=album)
|
||||||
|
tf = factories['music.TrackFile'](track=track)
|
||||||
|
favorite = factories['favorites.TrackFavorite'](track=track)
|
||||||
|
expected = [serializers.get_track_data(album, track, tf)]
|
||||||
|
expected[0]['starred'] = favorite.creation_date
|
||||||
|
data = serializers.get_starred_tracks_data([favorite])
|
||||||
|
assert data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_album_list2_serializer(factories):
|
||||||
|
album1 = factories['music.Album']()
|
||||||
|
album2 = factories['music.Album']()
|
||||||
|
|
||||||
|
qs = music_models.Album.objects.with_tracks_count().order_by('pk')
|
||||||
|
expected = [
|
||||||
|
serializers.get_album2_data(album1),
|
||||||
|
serializers.get_album2_data(album2),
|
||||||
|
]
|
||||||
|
data = serializers.get_album_list2_data(qs)
|
||||||
|
assert data == expected
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from django.utils import timezone
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from funkwhale_api.music import models as music_models
|
from funkwhale_api.music import models as music_models
|
||||||
|
@ -42,6 +45,26 @@ def test_exception_wrong_credentials(f, db, api_client):
|
||||||
assert response.data == expected
|
assert response.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('f', ['xml', 'json'])
|
||||||
|
def test_get_license(f, db, logged_in_api_client, mocker):
|
||||||
|
url = reverse('api:subsonic-get-license')
|
||||||
|
assert url.endswith('getLicense') is True
|
||||||
|
now = timezone.now()
|
||||||
|
mocker.patch('django.utils.timezone.now', return_value=now)
|
||||||
|
response = logged_in_api_client.get(url, {'f': f})
|
||||||
|
expected = {
|
||||||
|
'status': 'ok',
|
||||||
|
'version': '1.16.0',
|
||||||
|
'license': {
|
||||||
|
'valid': 'true',
|
||||||
|
'email': 'valid@valid.license',
|
||||||
|
'licenseExpires': now + datetime.timedelta(days=365)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('f', ['xml', 'json'])
|
@pytest.mark.parametrize('f', ['xml', 'json'])
|
||||||
def test_ping(f, db, api_client):
|
def test_ping(f, db, api_client):
|
||||||
url = reverse('api:subsonic-ping')
|
url = reverse('api:subsonic-ping')
|
||||||
|
@ -86,6 +109,21 @@ def test_get_artist(f, db, logged_in_api_client, factories):
|
||||||
assert response.data == expected
|
assert response.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('f', ['xml', 'json'])
|
||||||
|
def test_get_artist_info2(f, db, logged_in_api_client, factories):
|
||||||
|
url = reverse('api:subsonic-get-artist-info2')
|
||||||
|
assert url.endswith('getArtistInfo2') is True
|
||||||
|
artist = factories['music.Artist']()
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
'artist-info2': {}
|
||||||
|
}
|
||||||
|
response = logged_in_api_client.get(url, {'id': artist.pk})
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('f', ['xml', 'json'])
|
@pytest.mark.parametrize('f', ['xml', 'json'])
|
||||||
def test_get_album(f, db, logged_in_api_client, factories):
|
def test_get_album(f, db, logged_in_api_client, factories):
|
||||||
url = reverse('api:subsonic-get-album')
|
url = reverse('api:subsonic-get-album')
|
||||||
|
@ -118,3 +156,87 @@ def test_stream(f, db, logged_in_api_client, factories, mocker):
|
||||||
track_file=tf
|
track_file=tf
|
||||||
)
|
)
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('f', ['xml', 'json'])
|
||||||
|
def test_star(f, db, logged_in_api_client, factories):
|
||||||
|
url = reverse('api:subsonic-star')
|
||||||
|
assert url.endswith('star') is True
|
||||||
|
track = factories['music.Track']()
|
||||||
|
response = logged_in_api_client.get(url, {'f': f, 'id': track.pk})
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data == {'status': 'ok'}
|
||||||
|
|
||||||
|
favorite = logged_in_api_client.user.track_favorites.latest('id')
|
||||||
|
assert favorite.track == track
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('f', ['xml', 'json'])
|
||||||
|
def test_unstar(f, db, logged_in_api_client, factories):
|
||||||
|
url = reverse('api:subsonic-unstar')
|
||||||
|
assert url.endswith('unstar') is True
|
||||||
|
track = factories['music.Track']()
|
||||||
|
favorite = factories['favorites.TrackFavorite'](
|
||||||
|
track=track, user=logged_in_api_client.user)
|
||||||
|
response = logged_in_api_client.get(url, {'f': f, 'id': track.pk})
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data == {'status': 'ok'}
|
||||||
|
assert logged_in_api_client.user.track_favorites.count() == 0
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('f', ['xml', 'json'])
|
||||||
|
def test_get_starred2(f, db, logged_in_api_client, factories):
|
||||||
|
url = reverse('api:subsonic-get-starred2')
|
||||||
|
assert url.endswith('getStarred2') is True
|
||||||
|
track = factories['music.Track']()
|
||||||
|
favorite = factories['favorites.TrackFavorite'](
|
||||||
|
track=track, user=logged_in_api_client.user)
|
||||||
|
response = logged_in_api_client.get(url, {'f': f, 'id': track.pk})
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data == {
|
||||||
|
'song': serializers.get_starred_tracks_data([favorite])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('f', ['xml', 'json'])
|
||||||
|
def test_get_album_list2(f, db, logged_in_api_client, factories):
|
||||||
|
url = reverse('api:subsonic-get-album-list2')
|
||||||
|
assert url.endswith('getAlbumList2') is True
|
||||||
|
album1 = factories['music.Album']()
|
||||||
|
album2 = factories['music.Album']()
|
||||||
|
response = logged_in_api_client.get(url, {'f': f, 'type': 'newest'})
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data == {
|
||||||
|
'albumList2': {
|
||||||
|
'album': serializers.get_album_list2_data([album2, album1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('f', ['xml', 'json'])
|
||||||
|
def test_search3(f, db, logged_in_api_client, factories):
|
||||||
|
url = reverse('api:subsonic-search3')
|
||||||
|
assert url.endswith('search3') is True
|
||||||
|
artist = factories['music.Artist'](name='testvalue')
|
||||||
|
factories['music.Artist'](name='nope')
|
||||||
|
album = factories['music.Album'](title='testvalue')
|
||||||
|
factories['music.Album'](title='nope')
|
||||||
|
track = factories['music.Track'](title='testvalue')
|
||||||
|
factories['music.Track'](title='nope')
|
||||||
|
|
||||||
|
response = logged_in_api_client.get(url, {'f': f, 'query': 'testval'})
|
||||||
|
|
||||||
|
artist_qs = music_models.Artist.objects.with_albums_count().filter(
|
||||||
|
pk=artist.pk).values('_albums_count', 'id', 'name')
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.data == {
|
||||||
|
'searchResult3': {
|
||||||
|
'artist': [serializers.get_artist_data(a) for a in artist_qs],
|
||||||
|
'album': serializers.get_album_list2_data([album]),
|
||||||
|
'song': serializers.get_song_list_data([track]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue