Skip to content
Snippets Groups Projects
serializers.py 7.17 KiB
Newer Older
Eliot Berriot's avatar
Eliot Berriot committed
from django.db.models import Count, functions
from funkwhale_api.history import models as history_models
from funkwhale_api.music import models as music_models


def get_artist_data(artist_values):
    return {
Eliot Berriot's avatar
Eliot Berriot committed
        "id": artist_values["id"],
        "name": artist_values["name"],
        "albumCount": artist_values["_albums_count"],

class GetArtistsSerializer(serializers.Serializer):
    def to_representation(self, queryset):
Eliot Berriot's avatar
Eliot Berriot committed
        payload = {"ignoredArticles": "", "index": []}
        queryset = queryset.with_albums_count()
Eliot Berriot's avatar
Eliot Berriot committed
        queryset = queryset.order_by(functions.Lower("name"))
        values = queryset.values("id", "_albums_count", "name")

        first_letter_mapping = collections.defaultdict(list)
        for artist in values:
            if artist["name"]:
                first_letter_mapping[artist["name"][0].upper()].append(artist)

        for letter, artists in sorted(first_letter_mapping.items()):
            letter_data = {
Eliot Berriot's avatar
Eliot Berriot committed
                "name": letter,
                "artist": [get_artist_data(v) for v in artists],
Eliot Berriot's avatar
Eliot Berriot committed
            payload["index"].append(letter_data)
        return payload


class GetArtistSerializer(serializers.Serializer):
    def to_representation(self, artist):
Eliot Berriot's avatar
Eliot Berriot committed
        albums = artist.albums.prefetch_related("tracks__files")
Eliot Berriot's avatar
Eliot Berriot committed
            "id": artist.pk,
            "name": artist.name,
            "albumCount": len(albums),
            "album": [],
Eliot Berriot's avatar
Eliot Berriot committed
                "id": album.id,
                "artistId": artist.id,
                "name": album.title,
                "artist": artist.name,
                "created": album.creation_date,
                "songCount": len(album.tracks.all()),
Eliot Berriot's avatar
Eliot Berriot committed
                album_data["coverArt"] = "al-{}".format(album.id)
Eliot Berriot's avatar
Eliot Berriot committed
                album_data["year"] = album.release_date.year
            payload["album"].append(album_data)
def get_track_data(album, track, tf):
    data = {
Eliot Berriot's avatar
Eliot Berriot committed
        "id": track.pk,
        "isDir": "false",
        "title": track.title,
        "album": album.title,
        "artist": album.artist.name,
        "track": track.position or 1,
        "contentType": tf.mimetype,
        "suffix": tf.extension or "",
        "duration": tf.duration or 0,
        "created": track.creation_date,
        "albumId": album.pk,
        "artistId": album.artist.pk,
        "type": "music",
Eliot Berriot's avatar
Eliot Berriot committed
        data["coverArt"] = "al-{}".format(track.album.id)
Eliot Berriot's avatar
Eliot Berriot committed
        data["bitrate"] = int(tf.bitrate / 1000)
Eliot Berriot's avatar
Eliot Berriot committed
        data["size"] = tf.size
Eliot Berriot's avatar
Eliot Berriot committed
        data["year"] = album.release_date.year
    return data


def get_album2_data(album):
    payload = {
Eliot Berriot's avatar
Eliot Berriot committed
        "id": album.id,
        "artistId": album.artist.id,
        "name": album.title,
        "artist": album.artist.name,
        "created": album.creation_date,
Eliot Berriot's avatar
Eliot Berriot committed
        payload["coverArt"] = "al-{}".format(album.id)
Eliot Berriot's avatar
Eliot Berriot committed
        payload["songCount"] = album._tracks_count
Eliot Berriot's avatar
Eliot Berriot committed
        payload["songCount"] = len(album.tracks.prefetch_related("files"))
    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):
Eliot Berriot's avatar
Eliot Berriot committed
        tracks = album.tracks.prefetch_related("files").select_related("album")
        payload = get_album2_data(album)
Eliot Berriot's avatar
Eliot Berriot committed
            payload["year"] = album.release_date.year
Eliot Berriot's avatar
Eliot Berriot committed
        payload["song"] = get_song_list_data(tracks)
class GetSongSerializer(serializers.Serializer):
    def to_representation(self, track):
        tf = track.files.all()
        if not len(tf):
            return {}
        return get_track_data(track.album, track, tf[0])


def get_starred_tracks_data(favorites):
Eliot Berriot's avatar
Eliot Berriot committed
    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)
Eliot Berriot's avatar
Eliot Berriot committed
        td["starred"] = by_track_id[t.pk].creation_date
        data.append(td)
    return data


def get_album_list2_data(albums):
Eliot Berriot's avatar
Eliot Berriot committed
    return [get_album2_data(a) for a in albums]


def get_playlist_data(playlist):
    return {
Eliot Berriot's avatar
Eliot Berriot committed
        "id": playlist.pk,
        "name": playlist.name,
        "owner": playlist.user.username,
        "public": "false",
        "songCount": playlist._tracks_count,
        "duration": 0,
        "created": playlist.creation_date,
    }


def get_playlist_detail_data(playlist):
    data = get_playlist_data(playlist)
Eliot Berriot's avatar
Eliot Berriot committed
    qs = (
        playlist.playlist_tracks.select_related("track__album__artist")
        .prefetch_related("track__files")
        .order_by("index")
    )
    data["entry"] = []
    for plt in qs:
        try:
            tf = [tf for tf in plt.track.files.all()][0]
        except IndexError:
            continue
        td = get_track_data(plt.track.album, plt.track, tf)
Eliot Berriot's avatar
Eliot Berriot committed
        data["entry"].append(td)


def get_music_directory_data(artist):
Eliot Berriot's avatar
Eliot Berriot committed
    tracks = artist.tracks.select_related("album").prefetch_related("files")
    data = {"id": artist.pk, "parent": 1, "name": artist.name, "child": []}
    for track in tracks:
        try:
            tf = [tf for tf in track.files.all()][0]
        except IndexError:
            continue
        album = track.album
        td = {
Eliot Berriot's avatar
Eliot Berriot committed
            "id": track.pk,
            "isDir": "false",
            "title": track.title,
            "album": album.title,
            "artist": artist.name,
            "track": track.position or 1,
            "year": track.album.release_date.year if track.album.release_date else 0,
            "contentType": tf.mimetype,
            "suffix": tf.extension or "",
            "duration": tf.duration or 0,
            "created": track.creation_date,
            "albumId": album.pk,
            "artistId": artist.pk,
            "parent": artist.id,
            "type": "music",
Eliot Berriot's avatar
Eliot Berriot committed
            td["bitrate"] = int(tf.bitrate / 1000)
Eliot Berriot's avatar
Eliot Berriot committed
            td["size"] = tf.size
        data["child"].append(td)


class ScrobbleSerializer(serializers.Serializer):
    submission = serializers.BooleanField(default=True, required=False)
    id = serializers.PrimaryKeyRelatedField(
Eliot Berriot's avatar
Eliot Berriot committed
        queryset=music_models.Track.objects.annotate(files_count=Count("files")).filter(
            files_count__gt=0
        )
    )

    def create(self, data):
        return history_models.Listening.objects.create(
Eliot Berriot's avatar
Eliot Berriot committed
            user=self.context["user"], track=data["id"]