Skip to content

Commit

Permalink
🔀 Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
NeoLegends committed Aug 22, 2017
2 parents def5f13 + a213379 commit dd27eb0
Show file tree
Hide file tree
Showing 28 changed files with 2,744 additions and 2,729 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ build/Release
# Dependency directories
node_modules
jspm_packages
package-lock.json

# Optional npm cache directory
.npm
Expand Down
75 changes: 55 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

[![Greenkeeper badge](https://badges.greenkeeper.io/Festify/cordova-spotify.svg)](https://greenkeeper.io/)

An [Apache Cordova](https://cordova.apache.org/) plugin providing a thin wrapper over the Spotify SDK for iOS and Android.
An [Apache Cordova](https://cordova.apache.org/) plugin providing access to the Spotify SDK for iOS and Android.

[API documentation](#api-docs)

## Features

This plugin provides a very thin layer over the authentication and playback functionality of the Spotify SDK. It allows your users to authenticate using OAuth 2.0 and allows you to play Spotify tracks via their URI. Metadata functionality has deliberately been left out in favor of the [Web API](https://developer.spotify.com/web-api/). After your users have been authenticated, you are given the access token, so accessing the Web API is trivial.
This plugin provides a very simple and atomic layer over playback functionality of the Spotify SDK. It allows you to play Spotify tracks via their URI. Metadata and authentication functionality has deliberately been left out in favor of the [Web API](https://developer.spotify.com/web-api/) and other authentication solutions.

## Stability

Expand All @@ -22,30 +24,63 @@ Pull requests are very welcome! Please use the [gitmoji](https://gitmoji.carlosc
cordova plugin add cordova-spotify
```

API documentation will be provided at a later stage when the stability has improved.

Note: Make sure your installation path doesn't contain any spaces.

## Token Exchange Service
## <a name="api-docs"></a>API Documentation

The Spotify SDK needs some server code for the OAuth authentication because this plugin uses the authorization code flow only. This is because you probably don't want your users to have to login repeatedly every hour. Take a look at the Spotify [documentation](https://developer.spotify.com/web-api/authorization-guide/#authorization-code-flow) for more information.
### General

To easily implement the endpoints for the token swap and token refresh service, we built a [Serverless](https://serverless.com) service for [AWS Lambda](https://aws.amazon.com/lambda/). Make sure you [install the Serverless Framework properly](https://serverless.com/framework/docs/providers/aws/guide/installation/)!
The plugin has an extremely simple API that is focused just on playback. It consists of six functions clobbered onto `cordova.plugins.spotify`. In the following, treat all paths relative to that. The plugin handles all internal state and SDK initialization aspects automatically and hides these aspects from the developer.

For the execution of the functions to work you need to set some environmental configuration in the file `oauth-token-api/.env`
All functions are asynchronous and return promises. The plugin automatically polyfills promise support through `es6-promise-plugin`.

```bash
CLIENT_ID="<Your Spotify Client ID>"
CLIENT_SECRET="<Your Spotify Client Secret>"
CLIENT_CALLBACK_URL="<The callback url of your app>" # e.g. "festify-spotify://callback"
ENCRYPTION_SECRET="<Secret used to encrypt the refresh token - please generate>"
```
If the parameters have invalid values, an appropriate `Error` will be thrown immediately instead of returning a rejected promise. This is because invalid arguments are bugs and not runtime errors.

You can then deploy the functions like this:
### `getEventEmitter()`

```bash
cd oauth-token-api
serverless deploy
```
Obtains an event emitter that relays the events fired by the native SDKs. The emitter will be created once and then returned on subsequent invocations.

The events emitted are the following:
- `connectionmessage`
- `loggedin`
- `loggedout`
- `loginfailed`
- `playbackerror`
- `playbackevent`
- `temporaryerror`

In the case of `loginfailed`, `playbackevent` and `playbackerror`, the event contains a payload that describes what happened exactly. The payload is simply the name of the discriminant of the enum in the native SDK without the prefix (usually `kSp` or `kSpError`). See the offical documentation [here](https://spotify.github.io/android-sdk/player/com/spotify/sdk/android/player/Error.html) and [here](https://spotify.github.io/android-sdk/player/com/spotify/sdk/android/player/PlayerEvent.html) for all variants.

### `getPosition()`

Obtains the players position in _milliseconds_. If no track is currently loaded, returns 0.

### `play(trackUri: string, authOptions: object[, position: number])`

Plays the track with the given Spotify URI.

#### Parameters

- `trackUri`: The Spotify URI of the track to play. E.g. `spotify:track:6nTiIhLmQ3FWhvrGafw2z`. May not be null.
- `authOptions`: An object containing two keys:
- `token: string`: A valid Spotify access token with the `streaming` scope. May not be null.
- `clientId: string`: Your application's client ID as obtained from https://developer.spotify.com. May not be null.
- `position`: Optional. The position (in _milliseconds_) to start playing the track from. Must be >= 0.

`token` and `clientId` may change freely during runtime. The plugin will handle the required login / logout processes automatically when a new track is played.

### `pause()`

Pauses playback. If no track is loaded, returns normally.

### `resume()`

Resumes playback. If no track is loaded, the returned promise will be rejected with an error of type `not_playing`.

### `seekTo(position: number)`

Sets the playback position to the given value. If no track is loaded, the returned promise will be rejected with an error of type `not_playing`.

#### Parameters

Also, you need to register the client callback protocol inside the App Info.plist so that iOS knows which app to start when it is redirected when the authentication is done. Take a look at [this repository](https://github.com/Festify/festify-cordova-scheme-helper) to see how it's done.
- `position`: The position (in _milliseconds_) to seek to. Must be > 0.
18 changes: 0 additions & 18 deletions install-android.sh
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
#!/usr/bin/env bash

AUTH_INSTALL_PATH="plugins/cordova-spotify/src/android/spotify-auth"
AUTH_DOWNLOAD_PATH="https://github.com/spotify/android-auth/archive/1.0.tar.gz"
SDK_INSTALL_PATH="plugins/cordova-spotify/src/android/spotify-sdk"
SDK_DOWNLOAD_PATH="https://github.com/spotify/android-sdk/archive/24-noconnect-2.20b.tar.gz"

if [ ! -d "$AUTH_INSTALL_PATH" ]; then
mkdir -p "$AUTH_INSTALL_PATH"
curl -LsS $AUTH_DOWNLOAD_PATH | tar -xz -C "$AUTH_INSTALL_PATH" --strip 1
else
echo "Skipping auth library download since it's already there."
fi

if [ ! -d "$SDK_INSTALL_PATH" ]; then
mkdir -p "$SDK_INSTALL_PATH"
curl -LsS $SDK_DOWNLOAD_PATH | tar -xz -C "$SDK_INSTALL_PATH" --strip 1
else
echo "Skipping streaming SDK download since it's alredy there."
fi

cd "$(dirname $0)/src/android/spotify-auth"
echo "include ':auth-lib'" > settings.gradle

if [ ! -f "auth-lib/build/outputs/aar/spotify-android-auth-1.0.0.aar" ]; then
./gradlew clean build
else
echo "Skipping auth library build since the AAR is already there."
fi
2 changes: 1 addition & 1 deletion install-ios.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ DOWNLOAD_PATH="https://github.com/spotify/ios-sdk/archive/beta-25.tar.gz"

if [ ! -d $INSTALL_PATH ]; then
mkdir -p $INSTALL_PATH
curl -LsS $DOWNLOAD_PATH | tar -xzv -C $INSTALL_PATH --strip 1
curl -LsS $DOWNLOAD_PATH | tar -xz -C $INSTALL_PATH --strip 1
fi
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cordova-spotify",
"version": "0.4.1",
"version": "0.5.0",
"description": "Spotify SDK bindings for Cordova Applications",
"repository": {
"type": "git",
Expand All @@ -9,7 +9,7 @@
"engines": {
"cordovaDependencies": {
"0.2.2": {
"cordova": "^6.0.0 - 7.0.0"
"cordova": "^6.0.0 - 7.0.0"
}
}
},
Expand Down
7 changes: 6 additions & 1 deletion package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@
echo "✨ Starting JS build"
cd "$(dirname $0)/www"

npm install
if hash yarn 2>/dev/null; then
yarn
else
npm install
fi

./node_modules/.bin/webpack
9 changes: 3 additions & 6 deletions plugin.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<plugin id="cordova-spotify" version="0.4.1" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
<plugin id="cordova-spotify" version="0.5.0" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
<name>cordova-spotify</name>

<hook type="before_plugin_install" src="package.sh" />
Expand Down Expand Up @@ -38,9 +38,6 @@
<resource-file
src="src/android/spotify-sdk/spotify-player-24-noconnect-2.20b.aar"
target="libs/spotify-sdk.aar" />
<resource-file
src="src/android/spotify-auth/auth-lib/build/outputs/aar/spotify-android-auth-1.0.0.aar"
target="libs/spotify-auth.aar" />
</platform>

<platform name="ios">
Expand All @@ -60,8 +57,8 @@

<header-file src="src/ios/CordovaSpotify.h" />
<source-file src="src/ios/CordovaSpotify.m" />
<header-file src="src/ios/CordovaEventEmitter.h" />
<source-file src="src/ios/CordovaEventEmitter.m" />
<header-file src="src/ios/CordovaSpotifyEventEmitter.h" />
<source-file src="src/ios/CordovaSpotifyEventEmitter.m" />
<header-file src="src/ios/AudioStreamingDelegate.h" />
<source-file src="src/ios/AudioStreamingDelegate.m" />
<header-file src="src/ios/AudioStreamingPlaybackDelegate.h" />
Expand Down
35 changes: 35 additions & 0 deletions src/android/ConnectionEventsHandler.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,68 @@
package rocks.festify;

import java.util.ArrayList;

import android.util.Log;

import com.spotify.sdk.android.player.ConnectionStateCallback;
import com.spotify.sdk.android.player.Error;
import com.spotify.sdk.android.player.Player;

import rocks.festify.Emitter;

class ConnectionEventsHandler extends Emitter
implements ConnectionStateCallback {
private static final String TAG = "ConnectionEventsHandler";

private final ArrayList<Player.OperationCallback> loginCallbacks = new ArrayList<Player.OperationCallback>();
private final ArrayList<Runnable> logoutCallbacks = new ArrayList<Runnable>();

@Override
public void onConnectionMessage(String message) {
this.emit("connectionmessage", message);
}

@Override
public void onLoggedIn() {
for (Player.OperationCallback item : this.loginCallbacks) {
if (item != null) {
item.onSuccess();
}
}
loginCallbacks.clear();

this.emit("loggedin");
}

public void onLoggedIn(Player.OperationCallback runnable) {
this.loginCallbacks.add(runnable);
}

@Override
public void onLoggedOut() {
for (Runnable item : this.logoutCallbacks) {
if (item != null) {
item.run();
}
}
logoutCallbacks.clear();

this.emit("loggedout");
}

public void onLoggedOut(Runnable runnable) {
this.logoutCallbacks.add(runnable);
}

@Override
public void onLoginFailed(Error error) {
for (Player.OperationCallback item : this.loginCallbacks) {
if (item != null) {
item.onError(error);
}
}
loginCallbacks.clear();

this.emit("loginfailed", error);
}

Expand Down
Loading

0 comments on commit dd27eb0

Please sign in to comment.