kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
351 wiersze
11 KiB
Python
351 wiersze
11 KiB
Python
import datetime
|
|
|
|
import pytest
|
|
from django.db.models.aggregates import Count
|
|
|
|
from funkwhale_api.music import models as music_models
|
|
from funkwhale_api.subsonic import serializers
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"date, expected",
|
|
[
|
|
(datetime.datetime(2017, 1, 12, 9, 53, 12, 1890), "2017-01-12T09:53:12.000Z"),
|
|
(None, None),
|
|
],
|
|
)
|
|
def test_to_subsonic_date(date, expected):
|
|
assert serializers.to_subsonic_date(date) == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"input, expected",
|
|
[
|
|
("AC/DC", "AC_DC"),
|
|
("AC-DC", "AC-DC"),
|
|
("A" * 100, "A" * 50),
|
|
("Album (2019)", "Album (2019)"),
|
|
("Haven't", "Haven_t"),
|
|
],
|
|
)
|
|
def test_get_valid_filepart(input, expected):
|
|
assert serializers.get_valid_filepart(input) == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"factory_kwargs, suffix, expected",
|
|
[
|
|
(
|
|
{
|
|
"artist__name": "Hello",
|
|
"album__title": "World",
|
|
"title": "foo",
|
|
"position": None,
|
|
},
|
|
"mp3",
|
|
"Hello/World/foo.mp3",
|
|
),
|
|
(
|
|
{
|
|
"artist__name": "AC/DC",
|
|
"album__title": "escape/my",
|
|
"title": "sla/sh",
|
|
"position": 12,
|
|
},
|
|
"ogg",
|
|
"/".join(
|
|
[
|
|
serializers.get_valid_filepart("AC/DC"),
|
|
serializers.get_valid_filepart("escape/my"),
|
|
]
|
|
)
|
|
+ "/12 - {}.ogg".format(serializers.get_valid_filepart("sla/sh")),
|
|
),
|
|
],
|
|
)
|
|
def test_get_track_path(factory_kwargs, suffix, expected, factories):
|
|
track = factories["music.Track"](**factory_kwargs)
|
|
assert serializers.get_track_path(track, suffix) == expected
|
|
|
|
|
|
def test_get_artists_serializer(factories):
|
|
artist1 = factories["music.Artist"](name="eliot", with_cover=True)
|
|
artist2 = factories["music.Artist"](name="Ellena", with_cover=True)
|
|
artist3 = factories["music.Artist"](name="Rilay", with_cover=True)
|
|
artist4 = factories["music.Artist"](
|
|
name="", with_cover=False
|
|
) # Shouldn't be serialised
|
|
|
|
factories["music.Album"].create_batch(size=3, artist=artist1)
|
|
factories["music.Album"].create_batch(size=2, artist=artist2)
|
|
|
|
expected = {
|
|
"ignoredArticles": "",
|
|
"index": [
|
|
{
|
|
"name": "E",
|
|
"artist": [
|
|
{
|
|
"id": artist1.pk,
|
|
"name": artist1.name,
|
|
"albumCount": 3,
|
|
"coverArt": f"ar-{artist1.id}",
|
|
},
|
|
{
|
|
"id": artist2.pk,
|
|
"name": artist2.name,
|
|
"albumCount": 2,
|
|
"coverArt": f"ar-{artist2.id}",
|
|
},
|
|
],
|
|
},
|
|
{
|
|
"name": "R",
|
|
"artist": [
|
|
{
|
|
"id": artist3.pk,
|
|
"name": artist3.name,
|
|
"albumCount": 0,
|
|
"coverArt": f"ar-{artist3.id}",
|
|
}
|
|
],
|
|
},
|
|
],
|
|
}
|
|
|
|
queryset = artist1.__class__.objects.filter(
|
|
pk__in=[artist1.pk, artist2.pk, artist3.pk, artist4.pk]
|
|
)
|
|
|
|
assert serializers.GetArtistsSerializer(queryset).data == expected
|
|
|
|
|
|
def test_get_artist_serializer(factories):
|
|
artist = factories["music.Artist"](with_cover=True)
|
|
album = factories["music.Album"](artist=artist, with_cover=True)
|
|
tracks = factories["music.Track"].create_batch(size=3, album=album)
|
|
|
|
expected = {
|
|
"id": artist.pk,
|
|
"name": artist.name,
|
|
"albumCount": 1,
|
|
"coverArt": f"ar-{artist.id}",
|
|
"album": [
|
|
{
|
|
"id": album.pk,
|
|
"coverArt": f"al-{album.id}",
|
|
"artistId": artist.pk,
|
|
"name": album.title,
|
|
"artist": artist.name,
|
|
"songCount": len(tracks),
|
|
"created": serializers.to_subsonic_date(album.creation_date),
|
|
"year": album.release_date.year,
|
|
}
|
|
],
|
|
}
|
|
|
|
assert serializers.GetArtistSerializer(artist).data == expected
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"mimetype, extension, expected",
|
|
[
|
|
("audio/ogg", "noop", "audio/ogg"),
|
|
("", "ogg", "audio/ogg"),
|
|
("", "mp3", "audio/mpeg"),
|
|
("", "", "audio/mpeg"),
|
|
],
|
|
)
|
|
def test_get_track_data_content_type(mimetype, extension, expected, factories):
|
|
upload = factories["music.Upload"]()
|
|
upload.mimetype = mimetype
|
|
upload.audio_file = f"test.{extension}"
|
|
|
|
data = serializers.get_track_data(
|
|
album=upload.track.album, track=upload.track, upload=upload
|
|
)
|
|
|
|
assert data["contentType"] == expected
|
|
|
|
|
|
def test_get_album_serializer(factories):
|
|
artist = factories["music.Artist"]()
|
|
album = factories["music.Album"](artist=artist, with_cover=True)
|
|
track = factories["music.Track"](album=album, disc_number=42)
|
|
upload = factories["music.Upload"](track=track, bitrate=42000, duration=43, size=44)
|
|
tagged_item = factories["tags.TaggedItem"](content_object=album, tag__name="foo")
|
|
expected = {
|
|
"id": album.pk,
|
|
"artistId": artist.pk,
|
|
"name": album.title,
|
|
"artist": artist.name,
|
|
"songCount": 1,
|
|
"created": serializers.to_subsonic_date(album.creation_date),
|
|
"year": album.release_date.year,
|
|
"coverArt": f"al-{album.id}",
|
|
"genre": tagged_item.tag.name,
|
|
"duration": 43,
|
|
"playCount": album.tracks.aggregate(l=Count("listenings"))["l"] or 0,
|
|
"song": [
|
|
{
|
|
"id": track.pk,
|
|
"isDir": "false",
|
|
"title": track.title,
|
|
"coverArt": f"al-{album.id}",
|
|
"album": album.title,
|
|
"artist": artist.name,
|
|
"track": track.position,
|
|
"discNumber": track.disc_number,
|
|
"year": track.album.release_date.year,
|
|
"contentType": upload.mimetype,
|
|
"suffix": upload.extension or "",
|
|
"path": serializers.get_track_path(track, upload.extension),
|
|
"bitrate": 42,
|
|
"duration": 43,
|
|
"size": 44,
|
|
"created": serializers.to_subsonic_date(track.creation_date),
|
|
"albumId": album.pk,
|
|
"artistId": artist.pk,
|
|
"type": "music",
|
|
}
|
|
],
|
|
}
|
|
|
|
qs = album.__class__.objects.with_duration()
|
|
|
|
assert serializers.GetAlbumSerializer(qs.first()).data == expected
|
|
|
|
|
|
def test_starred_tracks2_serializer(factories):
|
|
artist = factories["music.Artist"]()
|
|
album = factories["music.Album"](artist=artist)
|
|
track = factories["music.Track"](album=album)
|
|
upload = factories["music.Upload"](track=track)
|
|
favorite = factories["favorites.TrackFavorite"](track=track)
|
|
expected = [serializers.get_track_data(album, track, upload)]
|
|
expected[0]["starred"] = serializers.to_subsonic_date(favorite.creation_date)
|
|
data = serializers.get_starred_tracks_data([favorite])
|
|
assert data == expected
|
|
|
|
|
|
def test_get_album_list2_serializer(factories):
|
|
album1 = factories["music.Album"]().__class__.objects.with_duration().first()
|
|
album2 = factories["music.Album"]().__class__.objects.with_duration().last()
|
|
|
|
qs = music_models.Album.objects.with_tracks_count().with_duration().order_by("pk")
|
|
expected = [
|
|
serializers.get_album2_data(album1),
|
|
serializers.get_album2_data(album2),
|
|
]
|
|
data = serializers.get_album_list2_data(qs)
|
|
assert data == expected
|
|
|
|
|
|
def test_playlist_serializer(factories):
|
|
plt = factories["playlists.PlaylistTrack"]()
|
|
playlist = plt.playlist
|
|
qs = music_models.Album.objects.with_tracks_count().order_by("pk")
|
|
expected = {
|
|
"id": playlist.pk,
|
|
"name": playlist.name,
|
|
"owner": playlist.user.username,
|
|
"public": "false",
|
|
"songCount": 1,
|
|
"duration": 0,
|
|
"created": serializers.to_subsonic_date(playlist.creation_date),
|
|
}
|
|
qs = playlist.__class__.objects.with_tracks_count()
|
|
data = serializers.get_playlist_data(qs.first())
|
|
assert data == expected
|
|
|
|
|
|
def test_playlist_detail_serializer(factories):
|
|
plt = factories["playlists.PlaylistTrack"]()
|
|
upload = factories["music.Upload"](track=plt.track)
|
|
playlist = plt.playlist
|
|
qs = music_models.Album.objects.with_tracks_count().order_by("pk")
|
|
expected = {
|
|
"id": playlist.pk,
|
|
"name": playlist.name,
|
|
"owner": playlist.user.username,
|
|
"public": "false",
|
|
"songCount": 1,
|
|
"duration": 0,
|
|
"created": serializers.to_subsonic_date(playlist.creation_date),
|
|
"entry": [serializers.get_track_data(plt.track.album, plt.track, upload)],
|
|
}
|
|
qs = playlist.__class__.objects.with_tracks_count()
|
|
data = serializers.get_playlist_detail_data(qs.first())
|
|
assert data == expected
|
|
|
|
|
|
def test_scrobble_serializer(factories):
|
|
upload = factories["music.Upload"]()
|
|
track = upload.track
|
|
user = factories["users.User"]()
|
|
payload = {"id": track.pk, "submission": True}
|
|
serializer = serializers.ScrobbleSerializer(data=payload, context={"user": user})
|
|
|
|
assert serializer.is_valid(raise_exception=True)
|
|
|
|
listening = serializer.save()
|
|
|
|
assert listening.user == user
|
|
assert listening.track == track
|
|
|
|
|
|
def test_channel_serializer(factories):
|
|
description = factories["common.Content"]()
|
|
channel = factories["audio.Channel"](
|
|
external=True, artist__description=description, artist__with_cover=True
|
|
)
|
|
upload = factories["music.Upload"](
|
|
playable=True, library=channel.library, duration=42
|
|
)
|
|
|
|
expected = {
|
|
"id": str(channel.uuid),
|
|
"url": channel.rss_url,
|
|
"title": channel.artist.name,
|
|
"description": description.as_plain_text,
|
|
"coverArt": f"at-{channel.artist.attachment_cover.uuid}",
|
|
"originalImageUrl": channel.artist.attachment_cover.url,
|
|
"status": "completed",
|
|
"episode": [serializers.get_channel_episode_data(upload, channel.uuid)],
|
|
}
|
|
data = serializers.get_channel_data(channel, [upload])
|
|
assert data == expected
|
|
|
|
|
|
def test_channel_episode_serializer(factories):
|
|
description = factories["common.Content"]()
|
|
channel = factories["audio.Channel"]()
|
|
track = factories["music.Track"](
|
|
description=description, artist=channel.artist, with_cover=True
|
|
)
|
|
upload = factories["music.Upload"](
|
|
playable=True, track=track, bitrate=128000, duration=42
|
|
)
|
|
|
|
expected = {
|
|
"id": str(upload.uuid),
|
|
"channelId": str(channel.uuid),
|
|
"streamId": upload.track.id,
|
|
"title": track.title,
|
|
"description": description.as_plain_text,
|
|
"coverArt": f"at-{track.attachment_cover.uuid}",
|
|
"isDir": "false",
|
|
"year": track.creation_date.year,
|
|
"created": track.creation_date.isoformat(),
|
|
"publishDate": track.creation_date.isoformat(),
|
|
"genre": "Podcast",
|
|
"size": upload.size,
|
|
"duration": upload.duration,
|
|
"bitrate": upload.bitrate / 1000,
|
|
"contentType": upload.mimetype,
|
|
"suffix": upload.extension,
|
|
"status": "completed",
|
|
}
|
|
data = serializers.get_channel_episode_data(upload, channel.uuid)
|
|
assert data == expected
|