Skip to content

Commit

Permalink
feat: Add playback speed control for podcasts and switch to local dev…
Browse files Browse the repository at this point in the history
…ice (#160)
  • Loading branch information
brim-borium authored Aug 16, 2023
1 parent cac351a commit 44ae5c4
Show file tree
Hide file tree
Showing 12 changed files with 374 additions and 91 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 3.0.0-dev.2
* Feat: add set podcastPlaybackSpeed and switchToLocalDevice for android (#160)

## 3.0.0-dev.1
* **BREAKINg**:feat: update spotify.android:auth from 1.2.6 to 2.1.0 and spotify.app.remote from 0.7.2 to 0.8.0
In the app/build.gradle add the following to the default config for auth to work as described [here](https://github.com/spotify/android-auth#integrating-the-library-into-your-project)
Expand Down
62 changes: 39 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# spotify_sdk

<p align="center">
<a href="https://pub.dev/packages/spotify_sdk"><img src="https://img.shields.io/badge/pub-3.0.0.dev1-orange" alt="build"></a>
<a href="https://pub.dev/packages/spotify_sdk"><img src="https://img.shields.io/badge/pub-3.0.0.dev.2-orange" alt="build"></a>
<a href="https://github.com/brim-borium/spotify_sdk"><img src="https://img.shields.io/github/stars/brim-borium/spotify_sdk?color=deeppink" alt="build"></a>
<a href="https://github.com/brim-borium/spotify_sdk/actions?query=workflow%3Aspotify_sdk"><img src="https://img.shields.io/github/actions/workflow/status/brim-borium/spotify_sdk/spotify_sdk.yml" alt="build"></a>
<a href="https://github.com/brim-borium/spotify_sdk/blob/main/LICENSE"><img src="https://img.shields.io/github/license/brim-borium/spotify_sdk?color=blue" alt="build"></a>
Expand Down Expand Up @@ -153,36 +153,44 @@ Token Swap is for now "web only". While the iOS SDK also supports the "token swa

#### Player Api

| Function | Description | Android | iOS | Web |
|---|---|---|---|---|
| getPlayerState | Gets the current player state ||||
| pause | Pauses the current track ||||
| play | Plays the given spotifyUri ||||
| queue | Queues given spotifyUri ||||
| resume | Resumes the current track ||||
| skipNext | Skips to next track ||||
| skipPrevious | Skips to previous track ||||
| skipToIndex | Skips to track at specified index in album or playlist ||| 🚧 |
| seekTo | Seeks the current track to the given position in milliseconds ||| 🚧 |
| seekToRelativePosition | Adds to the current position of the track the given milliseconds ||| 🚧 |
| subscribePlayerContext | Subscribes to the current player context ||||
| subscribePlayerState| Subscribes to the current player state ||||
| getCrossfadeState | Gets the current crossfade state ||||
| toggleShuffle | Cycles through the shuffle modes ||||
| setShuffle | Set the shuffle mode ||||
| toggleRepeat | Cycles through the repeat modes ||||
| setRepeatMode | Set the repeat mode ||||
The playerApi as described [here](https://spotify.github.io/android-sdk/app-remote-lib/docs/com/spotify/android/appremote/api/PlayerApi.html).

| Function | Description | Android | iOS | Web |
|-------------------------|---|--|---|---|
| getCrossfadeState | Gets the current crossfade state ||||
| getPlayerState | Gets the current player state ||||
| pause | Pauses the current track ||||
| play | Plays the given spotifyUri ||||
| playWithStreamType | Play the given Spotify uri with specific behaviour for that streamtype | 🚧 | 🚧 | 🚧 |
| queue | Queues given spotifyUri ||||
| resume | Resumes the current track ||||
| seekTo | Seeks the current track to the given position in milliseconds ||| 🚧 |
| seekToRelativePosition | Adds to the current position of the track the given milliseconds ||| 🚧 |
| setPodcastPlaybackSpeed | Set playback speed for Podcast || 🚧 | 🚧 |
| setRepeatMode | Set the repeat mode ||||
| setShuffle | Set the shuffle mode ||||
| skipNext | Skips to next track ||||
| skipPrevious | Skips to previous track ||||
| skipToIndex | Skips to track at specified index in album or playlist ||| 🚧 |
| subscribePlayerContext | Subscribes to the current player context ||||
| subscribePlayerState | Subscribes to the current player state ||||
| toggleRepeat | Cycles through the repeat modes ||||
| toggleShuffle | Cycles through the shuffle modes ||||

On Web, an automatic call to play may not work due to media activation policies which send an error: "Authentication Error: Browser prevented autoplay due to lack of interaction". This error is ignored by the SDK so you can still present a button for the user to click to `play` or `resume` to start playback. See the [Web SDK Troubleshooting guide](https://developer.spotify.com/documentation/web-playback-sdk/reference/#troubleshooting) for more details.

#### Images Api

The imagesApi as described [here](https://spotify.github.io/android-sdk/app-remote-lib/docs/com/spotify/android/appremote/api/ImagesApi.html).

| Function | Description| Android | iOS | Web |
|---|---|---|---|---|
| getImage | Get the image from the given spotifyUri ||| 🚧 |

#### User Api

The userApi as described [here](https://spotify.github.io/android-sdk/app-remote-lib/docs/com/spotify/android/appremote/api/UserApi.html).

| Function | Description| Android | iOS | Web |
|---|---|---|---|---|
| addToLibrary | Adds the given spotifyUri to the users library ||| 🚧 |
Expand All @@ -194,12 +202,20 @@ On Web, an automatic call to play may not work due to media activation policies

#### Connect Api

| Function | Description| Android | iOS | Web |
|---|---|---|---|---|
| connectSwitchToLocalDevice | Switch to play music on this (local) device | 🚧 | 🚧 | 🚧 |
The connectApi as described [here](https://spotify.github.io/android-sdk/app-remote-lib/docs/com/spotify/android/appremote/api/ConnectApi.html).

| Function | Description | Android | iOS | Web |
|----------------------------|--------------------------------------------|---|---|---|
| connectDecreaseVolume | Decrease volume by a step size determined | 🚧 | 🚧 | 🚧 |
| connectIncreaseVolume | Increase volume by a step size determined | 🚧 | 🚧 | 🚧 |
| connectSetVolume | Set a volume on the currently active device | 🚧 | 🚧 | 🚧 |
| connectSwitchToLocalDevice | Switch to play music on this (local) device || 🚧 | 🚧 |
| subscribeToVolumeState | Subscribe to volume state | 🚧 | 🚧 | 🚧 |

#### Content Api

The contentApi as described [here](https://spotify.github.io/android-sdk/app-remote-lib/docs/com/spotify/android/appremote/api/ContentApi.html).

| Function | Description| Android | iOS | Web |
|---|---|---|---|---|
| getChildrenOfItem | tbd | 🚧 | 🚧 | 🚧 |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package de.minimalme.spotify_sdk

import com.spotify.android.appremote.api.SpotifyAppRemote
import com.spotify.protocol.types.Image.Dimension
import com.spotify.protocol.types.ImageUri
import io.flutter.plugin.common.MethodChannel
import java.io.ByteArrayOutputStream
import android.graphics.Bitmap

class SpotifyConnectApi(spotifyAppRemote: SpotifyAppRemote?, result: MethodChannel.Result) : BaseSpotifyApi(spotifyAppRemote, result) {

private val errorConnectSwitchToLocalDevice = "errorConnectSwitchToLocalDevice"

private val connectApi = spotifyAppRemote?.connectApi

fun switchToLocalDevice() {
if (connectApi != null) {
connectApi.connectSwitchToLocalDevice()
.setResultCallback { result.success(true) }
.setErrorCallback { throwable -> result.error(errorConnectSwitchToLocalDevice, "error when switching to local device", throwable.toString()) }
} else {
spotifyRemoteAppNotSetError()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class SpotifyPlayerApi(spotifyAppRemote: SpotifyAppRemote?, result: MethodChanne
internal fun setPodcastPlaybackSpeed(podcastPlaybackSpeedValue: Int?) {
if (playerApi != null && podcastPlaybackSpeedValue != null) {

val podcastPlaybackSpeed = PlaybackSpeed.PodcastPlaybackSpeed.values()[podcastPlaybackSpeedValue]
val podcastPlaybackSpeed = PlaybackSpeed.PodcastPlaybackSpeed.values().firstOrNull{ it.value == podcastPlaybackSpeedValue }

playerApi.setPodcastPlaybackSpeed(podcastPlaybackSpeed)
.setResultCallback { result.success(true) }
Expand Down Expand Up @@ -221,4 +221,4 @@ class SpotifyPlayerApi(spotifyAppRemote: SpotifyAppRemote?, result: MethodChanne
spotifyRemoteAppNotSetError()
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ class SpotifySdkPlugin : MethodCallHandler, FlutterPlugin, ActivityAware, Plugin
private val methodGetAccessToken = "getAccessToken"
private val methodDisconnectFromSpotify = "disconnectFromSpotify"

//player api
// connectApi
private val methodSwitchToLocalDevice = "switchToLocalDevice"

//playerApi
private val methodGetCrossfadeState = "getCrossfadeState"
private val methodGetPlayerState = "getPlayerState"
private val methodPlay = "play"
Expand All @@ -84,13 +87,13 @@ class SpotifySdkPlugin : MethodCallHandler, FlutterPlugin, ActivityAware, Plugin
private val methodSetRepeatMode = "setRepeatMode"
private val methodIsSpotifyAppActive = "isSpotifyAppActive"

//user api
//userApi
private val methodAddToLibrary = "addToLibrary"
private val methodRemoveFromLibrary = "removeFromLibrary"
private val methodGetCapabilities = "getCapabilities"
private val methodGetLibraryState = "getLibraryState"

//images api
//imagesApi
private val methodGetImage = "getImage"

private val paramClientId = "clientId"
Expand Down Expand Up @@ -118,6 +121,7 @@ class SpotifySdkPlugin : MethodCallHandler, FlutterPlugin, ActivityAware, Plugin
private var pendingOperation: PendingOperation? = null
private var spotifyAppRemote: SpotifyAppRemote? = null
private var spotifyPlayerApi: SpotifyPlayerApi? = null
private var spotifyConnectApi: SpotifyConnectApi? = null
private var spotifyUserApi: SpotifyUserApi? = null
private var spotifyImagesApi: SpotifyImagesApi? = null

Expand Down Expand Up @@ -168,14 +172,17 @@ class SpotifySdkPlugin : MethodCallHandler, FlutterPlugin, ActivityAware, Plugin
spotifyPlayerApi = SpotifyPlayerApi(spotifyAppRemote, result)
spotifyUserApi = SpotifyUserApi(spotifyAppRemote, result)
spotifyImagesApi = SpotifyImagesApi(spotifyAppRemote, result)
spotifyConnectApi = SpotifyConnectApi(spotifyAppRemote, result)
}

when (call.method) {
//connecting to spotify
methodConnectToSpotify -> connectToSpotify(call.argument(paramClientId), call.argument(paramRedirectUrl), result)
methodGetAccessToken -> getAccessToken(call.argument(paramClientId), call.argument(paramRedirectUrl), call.argument(paramScope), result)
methodDisconnectFromSpotify -> disconnectFromSpotify(result)
//player api calls
//connectApi calls
methodSwitchToLocalDevice -> spotifyConnectApi?.switchToLocalDevice()
//playerApi calls
methodGetCrossfadeState -> spotifyPlayerApi?.getCrossfadeState()
methodGetPlayerState -> spotifyPlayerApi?.getPlayerState()
methodPlay -> spotifyPlayerApi?.play(call.argument(paramSpotifyUri))
Expand All @@ -193,12 +200,12 @@ class SpotifySdkPlugin : MethodCallHandler, FlutterPlugin, ActivityAware, Plugin
methodToggleRepeat -> spotifyPlayerApi?.toggleRepeat()
methodSetRepeatMode -> spotifyPlayerApi?.setRepeatMode(call.argument(paramRepeatMode))
methodIsSpotifyAppActive -> spotifyPlayerApi?.isSpotifyAppActive()
//user api calls
//userApi calls
methodAddToLibrary -> spotifyUserApi?.addToUserLibrary(call.argument(paramSpotifyUri))
methodRemoveFromLibrary -> spotifyUserApi?.removeFromUserLibrary(call.argument(paramSpotifyUri))
methodGetCapabilities -> spotifyUserApi?.getCapabilities()
methodGetLibraryState -> spotifyUserApi?.getLibraryState(call.argument(paramSpotifyUri))
//image api calls
//imageApi calls
methodGetImage -> spotifyImagesApi?.getImage(call.argument(paramImageUri), call.argument(paramImageDimension))
// method call is not implemented yet
else -> result.notImplemented()
Expand Down
4 changes: 2 additions & 2 deletions example/.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
```sh
CLIENT_ID=
REDIRECT_URL=
CLIENT_ID=61b2332ab76d45918a33f91c3268ec1e
REDIRECT_URL=comspotifytestsdk://callback
```
Loading

0 comments on commit 44ae5c4

Please sign in to comment.