spotifywebapiPython 1.0.151__py3-none-any.whl → 1.0.152__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of spotifywebapiPython might be problematic. Click here for more details.
- {spotifywebapiPython-1.0.151.dist-info → spotifywebapiPython-1.0.152.dist-info}/METADATA +1 -1
- {spotifywebapiPython-1.0.151.dist-info → spotifywebapiPython-1.0.152.dist-info}/RECORD +24 -24
- spotifywebapipython/const.py +1 -1
- spotifywebapipython/docs/__init__.html +8 -2
- spotifywebapipython/docs/index.html +2 -2
- spotifywebapipython/docs/search.js +1 -1
- spotifywebapipython/docs/spotifywebapipython/const.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/saappmessages.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/sautils.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyclient.html +337 -160
- spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html +2 -2
- spotifywebapipython/models/playerplaystate.py +42 -0
- spotifywebapipython/spotifyclient.py +773 -550
- spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py +37 -16
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfexceptions.py +10 -0
- {spotifywebapiPython-1.0.151.dist-info → spotifywebapiPython-1.0.152.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.151.dist-info → spotifywebapiPython-1.0.152.dist-info}/WHEEL +0 -0
- {spotifywebapiPython-1.0.151.dist-info → spotifywebapiPython-1.0.152.dist-info}/top_level.txt +0 -0
|
@@ -747,19 +747,28 @@ class SpotifyClient:
|
|
|
747
747
|
|
|
748
748
|
def _ResolveDeviceObject(
|
|
749
749
|
self,
|
|
750
|
-
device:str | SpotifyConnectDevice
|
|
750
|
+
device:str | SpotifyConnectDevice,
|
|
751
|
+
activateDevice:bool=True,
|
|
751
752
|
) -> SpotifyConnectDevice:
|
|
752
753
|
"""
|
|
753
754
|
Resolves a SpotifyConnectDevice object from a device identifier, name, or
|
|
754
|
-
SpotifyConnectDevice object argument value.
|
|
755
|
-
if the `device` argument could not be resolved
|
|
755
|
+
SpotifyConnectDevice object argument value. A null object will be returned
|
|
756
|
+
if the `device` argument could not be resolved.
|
|
756
757
|
|
|
757
758
|
Args:
|
|
758
|
-
device (str|SpotifyConnectDevice):
|
|
759
|
-
|
|
759
|
+
device (str | SpotifyConnectDevice) | None):
|
|
760
|
+
The target player device identifier.
|
|
761
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
762
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
763
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
764
|
+
for this argument.
|
|
765
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
766
|
+
activateDevice (bool):
|
|
767
|
+
True to activate the device if necessary; otherwise, False.
|
|
768
|
+
Default is True.
|
|
760
769
|
|
|
761
770
|
Returns:
|
|
762
|
-
A SpotifyConnectDevice object for the specified device.
|
|
771
|
+
A SpotifyConnectDevice object for the specified device if found; otherwise, null.
|
|
763
772
|
|
|
764
773
|
Raises:
|
|
765
774
|
SpotifyApiError:
|
|
@@ -780,13 +789,13 @@ class SpotifyClient:
|
|
|
780
789
|
|
|
781
790
|
else:
|
|
782
791
|
|
|
783
|
-
# no - ensure the specified device id / name is active and
|
|
784
|
-
# and return the SpotifyConnectDevice object.
|
|
785
|
-
#
|
|
792
|
+
# no - ensure the specified device id / name is active (optional) and
|
|
793
|
+
# available, and return the SpotifyConnectDevice object.
|
|
794
|
+
# a null object will be returned if the device id could not be found.
|
|
786
795
|
scDevice = self.GetSpotifyConnectDevice(
|
|
787
796
|
device,
|
|
788
797
|
refreshDeviceList=True,
|
|
789
|
-
activateDevice=
|
|
798
|
+
activateDevice=activateDevice)
|
|
790
799
|
|
|
791
800
|
return scDevice
|
|
792
801
|
|
|
@@ -1153,12 +1162,16 @@ class SpotifyClient:
|
|
|
1153
1162
|
Example: `spotify:track:6zd8T1PBe9JFHmuVnurdRp,spotify:track:1kWUud3vY5ij5r62zxpTRy`.
|
|
1154
1163
|
An unlimited number of items can be added in one request, but the more items the longer it
|
|
1155
1164
|
will take.
|
|
1156
|
-
deviceId (str):
|
|
1157
|
-
The
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1165
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
1166
|
+
The target player device identifier.
|
|
1167
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
1168
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
1169
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
1170
|
+
for this argument. An exception will be raised if the argument value could
|
|
1171
|
+
not be resolved or activated.
|
|
1172
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
1161
1173
|
verifyDeviceId (bool):
|
|
1174
|
+
DEPRECATED - deviceId is automatically verified as of v1.0.149.
|
|
1162
1175
|
True to verify a device id is active; otherwise, false to assume that a
|
|
1163
1176
|
device id is already active.
|
|
1164
1177
|
Default is True.
|
|
@@ -1180,7 +1193,7 @@ class SpotifyClient:
|
|
|
1180
1193
|
|
|
1181
1194
|
The Spotify Web API endpoint is called to add each item individually.
|
|
1182
1195
|
The Spotify Web API does not currently support adding more than 1 item to the queue at a time.
|
|
1183
|
-
|
|
1196
|
+
|
|
1184
1197
|
<details>
|
|
1185
1198
|
<summary>Sample Code</summary>
|
|
1186
1199
|
```python
|
|
@@ -1197,14 +1210,12 @@ class SpotifyClient:
|
|
|
1197
1210
|
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
1198
1211
|
apiMethodParms.AppendKeyValue("uris", uris)
|
|
1199
1212
|
apiMethodParms.AppendKeyValue("deviceId", deviceId)
|
|
1200
|
-
apiMethodParms.AppendKeyValue("verifyDeviceId", verifyDeviceId)
|
|
1213
|
+
apiMethodParms.AppendKeyValue("verifyDeviceId (DEPRECATED)", verifyDeviceId)
|
|
1201
1214
|
apiMethodParms.AppendKeyValue("delay", delay)
|
|
1202
1215
|
_logsi.LogMethodParmList(SILevel.Verbose, "Add items to playback queue", apiMethodParms)
|
|
1203
1216
|
|
|
1204
1217
|
# validations.
|
|
1205
1218
|
delay = validateDelay(delay, 0.15, 10)
|
|
1206
|
-
if (verifyDeviceId is None):
|
|
1207
|
-
verifyDeviceId = True
|
|
1208
1219
|
|
|
1209
1220
|
# build a list of all item uri's.
|
|
1210
1221
|
# remove any leading / trailing spaces in case user put a space between the items.
|
|
@@ -1217,7 +1228,7 @@ class SpotifyClient:
|
|
|
1217
1228
|
arrUris[idx] = arrUris[idx].strip()
|
|
1218
1229
|
|
|
1219
1230
|
# resolve / activate the device object if needed.
|
|
1220
|
-
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId)
|
|
1231
|
+
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
1221
1232
|
|
|
1222
1233
|
# process all uri's.
|
|
1223
1234
|
for idx in range(0, len(arrUris)):
|
|
@@ -1227,7 +1238,8 @@ class SpotifyClient:
|
|
|
1227
1238
|
{
|
|
1228
1239
|
'uri': arrUris[idx]
|
|
1229
1240
|
}
|
|
1230
|
-
|
|
1241
|
+
if (scDevice is not None):
|
|
1242
|
+
urlParms['device_id'] = scDevice.Id
|
|
1231
1243
|
|
|
1232
1244
|
# execute spotify web api request.
|
|
1233
1245
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/queue')
|
|
@@ -1980,7 +1992,7 @@ class SpotifyClient:
|
|
|
1980
1992
|
A comma-separated list of Spotify User ID's to check.
|
|
1981
1993
|
Maximum: 5 ID's.
|
|
1982
1994
|
Example: `1kWUud3vY5ij5r62zxpTRy,2takcwOaAZWiXQijPHIx7B`
|
|
1983
|
-
|
|
1995
|
+
DEPRECATED - A single item list containing current user's Spotify Username; Maximum of 1 id.
|
|
1984
1996
|
|
|
1985
1997
|
Returns:
|
|
1986
1998
|
Array of boolean, containing a single boolean status that indicates
|
|
@@ -2014,7 +2026,7 @@ class SpotifyClient:
|
|
|
2014
2026
|
# trace.
|
|
2015
2027
|
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
2016
2028
|
apiMethodParms.AppendKeyValue("playlistId", playlistId)
|
|
2017
|
-
apiMethodParms.AppendKeyValue("userIds", userIds)
|
|
2029
|
+
apiMethodParms.AppendKeyValue("userIds (DEPRECATED)", userIds)
|
|
2018
2030
|
_logsi.LogMethodParmList(SILevel.Verbose, "Check to see if users are following a playlist", apiMethodParms)
|
|
2019
2031
|
|
|
2020
2032
|
# validations.
|
|
@@ -5471,7 +5483,8 @@ class SpotifyClient:
|
|
|
5471
5483
|
Example: `sv_SE`
|
|
5472
5484
|
refresh (bool):
|
|
5473
5485
|
True to return real-time information from the spotify web api and
|
|
5474
|
-
update the cache; otherwise, False to just return the cached value.
|
|
5486
|
+
update the cache; otherwise, False to just return the cached value.
|
|
5487
|
+
Default is True.
|
|
5475
5488
|
|
|
5476
5489
|
Returns:
|
|
5477
5490
|
A `list[Category]` object that contains the list category details.
|
|
@@ -6089,6 +6102,94 @@ class SpotifyClient:
|
|
|
6089
6102
|
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
6090
6103
|
|
|
6091
6104
|
|
|
6105
|
+
def GetDevicePlaybackState(
|
|
6106
|
+
self,
|
|
6107
|
+
deviceId:str|SpotifyConnectDevice|None=None,
|
|
6108
|
+
) -> PlayerPlayState:
|
|
6109
|
+
"""
|
|
6110
|
+
Get information about the current playback state of the device, including track or episode,
|
|
6111
|
+
and progress. For Sonos devices, this will return the playstate of the device instead of the
|
|
6112
|
+
active Spotify Web API player playstate.
|
|
6113
|
+
|
|
6114
|
+
This method requires the `user-read-playback-state` scope.
|
|
6115
|
+
|
|
6116
|
+
This is not part of the Spotify Web API specification.
|
|
6117
|
+
|
|
6118
|
+
Args:
|
|
6119
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
6120
|
+
The target player device identifier.
|
|
6121
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
6122
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
6123
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
6124
|
+
for this argument. An exception will be raised if the argument value could
|
|
6125
|
+
not be resolved.
|
|
6126
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
6127
|
+
|
|
6128
|
+
Returns:
|
|
6129
|
+
A `PlayerPlayState` object that contains player state details as well as
|
|
6130
|
+
currently playing content.
|
|
6131
|
+
|
|
6132
|
+
Raises:
|
|
6133
|
+
SpotifyWebApiError:
|
|
6134
|
+
If the Spotify Web API request was for a non-authorization service
|
|
6135
|
+
and the response contains error information.
|
|
6136
|
+
SpotifyApiError:
|
|
6137
|
+
If the method fails for any other reason.
|
|
6138
|
+
|
|
6139
|
+
<details>
|
|
6140
|
+
<summary>Sample Code</summary>
|
|
6141
|
+
```python
|
|
6142
|
+
.. include:: ../docs/include/samplecode/SpotifyClient/GetDevicePlaybackState.py
|
|
6143
|
+
```
|
|
6144
|
+
</details>
|
|
6145
|
+
"""
|
|
6146
|
+
apiMethodName:str = 'GetDevicePlaybackState'
|
|
6147
|
+
apiMethodParms:SIMethodParmListContext = None
|
|
6148
|
+
result:PlayerPlayState = None
|
|
6149
|
+
|
|
6150
|
+
try:
|
|
6151
|
+
|
|
6152
|
+
# trace.
|
|
6153
|
+
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
6154
|
+
apiMethodParms.AppendKeyValue("deviceId", deviceId)
|
|
6155
|
+
_logsi.LogMethodParmList(SILevel.Verbose, "Get the current playback state of the device", apiMethodParms)
|
|
6156
|
+
|
|
6157
|
+
# resolve the device object; no need to activate it for what we want here.
|
|
6158
|
+
# this will also set the currently active device in the devices cache, as well as
|
|
6159
|
+
# add the playstate to the configuration cache.
|
|
6160
|
+
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, activateDevice=False)
|
|
6161
|
+
|
|
6162
|
+
# get cached Spotify Web API playerstate (_ResolveDeviceObject method just refreshed it).
|
|
6163
|
+
result = self.GetPlayerPlaybackState(refresh=False)
|
|
6164
|
+
|
|
6165
|
+
# is this a Sonos device?
|
|
6166
|
+
if (scDevice is not None) and (scDevice.IsSonos):
|
|
6167
|
+
|
|
6168
|
+
# get Sonos playback state via Sonos Controller instance.
|
|
6169
|
+
playerStateSonos:PlayerPlayState = self.GetPlayerPlaybackStateSonos(scDevice)
|
|
6170
|
+
|
|
6171
|
+
# return the device playstate.
|
|
6172
|
+
_logsi.LogVerbose("Sonos device %s playstate will be returned" % (scDevice.Title))
|
|
6173
|
+
result = playerStateSonos
|
|
6174
|
+
|
|
6175
|
+
# trace.
|
|
6176
|
+
_logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
|
|
6177
|
+
return result
|
|
6178
|
+
|
|
6179
|
+
except SpotifyApiError: raise # pass handled exceptions on thru
|
|
6180
|
+
except SpotifyWebApiError: raise # pass handled exceptions on thru
|
|
6181
|
+
except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
|
|
6182
|
+
except Exception as ex:
|
|
6183
|
+
|
|
6184
|
+
# format unhandled exception.
|
|
6185
|
+
raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
|
|
6186
|
+
|
|
6187
|
+
finally:
|
|
6188
|
+
|
|
6189
|
+
# trace.
|
|
6190
|
+
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
6191
|
+
|
|
6192
|
+
|
|
6092
6193
|
def GetEpisode(
|
|
6093
6194
|
self,
|
|
6094
6195
|
episodeId:str=None,
|
|
@@ -7491,7 +7592,8 @@ class SpotifyClient:
|
|
|
7491
7592
|
def GetPlayerPlaybackState(
|
|
7492
7593
|
self,
|
|
7493
7594
|
market:str=None,
|
|
7494
|
-
additionalTypes:str=None
|
|
7595
|
+
additionalTypes:str=None,
|
|
7596
|
+
refresh:bool=True,
|
|
7495
7597
|
) -> PlayerPlayState:
|
|
7496
7598
|
"""
|
|
7497
7599
|
Get information about the user's current playback state, including track or episode, progress,
|
|
@@ -7515,6 +7617,10 @@ class SpotifyClient:
|
|
|
7515
7617
|
Note: This parameter was introduced to allow existing clients to maintain their current behaviour
|
|
7516
7618
|
and might be deprecated in the future. In addition to providing this parameter, make sure that your client
|
|
7517
7619
|
properly handles cases of new types in the future by checking against the type field of each object.
|
|
7620
|
+
refresh (bool):
|
|
7621
|
+
True to return real-time information from the Spotify Web API and
|
|
7622
|
+
update the cache; otherwise, False to just return the cached value.
|
|
7623
|
+
Default is True.
|
|
7518
7624
|
|
|
7519
7625
|
Returns:
|
|
7520
7626
|
A `PlayerPlayState` object that contains player state details as well as
|
|
@@ -7543,8 +7649,25 @@ class SpotifyClient:
|
|
|
7543
7649
|
# trace.
|
|
7544
7650
|
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
7545
7651
|
apiMethodParms.AppendKeyValue("market", market)
|
|
7652
|
+
apiMethodParms.AppendKeyValue("additionalTypes", additionalTypes)
|
|
7653
|
+
apiMethodParms.AppendKeyValue("refresh", refresh)
|
|
7546
7654
|
_logsi.LogMethodParmList(SILevel.Verbose, "Get the user's current playback state", apiMethodParms)
|
|
7547
|
-
|
|
7655
|
+
|
|
7656
|
+
# validations.
|
|
7657
|
+
if (refresh is None):
|
|
7658
|
+
refresh = True
|
|
7659
|
+
|
|
7660
|
+
# are we getting the cached value? if so, then just return it.
|
|
7661
|
+
if (not refresh):
|
|
7662
|
+
|
|
7663
|
+
result = self._ConfigurationCache.get(apiMethodName, None)
|
|
7664
|
+
if (result is None):
|
|
7665
|
+
result = PlayerPlayState()
|
|
7666
|
+
|
|
7667
|
+
# trace.
|
|
7668
|
+
_logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName + " (cached)", type(result).__name__), result, excludeNonPublic=True)
|
|
7669
|
+
return result
|
|
7670
|
+
|
|
7548
7671
|
# ensure market was either supplied or implied; default if neither.
|
|
7549
7672
|
market = self._ValidateMarket(market)
|
|
7550
7673
|
|
|
@@ -7563,9 +7686,12 @@ class SpotifyClient:
|
|
|
7563
7686
|
|
|
7564
7687
|
# process results.
|
|
7565
7688
|
result = PlayerPlayState(root=msg.ResponseData)
|
|
7566
|
-
|
|
7689
|
+
|
|
7690
|
+
# update cache with result.
|
|
7691
|
+
self._ConfigurationCache[apiMethodName] = result
|
|
7692
|
+
|
|
7567
7693
|
# is this an episode? if so, then determine the item type (e.g. podcast or audiobook).
|
|
7568
|
-
if (
|
|
7694
|
+
if (not result.IsEmpty):
|
|
7569
7695
|
if (result.Item is not None):
|
|
7570
7696
|
result.ItemType = SpotifyClient.GetTypeFromUri(result.Item.Uri)
|
|
7571
7697
|
if (result.CurrentlyPlayingType == 'episode'):
|
|
@@ -7577,7 +7703,7 @@ class SpotifyClient:
|
|
|
7577
7703
|
|
|
7578
7704
|
# check for a restricted device; if found, then grab the device id from the
|
|
7579
7705
|
# cached list of spotify connect devices (if present).
|
|
7580
|
-
if
|
|
7706
|
+
if (not result.IsEmpty):
|
|
7581
7707
|
device:Device = result.Device
|
|
7582
7708
|
if (device is not None) and (device.Id is None or device.Id == ''):
|
|
7583
7709
|
cacheKey:str = 'GetSpotifyConnectDevices'
|
|
@@ -7589,7 +7715,7 @@ class SpotifyClient:
|
|
|
7589
7715
|
|
|
7590
7716
|
# update Spotify Connect Directory with active device details.
|
|
7591
7717
|
# IMPORTANT - make sure result contains an object, otherwise it's an endless loop!
|
|
7592
|
-
if result is not None:
|
|
7718
|
+
if (result is not None):
|
|
7593
7719
|
self.SpotifyConnectDirectory.UpdateActiveDevice(result)
|
|
7594
7720
|
|
|
7595
7721
|
# trace.
|
|
@@ -7610,173 +7736,389 @@ class SpotifyClient:
|
|
|
7610
7736
|
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
7611
7737
|
|
|
7612
7738
|
|
|
7613
|
-
def
|
|
7614
|
-
"""
|
|
7615
|
-
Get the list of objects that make up the user's playback queue.
|
|
7616
|
-
|
|
7617
|
-
This method requires the `user-read-currently-playing` and `user-read-playback-state` scope.
|
|
7618
|
-
|
|
7619
|
-
Returns:
|
|
7620
|
-
A `PlayerQueueInfo` object that contains the player queue information.
|
|
7621
|
-
|
|
7622
|
-
Raises:
|
|
7623
|
-
SpotifyWebApiError:
|
|
7624
|
-
If the Spotify Web API request was for a non-authorization service
|
|
7625
|
-
and the response contains error information.
|
|
7626
|
-
SpotifyApiError:
|
|
7627
|
-
If the method fails for any other reason.
|
|
7628
|
-
|
|
7629
|
-
<details>
|
|
7630
|
-
<summary>Sample Code</summary>
|
|
7631
|
-
```python
|
|
7632
|
-
.. include:: ../docs/include/samplecode/SpotifyClient/GetPlayerQueueInfo.py
|
|
7633
|
-
```
|
|
7634
|
-
</details>
|
|
7635
|
-
"""
|
|
7636
|
-
apiMethodName:str = 'GetPlayerQueueInfo'
|
|
7637
|
-
result:PlayHistoryPage = None
|
|
7638
|
-
|
|
7639
|
-
try:
|
|
7640
|
-
|
|
7641
|
-
# trace.
|
|
7642
|
-
_logsi.EnterMethod(SILevel.Debug, apiMethodName)
|
|
7643
|
-
_logsi.LogVerbose("Get the list of objects that make up the user's playback queue")
|
|
7644
|
-
|
|
7645
|
-
# execute spotify web api request.
|
|
7646
|
-
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/queue')
|
|
7647
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
7648
|
-
self.MakeRequest('GET', msg)
|
|
7649
|
-
|
|
7650
|
-
# process results.
|
|
7651
|
-
result = PlayerQueueInfo(root=msg.ResponseData)
|
|
7652
|
-
result.DateLastRefreshed = datetime.utcnow().timestamp()
|
|
7653
|
-
|
|
7654
|
-
# trace.
|
|
7655
|
-
_logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
|
|
7656
|
-
return result
|
|
7657
|
-
|
|
7658
|
-
except SpotifyApiError: raise # pass handled exceptions on thru
|
|
7659
|
-
except SpotifyWebApiError: raise # pass handled exceptions on thru
|
|
7660
|
-
except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
|
|
7661
|
-
except Exception as ex:
|
|
7662
|
-
|
|
7663
|
-
# format unhandled exception.
|
|
7664
|
-
raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
|
|
7665
|
-
|
|
7666
|
-
finally:
|
|
7667
|
-
|
|
7668
|
-
# trace.
|
|
7669
|
-
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
def GetPlayerRecentTracks(
|
|
7739
|
+
def GetPlayerPlaybackStateSonos(
|
|
7673
7740
|
self,
|
|
7674
|
-
|
|
7675
|
-
|
|
7676
|
-
before:int=None,
|
|
7677
|
-
limitTotal:int=None
|
|
7678
|
-
) -> PlayHistoryPage:
|
|
7741
|
+
scDevice:SpotifyConnectDevice,
|
|
7742
|
+
) -> PlayerPlayState:
|
|
7679
7743
|
"""
|
|
7680
|
-
Get
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
This method requires the `user-read-recently-played` scope.
|
|
7744
|
+
Get information about the Sonos user's current playback state, including track or episode, progress,
|
|
7745
|
+
and active device.
|
|
7684
7746
|
|
|
7747
|
+
This is not part of the Spotify Web API specification; it is for Sonos devices only!
|
|
7748
|
+
|
|
7685
7749
|
Args:
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
Default: 20, Range: 1 to 50.
|
|
7689
|
-
See the `limitTotal` argument for automatic paging option.
|
|
7690
|
-
after (int):
|
|
7691
|
-
Returns all items after (but not including) this cursor position, which is
|
|
7692
|
-
a Unix timestamp in milliseconds.
|
|
7693
|
-
If `after` is specified, `before` must not be specified.
|
|
7694
|
-
Use with limit to get the next set of items.
|
|
7695
|
-
Default: `0` (the first item).
|
|
7696
|
-
before (int):
|
|
7697
|
-
Returns all items before (but not including) this cursor position, which is
|
|
7698
|
-
a Unix timestamp in milliseconds.
|
|
7699
|
-
If `before` is specified, `after` must not be specified.
|
|
7700
|
-
Use with limit to get the next set of items.
|
|
7701
|
-
Default: `0` (the first item).
|
|
7702
|
-
limitTotal (int):
|
|
7703
|
-
The maximum number of items to return for the request.
|
|
7704
|
-
If specified, this argument overrides the limit and offset argument values
|
|
7705
|
-
and paging is automatically used to retrieve all available items up to the
|
|
7706
|
-
maximum number specified.
|
|
7707
|
-
Default: None (disabled)
|
|
7708
|
-
|
|
7709
|
-
Spotify currently limits the maximum number of items returned to 50 no matter what you
|
|
7710
|
-
supply for the `limitTotal` argument.
|
|
7711
|
-
|
|
7712
|
-
The `after` and `before` arguments are based upon local time (not UTC time). Recently
|
|
7713
|
-
played item history uses a local timestamp, and NOT a UTC timestamp.
|
|
7714
|
-
|
|
7715
|
-
If both `after` and `before` arguments are null (or zero), then a `before` value
|
|
7716
|
-
is generated that will retrieve the last 50 recently played tracks.
|
|
7750
|
+
scDevice (SpotifyConnectDevice):
|
|
7751
|
+
Spotify Connect device instance used to identify the Sonos player.
|
|
7717
7752
|
|
|
7718
7753
|
Returns:
|
|
7719
|
-
A `
|
|
7754
|
+
A `PlayerPlayState` object that contains Sonos player state details as well as
|
|
7755
|
+
currently playing content.
|
|
7720
7756
|
|
|
7721
7757
|
Raises:
|
|
7722
|
-
SpotifyWebApiError:
|
|
7723
|
-
If the Spotify Web API request was for a non-authorization service
|
|
7724
|
-
and the response contains error information.
|
|
7725
7758
|
SpotifyApiError:
|
|
7726
7759
|
If the method fails for any other reason.
|
|
7727
|
-
|
|
7728
|
-
<details>
|
|
7729
|
-
<summary>Sample Code - After DateTime</summary>
|
|
7730
|
-
```python
|
|
7731
|
-
.. include:: ../docs/include/samplecode/SpotifyClient/GetPlayerRecentTracks_AfterDateTime.py
|
|
7732
|
-
```
|
|
7733
|
-
</details>
|
|
7734
|
-
<details>
|
|
7735
|
-
<summary>Sample Code - For Past 1 Hour</summary>
|
|
7736
|
-
```python
|
|
7737
|
-
.. include:: ../docs/include/samplecode/SpotifyClient/GetPlayerRecentTracks_Past01Hours.py
|
|
7738
|
-
```
|
|
7739
|
-
</details>
|
|
7740
7760
|
"""
|
|
7741
|
-
apiMethodName:str = '
|
|
7761
|
+
apiMethodName:str = 'GetPlayerPlaybackStateSonos'
|
|
7742
7762
|
apiMethodParms:SIMethodParmListContext = None
|
|
7743
|
-
result:PlayHistoryPage = None
|
|
7744
7763
|
|
|
7745
7764
|
try:
|
|
7746
7765
|
|
|
7747
7766
|
# trace.
|
|
7748
7767
|
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
7749
|
-
apiMethodParms.AppendKeyValue("
|
|
7750
|
-
|
|
7751
|
-
apiMethodParms.AppendKeyValue("before", before)
|
|
7752
|
-
apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
|
|
7753
|
-
_logsi.LogMethodParmList(SILevel.Verbose, "Get tracks from the current user's recently played tracks", apiMethodParms)
|
|
7768
|
+
apiMethodParms.AppendKeyValue("scDevice", scDevice)
|
|
7769
|
+
_logsi.LogMethodParmList(SILevel.Verbose, "Get Sonos device current playback state", apiMethodParms)
|
|
7754
7770
|
|
|
7755
|
-
#
|
|
7756
|
-
|
|
7757
|
-
before = 0
|
|
7758
|
-
if (not isinstance(before,int)):
|
|
7759
|
-
before = int(before)
|
|
7771
|
+
# create playstate object.
|
|
7772
|
+
playerState = PlayerPlayState()
|
|
7760
7773
|
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
after = int(after)
|
|
7774
|
+
# get Sonos Controller instance for the device.
|
|
7775
|
+
_logsi.LogVerbose("Getting Sonos device status via Sonos Controller instance for device: %s" % (scDevice.Title))
|
|
7776
|
+
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
7765
7777
|
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7778
|
+
# build a spotify playback status instance with equivalent Sonos state values.
|
|
7779
|
+
sonosTrackInfo:dict = sonosPlayer.get_current_track_info()
|
|
7780
|
+
_logsi.LogDictionary(SILevel.Verbose, "Sonos device current_track_info results for device: %s" % (scDevice.Title), sonosTrackInfo, prettyPrint=True)
|
|
7781
|
+
sonosTransportInfo:dict = sonosPlayer.get_current_transport_info()
|
|
7782
|
+
_logsi.LogDictionary(SILevel.Verbose, "Sonos device get_current_transport_info results for device: %s" % (scDevice.Title), sonosTransportInfo, prettyPrint=True)
|
|
7770
7783
|
|
|
7771
|
-
#
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7784
|
+
# indicate this is a device-specific playstate.
|
|
7785
|
+
playerState.IsDeviceState = True
|
|
7786
|
+
playerState.DeviceMusicSource = "" + str(sonosPlayer.music_source)
|
|
7787
|
+
|
|
7788
|
+
# update Spotify Web API player state with Sonos player state.
|
|
7789
|
+
playerState._Device._Id = scDevice.Id
|
|
7790
|
+
playerState._Device._Name = sonosPlayer.player_name
|
|
7791
|
+
playerState._Device._VolumePercent = sonosPlayer.volume
|
|
7792
|
+
playerState._Device._IsActive = True
|
|
7793
|
+
playerState._Device._IsRestricted = True
|
|
7794
|
+
playerState._Device._SupportsVolume = True
|
|
7795
|
+
playerState._Device._Type = 'SPEAKER'
|
|
7796
|
+
|
|
7797
|
+
# try to get the spotify uri from the "metadata" music library DIDL value, as
|
|
7798
|
+
# the "uri" value (e.g. "x-sonos-vli:RINCON_38420B909DC801400:2,spotify:e934941535d7b182815bf688490ce8a8")
|
|
7799
|
+
# is not a true spotify uri value (e.g. "spotify:track:6kYyS9g4WJeRzTYqsmcMmM")
|
|
7800
|
+
spotifyUri:str = sonosTrackInfo.get('uri','')
|
|
7801
|
+
didl:str = sonosTrackInfo.get('metadata',None)
|
|
7802
|
+
if (didl):
|
|
7803
|
+
METADATA_ID:str = 'x-sonos-spotify:'
|
|
7804
|
+
idx:int = didl.find(METADATA_ID)
|
|
7805
|
+
if (idx > -1):
|
|
7806
|
+
spotifyUri:str = didl[idx + len(METADATA_ID):]
|
|
7807
|
+
spotifyUri = urllib.parse.unquote(spotifyUri)
|
|
7808
|
+
idx = spotifyUri.find('?')
|
|
7809
|
+
if (idx > -1):
|
|
7810
|
+
spotifyUri = spotifyUri[:idx]
|
|
7811
|
+
spotifyType = self.GetTypeFromUri(spotifyUri) or ''
|
|
7812
|
+
spotifyId = self.GetIdFromUri(spotifyUri) or ''
|
|
7813
|
+
|
|
7814
|
+
# set base item properties.
|
|
7815
|
+
playerState.IsEmpty = False
|
|
7816
|
+
playerState.ItemType = spotifyType
|
|
7817
|
+
sTimeValue:str = sonosTrackInfo.get('position',None)
|
|
7818
|
+
playerState._ProgressMS = mediaPositionHMS_toSeconds(sTimeValue) * 1000 # convert h:mm:ss to milliseconds
|
|
7819
|
+
|
|
7820
|
+
# set some item properties based on the playing type (episode or non-episode).
|
|
7821
|
+
if (spotifyType == 'episode'):
|
|
7822
|
+
|
|
7823
|
+
# get the episode data from spotify, as Sonos Soco data is incomplete.
|
|
7824
|
+
playerState._CurrentlyPlayingType = 'episode'
|
|
7825
|
+
episode:Episode = self.GetEpisode(spotifyId)
|
|
7826
|
+
if (episode.Id is not None):
|
|
7827
|
+
playerState._Item = episode
|
|
7828
|
+
if (playerState._Context is None):
|
|
7829
|
+
playerState._Context = Context()
|
|
7830
|
+
playerState._Context._Type = episode.Show.Type
|
|
7831
|
+
playerState._Context._Uri = episode.Show.Uri
|
|
7832
|
+
playerState._Context._Href = episode.Show.Href
|
|
7833
|
+
playerState._Context._ExternalUrls = episode.Show.ExternalUrls
|
|
7834
|
+
else:
|
|
7835
|
+
# if data could not be obtained from spotify, then use what's
|
|
7836
|
+
# available from Sonos Soco api metadata.
|
|
7837
|
+
playerState._Item = Episode()
|
|
7838
|
+
playerState._Item._Name = sonosTrackInfo.get('title','')
|
|
7839
|
+
playerState._Item._Uri = spotifyUri
|
|
7840
|
+
playerState._Item._Description = 'Sonos device does not provide a description'
|
|
7841
|
+
sTimeValue:str = sonosTrackInfo.get('duration',None)
|
|
7842
|
+
playerState._Item._DurationMS = mediaPositionHMS_toSeconds(sTimeValue) * 1000 # convert h:mm:ss to milliseconds
|
|
7843
|
+
playerState._Item._Explicit = False
|
|
7844
|
+
playerState._Item._Href = 'https://api.spotify.com/v1/episodes/' + spotifyId
|
|
7845
|
+
playerState._Item._HtmlDescription = playerState._Item._Description
|
|
7846
|
+
playerState._Item._Id = spotifyId
|
|
7847
|
+
playerState._Item.Images.append(ImageObject())
|
|
7848
|
+
playerState._Item.Images[0]._Url = sonosTrackInfo.get('album_art','')
|
|
7849
|
+
playerState._Item._TrackNumber = sonosTrackInfo.get('playlist_position','')
|
|
7850
|
+
playerState._Item._ReleaseDate = '0000'
|
|
7851
|
+
playerState._Item._ReleaseDatePrecision = 'year'
|
|
7852
|
+
playerState._Item._Type = 'episode'
|
|
7853
|
+
playerState._Item._Show = Show()
|
|
7854
|
+
playerState._Item._Show._Name = sonosTrackInfo.get('album','') # TODO get this from metadata (<r:podcast>The Elfstones of Shannara</r:podcast>)
|
|
7855
|
+
playerState._Item._Show.Images.append(ImageObject())
|
|
7856
|
+
playerState._Item._Show.Images[0]._Url = sonosTrackInfo.get('album_art','')
|
|
7857
|
+
playerState._Item._Show._Publisher = sonosTrackInfo.get('artist','')
|
|
7858
|
+
|
|
7859
|
+
# if show name not set then get it from metadata.
|
|
7860
|
+
if (playerState._Item._Show._Name == ''):
|
|
7861
|
+
if (didl):
|
|
7862
|
+
METADATA_ID:str = '<r:podcast>'
|
|
7863
|
+
METADATA_END:str = '</r:podcast>'
|
|
7864
|
+
idx:int = didl.find(METADATA_ID)
|
|
7865
|
+
if (idx > -1):
|
|
7866
|
+
metaValue:str = didl[idx + len(METADATA_ID):]
|
|
7867
|
+
idx = metaValue.find(METADATA_END)
|
|
7868
|
+
if (idx > -1):
|
|
7869
|
+
metaValue = metaValue[:idx]
|
|
7870
|
+
playerState._Item._Show._Name = metaValue
|
|
7871
|
+
|
|
7872
|
+
# if episode is playing then resolve the underlying type (audiobook / podcast show).
|
|
7873
|
+
if (self.IsChapterEpisode(spotifyId)):
|
|
7874
|
+
playerState.ItemType = 'audiobook'
|
|
7875
|
+
else:
|
|
7876
|
+
playerState.ItemType = 'podcast'
|
|
7877
|
+
|
|
7878
|
+
elif (spotifyType == 'track'):
|
|
7879
|
+
|
|
7880
|
+
# get the track data from spotify, as Sonos Soco data is incomplete.
|
|
7881
|
+
track:Track = self.GetTrack(spotifyId)
|
|
7882
|
+
if (track.Id is not None):
|
|
7883
|
+
playerState._Item = track
|
|
7884
|
+
if (playerState._Context is None):
|
|
7885
|
+
playerState._Context = Context()
|
|
7886
|
+
playerState._Context._Type = track.Album.Type
|
|
7887
|
+
playerState._Context._Uri = track.Album.Uri
|
|
7888
|
+
playerState._Context._Href = track.Album.Href
|
|
7889
|
+
playerState._Context._ExternalUrls = track.Album.ExternalUrls
|
|
7890
|
+
else:
|
|
7891
|
+
# if data could not be obtained from spotify, then use what's
|
|
7892
|
+
# available from Sonos Soco api metadata.
|
|
7893
|
+
playerState._CurrentlyPlayingType = 'track'
|
|
7894
|
+
playerState.ItemType = playerState._CurrentlyPlayingType
|
|
7895
|
+
playerState._Item = Track()
|
|
7896
|
+
playerState._Item._Name = sonosTrackInfo.get('title','')
|
|
7897
|
+
playerState._Item._Uri = spotifyUri
|
|
7898
|
+
playerState._Item._Description = 'Sonos device does not provide a description'
|
|
7899
|
+
sTimeValue:str = sonosTrackInfo.get('duration',None)
|
|
7900
|
+
playerState._Item._DurationMS = mediaPositionHMS_toSeconds(sTimeValue) * 1000 # convert h:mm:ss to milliseconds
|
|
7901
|
+
playerState._Item._Explicit = False
|
|
7902
|
+
playerState._Item._Href = 'https://api.spotify.com/v1/episodes/' + spotifyId
|
|
7903
|
+
playerState._Item._HtmlDescription = playerState._Item._Description
|
|
7904
|
+
playerState._Item._Id = spotifyId
|
|
7905
|
+
playerState._Item._TrackNumber = sonosTrackInfo.get('playlist_position','')
|
|
7906
|
+
playerState._Item._ReleaseDate = '0000'
|
|
7907
|
+
playerState._Item._ReleaseDatePrecision = 'year'
|
|
7908
|
+
playerState._Item._Type = 'track'
|
|
7909
|
+
playerState._Item._Album = Album()
|
|
7910
|
+
playerState._Item._Album._Name = sonosTrackInfo.get('album','')
|
|
7911
|
+
playerState._Item._Album.Images.append(ImageObject())
|
|
7912
|
+
playerState._Item._Album.Images[0]._Url = sonosTrackInfo.get('album_art','')
|
|
7913
|
+
playerState._Item.Artists.append(Artist())
|
|
7914
|
+
playerState._Item.Artists[0]._Name = sonosTrackInfo.get('artist','')
|
|
7915
|
+
|
|
7916
|
+
# set transport actions.
|
|
7917
|
+
currentTransportState:str = sonosTransportInfo.get('current_transport_state','')
|
|
7918
|
+
if currentTransportState == 'PLAYING':
|
|
7919
|
+
playerState._IsPlaying = True
|
|
7920
|
+
elif currentTransportState in ['PAUSED_PLAYBACK','STOPPED']:
|
|
7921
|
+
playerState.Actions._Pausing = True
|
|
7922
|
+
|
|
7923
|
+
# only update the following PlayState attributes from SoCo if they are NOT set.
|
|
7924
|
+
# these values are used to set the Sonos PlayMode value, which is the actual value that determines
|
|
7925
|
+
# what the Repeat and Shuffle settings are (ya, it's weird!). What is odd is that the Spotify
|
|
7926
|
+
# Web API PlayerState values for Shuffle and Repeat can be different than what the Sonos Controller
|
|
7927
|
+
# API (SoCo) report for the device! This is why we use the Spotify Web API PlayerState values.
|
|
7928
|
+
if playerState._ShuffleState is None:
|
|
7929
|
+
playerState._ShuffleState = sonosPlayer.shuffle
|
|
7930
|
+
if playerState._RepeatState is None:
|
|
7931
|
+
sonosRepeat = sonosPlayer.repeat
|
|
7932
|
+
if sonosRepeat == 'ONE':
|
|
7933
|
+
playerState._RepeatState = 'track'
|
|
7934
|
+
elif sonosRepeat == False:
|
|
7935
|
+
playerState._RepeatState = 'off'
|
|
7936
|
+
elif sonosRepeat == True:
|
|
7937
|
+
playerState._RepeatState = 'context'
|
|
7938
|
+
|
|
7939
|
+
# trace.
|
|
7940
|
+
_logsi.LogObject(SILevel.Verbose, "Current Spotify player PlayState (built from Sonos device current state) for device: %s" % (scDevice.Title), playerState, excludeNonPublic=True)
|
|
7941
|
+
return playerState
|
|
7942
|
+
|
|
7943
|
+
except SpotifyApiError: raise # pass handled exceptions on thru
|
|
7944
|
+
except Exception as ex:
|
|
7945
|
+
|
|
7946
|
+
# format unhandled exception.
|
|
7947
|
+
raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
|
|
7948
|
+
|
|
7949
|
+
finally:
|
|
7950
|
+
|
|
7951
|
+
# trace.
|
|
7952
|
+
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
7953
|
+
|
|
7954
|
+
|
|
7955
|
+
def GetPlayerQueueInfo(self) -> PlayerQueueInfo:
|
|
7956
|
+
"""
|
|
7957
|
+
Get the list of objects that make up the user's playback queue.
|
|
7958
|
+
|
|
7959
|
+
This method requires the `user-read-currently-playing` and `user-read-playback-state` scope.
|
|
7960
|
+
|
|
7961
|
+
Returns:
|
|
7962
|
+
A `PlayerQueueInfo` object that contains the player queue information.
|
|
7963
|
+
|
|
7964
|
+
Raises:
|
|
7965
|
+
SpotifyWebApiError:
|
|
7966
|
+
If the Spotify Web API request was for a non-authorization service
|
|
7967
|
+
and the response contains error information.
|
|
7968
|
+
SpotifyApiError:
|
|
7969
|
+
If the method fails for any other reason.
|
|
7970
|
+
|
|
7971
|
+
<details>
|
|
7972
|
+
<summary>Sample Code</summary>
|
|
7973
|
+
```python
|
|
7974
|
+
.. include:: ../docs/include/samplecode/SpotifyClient/GetPlayerQueueInfo.py
|
|
7975
|
+
```
|
|
7976
|
+
</details>
|
|
7977
|
+
"""
|
|
7978
|
+
apiMethodName:str = 'GetPlayerQueueInfo'
|
|
7979
|
+
result:PlayHistoryPage = None
|
|
7980
|
+
|
|
7981
|
+
try:
|
|
7982
|
+
|
|
7983
|
+
# trace.
|
|
7984
|
+
_logsi.EnterMethod(SILevel.Debug, apiMethodName)
|
|
7985
|
+
_logsi.LogVerbose("Get the list of objects that make up the user's playback queue")
|
|
7986
|
+
|
|
7987
|
+
# execute spotify web api request.
|
|
7988
|
+
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/queue')
|
|
7989
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
7990
|
+
self.MakeRequest('GET', msg)
|
|
7991
|
+
|
|
7992
|
+
# process results.
|
|
7993
|
+
result = PlayerQueueInfo(root=msg.ResponseData)
|
|
7994
|
+
result.DateLastRefreshed = datetime.utcnow().timestamp()
|
|
7995
|
+
|
|
7996
|
+
# trace.
|
|
7997
|
+
_logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
|
|
7998
|
+
return result
|
|
7999
|
+
|
|
8000
|
+
except SpotifyApiError: raise # pass handled exceptions on thru
|
|
8001
|
+
except SpotifyWebApiError: raise # pass handled exceptions on thru
|
|
8002
|
+
except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
|
|
8003
|
+
except Exception as ex:
|
|
8004
|
+
|
|
8005
|
+
# format unhandled exception.
|
|
8006
|
+
raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
|
|
8007
|
+
|
|
8008
|
+
finally:
|
|
8009
|
+
|
|
8010
|
+
# trace.
|
|
8011
|
+
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
8012
|
+
|
|
8013
|
+
|
|
8014
|
+
def GetPlayerRecentTracks(
|
|
8015
|
+
self,
|
|
8016
|
+
limit:int=50,
|
|
8017
|
+
after:int=None,
|
|
8018
|
+
before:int=None,
|
|
8019
|
+
limitTotal:int=None
|
|
8020
|
+
) -> PlayHistoryPage:
|
|
8021
|
+
"""
|
|
8022
|
+
Get tracks from the current user's recently played tracks.
|
|
8023
|
+
Note: Currently doesn't support podcast episodes.
|
|
8024
|
+
|
|
8025
|
+
This method requires the `user-read-recently-played` scope.
|
|
8026
|
+
|
|
8027
|
+
Args:
|
|
8028
|
+
limit (int):
|
|
8029
|
+
The maximum number of items to return in a page of items when manual paging is used.
|
|
8030
|
+
Default: 20, Range: 1 to 50.
|
|
8031
|
+
See the `limitTotal` argument for automatic paging option.
|
|
8032
|
+
after (int):
|
|
8033
|
+
Returns all items after (but not including) this cursor position, which is
|
|
8034
|
+
a Unix timestamp in milliseconds.
|
|
8035
|
+
If `after` is specified, `before` must not be specified.
|
|
8036
|
+
Use with limit to get the next set of items.
|
|
8037
|
+
Default: `0` (the first item).
|
|
8038
|
+
before (int):
|
|
8039
|
+
Returns all items before (but not including) this cursor position, which is
|
|
8040
|
+
a Unix timestamp in milliseconds.
|
|
8041
|
+
If `before` is specified, `after` must not be specified.
|
|
8042
|
+
Use with limit to get the next set of items.
|
|
8043
|
+
Default: `0` (the first item).
|
|
8044
|
+
limitTotal (int):
|
|
8045
|
+
The maximum number of items to return for the request.
|
|
8046
|
+
If specified, this argument overrides the limit and offset argument values
|
|
8047
|
+
and paging is automatically used to retrieve all available items up to the
|
|
8048
|
+
maximum number specified.
|
|
8049
|
+
Default: None (disabled)
|
|
8050
|
+
|
|
8051
|
+
Spotify currently limits the maximum number of items returned to 50 no matter what you
|
|
8052
|
+
supply for the `limitTotal` argument.
|
|
8053
|
+
|
|
8054
|
+
The `after` and `before` arguments are based upon local time (not UTC time). Recently
|
|
8055
|
+
played item history uses a local timestamp, and NOT a UTC timestamp.
|
|
8056
|
+
|
|
8057
|
+
If both `after` and `before` arguments are null (or zero), then a `before` value
|
|
8058
|
+
is generated that will retrieve the last 50 recently played tracks.
|
|
8059
|
+
|
|
8060
|
+
Returns:
|
|
8061
|
+
A `PlayHistoryPage` object that contains the recently played items.
|
|
8062
|
+
|
|
8063
|
+
Raises:
|
|
8064
|
+
SpotifyWebApiError:
|
|
8065
|
+
If the Spotify Web API request was for a non-authorization service
|
|
8066
|
+
and the response contains error information.
|
|
8067
|
+
SpotifyApiError:
|
|
8068
|
+
If the method fails for any other reason.
|
|
8069
|
+
|
|
8070
|
+
<details>
|
|
8071
|
+
<summary>Sample Code - After DateTime</summary>
|
|
8072
|
+
```python
|
|
8073
|
+
.. include:: ../docs/include/samplecode/SpotifyClient/GetPlayerRecentTracks_AfterDateTime.py
|
|
8074
|
+
```
|
|
8075
|
+
</details>
|
|
8076
|
+
<details>
|
|
8077
|
+
<summary>Sample Code - For Past 1 Hour</summary>
|
|
8078
|
+
```python
|
|
8079
|
+
.. include:: ../docs/include/samplecode/SpotifyClient/GetPlayerRecentTracks_Past01Hours.py
|
|
8080
|
+
```
|
|
8081
|
+
</details>
|
|
8082
|
+
"""
|
|
8083
|
+
apiMethodName:str = 'GetPlayerRecentTracks'
|
|
8084
|
+
apiMethodParms:SIMethodParmListContext = None
|
|
8085
|
+
result:PlayHistoryPage = None
|
|
8086
|
+
|
|
8087
|
+
try:
|
|
8088
|
+
|
|
8089
|
+
# trace.
|
|
8090
|
+
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
8091
|
+
apiMethodParms.AppendKeyValue("limit", limit)
|
|
8092
|
+
apiMethodParms.AppendKeyValue("after", after)
|
|
8093
|
+
apiMethodParms.AppendKeyValue("before", before)
|
|
8094
|
+
apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
|
|
8095
|
+
_logsi.LogMethodParmList(SILevel.Verbose, "Get tracks from the current user's recently played tracks", apiMethodParms)
|
|
8096
|
+
|
|
8097
|
+
# validations.
|
|
8098
|
+
if before is None:
|
|
8099
|
+
before = 0
|
|
8100
|
+
if (not isinstance(before,int)):
|
|
8101
|
+
before = int(before)
|
|
8102
|
+
|
|
8103
|
+
if after is None:
|
|
8104
|
+
after = 0
|
|
8105
|
+
if (not isinstance(after,int)):
|
|
8106
|
+
after = int(after)
|
|
8107
|
+
|
|
8108
|
+
if limit is None:
|
|
8109
|
+
limit = 20
|
|
8110
|
+
if not isinstance(limitTotal, int):
|
|
8111
|
+
limitTotal = 0
|
|
8112
|
+
|
|
8113
|
+
# if no before or after values, then get the last 50 tracks played.
|
|
8114
|
+
if (after == 0) and (before == 0):
|
|
8115
|
+
before = GetUnixTimestampMSFromUtcNow(seconds=-1)
|
|
8116
|
+
limitTotal = 100 # spotify only returns 50 max.
|
|
8117
|
+
_logsi.LogVerbose("Defaulting to retrieve play history of the last 50 recently played items (before = %d)" % before)
|
|
8118
|
+
|
|
8119
|
+
# are we auto-paging? if so, then use max limit.
|
|
8120
|
+
if limitTotal > 0:
|
|
8121
|
+
limit = 50
|
|
7780
8122
|
if limit > limitTotal:
|
|
7781
8123
|
limit = limitTotal
|
|
7782
8124
|
result = PlayHistoryPage()
|
|
@@ -9122,263 +9464,50 @@ class SpotifyClient:
|
|
|
9122
9464
|
```python
|
|
9123
9465
|
.. include:: ../docs/include/samplecode/SpotifyClient/GetShows.py
|
|
9124
9466
|
```
|
|
9125
|
-
</details>
|
|
9126
|
-
"""
|
|
9127
|
-
apiMethodName:str = 'GetShows'
|
|
9128
|
-
apiMethodParms:SIMethodParmListContext = None
|
|
9129
|
-
result:list[ShowSimplified] = []
|
|
9130
|
-
|
|
9131
|
-
try:
|
|
9132
|
-
|
|
9133
|
-
# trace.
|
|
9134
|
-
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
9135
|
-
apiMethodParms.AppendKeyValue("ids", ids)
|
|
9136
|
-
apiMethodParms.AppendKeyValue("market", market)
|
|
9137
|
-
_logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for multiple shows", apiMethodParms)
|
|
9138
|
-
|
|
9139
|
-
# ensure market was either supplied or implied; default if neither.
|
|
9140
|
-
market = self._ValidateMarket(market)
|
|
9141
|
-
|
|
9142
|
-
# build spotify web api request parameters.
|
|
9143
|
-
urlParms:dict = \
|
|
9144
|
-
{
|
|
9145
|
-
'ids': ids,
|
|
9146
|
-
}
|
|
9147
|
-
if market is not None:
|
|
9148
|
-
urlParms['market'] = market
|
|
9149
|
-
|
|
9150
|
-
# execute spotify web api request.
|
|
9151
|
-
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/shows')
|
|
9152
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
9153
|
-
msg.UrlParameters = urlParms
|
|
9154
|
-
self.MakeRequest('GET', msg)
|
|
9155
|
-
|
|
9156
|
-
# process results.
|
|
9157
|
-
items = msg.ResponseData.get('shows',None)
|
|
9158
|
-
if items is not None:
|
|
9159
|
-
for item in items:
|
|
9160
|
-
result.append(ShowSimplified(root=item))
|
|
9161
|
-
|
|
9162
|
-
# trace.
|
|
9163
|
-
_logsi.LogArray(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, 'list[ShowSimplified]'), result)
|
|
9164
|
-
return result
|
|
9165
|
-
|
|
9166
|
-
except SpotifyApiError: raise # pass handled exceptions on thru
|
|
9167
|
-
except SpotifyWebApiError: raise # pass handled exceptions on thru
|
|
9168
|
-
except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
|
|
9169
|
-
except Exception as ex:
|
|
9170
|
-
|
|
9171
|
-
# format unhandled exception.
|
|
9172
|
-
raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
|
|
9173
|
-
|
|
9174
|
-
finally:
|
|
9175
|
-
|
|
9176
|
-
# trace.
|
|
9177
|
-
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
9178
|
-
|
|
9179
|
-
|
|
9180
|
-
def GetSonosPlayerPlaybackState(
|
|
9181
|
-
self,
|
|
9182
|
-
scDevice:SpotifyConnectDevice,
|
|
9183
|
-
) -> PlayerPlayState:
|
|
9184
|
-
"""
|
|
9185
|
-
Get information about the Sonos user's current playback state, including track or episode, progress,
|
|
9186
|
-
and active device.
|
|
9187
|
-
|
|
9188
|
-
This is not part of the Spotify Web API specification; it is for Sonos devices only!
|
|
9189
|
-
|
|
9190
|
-
Args:
|
|
9191
|
-
scDevice (SpotifyConnectDevice):
|
|
9192
|
-
Spotify Connect device instance used to identify the Sonos player.
|
|
9193
|
-
|
|
9194
|
-
Returns:
|
|
9195
|
-
A `PlayerPlayState` object that contains Sonos player state details as well as
|
|
9196
|
-
currently playing content.
|
|
9197
|
-
|
|
9198
|
-
Raises:
|
|
9199
|
-
SpotifyApiError:
|
|
9200
|
-
If the method fails for any other reason.
|
|
9467
|
+
</details>
|
|
9201
9468
|
"""
|
|
9202
|
-
apiMethodName:str = '
|
|
9469
|
+
apiMethodName:str = 'GetShows'
|
|
9203
9470
|
apiMethodParms:SIMethodParmListContext = None
|
|
9471
|
+
result:list[ShowSimplified] = []
|
|
9204
9472
|
|
|
9205
9473
|
try:
|
|
9206
9474
|
|
|
9207
9475
|
# trace.
|
|
9208
9476
|
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
9209
|
-
apiMethodParms.AppendKeyValue("
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
# create playstate object.
|
|
9213
|
-
playerState = PlayerPlayState()
|
|
9214
|
-
|
|
9215
|
-
# get Sonos Controller instance for the device.
|
|
9216
|
-
sonosPlayer:Soco = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
9217
|
-
|
|
9218
|
-
# use the SoCo API to get Sonos playback status.
|
|
9219
|
-
# build a spotify playback status instance with equivalent Sonos state values.
|
|
9220
|
-
_logsi.LogVerbose("Getting Sonos device status via Sonos Control API for device: %s" % (scDevice.Title))
|
|
9221
|
-
sonosTrackInfo:dict = sonosPlayer.get_current_track_info()
|
|
9222
|
-
_logsi.LogDictionary(SILevel.Verbose, "Sonos device current_track_info results for device: %s" % (scDevice.Title), sonosTrackInfo, prettyPrint=True)
|
|
9223
|
-
sonosTransportInfo:dict = sonosPlayer.get_current_transport_info()
|
|
9224
|
-
_logsi.LogDictionary(SILevel.Verbose, "Sonos device get_current_transport_info results for device: %s" % (scDevice.Title), sonosTransportInfo, prettyPrint=True)
|
|
9225
|
-
|
|
9226
|
-
# update Spotify Web API player state with Sonos player state.
|
|
9227
|
-
playerState._Device._Id = scDevice.Id
|
|
9228
|
-
playerState._Device._Name = sonosPlayer.player_name
|
|
9229
|
-
playerState._Device._VolumePercent = sonosPlayer.volume
|
|
9230
|
-
playerState._Device._IsActive = True
|
|
9231
|
-
playerState._Device._IsRestricted = True
|
|
9232
|
-
playerState._Device._SupportsVolume = True
|
|
9233
|
-
playerState._Device._Type = 'SPEAKER'
|
|
9234
|
-
|
|
9235
|
-
# try to get the spotify uri from the "metadata" music library DIDL value, as
|
|
9236
|
-
# the "uri" value (e.g. "x-sonos-vli:RINCON_38420B909DC801400:2,spotify:e934941535d7b182815bf688490ce8a8")
|
|
9237
|
-
# is not a true spotify uri value (e.g. "spotify:track:6kYyS9g4WJeRzTYqsmcMmM")
|
|
9238
|
-
spotifyUri:str = sonosTrackInfo.get('uri','')
|
|
9239
|
-
didl:str = sonosTrackInfo.get('metadata',None)
|
|
9240
|
-
if (didl):
|
|
9241
|
-
METADATA_ID:str = 'x-sonos-spotify:'
|
|
9242
|
-
idx:int = didl.find(METADATA_ID)
|
|
9243
|
-
if (idx > -1):
|
|
9244
|
-
spotifyUri:str = didl[idx + len(METADATA_ID):]
|
|
9245
|
-
spotifyUri = urllib.parse.unquote(spotifyUri)
|
|
9246
|
-
idx = spotifyUri.find('?')
|
|
9247
|
-
if (idx > -1):
|
|
9248
|
-
spotifyUri = spotifyUri[:idx]
|
|
9249
|
-
spotifyType = self.GetTypeFromUri(spotifyUri) or ''
|
|
9250
|
-
spotifyId = self.GetIdFromUri(spotifyUri) or ''
|
|
9251
|
-
|
|
9252
|
-
# set base item properties.
|
|
9253
|
-
playerState.IsEmpty = False
|
|
9254
|
-
playerState.ItemType = spotifyType
|
|
9255
|
-
sTimeValue:str = sonosTrackInfo.get('position',None)
|
|
9256
|
-
playerState._ProgressMS = mediaPositionHMS_toSeconds(sTimeValue) * 1000 # convert h:mm:ss to milliseconds
|
|
9477
|
+
apiMethodParms.AppendKeyValue("ids", ids)
|
|
9478
|
+
apiMethodParms.AppendKeyValue("market", market)
|
|
9479
|
+
_logsi.LogMethodParmList(SILevel.Verbose, "Get Spotify catalog information for multiple shows", apiMethodParms)
|
|
9257
9480
|
|
|
9258
|
-
#
|
|
9259
|
-
|
|
9481
|
+
# ensure market was either supplied or implied; default if neither.
|
|
9482
|
+
market = self._ValidateMarket(market)
|
|
9260
9483
|
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
|
|
9265
|
-
|
|
9266
|
-
|
|
9267
|
-
|
|
9268
|
-
playerState._Context._Type = episode.Show.Type
|
|
9269
|
-
playerState._Context._Uri = episode.Show.Uri
|
|
9270
|
-
playerState._Context._Href = episode.Show.Href
|
|
9271
|
-
playerState._Context._ExternalUrls = episode.Show.ExternalUrls
|
|
9272
|
-
else:
|
|
9273
|
-
# if data could not be obtained from spotify, then use what's
|
|
9274
|
-
# available from Sonos Soco api metadata.
|
|
9275
|
-
playerState._Item = Episode()
|
|
9276
|
-
playerState._Item._Name = sonosTrackInfo.get('title','')
|
|
9277
|
-
playerState._Item._Uri = spotifyUri
|
|
9278
|
-
playerState._Item._Description = 'Sonos device does not provide a description'
|
|
9279
|
-
sTimeValue:str = sonosTrackInfo.get('duration',None)
|
|
9280
|
-
playerState._Item._DurationMS = mediaPositionHMS_toSeconds(sTimeValue) * 1000 # convert h:mm:ss to milliseconds
|
|
9281
|
-
playerState._Item._Explicit = False
|
|
9282
|
-
playerState._Item._Href = 'https://api.spotify.com/v1/episodes/' + spotifyId
|
|
9283
|
-
playerState._Item._HtmlDescription = playerState._Item._Description
|
|
9284
|
-
playerState._Item._Id = spotifyId
|
|
9285
|
-
playerState._Item.Images.append(ImageObject())
|
|
9286
|
-
playerState._Item.Images[0]._Url = sonosTrackInfo.get('album_art','')
|
|
9287
|
-
playerState._Item._TrackNumber = sonosTrackInfo.get('playlist_position','')
|
|
9288
|
-
playerState._Item._ReleaseDate = '0000'
|
|
9289
|
-
playerState._Item._ReleaseDatePrecision = 'year'
|
|
9290
|
-
playerState._Item._Type = 'episode'
|
|
9291
|
-
playerState._Item._Show = Show()
|
|
9292
|
-
playerState._Item._Show._Name = sonosTrackInfo.get('album','') # TODO get this from metadata (<r:podcast>The Elfstones of Shannara</r:podcast>)
|
|
9293
|
-
playerState._Item._Show.Images.append(ImageObject())
|
|
9294
|
-
playerState._Item._Show.Images[0]._Url = sonosTrackInfo.get('album_art','')
|
|
9295
|
-
playerState._Item._Show._Publisher = sonosTrackInfo.get('artist','')
|
|
9484
|
+
# build spotify web api request parameters.
|
|
9485
|
+
urlParms:dict = \
|
|
9486
|
+
{
|
|
9487
|
+
'ids': ids,
|
|
9488
|
+
}
|
|
9489
|
+
if market is not None:
|
|
9490
|
+
urlParms['market'] = market
|
|
9296
9491
|
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
playerState._Item._Show._Name = metaValue
|
|
9309
|
-
|
|
9310
|
-
# if episode is playing then resolve the underlying type (audiobook / podcast show).
|
|
9311
|
-
if (self.IsChapterEpisode(spotifyId)):
|
|
9312
|
-
playerState.ItemType = 'audiobook'
|
|
9313
|
-
else:
|
|
9314
|
-
playerState.ItemType = 'podcast'
|
|
9315
|
-
|
|
9316
|
-
elif (spotifyType == 'track'):
|
|
9317
|
-
|
|
9318
|
-
# get the track data from spotify, as Sonos Soco data is incomplete.
|
|
9319
|
-
track:Track = self.GetTrack(spotifyId)
|
|
9320
|
-
if (track.Id is not None):
|
|
9321
|
-
playerState._Item = track
|
|
9322
|
-
if (playerState._Context is None):
|
|
9323
|
-
playerState._Context = Context()
|
|
9324
|
-
playerState._Context._Type = track.Album.Type
|
|
9325
|
-
playerState._Context._Uri = track.Album.Uri
|
|
9326
|
-
playerState._Context._Href = track.Album.Href
|
|
9327
|
-
playerState._Context._ExternalUrls = track.Album.ExternalUrls
|
|
9328
|
-
else:
|
|
9329
|
-
# if data could not be obtained from spotify, then use what's
|
|
9330
|
-
# available from Sonos Soco api metadata.
|
|
9331
|
-
playerState._CurrentlyPlayingType = 'track'
|
|
9332
|
-
playerState.ItemType = playerState._CurrentlyPlayingType
|
|
9333
|
-
playerState._Item = Track()
|
|
9334
|
-
playerState._Item._Name = sonosTrackInfo.get('title','')
|
|
9335
|
-
playerState._Item._Uri = spotifyUri
|
|
9336
|
-
playerState._Item._Description = 'Sonos device does not provide a description'
|
|
9337
|
-
sTimeValue:str = sonosTrackInfo.get('duration',None)
|
|
9338
|
-
playerState._Item._DurationMS = mediaPositionHMS_toSeconds(sTimeValue) * 1000 # convert h:mm:ss to milliseconds
|
|
9339
|
-
playerState._Item._Explicit = False
|
|
9340
|
-
playerState._Item._Href = 'https://api.spotify.com/v1/episodes/' + spotifyId
|
|
9341
|
-
playerState._Item._HtmlDescription = playerState._Item._Description
|
|
9342
|
-
playerState._Item._Id = spotifyId
|
|
9343
|
-
playerState._Item._TrackNumber = sonosTrackInfo.get('playlist_position','')
|
|
9344
|
-
playerState._Item._ReleaseDate = '0000'
|
|
9345
|
-
playerState._Item._ReleaseDatePrecision = 'year'
|
|
9346
|
-
playerState._Item._Type = 'track'
|
|
9347
|
-
playerState._Item._Album = Album()
|
|
9348
|
-
playerState._Item._Album._Name = sonosTrackInfo.get('album','')
|
|
9349
|
-
playerState._Item._Album.Images.append(ImageObject())
|
|
9350
|
-
playerState._Item._Album.Images[0]._Url = sonosTrackInfo.get('album_art','')
|
|
9351
|
-
playerState._Item.Artists.append(Artist())
|
|
9352
|
-
playerState._Item.Artists[0]._Name = sonosTrackInfo.get('artist','')
|
|
9353
|
-
|
|
9354
|
-
# set transport actions.
|
|
9355
|
-
currentTransportState:str = sonosTransportInfo.get('current_transport_state','')
|
|
9356
|
-
if currentTransportState == 'PLAYING':
|
|
9357
|
-
playerState._IsPlaying = True
|
|
9358
|
-
elif currentTransportState in ['PAUSED_PLAYBACK','STOPPED']:
|
|
9359
|
-
playerState.Actions._Pausing = True
|
|
9360
|
-
|
|
9361
|
-
# only update the following PlayState attributes from SoCo if they are NOT set.
|
|
9362
|
-
# these values are used to set the Sonos PlayMode value, which is the actual value that determines
|
|
9363
|
-
# what the Repeat and Shuffle settings are (ya, it's weird!). What is odd is that the Spotify
|
|
9364
|
-
# Web API PlayerState values for Shuffle and Repeat can be different than what the Sonos Controller
|
|
9365
|
-
# API (SoCo) report for the device! This is why we use the Spotify Web API PlayerState values.
|
|
9366
|
-
if playerState._ShuffleState is None:
|
|
9367
|
-
playerState._ShuffleState = sonosPlayer.shuffle
|
|
9368
|
-
if playerState._RepeatState is None:
|
|
9369
|
-
sonosRepeat = sonosPlayer.repeat
|
|
9370
|
-
if sonosRepeat == 'ONE':
|
|
9371
|
-
playerState._RepeatState = 'track'
|
|
9372
|
-
elif sonosRepeat == False:
|
|
9373
|
-
playerState._RepeatState = 'off'
|
|
9374
|
-
elif sonosRepeat == True:
|
|
9375
|
-
playerState._RepeatState = 'context'
|
|
9492
|
+
# execute spotify web api request.
|
|
9493
|
+
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/shows')
|
|
9494
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
9495
|
+
msg.UrlParameters = urlParms
|
|
9496
|
+
self.MakeRequest('GET', msg)
|
|
9497
|
+
|
|
9498
|
+
# process results.
|
|
9499
|
+
items = msg.ResponseData.get('shows',None)
|
|
9500
|
+
if items is not None:
|
|
9501
|
+
for item in items:
|
|
9502
|
+
result.append(ShowSimplified(root=item))
|
|
9376
9503
|
|
|
9377
9504
|
# trace.
|
|
9378
|
-
_logsi.
|
|
9379
|
-
return
|
|
9505
|
+
_logsi.LogArray(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, 'list[ShowSimplified]'), result)
|
|
9506
|
+
return result
|
|
9380
9507
|
|
|
9381
9508
|
except SpotifyApiError: raise # pass handled exceptions on thru
|
|
9509
|
+
except SpotifyWebApiError: raise # pass handled exceptions on thru
|
|
9510
|
+
except SpotifyWebApiAuthenticationError: raise # pass handled exceptions on thru
|
|
9382
9511
|
except Exception as ex:
|
|
9383
9512
|
|
|
9384
9513
|
# format unhandled exception.
|
|
@@ -9393,7 +9522,7 @@ class SpotifyClient:
|
|
|
9393
9522
|
def GetSpotifyConnectDevice(
|
|
9394
9523
|
self,
|
|
9395
9524
|
deviceValue:str,
|
|
9396
|
-
verifyUserContext:bool=True,
|
|
9525
|
+
verifyUserContext:bool=True,
|
|
9397
9526
|
verifyTimeout:float=5.0,
|
|
9398
9527
|
refreshDeviceList:bool=False,
|
|
9399
9528
|
activateDevice:bool=True,
|
|
@@ -9439,7 +9568,7 @@ class SpotifyClient:
|
|
|
9439
9568
|
Returns:
|
|
9440
9569
|
A `SpotifyConnectDevice` object for the deviceValue if one could be resolved.
|
|
9441
9570
|
otherwise, a null value with the understanding that subsequent operations will probably
|
|
9442
|
-
fail since it's not in the Spotify Connect
|
|
9571
|
+
fail since it's not in the Spotify Connect device list.
|
|
9443
9572
|
|
|
9444
9573
|
Raises:
|
|
9445
9574
|
SpotifyWebApiError:
|
|
@@ -9476,14 +9605,14 @@ class SpotifyClient:
|
|
|
9476
9605
|
apiMethodName:str = 'GetSpotifyConnectDevice'
|
|
9477
9606
|
apiMethodParms:SIMethodParmListContext = None
|
|
9478
9607
|
scDevice:SpotifyConnectDevice = None
|
|
9479
|
-
sonosPlayer:
|
|
9608
|
+
sonosPlayer:SoCo = None
|
|
9480
9609
|
|
|
9481
9610
|
try:
|
|
9482
9611
|
|
|
9483
9612
|
# trace.
|
|
9484
9613
|
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
9485
9614
|
apiMethodParms.AppendKeyValue("deviceValue", deviceValue)
|
|
9486
|
-
apiMethodParms.AppendKeyValue("verifyUserContext", verifyUserContext)
|
|
9615
|
+
apiMethodParms.AppendKeyValue("verifyUserContext (DEPRECATED)", verifyUserContext)
|
|
9487
9616
|
apiMethodParms.AppendKeyValue("verifyTimeout", verifyTimeout)
|
|
9488
9617
|
apiMethodParms.AppendKeyValue("refreshDeviceList", refreshDeviceList)
|
|
9489
9618
|
apiMethodParms.AppendKeyValue("activateDevice", activateDevice)
|
|
@@ -9499,8 +9628,15 @@ class SpotifyClient:
|
|
|
9499
9628
|
refreshDeviceList = False
|
|
9500
9629
|
|
|
9501
9630
|
# resolve the device id from the specified device value.
|
|
9502
|
-
#
|
|
9503
|
-
scDevice = self._SpotifyConnectDirectory.GetDevice(deviceValue, refreshDynamicDevices=True)
|
|
9631
|
+
# returned value will be null if the device could not be resolved!
|
|
9632
|
+
scDevice = self._SpotifyConnectDirectory.GetDevice(deviceValue, refreshDynamicDevices=True, raiseExceptionIfNotFound=False)
|
|
9633
|
+
|
|
9634
|
+
# if device could not be resolved, then go no further as it will result in a
|
|
9635
|
+
# "device not found" error from the Spotify Web API anyway!
|
|
9636
|
+
if (scDevice is None):
|
|
9637
|
+
_logsi.LogVerbose("Spotify Player device was not found, and there is no active Spotify player; no need to re-activate")
|
|
9638
|
+
return None
|
|
9639
|
+
|
|
9504
9640
|
discovery:ZeroconfDiscoveryResult = scDevice.DiscoveryResult
|
|
9505
9641
|
info:ZeroconfGetInfo = scDevice.DeviceInfo
|
|
9506
9642
|
scDevice.WasReConnected = False
|
|
@@ -9510,28 +9646,13 @@ class SpotifyClient:
|
|
|
9510
9646
|
_logsi.LogVerbose("Spotify Connect device %s is already active; no need to re-activate" % (scDevice.Title))
|
|
9511
9647
|
return scDevice
|
|
9512
9648
|
|
|
9513
|
-
# is the device in the player device list? if so, then it's
|
|
9514
|
-
# if another user is controlling the device, then it will not be in the
|
|
9515
|
-
# for the current user.
|
|
9649
|
+
# is the device in the player device list? if so, then it's ready to be selected.
|
|
9650
|
+
# note that if another user is controlling the device, then it will not be in the
|
|
9651
|
+
# active device list for the current user.
|
|
9516
9652
|
if (scDevice.IsInDeviceList):
|
|
9517
9653
|
_logsi.LogVerbose("Spotify Connect device %s is already in the available device list; no need to re-activate" % (scDevice.Title))
|
|
9518
9654
|
return scDevice
|
|
9519
9655
|
|
|
9520
|
-
# chromecast devices always require activation if they are not the active device.
|
|
9521
|
-
# note that `transferPlayback=false`, as transfer should be done after we return to caller.
|
|
9522
|
-
if (scDevice.IsChromeCast):
|
|
9523
|
-
|
|
9524
|
-
# activate the spotify cast application on the device.
|
|
9525
|
-
_logsi.LogVerbose("Activating Chromecast Spotify Connect device: %s" % (scDevice.Title))
|
|
9526
|
-
self._SpotifyConnectDirectory.ActivateCastAppSpotify(scDevice.Name, transferPlayback=False)
|
|
9527
|
-
|
|
9528
|
-
# re-fetch device instance, as it has updated Zeroconf Response data.
|
|
9529
|
-
# do not need to refresh from Spotify Web API, as only zeroconf data was changed.
|
|
9530
|
-
scDevice = self._SpotifyConnectDirectory.GetDevice(deviceValue, refreshDynamicDevices=False)
|
|
9531
|
-
|
|
9532
|
-
# return device to caller.
|
|
9533
|
-
return scDevice
|
|
9534
|
-
|
|
9535
9656
|
# if this is a Sonos device and there is no Spotify Client Application token then don't bother.
|
|
9536
9657
|
# in this case, we will exit and let the calling method switch to the Sonos device and play
|
|
9537
9658
|
# using the Sonos local queue.
|
|
@@ -9555,13 +9676,28 @@ class SpotifyClient:
|
|
|
9555
9676
|
_logsi.LogVerbose("Target device is Sonos; getting Sonos Controller instance for device %s" % (scDevice.Title))
|
|
9556
9677
|
sonosPlayer = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
9557
9678
|
|
|
9558
|
-
# at this point, we will try to activate the device.
|
|
9559
|
-
|
|
9560
9679
|
# was device activation requested? if not, then we are done.
|
|
9561
9680
|
if (not activateDevice):
|
|
9562
9681
|
_logsi.LogVerbose("Activation not requested for Spotify Connect device: %s" % (scDevice.Title))
|
|
9563
9682
|
return scDevice
|
|
9564
9683
|
|
|
9684
|
+
# at this point, we will try to activate the device if needed.
|
|
9685
|
+
|
|
9686
|
+
# chromecast devices always require activation if they are not the active device.
|
|
9687
|
+
# note that `transferPlayback=false`, as transfer should be done after we return to caller.
|
|
9688
|
+
if (scDevice.IsChromeCast):
|
|
9689
|
+
|
|
9690
|
+
# activate the spotify cast application on the device.
|
|
9691
|
+
_logsi.LogVerbose("Activating Chromecast Spotify Connect device: %s" % (scDevice.Title))
|
|
9692
|
+
self._SpotifyConnectDirectory.ActivateCastAppSpotify(scDevice.Name, transferPlayback=False)
|
|
9693
|
+
|
|
9694
|
+
# re-fetch device instance, as it has updated Zeroconf Response data.
|
|
9695
|
+
# do not need to refresh from Spotify Web API, as only zeroconf data was changed.
|
|
9696
|
+
scDevice = self._SpotifyConnectDirectory.GetDevice(deviceValue, refreshDynamicDevices=False)
|
|
9697
|
+
|
|
9698
|
+
# return device to caller.
|
|
9699
|
+
return scDevice
|
|
9700
|
+
|
|
9565
9701
|
zcfResult:ZeroconfResponse
|
|
9566
9702
|
|
|
9567
9703
|
# store the currently active user of the device, in case we need to switch users later on.
|
|
@@ -9734,7 +9870,7 @@ class SpotifyClient:
|
|
|
9734
9870
|
# trace.
|
|
9735
9871
|
apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
|
|
9736
9872
|
apiMethodParms.AppendKeyValue("refresh", refresh)
|
|
9737
|
-
apiMethodParms.AppendKeyValue("sortResult", sortResult)
|
|
9873
|
+
apiMethodParms.AppendKeyValue("sortResult (DEPRECATED)", sortResult)
|
|
9738
9874
|
_logsi.LogMethodParmList(SILevel.Verbose, "Get available Spotify Connect devices", apiMethodParms)
|
|
9739
9875
|
|
|
9740
9876
|
# validations.
|
|
@@ -11361,11 +11497,14 @@ class SpotifyClient:
|
|
|
11361
11497
|
This method requires the `user-modify-playback-state` scope.
|
|
11362
11498
|
|
|
11363
11499
|
Args:
|
|
11364
|
-
deviceId (str):
|
|
11365
|
-
The
|
|
11366
|
-
|
|
11367
|
-
|
|
11368
|
-
|
|
11500
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
11501
|
+
The target player device identifier.
|
|
11502
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
11503
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
11504
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
11505
|
+
for this argument. An exception will be raised if the argument value could
|
|
11506
|
+
not be resolved or activated.
|
|
11507
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
11369
11508
|
delay (float):
|
|
11370
11509
|
Time delay (in seconds) to wait AFTER issuing the command to the player.
|
|
11371
11510
|
This delay will give the spotify web api time to process the change before
|
|
@@ -11405,20 +11544,21 @@ class SpotifyClient:
|
|
|
11405
11544
|
delay = validateDelay(delay, 0.50, 10)
|
|
11406
11545
|
|
|
11407
11546
|
# resolve / activate the device object if needed.
|
|
11408
|
-
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId)
|
|
11547
|
+
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
11409
11548
|
|
|
11410
11549
|
# is this an active Sonos device?
|
|
11411
|
-
if (scDevice
|
|
11550
|
+
if (scDevice is not None) and (scDevice.IsSonos):
|
|
11412
11551
|
|
|
11413
11552
|
_logsi.LogVerbose("Issuing command to Sonos device %s: PAUSE" % (scDevice.Title))
|
|
11414
|
-
sonosPlayer:
|
|
11553
|
+
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
11415
11554
|
sonosPlayer.pause()
|
|
11416
11555
|
|
|
11417
11556
|
else:
|
|
11418
11557
|
|
|
11419
11558
|
# build spotify web api request parameters.
|
|
11420
11559
|
urlParms:dict = {}
|
|
11421
|
-
|
|
11560
|
+
if (scDevice is not None):
|
|
11561
|
+
urlParms['device_id'] = scDevice.Id
|
|
11422
11562
|
|
|
11423
11563
|
# execute spotify web api request.
|
|
11424
11564
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/pause')
|
|
@@ -11487,11 +11627,14 @@ class SpotifyClient:
|
|
|
11487
11627
|
player to start playing the next track.
|
|
11488
11628
|
Default is `0`.
|
|
11489
11629
|
Example: `25000`
|
|
11490
|
-
deviceId (str):
|
|
11491
|
-
The
|
|
11492
|
-
|
|
11493
|
-
|
|
11494
|
-
|
|
11630
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
11631
|
+
The target player device identifier.
|
|
11632
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
11633
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
11634
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
11635
|
+
for this argument. An exception will be raised if the argument value could
|
|
11636
|
+
not be resolved or activated.
|
|
11637
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
11495
11638
|
delay (float):
|
|
11496
11639
|
Time delay (in seconds) to wait AFTER issuing the command to the player.
|
|
11497
11640
|
This delay will give the spotify web api time to process the change before
|
|
@@ -11556,7 +11699,7 @@ class SpotifyClient:
|
|
|
11556
11699
|
delay = validateDelay(delay, 0.50, 10)
|
|
11557
11700
|
|
|
11558
11701
|
# resolve / activate the device object if needed.
|
|
11559
|
-
scDevice = self._ResolveDeviceObject(deviceId)
|
|
11702
|
+
scDevice = self._ResolveDeviceObject(deviceId, False)
|
|
11560
11703
|
|
|
11561
11704
|
# build spotify web api request parameters.
|
|
11562
11705
|
reqData:dict = \
|
|
@@ -11570,7 +11713,9 @@ class SpotifyClient:
|
|
|
11570
11713
|
reqData['offset'] = { 'position': offsetPosition }
|
|
11571
11714
|
|
|
11572
11715
|
# formulate url parms; will manually add them since we are adding json body as well.
|
|
11573
|
-
urlParms:str = '
|
|
11716
|
+
urlParms:str = ''
|
|
11717
|
+
if (scDevice is not None):
|
|
11718
|
+
urlParms = '?device_id=%s' % scDevice.Id
|
|
11574
11719
|
|
|
11575
11720
|
# execute spotify web api request.
|
|
11576
11721
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/play{url_parms}'.format(url_parms=urlParms))
|
|
@@ -11614,11 +11759,14 @@ class SpotifyClient:
|
|
|
11614
11759
|
and starts playing them.
|
|
11615
11760
|
|
|
11616
11761
|
Args:
|
|
11617
|
-
deviceId (str):
|
|
11618
|
-
The
|
|
11619
|
-
|
|
11620
|
-
|
|
11621
|
-
|
|
11762
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
11763
|
+
The target player device identifier.
|
|
11764
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
11765
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
11766
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
11767
|
+
for this argument. An exception will be raised if the argument value could
|
|
11768
|
+
not be resolved or activated.
|
|
11769
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
11622
11770
|
shuffle (bool):
|
|
11623
11771
|
True to set player shuffle mode to on; otherwise, False for no shuffle.
|
|
11624
11772
|
delay (float):
|
|
@@ -11696,11 +11844,11 @@ class SpotifyClient:
|
|
|
11696
11844
|
arrUris.append(trackSaved.Track.Uri)
|
|
11697
11845
|
|
|
11698
11846
|
# resolve / activate the device object if needed.
|
|
11699
|
-
scDevice = self._ResolveDeviceObject(deviceId)
|
|
11847
|
+
scDevice = self._ResolveDeviceObject(deviceId, False)
|
|
11700
11848
|
|
|
11701
11849
|
# set desired shuffle mode.
|
|
11702
11850
|
if (shuffle == True):
|
|
11703
|
-
self.PlayerSetShuffleMode(shuffle, scDevice
|
|
11851
|
+
self.PlayerSetShuffleMode(shuffle, scDevice, delay)
|
|
11704
11852
|
|
|
11705
11853
|
# play the tracks.
|
|
11706
11854
|
# indicate device id has already been resolved.
|
|
@@ -11750,11 +11898,14 @@ class SpotifyClient:
|
|
|
11750
11898
|
player to start playing the next track.
|
|
11751
11899
|
Default is `0`.
|
|
11752
11900
|
Example: `25000`
|
|
11753
|
-
deviceId (str):
|
|
11754
|
-
The
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
|
|
11901
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
11902
|
+
The target player device identifier.
|
|
11903
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
11904
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
11905
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
11906
|
+
for this argument. An exception will be raised if the argument value could
|
|
11907
|
+
not be resolved or activated.
|
|
11908
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
11758
11909
|
delay (float):
|
|
11759
11910
|
Time delay (in seconds) to wait AFTER issuing the command to the player.
|
|
11760
11911
|
This delay will give the spotify web api time to process the change before
|
|
@@ -11813,7 +11964,7 @@ class SpotifyClient:
|
|
|
11813
11964
|
arrUris[idx] = arrUris[idx].strip()
|
|
11814
11965
|
|
|
11815
11966
|
# resolve / activate the device object if needed.
|
|
11816
|
-
scDevice = self._ResolveDeviceObject(deviceId)
|
|
11967
|
+
scDevice = self._ResolveDeviceObject(deviceId, False)
|
|
11817
11968
|
|
|
11818
11969
|
# left this here in case we want to implement it in the future.
|
|
11819
11970
|
|
|
@@ -11843,7 +11994,9 @@ class SpotifyClient:
|
|
|
11843
11994
|
reqData['uris'] = arrUris
|
|
11844
11995
|
|
|
11845
11996
|
# formulate url parms; will manually add them since we are adding json body as well.
|
|
11846
|
-
urlParms:str = '
|
|
11997
|
+
urlParms:str = ''
|
|
11998
|
+
if (scDevice is not None):
|
|
11999
|
+
urlParms = '?device_id=%s' % scDevice.Id
|
|
11847
12000
|
|
|
11848
12001
|
# execute spotify web api request.
|
|
11849
12002
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/play{url_parms}'.format(url_parms=urlParms))
|
|
@@ -11885,11 +12038,14 @@ class SpotifyClient:
|
|
|
11885
12038
|
This method requires the `user-modify-playback-state` scope.
|
|
11886
12039
|
|
|
11887
12040
|
Args:
|
|
11888
|
-
deviceId (str):
|
|
11889
|
-
The
|
|
11890
|
-
|
|
11891
|
-
|
|
11892
|
-
|
|
12041
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
12042
|
+
The target player device identifier.
|
|
12043
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
12044
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
12045
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
12046
|
+
for this argument. An exception will be raised if the argument value could
|
|
12047
|
+
not be resolved or activated.
|
|
12048
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
11893
12049
|
delay (float):
|
|
11894
12050
|
Time delay (in seconds) to wait AFTER issuing the command to the player.
|
|
11895
12051
|
This delay will give the spotify web api time to process the change before
|
|
@@ -11906,7 +12062,7 @@ class SpotifyClient:
|
|
|
11906
12062
|
This API only works for users who have Spotify Premium.
|
|
11907
12063
|
|
|
11908
12064
|
The order of execution is not guaranteed when you use this API with other Player API endpoints.
|
|
11909
|
-
|
|
12065
|
+
|
|
11910
12066
|
<details>
|
|
11911
12067
|
<summary>Sample Code</summary>
|
|
11912
12068
|
```python
|
|
@@ -11929,20 +12085,21 @@ class SpotifyClient:
|
|
|
11929
12085
|
delay = validateDelay(delay, 0.50, 10)
|
|
11930
12086
|
|
|
11931
12087
|
# resolve / activate the device object if needed.
|
|
11932
|
-
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId)
|
|
12088
|
+
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
11933
12089
|
|
|
11934
12090
|
# is this an active Sonos device?
|
|
11935
|
-
if (scDevice
|
|
12091
|
+
if (scDevice is not None) and (scDevice.IsSonos):
|
|
11936
12092
|
|
|
11937
12093
|
_logsi.LogVerbose("Issuing command to Sonos device %s: PLAY (RESUME)" % (scDevice.Title))
|
|
11938
|
-
sonosPlayer:
|
|
12094
|
+
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
11939
12095
|
sonosPlayer.play()
|
|
11940
12096
|
|
|
11941
12097
|
else:
|
|
11942
12098
|
|
|
11943
12099
|
# build spotify web api request parameters.
|
|
11944
12100
|
urlParms:dict = {}
|
|
11945
|
-
|
|
12101
|
+
if (scDevice is not None):
|
|
12102
|
+
urlParms['device_id'] = scDevice.Id
|
|
11946
12103
|
|
|
11947
12104
|
# execute spotify web api request.
|
|
11948
12105
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/play')
|
|
@@ -11993,11 +12150,14 @@ class SpotifyClient:
|
|
|
11993
12150
|
Passing in a position that is greater than the length of the track will cause the
|
|
11994
12151
|
player to start playing the next song.
|
|
11995
12152
|
Example = `25000` to start playing at the 25 second mark.
|
|
11996
|
-
deviceId (str):
|
|
11997
|
-
The
|
|
11998
|
-
|
|
11999
|
-
|
|
12000
|
-
|
|
12153
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
12154
|
+
The target player device identifier.
|
|
12155
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
12156
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
12157
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
12158
|
+
for this argument. An exception will be raised if the argument value could
|
|
12159
|
+
not be resolved or activated.
|
|
12160
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
12001
12161
|
delay (float):
|
|
12002
12162
|
Time delay (in seconds) to wait AFTER issuing the command to the player.
|
|
12003
12163
|
This delay will give the spotify web api time to process the change before
|
|
@@ -12063,13 +12223,13 @@ class SpotifyClient:
|
|
|
12063
12223
|
relativePositionMS = 0
|
|
12064
12224
|
|
|
12065
12225
|
# resolve / activate the device object if needed.
|
|
12066
|
-
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId)
|
|
12226
|
+
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
12067
12227
|
|
|
12068
12228
|
# was relative seeking specified?
|
|
12069
|
-
if (relativePositionMS != 0) and ((positionMS is None) or (positionMS <= 0)):
|
|
12229
|
+
if (scDevice is not None) and (relativePositionMS != 0) and ((positionMS is None) or (positionMS <= 0)):
|
|
12070
12230
|
|
|
12071
|
-
# get current track position.
|
|
12072
|
-
playState:PlayerPlayState = self.
|
|
12231
|
+
# get current track position (from cache, since we called _ResolveDeviceObject method above).
|
|
12232
|
+
playState:PlayerPlayState = self.GetDevicePlaybackState(scDevice)
|
|
12073
12233
|
newPositionMS:int = playState.ProgressMS
|
|
12074
12234
|
if (newPositionMS is not None) and (newPositionMS > 0):
|
|
12075
12235
|
|
|
@@ -12080,11 +12240,11 @@ class SpotifyClient:
|
|
|
12080
12240
|
positionMS = newPositionMS
|
|
12081
12241
|
|
|
12082
12242
|
# is this an active Sonos device?
|
|
12083
|
-
if (scDevice
|
|
12243
|
+
if (scDevice is not None) and (scDevice.IsSonos):
|
|
12084
12244
|
|
|
12085
12245
|
sonosPosition:str = mediaPositionHMS_fromSeconds(positionMS / 1000) # convert from milliseconds to Sonos H:MM:SS format
|
|
12086
12246
|
_logsi.LogVerbose("Issuing command to Sonos device %s: SEEK (sonosPosition=%s)" % (scDevice.Title, sonosPosition))
|
|
12087
|
-
sonosPlayer:
|
|
12247
|
+
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
12088
12248
|
sonosPlayer.seek(str(sonosPosition))
|
|
12089
12249
|
|
|
12090
12250
|
else:
|
|
@@ -12094,7 +12254,8 @@ class SpotifyClient:
|
|
|
12094
12254
|
{
|
|
12095
12255
|
'position_ms': positionMS
|
|
12096
12256
|
}
|
|
12097
|
-
|
|
12257
|
+
if (scDevice is not None):
|
|
12258
|
+
urlParms['device_id'] = scDevice.Id
|
|
12098
12259
|
|
|
12099
12260
|
# execute spotify web api request.
|
|
12100
12261
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/seek')
|
|
@@ -12136,11 +12297,14 @@ class SpotifyClient:
|
|
|
12136
12297
|
This method requires the `user-modify-playback-state` scope.
|
|
12137
12298
|
|
|
12138
12299
|
Args:
|
|
12139
|
-
deviceId (str):
|
|
12140
|
-
The
|
|
12141
|
-
|
|
12142
|
-
|
|
12143
|
-
|
|
12300
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
12301
|
+
The target player device identifier.
|
|
12302
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
12303
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
12304
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
12305
|
+
for this argument. An exception will be raised if the argument value could
|
|
12306
|
+
not be resolved or activated.
|
|
12307
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
12144
12308
|
delay (float):
|
|
12145
12309
|
Time delay (in seconds) to wait AFTER issuing the command to the player.
|
|
12146
12310
|
This delay will give the spotify web api time to process the change before
|
|
@@ -12180,20 +12344,21 @@ class SpotifyClient:
|
|
|
12180
12344
|
delay = validateDelay(delay, 0.50, 10)
|
|
12181
12345
|
|
|
12182
12346
|
# resolve / activate the device object if needed.
|
|
12183
|
-
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId)
|
|
12347
|
+
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
12184
12348
|
|
|
12185
12349
|
# is this an active Sonos device?
|
|
12186
|
-
if (scDevice
|
|
12350
|
+
if (scDevice is not None) and (scDevice.IsSonos):
|
|
12187
12351
|
|
|
12188
12352
|
_logsi.LogVerbose("Issuing command to Sonos device %s: NEXT" % (scDevice.Title))
|
|
12189
|
-
sonosPlayer:
|
|
12353
|
+
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
12190
12354
|
sonosPlayer.next()
|
|
12191
12355
|
|
|
12192
12356
|
else:
|
|
12193
12357
|
|
|
12194
12358
|
# build spotify web api request parameters.
|
|
12195
12359
|
urlParms:dict = {}
|
|
12196
|
-
|
|
12360
|
+
if (scDevice is not None):
|
|
12361
|
+
urlParms['device_id'] = scDevice.Id
|
|
12197
12362
|
|
|
12198
12363
|
# execute spotify web api request.
|
|
12199
12364
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/next')
|
|
@@ -12235,11 +12400,14 @@ class SpotifyClient:
|
|
|
12235
12400
|
This method requires the `user-modify-playback-state` scope.
|
|
12236
12401
|
|
|
12237
12402
|
Args:
|
|
12238
|
-
deviceId (str):
|
|
12239
|
-
The
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12403
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
12404
|
+
The target player device identifier.
|
|
12405
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
12406
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
12407
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
12408
|
+
for this argument. An exception will be raised if the argument value could
|
|
12409
|
+
not be resolved or activated.
|
|
12410
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
12243
12411
|
delay (float):
|
|
12244
12412
|
Time delay (in seconds) to wait AFTER issuing the command to the player.
|
|
12245
12413
|
This delay will give the spotify web api time to process the change before
|
|
@@ -12279,20 +12447,21 @@ class SpotifyClient:
|
|
|
12279
12447
|
delay = validateDelay(delay, 0.50, 10)
|
|
12280
12448
|
|
|
12281
12449
|
# resolve / activate the device object if needed.
|
|
12282
|
-
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId)
|
|
12450
|
+
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
12283
12451
|
|
|
12284
12452
|
# is this an active Sonos device?
|
|
12285
|
-
if (scDevice
|
|
12453
|
+
if (scDevice is not None) and (scDevice.IsSonos):
|
|
12286
12454
|
|
|
12287
12455
|
_logsi.LogVerbose("Issuing command to Sonos device %s: PREVIOUS" % (scDevice.Title))
|
|
12288
|
-
sonosPlayer:
|
|
12456
|
+
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
12289
12457
|
sonosPlayer.previous()
|
|
12290
12458
|
|
|
12291
12459
|
else:
|
|
12292
12460
|
|
|
12293
12461
|
# build spotify web api request parameters.
|
|
12294
12462
|
urlParms:dict = {}
|
|
12295
|
-
|
|
12463
|
+
if (scDevice is not None):
|
|
12464
|
+
urlParms['device_id'] = scDevice.Id
|
|
12296
12465
|
|
|
12297
12466
|
# execute spotify web api request.
|
|
12298
12467
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/previous')
|
|
@@ -12341,11 +12510,14 @@ class SpotifyClient:
|
|
|
12341
12510
|
- `context` - will repeat the current context.
|
|
12342
12511
|
- `off` - will turn repeat off.
|
|
12343
12512
|
Default: `off`
|
|
12344
|
-
deviceId (str):
|
|
12345
|
-
The
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12513
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
12514
|
+
The target player device identifier.
|
|
12515
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
12516
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
12517
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
12518
|
+
for this argument. An exception will be raised if the argument value could
|
|
12519
|
+
not be resolved or activated.
|
|
12520
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
12349
12521
|
delay (float):
|
|
12350
12522
|
Time delay (in seconds) to wait AFTER issuing the command to the player.
|
|
12351
12523
|
This delay will give the spotify web api time to process the change before
|
|
@@ -12386,13 +12558,13 @@ class SpotifyClient:
|
|
|
12386
12558
|
delay = validateDelay(delay, 0.50, 10)
|
|
12387
12559
|
|
|
12388
12560
|
# resolve / activate the device object if needed.
|
|
12389
|
-
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId)
|
|
12561
|
+
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
12390
12562
|
|
|
12391
12563
|
# is this an active Sonos device?
|
|
12392
|
-
if (scDevice
|
|
12564
|
+
if (scDevice is not None) and (scDevice.IsSonos):
|
|
12393
12565
|
|
|
12394
12566
|
# get current Spotify Connect player state.
|
|
12395
|
-
playerState = self.
|
|
12567
|
+
playerState = self.GetPlayerPlaybackStateSonos(scDevice)
|
|
12396
12568
|
|
|
12397
12569
|
# set the Sonos PlayMode directly (instead of setting the Sonos repeat property)!
|
|
12398
12570
|
# The Spotify Web API PlayerState `ShuffleState` value can sometimes be different than what the
|
|
@@ -12409,7 +12581,7 @@ class SpotifyClient:
|
|
|
12409
12581
|
|
|
12410
12582
|
# execute SoCo api request.
|
|
12411
12583
|
_logsi.LogVerbose("Issuing command to Sonos device %s: REPEAT (playmode=%s)" % (scDevice.Title, playMode))
|
|
12412
|
-
sonosPlayer:
|
|
12584
|
+
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
12413
12585
|
sonosPlayer.play_mode = playMode
|
|
12414
12586
|
|
|
12415
12587
|
else:
|
|
@@ -12419,7 +12591,8 @@ class SpotifyClient:
|
|
|
12419
12591
|
{
|
|
12420
12592
|
'state': state
|
|
12421
12593
|
}
|
|
12422
|
-
|
|
12594
|
+
if (scDevice is not None):
|
|
12595
|
+
urlParms['device_id'] = scDevice.Id
|
|
12423
12596
|
|
|
12424
12597
|
# execute spotify web api request.
|
|
12425
12598
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/repeat')
|
|
@@ -12467,11 +12640,14 @@ class SpotifyClient:
|
|
|
12467
12640
|
- `True` - Shuffle user's playback.
|
|
12468
12641
|
- `False` - Do not shuffle user's playback.
|
|
12469
12642
|
Default is False
|
|
12470
|
-
deviceId (str):
|
|
12471
|
-
The
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12643
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
12644
|
+
The target player device identifier.
|
|
12645
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
12646
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
12647
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
12648
|
+
for this argument. An exception will be raised if the argument value could
|
|
12649
|
+
not be resolved or activated.
|
|
12650
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
12475
12651
|
delay (float):
|
|
12476
12652
|
Time delay (in seconds) to wait AFTER issuing the command to the player.
|
|
12477
12653
|
This delay will give the spotify web api time to process the change before
|
|
@@ -12512,13 +12688,13 @@ class SpotifyClient:
|
|
|
12512
12688
|
delay = validateDelay(delay, 0.50, 10)
|
|
12513
12689
|
|
|
12514
12690
|
# resolve / activate the device object if needed.
|
|
12515
|
-
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId)
|
|
12691
|
+
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
12516
12692
|
|
|
12517
12693
|
# is this an active Sonos device?
|
|
12518
|
-
if (scDevice
|
|
12694
|
+
if (scDevice is not None) and (scDevice.IsSonos):
|
|
12519
12695
|
|
|
12520
12696
|
# get current Spotify Connect player state.
|
|
12521
|
-
playerState = self.
|
|
12697
|
+
playerState = self.GetPlayerPlaybackStateSonos(scDevice)
|
|
12522
12698
|
|
|
12523
12699
|
# set the Sonos PlayMode directly (instead of setting the Sonos `shuffle` property)!
|
|
12524
12700
|
# the Spotify Web API PlayerState `RepeatState` value can sometimes be different than what the
|
|
@@ -12536,7 +12712,7 @@ class SpotifyClient:
|
|
|
12536
12712
|
|
|
12537
12713
|
# execute SoCo api request.
|
|
12538
12714
|
_logsi.LogVerbose("Issuing command to Sonos device %s: SHUFFLE (playmode=%s)" % (scDevice.Title, playMode))
|
|
12539
|
-
sonosPlayer:
|
|
12715
|
+
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
12540
12716
|
sonosPlayer.play_mode = playMode
|
|
12541
12717
|
|
|
12542
12718
|
else:
|
|
@@ -12546,7 +12722,8 @@ class SpotifyClient:
|
|
|
12546
12722
|
{
|
|
12547
12723
|
'state': state
|
|
12548
12724
|
}
|
|
12549
|
-
|
|
12725
|
+
if (scDevice is not None):
|
|
12726
|
+
urlParms['device_id'] = scDevice.Id
|
|
12550
12727
|
|
|
12551
12728
|
# execute spotify web api request.
|
|
12552
12729
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/shuffle')
|
|
@@ -12593,11 +12770,14 @@ class SpotifyClient:
|
|
|
12593
12770
|
The volume to set.
|
|
12594
12771
|
Must be a value from 0 to 100 inclusive.
|
|
12595
12772
|
Example: `50`
|
|
12596
|
-
deviceId (str):
|
|
12597
|
-
The
|
|
12598
|
-
|
|
12599
|
-
|
|
12600
|
-
|
|
12773
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
12774
|
+
The target player device identifier.
|
|
12775
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
12776
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
12777
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
12778
|
+
for this argument. An exception will be raised if the argument value could
|
|
12779
|
+
not be resolved or activated.
|
|
12780
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
12601
12781
|
delay (float):
|
|
12602
12782
|
Time delay (in seconds) to wait AFTER issuing the command to the player.
|
|
12603
12783
|
This delay will give the spotify web api time to process the change before
|
|
@@ -12638,13 +12818,13 @@ class SpotifyClient:
|
|
|
12638
12818
|
delay = validateDelay(delay, 0.50, 10)
|
|
12639
12819
|
|
|
12640
12820
|
# resolve / activate the device object if needed.
|
|
12641
|
-
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId)
|
|
12821
|
+
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
12642
12822
|
|
|
12643
12823
|
# is this an active Sonos device?
|
|
12644
|
-
if (scDevice
|
|
12824
|
+
if (scDevice is not None) and (scDevice.IsSonos):
|
|
12645
12825
|
|
|
12646
12826
|
_logsi.LogVerbose("Issuing command to Sonos device %s: VOLUME = %s" % (scDevice.Title, volumePercent))
|
|
12647
|
-
sonosPlayer:
|
|
12827
|
+
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
12648
12828
|
sonosPlayer.volume = volumePercent
|
|
12649
12829
|
|
|
12650
12830
|
else:
|
|
@@ -12654,7 +12834,8 @@ class SpotifyClient:
|
|
|
12654
12834
|
{
|
|
12655
12835
|
'volume_percent': volumePercent
|
|
12656
12836
|
}
|
|
12657
|
-
|
|
12837
|
+
if (scDevice is not None):
|
|
12838
|
+
urlParms['device_id'] = scDevice.Id
|
|
12658
12839
|
|
|
12659
12840
|
# execute spotify web api request.
|
|
12660
12841
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/volume')
|
|
@@ -12692,6 +12873,7 @@ class SpotifyClient:
|
|
|
12692
12873
|
delay:float=0.50,
|
|
12693
12874
|
refreshDeviceList:bool=True,
|
|
12694
12875
|
forceActivateDevice:bool=True,
|
|
12876
|
+
deviceIdFrom:str=None,
|
|
12695
12877
|
) -> None:
|
|
12696
12878
|
"""
|
|
12697
12879
|
Transfer playback to a new Spotify Connect device and optionally begin playback.
|
|
@@ -12699,10 +12881,14 @@ class SpotifyClient:
|
|
|
12699
12881
|
This method requires the `user-modify-playback-state` scope.
|
|
12700
12882
|
|
|
12701
12883
|
Args:
|
|
12702
|
-
deviceId (str):
|
|
12703
|
-
The
|
|
12704
|
-
|
|
12705
|
-
|
|
12884
|
+
deviceId (str | SpotifyConnectDevice) | None):
|
|
12885
|
+
The target player device identifier.
|
|
12886
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
12887
|
+
SpotifyConnectDevice object, or null to utilize the active player device.
|
|
12888
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
12889
|
+
for this argument. An exception will be raised if the argument value could
|
|
12890
|
+
not be resolved or activated.
|
|
12891
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
12706
12892
|
play (bool):
|
|
12707
12893
|
The transfer method:
|
|
12708
12894
|
- `True` - ensure playback happens on new device.
|
|
@@ -12722,6 +12908,13 @@ class SpotifyClient:
|
|
|
12722
12908
|
force the device to reconnect to Spotify Connect; otherwise, False to not
|
|
12723
12909
|
disconnect.
|
|
12724
12910
|
Default is True.
|
|
12911
|
+
deviceIdFrom (str | SpotifyConnectDevice) | None):
|
|
12912
|
+
The player device identifier where play is being transferred from.
|
|
12913
|
+
This could be an id, name, a default device indicator (e.g. "*"), a
|
|
12914
|
+
SpotifyConnectDevice object, or null.
|
|
12915
|
+
A device is considered resolved if a SpotifyConnectDevice object is passed
|
|
12916
|
+
for this argument.
|
|
12917
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
12725
12918
|
|
|
12726
12919
|
Raises:
|
|
12727
12920
|
SpotifyWebApiError:
|
|
@@ -12733,6 +12926,11 @@ class SpotifyClient:
|
|
|
12733
12926
|
This API only works for users who have Spotify Premium.
|
|
12734
12927
|
|
|
12735
12928
|
The order of execution is not guaranteed when you use this API with other Player API endpoints.
|
|
12929
|
+
|
|
12930
|
+
The `deviceIdFrom` argument is not part of the Spotify Web API specification. If a value
|
|
12931
|
+
was supplied, then we will attempt to stop play on the device if it's needed. This is required
|
|
12932
|
+
if transferring playback from a Sonos device that is playing content on its local queue; if you
|
|
12933
|
+
don't stop playback on it, then it and the target device will both be playing!
|
|
12736
12934
|
|
|
12737
12935
|
<details>
|
|
12738
12936
|
<summary>Sample Code</summary>
|
|
@@ -12754,6 +12952,7 @@ class SpotifyClient:
|
|
|
12754
12952
|
apiMethodParms.AppendKeyValue("delay", delay)
|
|
12755
12953
|
apiMethodParms.AppendKeyValue("refreshDeviceList", refreshDeviceList)
|
|
12756
12954
|
apiMethodParms.AppendKeyValue("forceActivateDevice", forceActivateDevice)
|
|
12955
|
+
apiMethodParms.AppendKeyValue("deviceIdFrom", deviceIdFrom)
|
|
12757
12956
|
_logsi.LogMethodParmList(SILevel.Verbose, "Transfer playback to a new Spotify Connect device", apiMethodParms)
|
|
12758
12957
|
|
|
12759
12958
|
# validations.
|
|
@@ -12765,8 +12964,32 @@ class SpotifyClient:
|
|
|
12765
12964
|
if (forceActivateDevice is None):
|
|
12766
12965
|
forceActivateDevice = True
|
|
12767
12966
|
|
|
12967
|
+
# was a from deviceId specified? if so, then we will attempt to stop play on the device
|
|
12968
|
+
# if it's needed. this is required if transferring playback from a Sonos device that is
|
|
12969
|
+
# playing content on its local queue; if you don't stop playback on it, then it and the
|
|
12970
|
+
# target device will both be playing!
|
|
12971
|
+
if (deviceIdFrom is not None):
|
|
12972
|
+
|
|
12973
|
+
# trace.
|
|
12974
|
+
_logsi.LogVerbose("FROM deviceId supplied; checking to see if we need to pause play on device \"%s\" prior to transferring playback to device \"%s\"" % (deviceIdFrom, deviceId))
|
|
12975
|
+
|
|
12976
|
+
# resolve from device object; no need to activate it for what we want here.
|
|
12977
|
+
scDeviceFrom:SpotifyConnectDevice = self._ResolveDeviceObject(deviceIdFrom, activateDevice=False)
|
|
12978
|
+
|
|
12979
|
+
# if it's a Sonos, then pause the player.
|
|
12980
|
+
# note that for other brands, the Spotify Web API transfer playback takes care of
|
|
12981
|
+
# pausing the player since everything is under the Spotify players control.
|
|
12982
|
+
if (scDeviceFrom is not None) and (scDeviceFrom.IsSonos):
|
|
12983
|
+
self.PlayerMediaPause(scDeviceFrom)
|
|
12984
|
+
|
|
12768
12985
|
# resolve / activate the device object if needed.
|
|
12769
|
-
|
|
12986
|
+
# for transfer playback, we will always activate the device.
|
|
12987
|
+
scDevice = self._ResolveDeviceObject(deviceId, True)
|
|
12988
|
+
|
|
12989
|
+
# if device could not be resolved, then go no further as it will result in a
|
|
12990
|
+
# "device not found" error from the Spotify Web API anyway!
|
|
12991
|
+
if (scDevice is None):
|
|
12992
|
+
raise SpotifyConnectDeviceNotFound("Spotify Player device was not found, and there is no active Spotify player", logsi=_logsi)
|
|
12770
12993
|
|
|
12771
12994
|
# is this a Sonos device?
|
|
12772
12995
|
# if so, then control was automatically transferred by activating the device.
|