Plugin Models

Data models used across Spotube plugin interfaces.

All models are in the dev.krtirtho.plugin_interfaces package and use kotlinx.serialization.

Common

Thumbnail

@Serializable
data class Thumbnail(
    val url: String,
    val width: Int,
    val height: Int,
)

PaginationResult

@Serializable
data class PaginationResult<T>(
    val items: List<T>,
    val totalCount: Int,
    val nextPagination: PaginationStrategy?,
)

PaginationStrategy

sealed interface PaginationStrategy {
    @Serializable data class Offset(val offset: Int, val limit: Int) : PaginationStrategy
    @Serializable data class Cursor(val cursor: String?, val limit: Int) : PaginationStrategy
    @Serializable data class Page(val page: Int, val pageSize: Int) : PaginationStrategy
    @Serializable data class Continuation(val continuationToken: String?) : PaginationStrategy
}

Metadata models

MetadataTrack

Property Type Description
id String Unique track ID
title String Track title
durationMs Long Duration in milliseconds
trackNumber Int? Track number on the album
discNumber Int? Disc number
artists List<MetadataArtist.Basic> Track artists
album MetadataAlbum.Detailed? Parent album
thumbnails List<Thumbnail>? Track artwork
explicit Boolean? Explicit content flag
popularity Int? Popularity score
isrcCode String? ISRC identifier
externalUri String? Link to track on external service

MetadataAlbum

Sealed class with two variants:

sealed class MetadataAlbum {
    abstract val id: String
    abstract val title: String
    abstract val description: String?
    abstract val thumbnails: List<Thumbnail>
    abstract val albumType: MetadataAlbumType
    abstract val artists: List<MetadataArtist.Basic>
    abstract val externalUri: String?
}
Variant Additional fields
Basic -
Detailed releaseDate: String?, genres: List<String>, trackCount: Int

MetadataAlbumType: Single, Album, Collection

MetadataArtist

Sealed class:

sealed class MetadataArtist {
    abstract val id: String
    abstract val name: String
    abstract val thumbnails: List<Thumbnail>
    abstract val externalUri: String?
}
Variant Additional fields
Basic -
Detailed genres: List<String>?, biography: String?, followersCount: Int?

MetadataArtistOverview

@Serializable
data class MetadataArtistOverview(
    val artist: MetadataArtist.Detailed,
    val top10Tracks: List<MetadataTrack>,
    val albums: PaginationResult<MetadataAlbum.Detailed>,
    val relatedArtists: PaginationResult<MetadataArtist.Basic>,
    val featuredPlaylists: PaginationResult<MetadataPlaylist>,
)

MetadataPlaylist

Property Type Description
id String Unique playlist ID
title String Playlist name
description String? Playlist description
thumbnails List<Thumbnail> Playlist artwork
trackCount Int Number of tracks
externalUri String? Link to playlist on external service
owner MetadataUser? Playlist owner

MetadataUser

Property Type Description
id String Unique user ID
username String Username
displayName String? Display name
thumbnails List<Thumbnail> User avatars
externalUri String? Link to user profile on external service

MetadataSearchResult

Sealed class:

sealed class MetadataSearchResult {
    @Serializable data class Track(val data: MetadataTrack) : MetadataSearchResult()
    @Serializable data class Artist(val data: MetadataArtist.Basic) : MetadataSearchResult()
    @Serializable data class Album(val data: MetadataAlbum.Basic) : MetadataSearchResult()
    @Serializable data class Playlist(val data: MetadataPlaylist) : MetadataSearchResult()
    @Serializable data class User(val data: MetadataUser) : MetadataSearchResult()
}

MetadataSupportedSearchType: TRACK, ARTIST, ALBUM, PLAYLIST, USER, ALL

MetadataBrowseSection

Property Type Description
title String Section title
description String? Optional section description
items List<MetadataBrowseItem> Items in the section
moreLink String? Link/ID for "see more" pagination

MetadataBrowseItem

sealed interface MetadataBrowseItem {
    @Serializable data class Track(val data: MetadataTrack) : MetadataBrowseItem
    @Serializable data class Album(val data: MetadataAlbum.Basic) : MetadataBrowseItem
    @Serializable data class Artist(val data: MetadataArtist.Basic) : MetadataBrowseItem
    @Serializable data class Playlist(val data: MetadataPlaylist) : MetadataBrowseItem
    @Serializable data class User(val data: MetadataUser) : MetadataBrowseItem
}

MetadataBrowseGenre

@Serializable
data class MetadataBrowseGenre(
    val id: String,
    val name: String,
)

Audio models

AudioFormat

@Serializable
data class AudioFormat(
    val codec: String,
    val container: String,
    val qualities: List<AudioQuality>,
)

AudioQuality

sealed interface AudioQuality {
    @Serializable data class Lossy(val bitrate: Int) : AudioQuality
    @Serializable data class Lossless(val sampleRate: Int, val channels: Int) : AudioQuality
}

AudioSource

sealed class AudioSource(
    abstract val id: String,
    abstract val title: String,
    abstract val artist: String?,
    abstract val album: String?,
    abstract val thumbnails: List<Thumbnail>,
    abstract val externalUri: String?,
    abstract val confidence: Float,
) {
    @Serializable data class Basic(...) : AudioSource()
    @Serializable data class Streamed(
        val streams: List<AudioStream>,
        ...
    ) : AudioSource()
}

AudioStream

sealed interface AudioStream {
    val url: String
    val codec: String
    val container: String
    val protocol: StreamProtocol

    @Serializable data class Lossy(val bitrate: Int, ...) : AudioStream
    @Serializable data class Lossless(val sampleRate: Int, val channels: Int, ...) : AudioStream
}

enum class StreamProtocol { HLS, DASH, PROGRESSIVE }

Lyrics models

LyricsResponse

@Serializable
data class LyricsResponse(
    val syncedLyrics: List<LyricsLine>?,
    val plainLyrics: String?,
)

LyricsLine

@Serializable
data class LyricsLine(
    val time: Long,
    val text: String,
)

Scrobble models

ScrobbleTrack

@Serializable
data class ScrobbleTrack(
    val timestamp: Long,
    val trackId: String,
    val artistId: String,
    val albumId: String?,
    val trackName: String,
    val artistName: String,
    val albumName: String?,
    val streamingProvider: String,
    val durationMs: Long?,
)

HTTP models

HttpResponse

@Serializable
data class HttpResponse(
    val statusCode: Int,
    val headers: Map<String, String>,
    val body: String?,
)

HttpMethod

enum class HttpMethod(val value: String) {
    Get("GET"),
    Post("POST"),
    Put("PUT"),
    Delete("DELETE"),
    Patch("PATCH"),
    Head("HEAD"),
    Options("OPTIONS"),
}

Core models

PluginUpdateInfo

@Serializable
data class PluginUpdateInfo(
    val latestVersion: SemVer,
    val directDownloadUrl: String,
    val releaseNotes: String,
)