See #272: updated API to return upload data on tracks
This commit is contained in:
parent
8489c79c89
commit
d3f8fb6cb0
|
@ -51,7 +51,7 @@ class TrackFavoriteViewSet(
|
||||||
queryset = queryset.filter(
|
queryset = queryset.filter(
|
||||||
fields.privacy_level_query(self.request.user, "user__privacy_level")
|
fields.privacy_level_query(self.request.user, "user__privacy_level")
|
||||||
)
|
)
|
||||||
tracks = Track.objects.annotate_playable_by_actor(
|
tracks = Track.objects.with_playable_uploads(
|
||||||
music_utils.get_actor_from_request(self.request)
|
music_utils.get_actor_from_request(self.request)
|
||||||
).select_related("artist", "album__artist")
|
).select_related("artist", "album__artist")
|
||||||
queryset = queryset.prefetch_related(Prefetch("track", queryset=tracks))
|
queryset = queryset.prefetch_related(Prefetch("track", queryset=tracks))
|
||||||
|
|
|
@ -41,7 +41,7 @@ class ListeningViewSet(
|
||||||
queryset = queryset.filter(
|
queryset = queryset.filter(
|
||||||
fields.privacy_level_query(self.request.user, "user__privacy_level")
|
fields.privacy_level_query(self.request.user, "user__privacy_level")
|
||||||
)
|
)
|
||||||
tracks = Track.objects.annotate_playable_by_actor(
|
tracks = Track.objects.with_playable_uploads(
|
||||||
music_utils.get_actor_from_request(self.request)
|
music_utils.get_actor_from_request(self.request)
|
||||||
).select_related("artist", "album__artist")
|
).select_related("artist", "album__artist")
|
||||||
return queryset.prefetch_related(Prefetch("track", queryset=tracks))
|
return queryset.prefetch_related(Prefetch("track", queryset=tracks))
|
||||||
|
|
|
@ -124,8 +124,8 @@ class ArtistQuerySet(models.QuerySet):
|
||||||
|
|
||||||
def annotate_playable_by_actor(self, actor):
|
def annotate_playable_by_actor(self, actor):
|
||||||
tracks = (
|
tracks = (
|
||||||
Track.objects.playable_by(actor)
|
Upload.objects.playable_by(actor)
|
||||||
.filter(artist=models.OuterRef("id"))
|
.filter(track__artist=models.OuterRef("id"))
|
||||||
.order_by("id")
|
.order_by("id")
|
||||||
.values("id")[:1]
|
.values("id")[:1]
|
||||||
)
|
)
|
||||||
|
@ -192,8 +192,8 @@ class AlbumQuerySet(models.QuerySet):
|
||||||
|
|
||||||
def annotate_playable_by_actor(self, actor):
|
def annotate_playable_by_actor(self, actor):
|
||||||
tracks = (
|
tracks = (
|
||||||
Track.objects.playable_by(actor)
|
Upload.objects.playable_by(actor)
|
||||||
.filter(album=models.OuterRef("id"))
|
.filter(track__album=models.OuterRef("id"))
|
||||||
.order_by("id")
|
.order_by("id")
|
||||||
.values("id")[:1]
|
.values("id")[:1]
|
||||||
)
|
)
|
||||||
|
@ -207,6 +207,15 @@ class AlbumQuerySet(models.QuerySet):
|
||||||
else:
|
else:
|
||||||
return self.exclude(tracks__in=tracks).distinct()
|
return self.exclude(tracks__in=tracks).distinct()
|
||||||
|
|
||||||
|
def with_prefetched_tracks_and_playable_uploads(self, actor):
|
||||||
|
tracks = Track.objects.with_playable_uploads(actor)
|
||||||
|
return self.prefetch_related(
|
||||||
|
models.Prefetch(
|
||||||
|
'tracks',
|
||||||
|
queryset=tracks,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Album(APIModelMixin):
|
class Album(APIModelMixin):
|
||||||
title = models.CharField(max_length=255)
|
title = models.CharField(max_length=255)
|
||||||
|
@ -403,18 +412,14 @@ class TrackQuerySet(models.QuerySet):
|
||||||
else:
|
else:
|
||||||
return self.exclude(uploads__in=files).distinct()
|
return self.exclude(uploads__in=files).distinct()
|
||||||
|
|
||||||
def annotate_duration(self):
|
def with_playable_uploads(self, actor):
|
||||||
first_upload = Upload.objects.filter(track=models.OuterRef("pk")).order_by("pk")
|
uploads = Upload.objects.playable_by(actor).select_related('track')
|
||||||
return self.annotate(
|
return self.prefetch_related(
|
||||||
duration=models.Subquery(first_upload.values("duration")[:1])
|
models.Prefetch(
|
||||||
)
|
'uploads',
|
||||||
|
queryset=uploads,
|
||||||
def annotate_file_data(self):
|
to_attr='playable_uploads'
|
||||||
first_upload = Upload.objects.filter(track=models.OuterRef("pk")).order_by("pk")
|
)
|
||||||
return self.annotate(
|
|
||||||
bitrate=models.Subquery(first_upload.values("bitrate")[:1]),
|
|
||||||
size=models.Subquery(first_upload.values("size")[:1]),
|
|
||||||
mimetype=models.Subquery(first_upload.values("mimetype")[:1]),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ class ArtistSimpleSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class AlbumTrackSerializer(serializers.ModelSerializer):
|
class AlbumTrackSerializer(serializers.ModelSerializer):
|
||||||
artist = ArtistSimpleSerializer(read_only=True)
|
artist = ArtistSimpleSerializer(read_only=True)
|
||||||
is_playable = serializers.SerializerMethodField()
|
uploads = serializers.SerializerMethodField()
|
||||||
listen_url = serializers.SerializerMethodField()
|
listen_url = serializers.SerializerMethodField()
|
||||||
duration = serializers.SerializerMethodField()
|
duration = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
@ -73,16 +73,14 @@ class AlbumTrackSerializer(serializers.ModelSerializer):
|
||||||
"artist",
|
"artist",
|
||||||
"creation_date",
|
"creation_date",
|
||||||
"position",
|
"position",
|
||||||
"is_playable",
|
"uploads",
|
||||||
"listen_url",
|
"listen_url",
|
||||||
"duration",
|
"duration",
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_is_playable(self, obj):
|
def get_uploads(self, obj):
|
||||||
try:
|
uploads = getattr(obj, "playable_uploads", [])
|
||||||
return bool(obj.is_playable_by_actor)
|
return TrackUploadSerializer(uploads, many=True).data
|
||||||
except AttributeError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_listen_url(self, obj):
|
def get_listen_url(self, obj):
|
||||||
return obj.listen_url
|
return obj.listen_url
|
||||||
|
@ -123,7 +121,9 @@ class AlbumSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
def get_is_playable(self, obj):
|
def get_is_playable(self, obj):
|
||||||
try:
|
try:
|
||||||
return any([bool(t.is_playable_by_actor) for t in obj.tracks.all()])
|
return any(
|
||||||
|
[bool(getattr(t, "playable_uploads", [])) for t in obj.tracks.all()]
|
||||||
|
)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -145,16 +145,26 @@ class TrackAlbumSerializer(serializers.ModelSerializer):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TrackUploadSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = models.Upload
|
||||||
|
fields = (
|
||||||
|
"uuid",
|
||||||
|
"listen_url",
|
||||||
|
"size",
|
||||||
|
"duration",
|
||||||
|
"bitrate",
|
||||||
|
"mimetype",
|
||||||
|
"extension",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TrackSerializer(serializers.ModelSerializer):
|
class TrackSerializer(serializers.ModelSerializer):
|
||||||
artist = ArtistSimpleSerializer(read_only=True)
|
artist = ArtistSimpleSerializer(read_only=True)
|
||||||
album = TrackAlbumSerializer(read_only=True)
|
album = TrackAlbumSerializer(read_only=True)
|
||||||
lyrics = serializers.SerializerMethodField()
|
lyrics = serializers.SerializerMethodField()
|
||||||
is_playable = serializers.SerializerMethodField()
|
uploads = serializers.SerializerMethodField()
|
||||||
listen_url = serializers.SerializerMethodField()
|
listen_url = serializers.SerializerMethodField()
|
||||||
duration = serializers.SerializerMethodField()
|
|
||||||
bitrate = serializers.SerializerMethodField()
|
|
||||||
size = serializers.SerializerMethodField()
|
|
||||||
mimetype = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Track
|
model = models.Track
|
||||||
|
@ -167,12 +177,8 @@ class TrackSerializer(serializers.ModelSerializer):
|
||||||
"creation_date",
|
"creation_date",
|
||||||
"position",
|
"position",
|
||||||
"lyrics",
|
"lyrics",
|
||||||
"is_playable",
|
"uploads",
|
||||||
"listen_url",
|
"listen_url",
|
||||||
"duration",
|
|
||||||
"bitrate",
|
|
||||||
"size",
|
|
||||||
"mimetype",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_lyrics(self, obj):
|
def get_lyrics(self, obj):
|
||||||
|
@ -181,35 +187,9 @@ class TrackSerializer(serializers.ModelSerializer):
|
||||||
def get_listen_url(self, obj):
|
def get_listen_url(self, obj):
|
||||||
return obj.listen_url
|
return obj.listen_url
|
||||||
|
|
||||||
def get_is_playable(self, obj):
|
def get_uploads(self, obj):
|
||||||
try:
|
uploads = getattr(obj, "playable_uploads", [])
|
||||||
return bool(obj.is_playable_by_actor)
|
return TrackUploadSerializer(uploads, many=True).data
|
||||||
except AttributeError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_duration(self, obj):
|
|
||||||
try:
|
|
||||||
return obj.duration
|
|
||||||
except AttributeError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_bitrate(self, obj):
|
|
||||||
try:
|
|
||||||
return obj.bitrate
|
|
||||||
except AttributeError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_size(self, obj):
|
|
||||||
try:
|
|
||||||
return obj.size
|
|
||||||
except AttributeError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_mimetype(self, obj):
|
|
||||||
try:
|
|
||||||
return obj.mimetype
|
|
||||||
except AttributeError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
class LibraryForOwnerSerializer(serializers.ModelSerializer):
|
class LibraryForOwnerSerializer(serializers.ModelSerializer):
|
||||||
|
|
|
@ -5,7 +5,6 @@ import mutagen
|
||||||
import pydub
|
import pydub
|
||||||
|
|
||||||
from funkwhale_api.common.search import normalize_query, get_query # noqa
|
from funkwhale_api.common.search import normalize_query, get_query # noqa
|
||||||
from funkwhale_api.common import utils
|
|
||||||
|
|
||||||
|
|
||||||
def guess_mimetype(f):
|
def guess_mimetype(f):
|
||||||
|
|
|
@ -93,17 +93,9 @@ class AlbumViewSet(viewsets.ReadOnlyModelViewSet):
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = super().get_queryset()
|
queryset = super().get_queryset()
|
||||||
tracks = models.Track.objects.annotate_playable_by_actor(
|
tracks = models.Track.objects.select_related("artist").with_playable_uploads(
|
||||||
utils.get_actor_from_request(self.request)
|
utils.get_actor_from_request(self.request)
|
||||||
).select_related("artist")
|
)
|
||||||
if (
|
|
||||||
hasattr(self, "kwargs")
|
|
||||||
and self.kwargs
|
|
||||||
and self.request.method.lower() == "get"
|
|
||||||
):
|
|
||||||
# we are detailing a single album, so we can add the overhead
|
|
||||||
# to fetch additional data
|
|
||||||
tracks = tracks.annotate_duration()
|
|
||||||
qs = queryset.prefetch_related(Prefetch("tracks", queryset=tracks))
|
qs = queryset.prefetch_related(Prefetch("tracks", queryset=tracks))
|
||||||
return qs.distinct()
|
return qs.distinct()
|
||||||
|
|
||||||
|
@ -194,18 +186,10 @@ class TrackViewSet(TagViewSetMixin, viewsets.ReadOnlyModelViewSet):
|
||||||
if user.is_authenticated and filter_favorites == "true":
|
if user.is_authenticated and filter_favorites == "true":
|
||||||
queryset = queryset.filter(track_favorites__user=user)
|
queryset = queryset.filter(track_favorites__user=user)
|
||||||
|
|
||||||
queryset = queryset.annotate_playable_by_actor(
|
queryset = queryset.with_playable_uploads(
|
||||||
utils.get_actor_from_request(self.request)
|
utils.get_actor_from_request(self.request)
|
||||||
).annotate_duration()
|
)
|
||||||
if (
|
return queryset
|
||||||
hasattr(self, "kwargs")
|
|
||||||
and self.kwargs
|
|
||||||
and self.request.method.lower() == "get"
|
|
||||||
):
|
|
||||||
# we are detailing a single track, so we can add the overhead
|
|
||||||
# to fetch additional data
|
|
||||||
queryset = queryset.annotate_file_data()
|
|
||||||
return queryset.distinct()
|
|
||||||
|
|
||||||
@detail_route(methods=["get"])
|
@detail_route(methods=["get"])
|
||||||
@transaction.non_atomic_requests
|
@transaction.non_atomic_requests
|
||||||
|
|
|
@ -38,15 +38,14 @@ class PlaylistQuerySet(models.QuerySet):
|
||||||
)
|
)
|
||||||
return self.prefetch_related(plt_prefetch)
|
return self.prefetch_related(plt_prefetch)
|
||||||
|
|
||||||
def annotate_playable_by_actor(self, actor):
|
def with_playable_plts(self, actor):
|
||||||
plts = (
|
return self.prefetch_related(
|
||||||
PlaylistTrack.objects.playable_by(actor)
|
models.Prefetch(
|
||||||
.filter(playlist=models.OuterRef("id"))
|
"playlist_tracks",
|
||||||
.order_by("id")
|
queryset=PlaylistTrack.objects.playable_by(actor),
|
||||||
.values("id")[:1]
|
to_attr="playable_plts",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
subquery = models.Subquery(plts)
|
|
||||||
return self.annotate(is_playable_by_actor=subquery)
|
|
||||||
|
|
||||||
def playable_by(self, actor, include=True):
|
def playable_by(self, actor, include=True):
|
||||||
plts = PlaylistTrack.objects.playable_by(actor, include)
|
plts = PlaylistTrack.objects.playable_by(actor, include)
|
||||||
|
@ -148,7 +147,7 @@ class Playlist(models.Model):
|
||||||
|
|
||||||
class PlaylistTrackQuerySet(models.QuerySet):
|
class PlaylistTrackQuerySet(models.QuerySet):
|
||||||
def for_nested_serialization(self, actor=None):
|
def for_nested_serialization(self, actor=None):
|
||||||
tracks = music_models.Track.objects.annotate_playable_by_actor(actor)
|
tracks = music_models.Track.objects.with_playable_uploads(actor)
|
||||||
tracks = tracks.select_related("artist", "album__artist")
|
tracks = tracks.select_related("artist", "album__artist")
|
||||||
return self.prefetch_related(
|
return self.prefetch_related(
|
||||||
models.Prefetch("track", queryset=tracks, to_attr="_prefetched_track")
|
models.Prefetch("track", queryset=tracks, to_attr="_prefetched_track")
|
||||||
|
@ -156,8 +155,8 @@ class PlaylistTrackQuerySet(models.QuerySet):
|
||||||
|
|
||||||
def annotate_playable_by_actor(self, actor):
|
def annotate_playable_by_actor(self, actor):
|
||||||
tracks = (
|
tracks = (
|
||||||
music_models.Track.objects.playable_by(actor)
|
music_models.Upload.objects.playable_by(actor)
|
||||||
.filter(pk=models.OuterRef("track"))
|
.filter(track__pk=models.OuterRef("track"))
|
||||||
.order_by("id")
|
.order_by("id")
|
||||||
.values("id")[:1]
|
.values("id")[:1]
|
||||||
)
|
)
|
||||||
|
|
|
@ -93,7 +93,7 @@ class PlaylistSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
def get_is_playable(self, obj):
|
def get_is_playable(self, obj):
|
||||||
try:
|
try:
|
||||||
return bool(obj.is_playable_by_actor)
|
return bool(obj.playable_plts)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ class PlaylistViewSet(
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return self.queryset.filter(
|
return self.queryset.filter(
|
||||||
fields.privacy_level_query(self.request.user)
|
fields.privacy_level_query(self.request.user)
|
||||||
).annotate_playable_by_actor(music_utils.get_actor_from_request(self.request))
|
).with_playable_plts(music_utils.get_actor_from_request(self.request))
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
return serializer.save(
|
return serializer.save(
|
||||||
|
|
|
@ -35,7 +35,6 @@ def test_user_can_get_his_favorites(api_request, factories, logged_in_client, cl
|
||||||
"creation_date": favorite.creation_date.isoformat().replace("+00:00", "Z"),
|
"creation_date": favorite.creation_date.isoformat().replace("+00:00", "Z"),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
expected[0]["track"]["is_playable"] = False
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
assert response.data["results"] == expected
|
assert response.data["results"] == expected
|
||||||
|
|
||||||
|
|
|
@ -464,24 +464,6 @@ def test_library_queryset_with_follows(factories):
|
||||||
assert l2._follows == [follow]
|
assert l2._follows == [follow]
|
||||||
|
|
||||||
|
|
||||||
def test_annotate_duration(factories):
|
|
||||||
tf = factories["music.Upload"](duration=32)
|
|
||||||
|
|
||||||
track = models.Track.objects.annotate_duration().get(pk=tf.track.pk)
|
|
||||||
|
|
||||||
assert track.duration == 32
|
|
||||||
|
|
||||||
|
|
||||||
def test_annotate_file_data(factories):
|
|
||||||
tf = factories["music.Upload"](size=42, bitrate=55, mimetype="audio/ogg")
|
|
||||||
|
|
||||||
track = models.Track.objects.annotate_file_data().get(pk=tf.track.pk)
|
|
||||||
|
|
||||||
assert track.size == 42
|
|
||||||
assert track.bitrate == 55
|
|
||||||
assert track.mimetype == "audio/ogg"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"model,factory_args,namespace",
|
"model,factory_args,namespace",
|
||||||
[
|
[
|
||||||
|
|
|
@ -48,6 +48,7 @@ def test_artist_with_albums_serializer(factories, to_api_date):
|
||||||
def test_album_track_serializer(factories, to_api_date):
|
def test_album_track_serializer(factories, to_api_date):
|
||||||
upload = factories["music.Upload"]()
|
upload = factories["music.Upload"]()
|
||||||
track = upload.track
|
track = upload.track
|
||||||
|
setattr(track, "playable_uploads", [upload])
|
||||||
|
|
||||||
expected = {
|
expected = {
|
||||||
"id": track.id,
|
"id": track.id,
|
||||||
|
@ -56,7 +57,7 @@ def test_album_track_serializer(factories, to_api_date):
|
||||||
"mbid": str(track.mbid),
|
"mbid": str(track.mbid),
|
||||||
"title": track.title,
|
"title": track.title,
|
||||||
"position": track.position,
|
"position": track.position,
|
||||||
"is_playable": None,
|
"uploads": [serializers.TrackUploadSerializer(upload).data],
|
||||||
"creation_date": to_api_date(track.creation_date),
|
"creation_date": to_api_date(track.creation_date),
|
||||||
"listen_url": track.listen_url,
|
"listen_url": track.listen_url,
|
||||||
"duration": None,
|
"duration": None,
|
||||||
|
@ -127,7 +128,7 @@ def test_album_serializer(factories, to_api_date):
|
||||||
"title": album.title,
|
"title": album.title,
|
||||||
"artist": serializers.ArtistSimpleSerializer(album.artist).data,
|
"artist": serializers.ArtistSimpleSerializer(album.artist).data,
|
||||||
"creation_date": to_api_date(album.creation_date),
|
"creation_date": to_api_date(album.creation_date),
|
||||||
"is_playable": None,
|
"is_playable": False,
|
||||||
"cover": {
|
"cover": {
|
||||||
"original": album.cover.url,
|
"original": album.cover.url,
|
||||||
"square_crop": album.cover.crop["400x400"].url,
|
"square_crop": album.cover.crop["400x400"].url,
|
||||||
|
@ -145,7 +146,7 @@ def test_album_serializer(factories, to_api_date):
|
||||||
def test_track_serializer(factories, to_api_date):
|
def test_track_serializer(factories, to_api_date):
|
||||||
upload = factories["music.Upload"]()
|
upload = factories["music.Upload"]()
|
||||||
track = upload.track
|
track = upload.track
|
||||||
|
setattr(track, "playable_uploads", [upload])
|
||||||
expected = {
|
expected = {
|
||||||
"id": track.id,
|
"id": track.id,
|
||||||
"artist": serializers.ArtistSimpleSerializer(track.artist).data,
|
"artist": serializers.ArtistSimpleSerializer(track.artist).data,
|
||||||
|
@ -153,14 +154,10 @@ def test_track_serializer(factories, to_api_date):
|
||||||
"mbid": str(track.mbid),
|
"mbid": str(track.mbid),
|
||||||
"title": track.title,
|
"title": track.title,
|
||||||
"position": track.position,
|
"position": track.position,
|
||||||
"is_playable": None,
|
"uploads": [serializers.TrackUploadSerializer(upload).data],
|
||||||
"creation_date": to_api_date(track.creation_date),
|
"creation_date": to_api_date(track.creation_date),
|
||||||
"lyrics": track.get_lyrics_url(),
|
"lyrics": track.get_lyrics_url(),
|
||||||
"listen_url": track.listen_url,
|
"listen_url": track.listen_url,
|
||||||
"duration": None,
|
|
||||||
"size": None,
|
|
||||||
"bitrate": None,
|
|
||||||
"mimetype": None,
|
|
||||||
}
|
}
|
||||||
serializer = serializers.TrackSerializer(track)
|
serializer = serializers.TrackSerializer(track)
|
||||||
assert serializer.data == expected
|
assert serializer.data == expected
|
||||||
|
@ -260,3 +257,20 @@ def test_manage_upload_action_relaunch_import(factories, mocker):
|
||||||
finished.refresh_from_db()
|
finished.refresh_from_db()
|
||||||
assert finished.import_status == "finished"
|
assert finished.import_status == "finished"
|
||||||
assert m.call_count == 3
|
assert m.call_count == 3
|
||||||
|
|
||||||
|
|
||||||
|
def test_track_upload_serializer(factories):
|
||||||
|
upload = factories["music.Upload"]()
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"listen_url": upload.listen_url,
|
||||||
|
"uuid": str(upload.uuid),
|
||||||
|
"size": upload.size,
|
||||||
|
"bitrate": upload.bitrate,
|
||||||
|
"mimetype": upload.mimetype,
|
||||||
|
"extension": upload.extension,
|
||||||
|
"duration": upload.duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
serializer = serializers.TrackUploadSerializer(upload)
|
||||||
|
assert serializer.data == expected
|
||||||
|
|
|
@ -549,11 +549,11 @@ def test_scan_page_trigger_next_page_scan_skip_if_same(mocker, factories, r_mock
|
||||||
|
|
||||||
|
|
||||||
def test_clean_transcoding_cache(preferences, now, factories):
|
def test_clean_transcoding_cache(preferences, now, factories):
|
||||||
preferences['music__transcoding_cache_duration'] = 60
|
preferences["music__transcoding_cache_duration"] = 60
|
||||||
u1 = factories['music.UploadVersion'](
|
u1 = factories["music.UploadVersion"](
|
||||||
accessed_date=now - datetime.timedelta(minutes=61)
|
accessed_date=now - datetime.timedelta(minutes=61)
|
||||||
)
|
)
|
||||||
u2 = factories['music.UploadVersion'](
|
u2 = factories["music.UploadVersion"](
|
||||||
accessed_date=now - datetime.timedelta(minutes=59)
|
accessed_date=now - datetime.timedelta(minutes=59)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -39,13 +39,11 @@ def test_album_list_serializer(api_request, factories, logged_in_api_client):
|
||||||
).track
|
).track
|
||||||
album = track.album
|
album = track.album
|
||||||
request = api_request.get("/")
|
request = api_request.get("/")
|
||||||
qs = album.__class__.objects.all()
|
qs = album.__class__.objects.with_prefetched_tracks_and_playable_uploads(None)
|
||||||
serializer = serializers.AlbumSerializer(
|
serializer = serializers.AlbumSerializer(
|
||||||
qs, many=True, context={"request": request}
|
qs, many=True, context={"request": request}
|
||||||
)
|
)
|
||||||
expected = {"count": 1, "next": None, "previous": None, "results": serializer.data}
|
expected = {"count": 1, "next": None, "previous": None, "results": serializer.data}
|
||||||
expected["results"][0]["is_playable"] = True
|
|
||||||
expected["results"][0]["tracks"][0]["is_playable"] = True
|
|
||||||
url = reverse("api:v1:albums-list")
|
url = reverse("api:v1:albums-list")
|
||||||
response = logged_in_api_client.get(url)
|
response = logged_in_api_client.get(url)
|
||||||
|
|
||||||
|
@ -58,12 +56,11 @@ def test_track_list_serializer(api_request, factories, logged_in_api_client):
|
||||||
library__privacy_level="everyone", import_status="finished"
|
library__privacy_level="everyone", import_status="finished"
|
||||||
).track
|
).track
|
||||||
request = api_request.get("/")
|
request = api_request.get("/")
|
||||||
qs = track.__class__.objects.all()
|
qs = track.__class__.objects.with_playable_uploads(None)
|
||||||
serializer = serializers.TrackSerializer(
|
serializer = serializers.TrackSerializer(
|
||||||
qs, many=True, context={"request": request}
|
qs, many=True, context={"request": request}
|
||||||
)
|
)
|
||||||
expected = {"count": 1, "next": None, "previous": None, "results": serializer.data}
|
expected = {"count": 1, "next": None, "previous": None, "results": serializer.data}
|
||||||
expected["results"][0]["is_playable"] = True
|
|
||||||
url = reverse("api:v1:tracks-list")
|
url = reverse("api:v1:tracks-list")
|
||||||
response = logged_in_api_client.get(url)
|
response = logged_in_api_client.get(url)
|
||||||
|
|
||||||
|
|
|
@ -150,10 +150,6 @@ def test_playlist_playable_by_anonymous(privacy_level, expected, factories):
|
||||||
factories["music.Upload"](
|
factories["music.Upload"](
|
||||||
track=track, library__privacy_level=privacy_level, import_status="finished"
|
track=track, library__privacy_level=privacy_level, import_status="finished"
|
||||||
)
|
)
|
||||||
queryset = playlist.__class__.objects.playable_by(None).annotate_playable_by_actor(
|
queryset = playlist.__class__.objects.playable_by(None).with_playable_plts(None)
|
||||||
None
|
|
||||||
)
|
|
||||||
match = playlist in list(queryset)
|
match = playlist in list(queryset)
|
||||||
assert match is expected
|
assert match is expected
|
||||||
if expected:
|
|
||||||
assert bool(queryset.first().is_playable_by_actor) is expected
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ def test_can_list_tracks_from_playlist(level, factories, logged_in_api_client):
|
||||||
url = reverse("api:v1:playlists-tracks", kwargs={"pk": plt.playlist.pk})
|
url = reverse("api:v1:playlists-tracks", kwargs={"pk": plt.playlist.pk})
|
||||||
response = logged_in_api_client.get(url)
|
response = logged_in_api_client.get(url)
|
||||||
serialized_plt = serializers.PlaylistTrackSerializer(plt).data
|
serialized_plt = serializers.PlaylistTrackSerializer(plt).data
|
||||||
serialized_plt["track"]["is_playable"] = False
|
|
||||||
assert response.data["count"] == 1
|
assert response.data["count"] == 1
|
||||||
assert response.data["results"][0] == serialized_plt
|
assert response.data["results"][0] == serialized_plt
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue