|
|
|
@ -5,16 +5,15 @@ import 'dart:async'; |
|
|
|
import 'dart:convert'; |
|
|
|
import 'dart:core'; |
|
|
|
import 'dart:developer'; |
|
|
|
import 'dart:html'; |
|
|
|
import 'dart:js_interop'; |
|
|
|
import 'dart:math' as math; |
|
|
|
|
|
|
|
import 'package:crypto/crypto.dart'; |
|
|
|
import 'package:dio/dio.dart'; |
|
|
|
import 'package:flutter/services.dart'; |
|
|
|
import 'package:flutter_web_plugins/flutter_web_plugins.dart'; |
|
|
|
import 'package:js/js.dart'; |
|
|
|
import 'package:js/js_util.dart'; |
|
|
|
import 'package:synchronized/synchronized.dart' as synchronized; |
|
|
|
import 'package:web/web.dart' as web; |
|
|
|
|
|
|
|
import 'enums/repeat_mode_enum.dart'; |
|
|
|
import 'models/album.dart'; |
|
|
|
@ -52,6 +51,9 @@ class SpotifySdkPlugin { |
|
|
|
/// Current Spotify SDK player instance. |
|
|
|
Player? _currentPlayer; |
|
|
|
|
|
|
|
/// Current device ID (存储在 Dart 侧,因为 extension type 不支持实例字段) |
|
|
|
String? _currentDeviceID; |
|
|
|
|
|
|
|
/// Current Spotify auth token. |
|
|
|
SpotifyToken? _spotifyToken; |
|
|
|
|
|
|
|
@ -172,18 +174,19 @@ class SpotifySdkPlugin { |
|
|
|
// create player |
|
|
|
_currentPlayer = Player(PlayerOptions( |
|
|
|
name: playerName, |
|
|
|
getOAuthToken: allowInterop((Function callback, t) { |
|
|
|
getOAuthToken: ((JSAny? callback, JSAny? t) { |
|
|
|
_getSpotifyAuthToken().then((value) { |
|
|
|
callback(value); |
|
|
|
(callback as JSFunction).callAsFunction(null, value.toJS); |
|
|
|
}); |
|
|
|
}))); |
|
|
|
}).toJS)); |
|
|
|
|
|
|
|
_registerPlayerEvents(_currentPlayer!); |
|
|
|
var result = await promiseToFuture(_currentPlayer!.connect()); |
|
|
|
var result = |
|
|
|
(await _currentPlayer!.connect().toDart).toDart; |
|
|
|
if (result == true) { |
|
|
|
// wait for the confirmation |
|
|
|
num time = 0; |
|
|
|
while (_currentPlayer!.deviceID == null) { |
|
|
|
while (_currentDeviceID == null) { |
|
|
|
await Future.delayed(const Duration(milliseconds: 200)); |
|
|
|
time += 200; |
|
|
|
if (time > 10000) { |
|
|
|
@ -242,19 +245,19 @@ class SpotifySdkPlugin { |
|
|
|
call.arguments[ParamNames.repeatMode] as RepeatMode?); |
|
|
|
break; |
|
|
|
case MethodNames.resume: |
|
|
|
await promiseToFuture(_currentPlayer?.resume()); |
|
|
|
await _currentPlayer!.resume().toDart; |
|
|
|
break; |
|
|
|
case MethodNames.pause: |
|
|
|
await promiseToFuture(_currentPlayer?.pause()); |
|
|
|
await _currentPlayer!.pause().toDart; |
|
|
|
break; |
|
|
|
case MethodNames.skipNext: |
|
|
|
await promiseToFuture(_currentPlayer?.nextTrack()); |
|
|
|
await _currentPlayer!.nextTrack().toDart; |
|
|
|
break; |
|
|
|
case MethodNames.skipPrevious: |
|
|
|
await promiseToFuture(_currentPlayer?.previousTrack()); |
|
|
|
await _currentPlayer!.previousTrack().toDart; |
|
|
|
break; |
|
|
|
case MethodNames.getPlayerState: |
|
|
|
var stateRaw = await promiseToFuture(_currentPlayer?.getCurrentState()) |
|
|
|
var stateRaw = (await _currentPlayer!.getCurrentState().toDart) |
|
|
|
as WebPlaybackState?; |
|
|
|
if (stateRaw == null) return null; |
|
|
|
return jsonEncode(toPlayerState(stateRaw)!.toJson()); |
|
|
|
@ -272,10 +275,13 @@ class SpotifySdkPlugin { |
|
|
|
log('Loading Spotify SDK...'); |
|
|
|
|
|
|
|
// link spotify ready function |
|
|
|
_onSpotifyWebPlaybackSDKReady = allowInterop(_onSpotifyInitialized); |
|
|
|
_onSpotifyWebPlaybackSDKReady = _onSpotifyInitialized.toJS; |
|
|
|
|
|
|
|
// load spotify sdk |
|
|
|
querySelector('body')!.children.add(ScriptElement()..src = spotifySdkUrl); |
|
|
|
final script = |
|
|
|
web.document.createElement('script') as web.HTMLScriptElement; |
|
|
|
script.src = spotifySdkUrl; |
|
|
|
web.document.body!.appendChild(script); |
|
|
|
|
|
|
|
// wait for initialization |
|
|
|
while (_sdkLoaded == false) { |
|
|
|
@ -294,33 +300,37 @@ class SpotifySdkPlugin { |
|
|
|
void _registerPlayerEvents(Player player) { |
|
|
|
// player state |
|
|
|
player.addListener('player_state_changed', |
|
|
|
allowInterop((WebPlaybackState? state) { |
|
|
|
if (state == null) return; |
|
|
|
((JSAny? stateObj) { |
|
|
|
if (stateObj == null) return; |
|
|
|
var state = stateObj as WebPlaybackState; |
|
|
|
playerStateEventController |
|
|
|
.add(jsonEncode(toPlayerState(state)!.toJson())); |
|
|
|
playerContextEventController |
|
|
|
.add(jsonEncode(toPlayerContext(state)!.toJson())); |
|
|
|
})); |
|
|
|
}).toJS); |
|
|
|
|
|
|
|
// ready/not ready |
|
|
|
player.addListener('ready', allowInterop((WebPlaybackPlayer player) { |
|
|
|
player.addListener('ready', ((JSAny? playerObj) { |
|
|
|
var p = playerObj as WebPlaybackPlayer; |
|
|
|
log('Spotify SDK ready!'); |
|
|
|
_onSpotifyConnected(player.device_id); |
|
|
|
})); |
|
|
|
player.addListener('not_ready', allowInterop((event) { |
|
|
|
_onSpotifyConnected(p.device_id); |
|
|
|
}).toJS); |
|
|
|
player.addListener('not_ready', ((JSAny? event) { |
|
|
|
_onSpotifyDisconnected( |
|
|
|
errorCode: 'Spotify SDK not ready', |
|
|
|
errorDetails: 'Spotify SDK is not ready to take requests'); |
|
|
|
})); |
|
|
|
}).toJS); |
|
|
|
|
|
|
|
// errors |
|
|
|
player.addListener('initialization_error', |
|
|
|
allowInterop((WebPlaybackError error) { |
|
|
|
((JSAny? errorObj) { |
|
|
|
var error = errorObj as WebPlaybackError; |
|
|
|
_onSpotifyDisconnected( |
|
|
|
errorCode: 'Initialization Error', errorDetails: error.message); |
|
|
|
})); |
|
|
|
}).toJS); |
|
|
|
player.addListener('authentication_error', |
|
|
|
allowInterop((WebPlaybackError error) { |
|
|
|
((JSAny? errorObj) { |
|
|
|
var error = errorObj as WebPlaybackError; |
|
|
|
// If the error is due to browser security, don't disconnect. |
|
|
|
// The user needs to interact with the SDK to trigger media activation. |
|
|
|
// https://developer.spotify.com/documentation/web-playback-sdk/quick-start/#mobile-support |
|
|
|
@ -330,14 +340,16 @@ class SpotifySdkPlugin { |
|
|
|
} |
|
|
|
_onSpotifyDisconnected( |
|
|
|
errorCode: 'Authentication Error', errorDetails: error.message); |
|
|
|
})); |
|
|
|
player.addListener('account_error', allowInterop((WebPlaybackError error) { |
|
|
|
}).toJS); |
|
|
|
player.addListener('account_error', ((JSAny? errorObj) { |
|
|
|
var error = errorObj as WebPlaybackError; |
|
|
|
_onSpotifyDisconnected( |
|
|
|
errorCode: 'Account Error', errorDetails: error.message); |
|
|
|
})); |
|
|
|
player.addListener('playback_error', allowInterop((WebPlaybackError error) { |
|
|
|
}).toJS); |
|
|
|
player.addListener('playback_error', ((JSAny? errorObj) { |
|
|
|
var error = errorObj as WebPlaybackError; |
|
|
|
log('playback_error: ${error.message}'); |
|
|
|
})); |
|
|
|
}).toJS); |
|
|
|
} |
|
|
|
|
|
|
|
/// Called when the Spotify SDK is first loaded. |
|
|
|
@ -347,7 +359,7 @@ class SpotifySdkPlugin { |
|
|
|
|
|
|
|
/// Called when the plugin successfully connects to the spotify web sdk. |
|
|
|
void _onSpotifyConnected(String deviceId) { |
|
|
|
_currentPlayer!.deviceID = deviceId; |
|
|
|
_currentDeviceID = deviceId; |
|
|
|
|
|
|
|
// emit connected event |
|
|
|
connectionStatusEventController.add(jsonEncode(ConnectionStatus( |
|
|
|
@ -362,6 +374,7 @@ class SpotifySdkPlugin { |
|
|
|
void _onSpotifyDisconnected({String? errorCode, String? errorDetails}) { |
|
|
|
_unregisterPlayerEvents(_currentPlayer!); |
|
|
|
_currentPlayer = null; |
|
|
|
_currentDeviceID = null; |
|
|
|
|
|
|
|
if (errorCode != null) { |
|
|
|
// disconnected due to error |
|
|
|
@ -445,27 +458,32 @@ class SpotifySdkPlugin { |
|
|
|
); |
|
|
|
|
|
|
|
// opening auth window |
|
|
|
var authPopup = window.open( |
|
|
|
var authPopup = web.window.open( |
|
|
|
authorizationUri.toString(), |
|
|
|
'Spotify Authorization', |
|
|
|
); |
|
|
|
String? message; |
|
|
|
var sub = window.onMessage.listen(allowInterop((event) { |
|
|
|
message = event.data.toString(); |
|
|
|
// ensure the message contains auth code |
|
|
|
if (!message!.startsWith('?code=')) { |
|
|
|
message = null; |
|
|
|
final messageHandler = ((JSAny? e) { |
|
|
|
final event = e as web.MessageEvent; |
|
|
|
if (event.data != null && event.data!.isA<JSString>()) { |
|
|
|
final str = (event.data as JSString).toDart; |
|
|
|
// ensure the message contains auth code |
|
|
|
if (str.startsWith('?code=')) { |
|
|
|
message = str; |
|
|
|
} |
|
|
|
} |
|
|
|
})); |
|
|
|
}).toJS; |
|
|
|
web.window.addEventListener('message', messageHandler); |
|
|
|
|
|
|
|
// loop and wait for auth |
|
|
|
while (authPopup.closed == false && message == null) { |
|
|
|
while (authPopup?.closed == false && message == null) { |
|
|
|
// await response from the window |
|
|
|
await Future.delayed(const Duration(milliseconds: 250)); |
|
|
|
} |
|
|
|
|
|
|
|
// error if window closed by user |
|
|
|
if (message == null) { |
|
|
|
web.window.removeEventListener('message', messageHandler); |
|
|
|
throw PlatformException( |
|
|
|
message: 'User closed authentication window', |
|
|
|
code: 'Authentication Error'); |
|
|
|
@ -476,6 +494,7 @@ class SpotifySdkPlugin { |
|
|
|
|
|
|
|
// check if state is the same |
|
|
|
if (state != parsedMessage.queryParameters['state']) { |
|
|
|
web.window.removeEventListener('message', messageHandler); |
|
|
|
throw PlatformException( |
|
|
|
message: 'Invalid state', code: 'Authentication Error'); |
|
|
|
} |
|
|
|
@ -483,16 +502,17 @@ class SpotifySdkPlugin { |
|
|
|
// check for error |
|
|
|
if (parsedMessage.queryParameters['error'] != null || |
|
|
|
parsedMessage.queryParameters['code'] == null) { |
|
|
|
web.window.removeEventListener('message', messageHandler); |
|
|
|
throw PlatformException( |
|
|
|
message: "${parsedMessage.queryParameters['error']}", |
|
|
|
code: 'Authentication Error'); |
|
|
|
} |
|
|
|
|
|
|
|
// close auth window |
|
|
|
if (authPopup.closed == false) { |
|
|
|
authPopup.close(); |
|
|
|
if (authPopup?.closed == false) { |
|
|
|
authPopup?.close(); |
|
|
|
} |
|
|
|
await sub.cancel(); |
|
|
|
web.window.removeEventListener('message', messageHandler); |
|
|
|
|
|
|
|
// exchange auth code for access and refresh tokens |
|
|
|
dynamic authResponse; |
|
|
|
@ -613,7 +633,7 @@ class SpotifySdkPlugin { |
|
|
|
|
|
|
|
/// Starts track playback on the device. |
|
|
|
Future _play(String? uri) async { |
|
|
|
if (_currentPlayer?.deviceID == null) { |
|
|
|
if (_currentDeviceID == null) { |
|
|
|
throw PlatformException( |
|
|
|
message: 'Spotify player not connected!', code: 'Playback Error'); |
|
|
|
} |
|
|
|
@ -623,7 +643,7 @@ class SpotifySdkPlugin { |
|
|
|
data: { |
|
|
|
'uris': [uri] |
|
|
|
}, |
|
|
|
queryParameters: {'device_id': _currentPlayer!.deviceID}, |
|
|
|
queryParameters: {'device_id': _currentDeviceID}, |
|
|
|
options: Options( |
|
|
|
headers: { |
|
|
|
'Content-Type': 'application/json', |
|
|
|
@ -635,14 +655,14 @@ class SpotifySdkPlugin { |
|
|
|
|
|
|
|
/// Adds a given track to the playback queue. |
|
|
|
Future _queue(String? uri) async { |
|
|
|
if (_currentPlayer?.deviceID == null) { |
|
|
|
if (_currentDeviceID == null) { |
|
|
|
throw PlatformException( |
|
|
|
message: 'Spotify player not connected!', code: 'Playback Error'); |
|
|
|
} |
|
|
|
|
|
|
|
await _dio.post( |
|
|
|
'/queue', |
|
|
|
queryParameters: {'uri': uri, 'device_id': _currentPlayer!.deviceID}, |
|
|
|
queryParameters: {'uri': uri, 'device_id': _currentDeviceID}, |
|
|
|
options: Options( |
|
|
|
headers: { |
|
|
|
'Content-Type': 'application/json', |
|
|
|
@ -654,7 +674,7 @@ class SpotifySdkPlugin { |
|
|
|
|
|
|
|
/// Sets whether shuffle should be enabled. |
|
|
|
Future _setShuffle(bool? shuffleEnabled) async { |
|
|
|
if (_currentPlayer?.deviceID == null) { |
|
|
|
if (_currentDeviceID == null) { |
|
|
|
throw PlatformException( |
|
|
|
message: 'Spotify player not connected!', code: 'Set Shuffle Error'); |
|
|
|
} |
|
|
|
@ -663,7 +683,7 @@ class SpotifySdkPlugin { |
|
|
|
'/shuffle', |
|
|
|
queryParameters: { |
|
|
|
'state': shuffleEnabled, |
|
|
|
'device_id': _currentPlayer!.deviceID |
|
|
|
'device_id': _currentDeviceID |
|
|
|
}, |
|
|
|
options: Options( |
|
|
|
headers: { |
|
|
|
@ -676,7 +696,7 @@ class SpotifySdkPlugin { |
|
|
|
|
|
|
|
/// Sets the repeat mode. |
|
|
|
Future _setRepeatMode(RepeatMode? repeatMode) async { |
|
|
|
if (_currentPlayer?.deviceID == null) { |
|
|
|
if (_currentDeviceID == null) { |
|
|
|
throw PlatformException( |
|
|
|
message: 'Spotify player not connected!', |
|
|
|
code: 'Set Repeat Mode Error'); |
|
|
|
@ -686,7 +706,7 @@ class SpotifySdkPlugin { |
|
|
|
'/repeat', |
|
|
|
queryParameters: { |
|
|
|
'state': repeatMode.toString().substring(11), |
|
|
|
'device_id': _currentPlayer!.deviceID |
|
|
|
'device_id': _currentDeviceID |
|
|
|
}, |
|
|
|
options: Options( |
|
|
|
headers: { |
|
|
|
@ -699,14 +719,14 @@ class SpotifySdkPlugin { |
|
|
|
|
|
|
|
/// Toggles shuffle on the current player. |
|
|
|
Future toggleShuffle({bool? state}) async { |
|
|
|
if (_currentPlayer?.deviceID == null) { |
|
|
|
if (_currentDeviceID == null) { |
|
|
|
throw PlatformException( |
|
|
|
message: 'Spotify player not connected!', code: 'Playback Error'); |
|
|
|
} |
|
|
|
|
|
|
|
await _dio.put( |
|
|
|
'/shuffle', |
|
|
|
queryParameters: {'state': state, 'device_id': _currentPlayer!.deviceID}, |
|
|
|
queryParameters: {'state': state, 'device_id': _currentDeviceID}, |
|
|
|
options: Options( |
|
|
|
headers: { |
|
|
|
'Content-Type': 'application/json', |
|
|
|
@ -718,14 +738,14 @@ class SpotifySdkPlugin { |
|
|
|
|
|
|
|
/// Toggles repeat on the current player. |
|
|
|
Future toggleRepeat({bool? state}) async { |
|
|
|
if (_currentPlayer?.deviceID == null) { |
|
|
|
if (_currentDeviceID == null) { |
|
|
|
throw PlatformException( |
|
|
|
message: 'Spotify player not connected!', code: 'Playback Error'); |
|
|
|
} |
|
|
|
|
|
|
|
await _dio.put( |
|
|
|
'/repeat', |
|
|
|
queryParameters: {'state': state, 'device_id': _currentPlayer!.deviceID}, |
|
|
|
queryParameters: {'state': state, 'device_id': _currentDeviceID}, |
|
|
|
options: Options( |
|
|
|
headers: { |
|
|
|
'Content-Type': 'application/json', |
|
|
|
@ -744,7 +764,8 @@ class SpotifySdkPlugin { |
|
|
|
var artists = <Artist>[]; |
|
|
|
|
|
|
|
if (trackRaw != null) { |
|
|
|
for (var artist in trackRaw.artists) { |
|
|
|
for (var i = 0; i < trackRaw.artists.length; i++) { |
|
|
|
var artist = trackRaw.artists[i] as WebPlaybackArtist; |
|
|
|
artists.add(Artist(artist.name, artist.uri)); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -770,7 +791,7 @@ class SpotifySdkPlugin { |
|
|
|
artists[0], |
|
|
|
artists, |
|
|
|
-1, |
|
|
|
ImageUri(albumRaw.images[0].url), |
|
|
|
ImageUri((albumRaw.images[0] as WebPlaybackAlbumImage).url), |
|
|
|
trackRaw.name, |
|
|
|
trackRaw.uri, |
|
|
|
trackRaw.linked_from.uri, |
|
|
|
@ -806,87 +827,79 @@ class SpotifySdkPlugin { |
|
|
|
/// Allows assigning the function onSpotifyWebPlaybackSDKReady |
|
|
|
/// to be callable from `window.onSpotifyWebPlaybackSDKReady()` |
|
|
|
@JS('onSpotifyWebPlaybackSDKReady') |
|
|
|
external set _onSpotifyWebPlaybackSDKReady(void Function()? f); |
|
|
|
external set _onSpotifyWebPlaybackSDKReady(JSFunction? f); |
|
|
|
|
|
|
|
/// Allows assigning the function onSpotifyWebPlaybackSDKReady |
|
|
|
/// to be callable from `window.onSpotifyWebPlaybackSDKReady()` |
|
|
|
/// Allows checking if onSpotifyWebPlaybackSDKReady has been set |
|
|
|
@JS('onSpotifyWebPlaybackSDKReady') |
|
|
|
external void Function()? get _onSpotifyWebPlaybackSDKReady; |
|
|
|
external JSFunction? get _onSpotifyWebPlaybackSDKReady; |
|
|
|
|
|
|
|
/// Spotify Player Object |
|
|
|
@JS('Spotify.Player') |
|
|
|
class Player { |
|
|
|
/// Device id of the player. |
|
|
|
String? deviceID; |
|
|
|
|
|
|
|
extension type Player._(JSObject _) implements JSObject { |
|
|
|
/// The main constructor for initializing the Web Playback SDK. |
|
|
|
/// It should contain an object with the player name, volume and access token. |
|
|
|
external Player(PlayerOptions options); |
|
|
|
|
|
|
|
/// Connects Web Playback SDK instance to Spotify |
|
|
|
/// with the credentials provided during initialization. |
|
|
|
external dynamic connect(); |
|
|
|
external JSPromise<JSBoolean> connect(); |
|
|
|
|
|
|
|
/// Closes the current session that Web Playback SDK has with Spotify. |
|
|
|
external void disconnect(); |
|
|
|
|
|
|
|
/// Create a new event listener in the Web Playback SDK. |
|
|
|
external void addListener(String type, Function callback); |
|
|
|
external void addListener(String type, JSFunction callback); |
|
|
|
|
|
|
|
/// Remove an event listener in the Web Playback SDK. |
|
|
|
// ignore: non_constant_identifier_names |
|
|
|
external void removeListener(String event_name); |
|
|
|
|
|
|
|
/// Collect metadata on local playback. |
|
|
|
external dynamic getCurrentState(); |
|
|
|
external JSPromise<JSAny?> getCurrentState(); |
|
|
|
|
|
|
|
/// Rename the Spotify Player device. |
|
|
|
/// This is visible across all Spotify Connect devices. |
|
|
|
external dynamic setName(String name); |
|
|
|
external JSPromise setName(String name); |
|
|
|
|
|
|
|
/// Set the local volume for the Web Playback SDK. |
|
|
|
external dynamic setVolume(double volume); |
|
|
|
external JSPromise setVolume(double volume); |
|
|
|
|
|
|
|
/// Pause the local playback. |
|
|
|
external dynamic pause(); |
|
|
|
external JSPromise pause(); |
|
|
|
|
|
|
|
/// Resume the local playback. |
|
|
|
external dynamic resume(); |
|
|
|
external JSPromise resume(); |
|
|
|
|
|
|
|
/// Resume/pause the local playback. |
|
|
|
external dynamic togglePlay(); |
|
|
|
external JSPromise togglePlay(); |
|
|
|
|
|
|
|
/// Seek to a position in the current track in local playback. |
|
|
|
// ignore: non_constant_identifier_names |
|
|
|
external dynamic seek(int position_ms); |
|
|
|
external JSPromise seek(int position_ms); |
|
|
|
|
|
|
|
/// Switch to the previous track in local playback. |
|
|
|
external dynamic previousTrack(); |
|
|
|
external JSPromise previousTrack(); |
|
|
|
|
|
|
|
/// Skip to the next track in local playback. |
|
|
|
external dynamic nextTrack(); |
|
|
|
external JSPromise nextTrack(); |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify player options object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class PlayerOptions { |
|
|
|
extension type PlayerOptions._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external String get name; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external Function get getOAuthToken; |
|
|
|
external JSFunction get getOAuthToken; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external double get volume; |
|
|
|
|
|
|
|
// ignore: public_member_api_docs |
|
|
|
external factory PlayerOptions( |
|
|
|
{String? name, Function? getOAuthToken, double? volume}); |
|
|
|
{String? name, JSFunction? getOAuthToken, double? volume}); |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify playback object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlaybackPlayer { |
|
|
|
extension type WebPlaybackPlayer._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs, non_constant_identifier_names |
|
|
|
external String get device_id; |
|
|
|
// ignore: public_member_api_docs, non_constant_identifier_names |
|
|
|
@ -894,9 +907,7 @@ class WebPlaybackPlayer { |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify playback state object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlaybackState { |
|
|
|
extension type WebPlaybackState._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external WebPlayerContext get context; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
@ -916,7 +927,7 @@ class WebPlaybackState { |
|
|
|
external factory WebPlaybackState( |
|
|
|
{WebPlayerContext? context, |
|
|
|
WebPlayerDisallows? disallows, |
|
|
|
bool? paysed, |
|
|
|
bool? paused, |
|
|
|
int? position, |
|
|
|
// ignore: non_constant_identifier_names |
|
|
|
int? repeat_mode, |
|
|
|
@ -926,9 +937,7 @@ class WebPlaybackState { |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify player context object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlayerContext { |
|
|
|
extension type WebPlayerContext._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external String get uri; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
@ -940,9 +949,7 @@ class WebPlayerContext { |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify player context metadata object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlayerContextMetadata { |
|
|
|
extension type WebPlayerContextMetadata._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external String get title; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
@ -956,9 +963,7 @@ class WebPlayerContextMetadata { |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify player disallows object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlayerDisallows { |
|
|
|
extension type WebPlayerDisallows._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external bool get pausing; |
|
|
|
// ignore: public_member_api_docs, non_constant_identifier_names |
|
|
|
@ -990,30 +995,26 @@ class WebPlayerDisallows { |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify player track window object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlayerTrackWindow { |
|
|
|
extension type WebPlayerTrackWindow._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs, non_constant_identifier_names |
|
|
|
external WebPlaybackTrack? get current_track; |
|
|
|
// ignore: public_member_api_docs, non_constant_identifier_names |
|
|
|
external List<WebPlaybackTrack>? get previous_tracks; |
|
|
|
external JSArray? get previous_tracks; |
|
|
|
// ignore: public_member_api_docs, non_constant_identifier_names |
|
|
|
external List<WebPlaybackTrack>? get next_tracks; |
|
|
|
external JSArray? get next_tracks; |
|
|
|
|
|
|
|
// ignore: public_member_api_docs |
|
|
|
external factory WebPlayerTrackWindow( |
|
|
|
// ignore: non_constant_identifier_names |
|
|
|
{WebPlaybackTrack? current_track, |
|
|
|
// ignore: non_constant_identifier_names |
|
|
|
List<WebPlaybackTrack>? previous_tracks, |
|
|
|
JSArray? previous_tracks, |
|
|
|
// ignore: non_constant_identifier_names |
|
|
|
List<WebPlaybackTrack>? next_tracks}); |
|
|
|
JSArray? next_tracks}); |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify playback track object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlaybackTrack { |
|
|
|
extension type WebPlaybackTrack._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external String get uri; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
@ -1029,7 +1030,7 @@ class WebPlaybackTrack { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external WebPlaybackAlbum get album; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external List<WebPlaybackArtist> get artists; |
|
|
|
external JSArray get artists; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
// ignore: non_constant_identifier_names |
|
|
|
external WebLinkedFrom get linked_from; |
|
|
|
@ -1045,31 +1046,27 @@ class WebPlaybackTrack { |
|
|
|
// ignore: non_constant_identifier_names |
|
|
|
bool? is_playable, |
|
|
|
WebPlaybackAlbum? album, |
|
|
|
List<WebPlaybackArtist>? artists, |
|
|
|
JSArray? artists, |
|
|
|
// ignore: non_constant_identifier_names |
|
|
|
WebLinkedFrom? linked_from}); |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify playback album object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlaybackAlbum { |
|
|
|
extension type WebPlaybackAlbum._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external String get uri; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external String get name; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external List<WebPlaybackAlbumImage> get images; |
|
|
|
external JSArray get images; |
|
|
|
|
|
|
|
// ignore: public_member_api_docs |
|
|
|
external factory WebPlaybackAlbum( |
|
|
|
{String? uri, String? name, List<WebPlaybackAlbumImage>? images}); |
|
|
|
{String? uri, String? name, JSArray? images}); |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify playback album object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebLinkedFrom { |
|
|
|
extension type WebLinkedFrom._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external String get uri; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
@ -1080,9 +1077,7 @@ class WebLinkedFrom { |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify artist object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlaybackArtist { |
|
|
|
extension type WebPlaybackArtist._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external String get uri; |
|
|
|
// ignore: public_member_api_docs |
|
|
|
@ -1093,9 +1088,7 @@ class WebPlaybackArtist { |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify album image object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlaybackAlbumImage { |
|
|
|
extension type WebPlaybackAlbumImage._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external String get url; |
|
|
|
|
|
|
|
@ -1104,9 +1097,7 @@ class WebPlaybackAlbumImage { |
|
|
|
} |
|
|
|
|
|
|
|
/// Spotify playback error object |
|
|
|
@JS() |
|
|
|
@anonymous |
|
|
|
class WebPlaybackError { |
|
|
|
extension type WebPlaybackError._(JSObject _) implements JSObject { |
|
|
|
// ignore: public_member_api_docs |
|
|
|
external String get message; |
|
|
|
|
|
|
|
|