Research
Security News
Malicious npm Package Targets Solana Developers and Hijacks Funds
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
com.adamratzman:spotify-api-kotlin-tvosarm64
Advanced tools
A Kotlin wrapper for the Spotify Web API.
A Kotlin implementation of the Spotify Web API, supporting Kotlin/JS, Kotlin/Android, Kotlin/JVM, and Kotlin/Native (macOS, Windows, Linux).
This library has first-class support for Java and is a viable alternative for Java development. Please see the Java section for more details.
Use this library in Kotlin, Java, JavaScript, Swift, or native code! Because this library targets both iOS and Android, it can also be used in KMM (Kotlin Multiplatform Mobile) applications as a shared source.
Current version:
repositories {
mavenCentral()
}
implementation("com.adamratzman:spotify-api-kotlin-core:VERSION")
Please see the JS Spotify Web Playback SDK wrapper to learn how to use Spotify's web playback SDK in a browser application.
Note: For information on how to integrate implicit/PKCE authentication, Spotify app remote, and Spotify broadcast notifications into your application, please see the Android README.
If you declare any release types not named debug or release, you may see "Could not resolve com.adamratzman:spotify-api-kotlin-android:VERSION". You need to do the following for each release type not named debug or release:
android {
buildTypes {
yourReleaseType1 {
// ...
matchingFallbacks = ['release', 'debug']
}
yourReleaseType2 {
// ...
matchingFallbacks = ['release', 'debug']
}
...
}
}
To successfully build, you might need to exclude kotlin_module files from the packaging. To do this, inside the android/buildTypes/release closure, you would put:
packagingOptions {
exclude 'META-INF/*.kotlin_module'
}
You can find a simple sample application demonstrating how to use spotify-web-api-kotlin in a modern Android app, as well as how to integrate with the Spotify app, here.
The spotify-web-api-kotlin
JavaDocs are hosted here.
If you have a question, you can:
Feature | JVM | Android | JS | Native (Mac/Windows/Linux) |
---|---|---|---|---|
Edit client playlist | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Unsupported |
Remove playlist tracks | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Unsupported |
Please feel free to open an issue/discussion on GitHub or Discord if you need access to one of these features or have an interest in implementing one, as direction can be provided.
To decide which api you need (SpotifyAppApi, SpotifyClientApi, SpotifyImplicitGrantApi), you can refer to the sections below or the Spotify authorization guide. In general:
Note: You can use the online Spotify OAuth Token Generator tool to generate a client token for local testing.
This provides access only to public Spotify endpoints. Use this when you have a server-side application. Note that implicit grant authorization provides a higher api ratelimit, so consider using implicit grant if your application has significant usage.
By default, the SpotifyApi Token
automatically regenerates when needed.
This can be changed by overriding the automaticRefresh
builder setting.
There are four exposed builders, depending on the level of control you need over api creation. Please see the spotifyAppApi builder docs for a full list of available builders.
You will need:
Example creation (default settings)
val api = spotifyAppApi("clientId", "clientSecret").build() // create and build api
println(api.browse.getNewReleases()) // use it
Example creation, using an existing Token and setting automatic token refresh to false
val token = spotifyAppApi(spotifyClientId, spotifyClientSecret).build().token
val api = spotifyAppApi(
"clientId",
"clientSecret",
token
) {
automaticRefresh = false
}.build()
println(api.browse.getNewReleases()) // use it
The SpotifyClientApi
is a superset of SpotifyApi
; thus, nothing changes if you want to
access public data.
This library does not provide a method to retrieve the code from your callback url; instead,
you must implement that with a web server.
Automatic Token refresh is available only when building with an authorization code or a
Token
object. Otherwise, it will expire Token.expiresIn
seconds after creation.
Make sure your application has requested the proper Scopes in order to
ensure proper function of this library. The api option requiredScopes
allows you to verify
that a client has actually authorized with the scopes you are expecting.
You will need:
Use the PKCE builders and helper methods if you are using the Spotify client authorization PKCE flow.
Building via PKCE returns a SpotifyClientApi
which has modified refresh logic.
Use cases:
To learn more about the PKCE flow, please read the Spotify authorization guide. Some highlights about the flow are:
This library contains helpful methods that can be used to simplify the PKCE authorization process.
This includes getSpotifyPkceCodeChallenge
, which SHA256 hashes and base64url encodes the code
challenge, and getSpotifyPkceAuthorizationUrl
, which allows you to generate an easy authorization url for PKCE flow.
Please see the spotifyClientPkceApi builder docs for a full list of available builders.
Takeaway: Use PKCE authorization flow in applications where you cannot secure the client secret.
To get a PKCE authorization url, to which you can redirect a user, you can use the getSpotifyPkceAuthorizationUrl
top-level method. An example is shown below, requesting 4 different scopes.
val codeVerifier = "thisisaveryrandomalphanumericcodeverifierandisgreaterthan43characters"
val codeChallenge = getSpotifyPkceCodeChallenge(codeVerifier) // helper method
val url: String = getSpotifyPkceAuthorizationUrl(
SpotifyScope.PLAYLIST_READ_PRIVATE,
SpotifyScope.PLAYLIST_MODIFY_PRIVATE,
SpotifyScope.USER_FOLLOW_READ,
SpotifyScope.USER_LIBRARY_MODIFY,
clientId = "clientId",
redirectUri = "your-redirect-uri",
codeChallenge = codeChallenge
)
There is also an optional parameter state
, which helps you verify the authorization.
Note: If you want automatic token refresh, you need to pass in your application client id and redirect uri
when using the spotifyClientPkceApi
.
SpotifyClientApi
.val codeVerifier = "thisisaveryrandomalphanumericcodeverifierandisgreaterthan43characters"
val code: String = ...
val api = spotifyClientPkceApi(
"clientId", // optional. include for token refresh
"your-redirect-uri", // optional. include for token refresh
code,
codeVerifier // the same code verifier you used to generate the code challenge
) {
retryWhenRateLimited = false
}.build()
println(api.library.getSavedTracks().take(10).filterNotNull().map { it.track.name })
To get a non-PKCE authorization url, to which you can redirect a user, you can use the getSpotifyAuthorizationUrl
top-level method. An example is shown below, requesting 4 different scopes.
val url: String = getSpotifyAuthorizationUrl(
SpotifyScope.PLAYLIST_READ_PRIVATE,
SpotifyScope.PLAYLIST_MODIFY_PRIVATE,
SpotifyScope.USER_FOLLOW_READ,
SpotifyScope.USER_LIBRARY_MODIFY,
clientId = "clientId",
redirectUri = "your-redirect-uri",
state = "your-special-state" // optional
)
There are also several optional parameters, allowing you to set whether the authorization url is meant for implicit grant flow, the state, and whether a re-authorization dialog should be shown to users.
There are several exposed builders, depending on the level of control you need over api creation. Please see the spotifyClientApi builder docs for a full list of available builders.
In this example, automatic token refresh is turned on by default.
val authCode = ""
val api = spotifyClientApi(
"clientId",
"clientSecret",
"your-redirect-uri",
authCode
).build() // create and build api
println(api.personalization.getTopTracks(limit = 5).items.map { it.name }) // print user top tracks
In this case, if you provide a client id to the builder, automatic token refresh will also be turned on.
val token: Token = ... // your existing token
val api = spotifyClientApi(
"clientId",
"clientSecret",
"your-redirect-uri",
token
) {
onTokenRefresh = {
println("Token refreshed at ${System.currentTimeMillis()}")
}
}.build()
println(api.personalization.getTopTracks(limit = 5).items.map { it.name })
Use the SpotifyImplicitGrantApi
if you are using the Spotify implicit grant flow.
SpotifyImplicitGrantApi
is a superset of SpotifyClientApi
.
Unlike the other builders, the spotifyImplicitGrantApi
builder method directly returns
a SpotifyImplicitGrantApi
instead of an api builder.
Use cases:
To learn more about the implicit grant flow, please read the Spotify authorization guide. Some highlights about the flow are:
Please see the spotifyImplicitGrantApi builder docs for a full list of available builders.
The Kotlin/JS target contains the parseSpotifyCallbackHashToToken
method, which will parse the hash
for the current url into a Token object, with which you can then instantiate the api.
Takeaway: There are two ways to use implicit grant flow, browser-side only and browser and server. This library provides easy access for both.
val token: Token = ...
val api = spotifyImplicitGrantApi(
null,
null,
token
) // create api. there is no need to build it
println(api.personalization.getTopArtists(limit = 1)[0].name) // use it
There are three pluggable blocks in each api's corresponding builder
credentials
lets you set the client id, client secret, and redirect uriauthorization
lets you set the type of api authorization you are using.
Acceptable types include: an authorization code, a Token
object, a Token's access code string, and an optional refresh token stringoptions
lets you configure API options to your own specific needsThis library does not attempt to be prescriptivist.
All API options are located in SpotifyApiOptions
and their default values can be overridden; however, use caution in doing so, as
most of the default values either allow for significant performance or feature enhancements to the API instance.
useCache
: Set whether to cache requests. Default: truecacheLimit
: The maximum amount of cached requests allowed at one time. Null means no limit. Default: 200automaticRefresh
: Enable or disable automatic refresh of the Spotify access token when it expires. Default: trueretryWhenRateLimited
: Set whether to block the current thread and wait until the API can retry the request. Default: trueenableLogger
: Set whether to enable to the exception logger. Default: truetestTokenValidity
: After API creation, test whether the token is valid by performing a lightweight request. Default: falsedefaultLimit
: The default amount of objects to retrieve in one request. Default: 50json
: The Json serializer/deserializer instance.allowBulkRequests
: Allow splitting too-large requests into smaller, allowable api requests. Default: truerequestTimeoutMillis
: The maximum time, in milliseconds, before terminating an http request. Default: 100000msrefreshTokenProducer
: Provide if you want to use your own logic when refreshing a Spotify token.requiredScopes
: Scopes that your application requires to function (only applicable to SpotifyClientApi
and SpotifyImplicitGrantApi
).
This verifies that the token your user authorized with actually contains the scopes your
application needs to function.Notes:
useCache
should be truecacheLimit
is per Endpoint, not per API. Don't be surprised if you end up with over 200 items in your cache with the default settings.automaticRefresh
is disabled when client secret is not provided, or if tokenString is provided in SpotifyClientApiallowBulkRequests
for example, lets you query 80 artists in one wrapper call by splitting it into 50 artists + 30 artistsrefreshTokenProducer
is useful when you want to re-authorize with the Spotify Auth SDK or elsewhereAPIs available in all SpotifyApi
instances, including SpotifyClientApi
and SpotifyImplicitGrantApi
:
SearchApi
(searching items)AlbumApi
(get information about albums)BrowseApi
(browse new releases, featured playlists, categories, and recommendations)ArtistApi
(get information about artists)PlaylistApi
(get information about playlists)UserApi
(get public information about users on Spotify)TrackApi
(get information about tracks)FollowingApi
(check whether users follow playlists)APIs available only in SpotifyClientApi
and SpotifyImplicitGrantApi
instances:
ClientSearchApi
(all the methods in SearchApi
, and searching shows and episodes)EpisodeApi
(get information about episodes)ShowApi
(get information about shows)ClientPlaylistApi
(all the methods in PlaylistApi
, and get and manage user playlists)ClientProfileApi
(all the methods in UserApi
, and get the user profile, depending on scopes)ClientFollowingApi
(all the methods in FollowingApi
, and get and manage following of playlists, artists, and users)ClientPersonalizationApi
(get user top tracks and artists)ClientLibraryApi
(get and manage saved tracks and albums)ClientPlayerApi
(view and control Spotify playback)This library has first-class support for Java! You have two choices when using this library: async-only with Kotlin
suspend functions (using SpotifyContinuation), or by using the SpotifyRestAction
class. Using SpotifyRestAction
s are
recommended.
Abstracting requests into a SpotifyRestAction
class allows for a lot of flexibility in sending and receiving requests.
This class includes options for asynchronous and blocking execution in all endpoints. However,
due to this, you must call one of the provided methods in order for the call
to execute! The SpotifyRestAction
provides many methods and fields for use, including blocking and asynchronous ones. For example,
hasRun()
tells you whether the rest action has been startedhasCompleted()
tells you whether this rest action has been fully executed and completedcomplete()
blocks the current thread and returns the resultsuspendComplete(context: CoroutineContext = Dispatchers.Default)
switches to given context, invokes the supplier, and synchronously retrieves the result.suspendQueue()
suspends the coroutine, invokes the supplier asynchronously, and resumes with the resultqueue()
executes and immediately returnsqueue(consumer: (T) -> Unit)
executes the provided callback as soon as the request
is asynchronously evaluatedqueueAfter(quantity: Int, timeUnit: TimeUnit, consumer: (T) -> Unit)
executes the
provided callback after the provided time. As long as supplier execution is less than the provided
time, this will likely be accurate within a few milliseconds.asFuture()
transforms the supplier into a CompletableFuture
(only JVM)Here's an example of how easy it is to use spotify-web-api-kotlin
with a SpotifyRestAction
:
var api = SpotifyApiBuilderKt.spotifyAppApi(Const.clientId, Const.clientSecret).buildRestAction(true).complete();
var album = api.getAlbums().getAlbumRestAction("spotify:album:0b23AHutIA1BOW0u1dZ6wM", null).complete();
System.out.println("Album name is: " + album.getName());
Continuation
sUnfortunately, coroutines don't play very nicely with Java code. Fortunately, however, we provide a wrapper around Kotlin's
Continuation
class that allows you to directly implement onSuccess
and onFailure
handlers on API methods.
Please see below for an example:
import com.adamratzman.spotify.SpotifyApiBuilderKt;
import com.adamratzman.spotify.SpotifyAppApi;
import com.adamratzman.spotify.javainterop.SpotifyContinuation;
import com.adamratzman.spotify.models.Album;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ExecutionException;
public class SpotifyTestApp {
static SpotifyAppApi api;
public static void main(String[] args) throws ExecutionException, InterruptedException {
var id = "spotify-client-id";
var secret = "spotify-client-secret";
SpotifyApiBuilderKt.spotifyAppApi(id, secret).build(true, new SpotifyContinuation<>() {
@Override
public void onSuccess(SpotifyAppApi spotifyAppApi) {
api = spotifyAppApi;
runAlbumSearch();
}
@Override
public void onFailure(@NotNull Throwable throwable) {
throwable.printStackTrace();
}
});
Thread.sleep(1000000);
}
public static void runAlbumSearch() {
api.getAlbums().getAlbum("spotify:album:0b23AHutIA1BOW0u1dZ6wM", null, new SpotifyContinuation<>() {
@Override
public void onSuccess(Album album) {
System.out.println("Album name is: " + album.getName() + ". Exiting now..");
System.exit(0);
}
@Override
public void onFailure(@NotNull Throwable throwable) {
throwable.printStackTrace();
}
});
}
}
For information on how to integrate implicit/PKCE authentication, Spotify app remote, and Spotify broadcast notifications into your application, please see the Android README.
spotify-web-api-kotlin
provides a wrapper around Spotify's Web Playback SDK
for playing music via Spotify in the browser on your own site.
To do this, you need to create a Player
instance and then use the associated methods to register listeners, play,
and get current context.
Please see an example of how to do this here. An example project, spotify-web-api-browser-example, demonstrates how to create a frontend JS Kotlin application with Spotify integration and that will play music in the browser.
Notes:
<script src="https://sdk.scdn.co/spotify-player.js"></script>
window.onSpotifyWebPlaybackSDKReady
function immediately afterwards - this should load your main application bundle.
Otherwise, you will get errors. An example is below:<html>
<head>
...
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script>
jQuery.loadScript = function (url, callback) {
jQuery.ajax({
url: url,
dataType: 'script',
success: callback,
async: true
});
}
</script>
<script src="https://sdk.scdn.co/spotify-player.js"></script>
<script>
window.onSpotifyWebPlaybackSDKReady = () => {
$.loadScript("main.bundle.js")
}
</script>
</head>
<body>
....
</body>
</html>
The easiest way to build the API is using .build() after a builder
runBlocking {
val api = spotifyAppApi(clientId, clientSecret).build()
}
If you are using an authorization flow or token that does not support automatic token refresh, SpotifyException.ReAuthenticationNeededException
will be thrown. You should put your requests, if creating an application, behind a try/catch block to re-authenticate users if this
exception is thrown.
Spotify provides these three object models in order to simplify our lives as developers. So let's see what we can do with them!
PagingObjects are a container for the requested objects (items
), but also include
important information useful in future calls. It contains the request's limit
and offset
, along with
(sometimes) a link to the next and last page of items and the total number of items returned.
If a link to the next or previous page is provided, we can use the getNext
and getPrevious
methods to retrieve
the respective PagingObjects
A cursor-based paging object is a PagingObject with a cursor added on that can be used as a key to find the next
page of items. The value in the cursor, after
, describes after what object to begin the query.
Just like with PagingObjects, you can get the next page of items with getNext
. However, there is no
provided implementation of after
in this library. You will need to do it yourself, if necessary.
Some endpoints, like PlaylistAPI.getPlaylistTracks
, return a LinkedResult, which is a simple wrapper around the
list of objects. With this, we have access to its Spotify API url (with href
), and we provide simple methods to parse
that url.
For obvious reasons, in most cases, making asynchronous requests via queue
or queueAfter
is preferred. However,
the synchronous format is also shown.
val api = spotifyAppApi(
System.getenv("SPOTIFY_CLIENT_ID"),
System.getenv("SPOTIFY_CLIENT_SECRET")
).build()
// print out the names of the twenty most similar songs to the search
println(api.search.searchTrack("Début de la Suite").joinToString { it.name })
// simple, right? what about if we want to print out the featured playlists message from the "Overview" tab?
println(api.browse.getFeaturedPlaylists().message)
// easy! let's try something a little harder
// let's find out Bénabar's Spotify ID, find his top tracks, and print them out
val benabarId = api.search.searchArtist("Bénabar")[0].id
// this works; a redundant way would be: api.artists.getArtist("spotify:artist:6xoAWsIOZxJVPpo7Qvqaqv").id
println(api.artists.getArtistTopTracks(benabarId).joinToString { it.name })
Spotify keeps many instances of most tracks on their servers, available in different markets. As such, if we use endpoints that return tracks, we do not know if these tracks are playable in our market. That's where track relinking comes in.
To relink in a specified market, we must supply a market
parameter for endpoints where available.
In both Track and SimpleTrack objects in an endpoint response, there is a nullable field called linked_from
.
If the track is unable to be played in the specified market and there is an alternative that is playable, this
will be populated with the href, uri, and, most importantly, the id of the track.
You can then use this track in SpotifyClientApi
endpoints such as playing or saving the track, knowing that it will be playable
in your market!
See CONTRIBUTING.md
FAQs
A Kotlin wrapper for the Spotify Web API.
We found that com.adamratzman:spotify-api-kotlin-tvosarm64 demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.
Security News
Socket's package search now displays weekly downloads for npm packages, helping developers quickly assess popularity and make more informed decisions.