spotifywebapiPython 1.0.173__py3-none-any.whl → 1.0.175__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.173.dist-info → spotifywebapiPython-1.0.175.dist-info}/METADATA +1 -1
- {spotifywebapiPython-1.0.173.dist-info → spotifywebapiPython-1.0.175.dist-info}/RECORD +23 -23
- spotifywebapipython/const.py +1 -1
- spotifywebapipython/docs/__init__.html +16 -4
- spotifywebapipython/docs/index.html +3 -3
- spotifywebapipython/docs/search.js +1 -1
- spotifywebapipython/docs/spotifywebapipython/const.html +4 -4
- spotifywebapipython/docs/spotifywebapipython/saappmessages.html +37 -3
- spotifywebapipython/docs/spotifywebapipython/sautils.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/spotifyclient.html +43 -21
- spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html +3 -3
- spotifywebapipython/saappmessages.py +10 -0
- spotifywebapipython/spotifyclient.py +158 -70
- spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py +10 -8
- {spotifywebapiPython-1.0.173.dist-info → spotifywebapiPython-1.0.175.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.173.dist-info → spotifywebapiPython-1.0.175.dist-info}/WHEEL +0 -0
- {spotifywebapiPython-1.0.173.dist-info → spotifywebapiPython-1.0.175.dist-info}/top_level.txt +0 -0
|
@@ -10,6 +10,7 @@ from soco.core import (
|
|
|
10
10
|
)
|
|
11
11
|
from soco.plugins.sharelink import ShareLinkPlugin
|
|
12
12
|
import time
|
|
13
|
+
import threading
|
|
13
14
|
from typing import Tuple, Callable, Union
|
|
14
15
|
from urllib3 import PoolManager, Timeout, HTTPResponse
|
|
15
16
|
from urllib.parse import urlencode
|
|
@@ -208,6 +209,8 @@ class SpotifyClient:
|
|
|
208
209
|
self._SpotifyConnectDiscoveryTimeout:float = float(spotifyConnectDiscoveryTimeout)
|
|
209
210
|
self._SpotifyConnectDirectory:SpotifyConnectDirectoryTask = None
|
|
210
211
|
self._SpotifyConnectDirectoryEnabled:bool = spotifyConnectDirectoryEnabled
|
|
212
|
+
self._SpotifyWebPlayerToken:SpotifyWebPlayerToken = None
|
|
213
|
+
self._SpotifyWebPlayerToken_RLock:threading.RLock = threading.RLock()
|
|
211
214
|
self._TokenStorageDir:str = tokenStorageDir
|
|
212
215
|
self._TokenStorageFile:str = tokenStorageFile
|
|
213
216
|
self._TokenUpdater:Callable = tokenUpdater
|
|
@@ -797,44 +800,54 @@ class SpotifyClient:
|
|
|
797
800
|
credentials are then converted into an authorization access token which is used by
|
|
798
801
|
Spotify Web API endpoints to start playback on the specified device id.
|
|
799
802
|
"""
|
|
800
|
-
result:SpotifyWebPlayerToken = None
|
|
801
|
-
|
|
802
803
|
# are spotify web player credentials configured? if not, then don't bother!
|
|
803
804
|
if (not self._HasSpotifyWebPlayerCredentials):
|
|
804
|
-
return
|
|
805
|
+
return None
|
|
805
806
|
|
|
806
|
-
#
|
|
807
|
-
|
|
807
|
+
# make the following thread-safe, so we don't retrieve multiple tokens.
|
|
808
|
+
with self._SpotifyWebPlayerToken_RLock:
|
|
808
809
|
|
|
809
|
-
#
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
tokenStorageFile=self._TokenStorageFile)
|
|
814
|
-
if tokenWP is not None:
|
|
815
|
-
result = tokenWP.HeaderValue
|
|
816
|
-
_logsi.LogVerbose("Spotify Web Player authorization access token will be used")
|
|
810
|
+
# if token already retrieved and has not expired, then use it.
|
|
811
|
+
if (self._SpotifyWebPlayerToken is not None) and (not self._SpotifyWebPlayerToken.IsExpired):
|
|
812
|
+
_logsi.LogVerbose(SAAppMessages.MSG_SPOTIFY_WEB_PLAYER_TOKEN_INUSE, colorValue=SIColors.Gold)
|
|
813
|
+
return self._SpotifyWebPlayerToken.HeaderValue
|
|
817
814
|
|
|
818
|
-
|
|
815
|
+
# was a device argument passed? if not, then just refresh the token.
|
|
816
|
+
if (scDevice is None):
|
|
819
817
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
818
|
+
# get spotify web player access token info from spotify web player cookie credentials.
|
|
819
|
+
_logsi.LogVerbose(SAAppMessages.MSG_SPOTIFY_WEB_PLAYER_TOKEN_REFRESHED % (self._SpotifyConnectLoginId), colorValue=SIColors.Gold)
|
|
820
|
+
self._SpotifyWebPlayerToken = SpotifyWebPlayerToken(
|
|
821
|
+
profileId=self._SpotifyConnectLoginId,
|
|
822
|
+
tokenStorageDir=self._TokenStorageDir,
|
|
823
|
+
tokenStorageFile=self._TokenStorageFile)
|
|
823
824
|
|
|
824
|
-
|
|
825
|
-
|
|
825
|
+
if self._SpotifyWebPlayerToken is not None:
|
|
826
|
+
_logsi.LogVerbose(SAAppMessages.MSG_SPOTIFY_WEB_PLAYER_TOKEN_INUSE, colorValue=SIColors.Gold)
|
|
827
|
+
return self._SpotifyWebPlayerToken.HeaderValue
|
|
826
828
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
829
|
+
else:
|
|
830
|
+
|
|
831
|
+
# was the device resolved? if not, then don't bother!
|
|
832
|
+
if (not isinstance(scDevice, SpotifyConnectDevice)):
|
|
833
|
+
return None
|
|
834
|
+
|
|
835
|
+
# is the device restricted or Sonos?
|
|
836
|
+
if (scDevice.IsSonos or scDevice.IsRestricted):
|
|
837
|
+
|
|
838
|
+
# get spotify web player access token info from spotify web player cookie credentials.
|
|
839
|
+
_logsi.LogVerbose(SAAppMessages.MSG_SPOTIFY_WEB_PLAYER_TOKEN_REFRESHED % (self._SpotifyConnectLoginId), colorValue=SIColors.Gold)
|
|
840
|
+
self._SpotifyWebPlayerToken = SpotifyWebPlayerToken(
|
|
841
|
+
profileId=self._SpotifyConnectLoginId,
|
|
842
|
+
tokenStorageDir=self._TokenStorageDir,
|
|
843
|
+
tokenStorageFile=self._TokenStorageFile)
|
|
844
|
+
|
|
845
|
+
if self._SpotifyWebPlayerToken is not None:
|
|
846
|
+
_logsi.LogVerbose(SAAppMessages.MSG_SPOTIFY_WEB_PLAYER_TOKEN_INUSE, colorValue=SIColors.Gold)
|
|
847
|
+
return self._SpotifyWebPlayerToken.HeaderValue
|
|
835
848
|
|
|
836
849
|
# return result to caller.
|
|
837
|
-
return
|
|
850
|
+
return None
|
|
838
851
|
|
|
839
852
|
|
|
840
853
|
|
|
@@ -1388,9 +1401,14 @@ class SpotifyClient:
|
|
|
1388
1401
|
# resolve the device object from the device id.
|
|
1389
1402
|
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
1390
1403
|
|
|
1404
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
1405
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
1406
|
+
# note that the token is only used to control "restricted" devices (such as Sonos).
|
|
1407
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue(scDevice)
|
|
1408
|
+
|
|
1391
1409
|
# is this an active Sonos device?
|
|
1392
1410
|
# Sonos device can still be active, even if there is no active device in Spotify playstate.
|
|
1393
|
-
if (scDevice is not None) and (scDevice.IsSonos):
|
|
1411
|
+
if (scDevice is not None) and (scDevice.IsSonos) and (accessTokenHeaderValue is None):
|
|
1394
1412
|
|
|
1395
1413
|
# trace.
|
|
1396
1414
|
_logsi.LogVerbose("Items will be added to Sonos local queue for device: %s" % (scDevice.Title))
|
|
@@ -1429,7 +1447,7 @@ class SpotifyClient:
|
|
|
1429
1447
|
|
|
1430
1448
|
# execute spotify web api request.
|
|
1431
1449
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/queue')
|
|
1432
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
1450
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
1433
1451
|
msg.UrlParameters = urlParms
|
|
1434
1452
|
self.MakeRequest('POST', msg)
|
|
1435
1453
|
|
|
@@ -8463,7 +8481,16 @@ class SpotifyClient:
|
|
|
8463
8481
|
If the Spotify Web API request was for a non-authorization service
|
|
8464
8482
|
and the response contains error information.
|
|
8465
8483
|
SpotifyApiError:
|
|
8466
|
-
If the method fails for any other reason.
|
|
8484
|
+
If the method fails for any other reason.
|
|
8485
|
+
|
|
8486
|
+
<span class="warning">
|
|
8487
|
+
<b>DEPRECATED functionality as of 2024/11/27</b>
|
|
8488
|
+
For unauthorized Spotify Developer Applications, the api endpoint will return a `404 - Resource Not Found` exception if a Spotify Algorithmic playlist is specified.<br/>
|
|
8489
|
+
For authorized Spotify Developer Applications, the api endpoint will return details if a Spotify Algorithmic playlist is specified.<br/>
|
|
8490
|
+
More information about the deprecated functionality can be found on the
|
|
8491
|
+
<a href="https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api" target="_blank">Spotify Developer Forum Blog</a>
|
|
8492
|
+
page.
|
|
8493
|
+
<span>
|
|
8467
8494
|
|
|
8468
8495
|
<details>
|
|
8469
8496
|
<summary>Sample Code</summary>
|
|
@@ -8712,16 +8739,27 @@ class SpotifyClient:
|
|
|
8712
8739
|
If the Spotify Web API request was for a non-authorization service
|
|
8713
8740
|
and the response contains error information.
|
|
8714
8741
|
SpotifyApiError:
|
|
8715
|
-
If the method fails for any other reason.
|
|
8742
|
+
If the method fails for any other reason.
|
|
8743
|
+
|
|
8744
|
+
<span class="warning">
|
|
8745
|
+
<b>Notes regarding `limit_total` processing</b>
|
|
8746
|
+
There appears to be a bug in the Spotify Web API that forces you to use manual paging if
|
|
8747
|
+
utilizing the `fields` argument. It has been found that the API will only return a value
|
|
8748
|
+
of 50 (maximum) or less in the page `total` value if the `fields` argument is supplied.
|
|
8749
|
+
The API will return the total number of playlist items in the page `total` value if the `fields`
|
|
8750
|
+
argument is NOT supplied. A good playlist id to test this on is `1XhVM7jWPrGLTiNiAy97Za`,
|
|
8751
|
+
which is the largest playlist on spotify (4700+ items).
|
|
8752
|
+
<span>
|
|
8753
|
+
|
|
8754
|
+
<span class="warning">
|
|
8755
|
+
<b>DEPRECATED functionality as of 2024/11/27</b>
|
|
8756
|
+
Spotify Algorithmic playlists (e.g. "Made For You", "Daily Mix n", etc) will no longer be included
|
|
8757
|
+
in the returned results for unauthorized Spotify Developer Applications; they will be included in
|
|
8758
|
+
the results for authorized Spotify Developer Applications. More information about the deprecated
|
|
8759
|
+
functionality can be found on the <a href="https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api"
|
|
8760
|
+
target="_blank">Spotify Developer Forum Blog</a> page.
|
|
8761
|
+
<span>
|
|
8716
8762
|
|
|
8717
|
-
* Notes regarding `limit_total` processing.
|
|
8718
|
-
There appears to be a bug in the Spotify Web API that forces you to use manual paging if
|
|
8719
|
-
utilizing the `fields` argument. It has been found that the API will only return a value
|
|
8720
|
-
of 50 (maximum) or less in the page `total` value if the `fields` argument is supplied.
|
|
8721
|
-
The API will return the total number of playlist items in the page `total` value if the `fields`
|
|
8722
|
-
argument is NOT supplied. A good playlist id to test this on is `1XhVM7jWPrGLTiNiAy97Za`,
|
|
8723
|
-
which is the largest playlist on spotify (4700+ items).
|
|
8724
|
-
|
|
8725
8763
|
<details>
|
|
8726
8764
|
<summary>Sample Code - Manual Paging</summary>
|
|
8727
8765
|
```python
|
|
@@ -8752,6 +8790,10 @@ class SpotifyClient:
|
|
|
8752
8790
|
apiMethodParms.AppendKeyValue("limitTotal", limitTotal)
|
|
8753
8791
|
_logsi.LogMethodParmList(SILevel.Verbose, "Get full details of the items of a playlist owned by a Spotify user", apiMethodParms)
|
|
8754
8792
|
|
|
8793
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
8794
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
8795
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue()
|
|
8796
|
+
|
|
8755
8797
|
# validations.
|
|
8756
8798
|
if limit is None:
|
|
8757
8799
|
limit = 20
|
|
@@ -8796,7 +8838,7 @@ class SpotifyClient:
|
|
|
8796
8838
|
|
|
8797
8839
|
# execute spotify web api request.
|
|
8798
8840
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/playlists/{id}/tracks'.format(id=playlistId))
|
|
8799
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
8841
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
8800
8842
|
msg.UrlParameters = urlParms
|
|
8801
8843
|
self.MakeRequest('GET', msg)
|
|
8802
8844
|
|
|
@@ -8891,13 +8933,17 @@ class SpotifyClient:
|
|
|
8891
8933
|
If the Spotify Web API request was for a non-authorization service
|
|
8892
8934
|
and the response contains error information.
|
|
8893
8935
|
SpotifyApiError:
|
|
8894
|
-
If the method fails for any other reason.
|
|
8936
|
+
If the method fails for any other reason.
|
|
8937
|
+
|
|
8938
|
+
<span class="warning">
|
|
8939
|
+
<b>DEPRECATED functionality as of 2024/11/27</b>
|
|
8940
|
+
Spotify Algorithmic playlists (e.g. "Made For You", "Daily Mix n", etc) will no longer be included
|
|
8941
|
+
in the returned results for unauthorized Spotify Developer Applications; they will be included in
|
|
8942
|
+
the results for authorized Spotify Developer Applications. More information about the deprecated
|
|
8943
|
+
functionality can be found on the <a href="https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api"
|
|
8944
|
+
target="_blank">Spotify Developer Forum Blog</a> page.
|
|
8945
|
+
<span>
|
|
8895
8946
|
|
|
8896
|
-
As of 2024/11/27, the Spotify Web API will only return user-defined playlists in the results. It will
|
|
8897
|
-
not return any Spotify Algorithmic playlists (e.g. "Daily Mix 1", "Discover Weekly", and other "Made For You"
|
|
8898
|
-
playlists). It will also not return playlist folders. More information can be found on the [Spotify Developer
|
|
8899
|
-
Forum Blog post](https://developer.spotify.com/blog/2024-11-27-changes-to-the-web-api) that was conveyed on November 27, 2024.
|
|
8900
|
-
|
|
8901
8947
|
<details>
|
|
8902
8948
|
<summary>Sample Code - Manual Paging</summary>
|
|
8903
8949
|
```python
|
|
@@ -11753,7 +11799,7 @@ class SpotifyClient:
|
|
|
11753
11799
|
This API only works for users who have Spotify Premium.
|
|
11754
11800
|
|
|
11755
11801
|
The order of execution is not guaranteed when you use this API with other Player API endpoints.
|
|
11756
|
-
|
|
11802
|
+
|
|
11757
11803
|
<details>
|
|
11758
11804
|
<summary>Sample Code</summary>
|
|
11759
11805
|
```python
|
|
@@ -11778,9 +11824,14 @@ class SpotifyClient:
|
|
|
11778
11824
|
# resolve the device object from the device id.
|
|
11779
11825
|
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
11780
11826
|
|
|
11827
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
11828
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
11829
|
+
# note that the token is only used to control "restricted" devices (such as Sonos).
|
|
11830
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue(scDevice)
|
|
11831
|
+
|
|
11781
11832
|
# is this an active Sonos device?
|
|
11782
11833
|
# Sonos device can still be active, even if there is no active device in Spotify playstate.
|
|
11783
|
-
if (scDevice is not None) and (scDevice.IsSonos):
|
|
11834
|
+
if (scDevice is not None) and (scDevice.IsSonos) and (accessTokenHeaderValue is None):
|
|
11784
11835
|
|
|
11785
11836
|
_logsi.LogVerbose("Issuing command to Sonos device %s: PAUSE" % (scDevice.Title))
|
|
11786
11837
|
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
@@ -11799,7 +11850,7 @@ class SpotifyClient:
|
|
|
11799
11850
|
|
|
11800
11851
|
# execute spotify web api request.
|
|
11801
11852
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/pause')
|
|
11802
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
11853
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
11803
11854
|
msg.UrlParameters = urlParms
|
|
11804
11855
|
self.MakeRequest('PUT', msg)
|
|
11805
11856
|
|
|
@@ -12470,9 +12521,14 @@ class SpotifyClient:
|
|
|
12470
12521
|
# we activate the device here, as it may have been paused for a long time.
|
|
12471
12522
|
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, True)
|
|
12472
12523
|
|
|
12524
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
12525
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
12526
|
+
# note that the token is only used to control "restricted" devices (such as Sonos).
|
|
12527
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue(scDevice)
|
|
12528
|
+
|
|
12473
12529
|
# is this an active Sonos device?
|
|
12474
12530
|
# Sonos device can still be active, even if there is no active device in Spotify playstate.
|
|
12475
|
-
if (scDevice is not None) and (scDevice.IsSonos):
|
|
12531
|
+
if (scDevice is not None) and (scDevice.IsSonos) and (accessTokenHeaderValue is None):
|
|
12476
12532
|
|
|
12477
12533
|
_logsi.LogVerbose("Issuing command to Sonos device %s: PLAY (RESUME)" % (scDevice.Title))
|
|
12478
12534
|
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
@@ -12491,7 +12547,7 @@ class SpotifyClient:
|
|
|
12491
12547
|
|
|
12492
12548
|
# execute spotify web api request.
|
|
12493
12549
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/play')
|
|
12494
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
12550
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
12495
12551
|
msg.UrlParameters = urlParms
|
|
12496
12552
|
self.MakeRequest('PUT', msg)
|
|
12497
12553
|
|
|
@@ -12627,9 +12683,14 @@ class SpotifyClient:
|
|
|
12627
12683
|
newPositionMS = 0
|
|
12628
12684
|
positionMS = newPositionMS
|
|
12629
12685
|
|
|
12686
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
12687
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
12688
|
+
# note that the token is only used to control "restricted" devices (such as Sonos).
|
|
12689
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue(scDevice)
|
|
12690
|
+
|
|
12630
12691
|
# is this an active Sonos device?
|
|
12631
12692
|
# Sonos device can still be active, even if there is no active device in Spotify playstate.
|
|
12632
|
-
if (scDevice is not None) and (scDevice.IsSonos):
|
|
12693
|
+
if (scDevice is not None) and (scDevice.IsSonos) and (accessTokenHeaderValue is None):
|
|
12633
12694
|
|
|
12634
12695
|
sonosPosition:str = mediaPositionHMS_fromSeconds(positionMS / 1000) # convert from milliseconds to Sonos H:MM:SS format
|
|
12635
12696
|
_logsi.LogVerbose("Issuing command to Sonos device %s: SEEK (sonosPosition=%s)" % (scDevice.Title, sonosPosition))
|
|
@@ -12652,7 +12713,7 @@ class SpotifyClient:
|
|
|
12652
12713
|
|
|
12653
12714
|
# execute spotify web api request.
|
|
12654
12715
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/seek')
|
|
12655
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
12716
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
12656
12717
|
msg.UrlParameters = urlParms
|
|
12657
12718
|
self.MakeRequest('PUT', msg)
|
|
12658
12719
|
|
|
@@ -12739,9 +12800,14 @@ class SpotifyClient:
|
|
|
12739
12800
|
# resolve the device object from the device id.
|
|
12740
12801
|
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
12741
12802
|
|
|
12803
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
12804
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
12805
|
+
# note that the token is only used to control "restricted" devices (such as Sonos).
|
|
12806
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue(scDevice)
|
|
12807
|
+
|
|
12742
12808
|
# is this an active Sonos device?
|
|
12743
12809
|
# Sonos device can still be active, even if there is no active device in Spotify playstate.
|
|
12744
|
-
if (scDevice is not None) and (scDevice.IsSonos):
|
|
12810
|
+
if (scDevice is not None) and (scDevice.IsSonos) and (accessTokenHeaderValue is None):
|
|
12745
12811
|
|
|
12746
12812
|
_logsi.LogVerbose("Issuing command to Sonos device %s: NEXT" % (scDevice.Title))
|
|
12747
12813
|
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
@@ -12760,7 +12826,7 @@ class SpotifyClient:
|
|
|
12760
12826
|
|
|
12761
12827
|
# execute spotify web api request.
|
|
12762
12828
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/next')
|
|
12763
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
12829
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
12764
12830
|
msg.UrlParameters = urlParms
|
|
12765
12831
|
self.MakeRequest('POST', msg)
|
|
12766
12832
|
|
|
@@ -12847,9 +12913,14 @@ class SpotifyClient:
|
|
|
12847
12913
|
# resolve the device object from the device id.
|
|
12848
12914
|
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
12849
12915
|
|
|
12916
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
12917
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
12918
|
+
# note that the token is only used to control "restricted" devices (such as Sonos).
|
|
12919
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue(scDevice)
|
|
12920
|
+
|
|
12850
12921
|
# is this an active Sonos device?
|
|
12851
12922
|
# Sonos device can still be active, even if there is no active device in Spotify playstate.
|
|
12852
|
-
if (scDevice is not None) and (scDevice.IsSonos):
|
|
12923
|
+
if (scDevice is not None) and (scDevice.IsSonos) and (accessTokenHeaderValue is None):
|
|
12853
12924
|
|
|
12854
12925
|
_logsi.LogVerbose("Issuing command to Sonos device %s: PREVIOUS" % (scDevice.Title))
|
|
12855
12926
|
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
@@ -12868,7 +12939,7 @@ class SpotifyClient:
|
|
|
12868
12939
|
|
|
12869
12940
|
# execute spotify web api request.
|
|
12870
12941
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/previous')
|
|
12871
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
12942
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
12872
12943
|
msg.UrlParameters = urlParms
|
|
12873
12944
|
self.MakeRequest('POST', msg)
|
|
12874
12945
|
|
|
@@ -12963,9 +13034,14 @@ class SpotifyClient:
|
|
|
12963
13034
|
# resolve the device object from the device id.
|
|
12964
13035
|
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
12965
13036
|
|
|
13037
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
13038
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
13039
|
+
# note that the token is only used to control "restricted" devices (such as Sonos).
|
|
13040
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue(scDevice)
|
|
13041
|
+
|
|
12966
13042
|
# is this an active Sonos device?
|
|
12967
13043
|
# Sonos device can still be active, even if there is no active device in Spotify playstate.
|
|
12968
|
-
if (scDevice is not None) and (scDevice.IsSonos):
|
|
13044
|
+
if (scDevice is not None) and (scDevice.IsSonos) and (accessTokenHeaderValue is None):
|
|
12969
13045
|
|
|
12970
13046
|
# get current Spotify Connect player state.
|
|
12971
13047
|
playerState = self.GetPlayerPlaybackStateSonos(scDevice)
|
|
@@ -13004,7 +13080,7 @@ class SpotifyClient:
|
|
|
13004
13080
|
|
|
13005
13081
|
# execute spotify web api request.
|
|
13006
13082
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/repeat')
|
|
13007
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
13083
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
13008
13084
|
msg.UrlParameters = urlParms
|
|
13009
13085
|
self.MakeRequest('PUT', msg)
|
|
13010
13086
|
|
|
@@ -13098,9 +13174,14 @@ class SpotifyClient:
|
|
|
13098
13174
|
# resolve the device object from the device id.
|
|
13099
13175
|
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
13100
13176
|
|
|
13177
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
13178
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
13179
|
+
# note that the token is only used to control "restricted" devices (such as Sonos).
|
|
13180
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue(scDevice)
|
|
13181
|
+
|
|
13101
13182
|
# is this an active Sonos device?
|
|
13102
13183
|
# Sonos device can still be active, even if there is no active device in Spotify playstate.
|
|
13103
|
-
if (scDevice is not None) and (scDevice.IsSonos):
|
|
13184
|
+
if (scDevice is not None) and (scDevice.IsSonos) and (accessTokenHeaderValue is None):
|
|
13104
13185
|
|
|
13105
13186
|
# get current Spotify Connect player state.
|
|
13106
13187
|
playerState = self.GetPlayerPlaybackStateSonos(scDevice)
|
|
@@ -13140,7 +13221,7 @@ class SpotifyClient:
|
|
|
13140
13221
|
|
|
13141
13222
|
# execute spotify web api request.
|
|
13142
13223
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/shuffle')
|
|
13143
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
13224
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
13144
13225
|
msg.UrlParameters = urlParms
|
|
13145
13226
|
self.MakeRequest('PUT', msg)
|
|
13146
13227
|
|
|
@@ -13233,9 +13314,14 @@ class SpotifyClient:
|
|
|
13233
13314
|
# resolve the device object from the device id.
|
|
13234
13315
|
scDevice:SpotifyConnectDevice = self._ResolveDeviceObject(deviceId, False)
|
|
13235
13316
|
|
|
13317
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
13318
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
13319
|
+
# note that the token is only used to control "restricted" devices (such as Sonos).
|
|
13320
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue(scDevice)
|
|
13321
|
+
|
|
13236
13322
|
# is this an active Sonos device?
|
|
13237
13323
|
# Sonos device can still be active, even if there is no active device in Spotify playstate.
|
|
13238
|
-
if (scDevice is not None) and (scDevice.IsSonos):
|
|
13324
|
+
if (scDevice is not None) and (scDevice.IsSonos) and (accessTokenHeaderValue is None):
|
|
13239
13325
|
|
|
13240
13326
|
_logsi.LogVerbose("Issuing command to Sonos device %s: VOLUME = %s" % (scDevice.Title, volumePercent))
|
|
13241
13327
|
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
@@ -13257,7 +13343,7 @@ class SpotifyClient:
|
|
|
13257
13343
|
|
|
13258
13344
|
# execute spotify web api request.
|
|
13259
13345
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player/volume')
|
|
13260
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
13346
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
13261
13347
|
msg.UrlParameters = urlParms
|
|
13262
13348
|
self.MakeRequest('PUT', msg)
|
|
13263
13349
|
|
|
@@ -13407,12 +13493,16 @@ class SpotifyClient:
|
|
|
13407
13493
|
# if not, then raise an exception as the Spotify Web API request will fail anyway.
|
|
13408
13494
|
self._CheckForDeviceNotFound(scDevice, deviceId)
|
|
13409
13495
|
|
|
13496
|
+
# are spotify web player credentials configured? if so, then we will use them to create
|
|
13497
|
+
# an elevated authorization access token for the Spotify Web API endpoint call.
|
|
13498
|
+
accessTokenHeaderValue:str = self._GetSpotifyWebPlayerTokenHeaderValue()
|
|
13499
|
+
|
|
13410
13500
|
# is this a Sonos device?
|
|
13411
13501
|
# if so, then control was automatically transferred by activating the device.
|
|
13412
13502
|
# note that the Spotify Web API cannot stop nor start play on the device either,
|
|
13413
13503
|
# as it's considered a restricted device and the Spotify Web API cannot control it!
|
|
13414
13504
|
# all requests to control the device will be made via the Sonos Controller API.
|
|
13415
|
-
if (scDevice.IsSonos):
|
|
13505
|
+
if (scDevice.IsSonos) and (accessTokenHeaderValue is None):
|
|
13416
13506
|
|
|
13417
13507
|
# get Sonos Controller instance for the device.
|
|
13418
13508
|
sonosPlayer:SoCo = self.SpotifyConnectDirectory.GetSonosPlayer(scDevice)
|
|
@@ -13427,13 +13517,11 @@ class SpotifyClient:
|
|
|
13427
13517
|
wasCmdIssued:bool = False
|
|
13428
13518
|
if currentTransportState == 'PLAYING':
|
|
13429
13519
|
if play == False:
|
|
13430
|
-
|
|
13431
|
-
sonosPlayer.pause()
|
|
13520
|
+
self.PlayerMediaPause(scDevice)
|
|
13432
13521
|
wasCmdIssued = True
|
|
13433
13522
|
elif currentTransportState in ['PAUSED_PLAYBACK','STOPPED','TRANSITIONING']:
|
|
13434
13523
|
if play == True:
|
|
13435
|
-
|
|
13436
|
-
sonosPlayer.play()
|
|
13524
|
+
self.PlayerMediaResume(scDevice)
|
|
13437
13525
|
wasCmdIssued = True
|
|
13438
13526
|
|
|
13439
13527
|
# give Sonos Controller time to process the change.
|
|
@@ -13476,7 +13564,7 @@ class SpotifyClient:
|
|
|
13476
13564
|
|
|
13477
13565
|
# execute spotify web api request.
|
|
13478
13566
|
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, '/me/player')
|
|
13479
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
13567
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = accessTokenHeaderValue or self.AuthToken.HeaderValue
|
|
13480
13568
|
msg.RequestJson = reqData
|
|
13481
13569
|
self.MakeRequest('PUT', msg)
|
|
13482
13570
|
|
|
@@ -1057,18 +1057,20 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
1057
1057
|
|
|
1058
1058
|
# if Sonos Controller instance is the group coordinator then we are done.
|
|
1059
1059
|
if (sonosPlayer.is_coordinator):
|
|
1060
|
-
_logsi.
|
|
1060
|
+
if _logsi.IsOn(SILevel.Verbose):
|
|
1061
|
+
_logsi.LogVerbose("Sonos Controller instance is a group coordinator for device: %s" % (device.Title))
|
|
1062
|
+
_logsi.LogObject(SILevel.Verbose, "Sonos Controller instance for device: %s" % (device.Title), sonosPlayer)
|
|
1063
|
+
_logsi.LogDictionary(SILevel.Verbose, "Sonos Controller instance for device: %s (speaker_info)" % (device.Title), sonosPlayer.speaker_info)
|
|
1064
|
+
_logsi.LogObject(SILevel.Verbose, "Sonos Controller instance for device: %s (group)" % (device.Title), sonosPlayer.group)
|
|
1065
|
+
_logsi.LogObject(SILevel.Verbose, "Sonos Controller instance for device: %s (zone_group_state)" % (device.Title), sonosPlayer.zone_group_state)
|
|
1066
|
+
return sonosPlayer
|
|
1067
|
+
|
|
1068
|
+
# trace.
|
|
1069
|
+
if _logsi.IsOn(SILevel.Verbose):
|
|
1061
1070
|
_logsi.LogObject(SILevel.Verbose, "Sonos Controller instance for device: %s" % (device.Title), sonosPlayer)
|
|
1062
1071
|
_logsi.LogDictionary(SILevel.Verbose, "Sonos Controller instance for device: %s (speaker_info)" % (device.Title), sonosPlayer.speaker_info)
|
|
1063
1072
|
_logsi.LogObject(SILevel.Verbose, "Sonos Controller instance for device: %s (group)" % (device.Title), sonosPlayer.group)
|
|
1064
1073
|
_logsi.LogObject(SILevel.Verbose, "Sonos Controller instance for device: %s (zone_group_state)" % (device.Title), sonosPlayer.zone_group_state)
|
|
1065
|
-
return sonosPlayer
|
|
1066
|
-
|
|
1067
|
-
# trace.
|
|
1068
|
-
_logsi.LogObject(SILevel.Verbose, "Sonos Controller instance for device: %s" % (device.Title), sonosPlayer)
|
|
1069
|
-
_logsi.LogDictionary(SILevel.Verbose, "Sonos Controller instance for device: %s (speaker_info)" % (device.Title), sonosPlayer.speaker_info)
|
|
1070
|
-
_logsi.LogObject(SILevel.Verbose, "Sonos Controller instance for device: %s (group)" % (device.Title), sonosPlayer.group)
|
|
1071
|
-
_logsi.LogObject(SILevel.Verbose, "Sonos Controller instance for device: %s (zone_group_state)" % (device.Title), sonosPlayer.zone_group_state)
|
|
1072
1074
|
|
|
1073
1075
|
# is the device part of a group? if so, then use the group coordinator.
|
|
1074
1076
|
if (sonosPlayer.group is not None):
|
|
File without changes
|
|
File without changes
|
{spotifywebapiPython-1.0.173.dist-info → spotifywebapiPython-1.0.175.dist-info}/top_level.txt
RENAMED
|
File without changes
|