spotifywebapiPython 1.0.150__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.150.dist-info → spotifywebapiPython-1.0.152.dist-info}/METADATA +2 -1
- {spotifywebapiPython-1.0.150.dist-info → spotifywebapiPython-1.0.152.dist-info}/RECORD +26 -26
- spotifywebapipython/const.py +6 -1
- spotifywebapipython/docs/__init__.html +15 -2
- spotifywebapipython/docs/index.html +2 -2
- spotifywebapipython/docs/search.js +1 -1
- spotifywebapipython/docs/spotifywebapipython/const.html +20 -3
- spotifywebapipython/docs/spotifywebapipython/saappmessages.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/sautils.html +65 -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 -120
- 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/models/spotifyconnectdevice.py +12 -0
- spotifywebapipython/sautils.py +50 -0
- spotifywebapipython/spotifyclient.py +847 -296
- spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py +98 -16
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfexceptions.py +10 -0
- {spotifywebapiPython-1.0.150.dist-info → spotifywebapiPython-1.0.152.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.150.dist-info → spotifywebapiPython-1.0.152.dist-info}/WHEEL +0 -0
- {spotifywebapiPython-1.0.150.dist-info → spotifywebapiPython-1.0.152.dist-info}/top_level.txt +0 -0
|
@@ -6,12 +6,14 @@ from datetime import datetime
|
|
|
6
6
|
import hashlib
|
|
7
7
|
from pychromecast import CastBrowser, CastInfo, Chromecast, get_chromecast_from_cast_info
|
|
8
8
|
import socket
|
|
9
|
+
from soco import SoCo
|
|
9
10
|
import threading
|
|
10
11
|
import time
|
|
11
12
|
from uuid import UUID
|
|
12
13
|
from zeroconf import Zeroconf, ServiceBrowser
|
|
13
14
|
|
|
14
15
|
# our package imports.
|
|
16
|
+
from .spotifyconnectzeroconfexceptions import SpotifyConnectDeviceNotFound
|
|
15
17
|
from .spotifyconnectzeroconfcastapptask import SpotifyConnectZeroconfCastAppTask
|
|
16
18
|
from .spotifyconnectzeroconfcastlistener import SpotifyConnectZeroconfCastListener
|
|
17
19
|
from .spotifyconnectdeviceeventargs import SpotifyConnectDeviceEventArgs
|
|
@@ -101,6 +103,7 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
101
103
|
self._CastBrowser:CastBrowser = None
|
|
102
104
|
self._InitialDiscoveryTimeout = initialDiscoveryTimeout
|
|
103
105
|
self._IsStopRequested:bool = False
|
|
106
|
+
self._SonosPlayers:dict = {}
|
|
104
107
|
self._SpotifyClientInstance = spotifyClientInstance
|
|
105
108
|
self._SpotifyConnectBrowser:ServiceBrowser = None
|
|
106
109
|
self._SpotifyConnectDevices:SpotifyConnectDevices = SpotifyConnectDevices()
|
|
@@ -731,33 +734,42 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
731
734
|
self,
|
|
732
735
|
value:str,
|
|
733
736
|
refreshDynamicDevices:bool=True,
|
|
737
|
+
raiseExceptionIfNotFound:bool=True,
|
|
734
738
|
) -> SpotifyConnectDevice:
|
|
735
739
|
"""
|
|
736
|
-
Returns a `SpotifyConnectDevice` object for the specified device name / id if found
|
|
737
|
-
|
|
740
|
+
Returns a `SpotifyConnectDevice` object for the specified device name / id if found
|
|
741
|
+
in the devices collection. otherwise, returns the currently active player
|
|
742
|
+
`SpotifyConnectDevice` object is returned. otherwise, null is returned.
|
|
738
743
|
|
|
739
744
|
Args:
|
|
740
|
-
value (str):
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
745
|
+
value (str | None):
|
|
746
|
+
The target player device identifier.
|
|
747
|
+
This could be an id, name, a default device indicator (e.g. "*"), or null
|
|
748
|
+
to utilize the active player device.
|
|
749
|
+
Examples are `0d1841b0976bae2a3a310dd74c0f3df354899bc8`, `Office`, `*`, None.
|
|
744
750
|
refreshDynamicDevices (bool):
|
|
745
751
|
True to refresh the list of dynamically added devices and the active player
|
|
746
752
|
state from real-time Spotify Web API data; otherwise, false to use the
|
|
747
753
|
current cached state and device list.
|
|
748
754
|
Default is True.
|
|
755
|
+
raiseExceptionIfNotFound (bool):
|
|
756
|
+
True to raise an exception if a device could not be resolved;
|
|
757
|
+
otherwise, False to just return a null value.
|
|
758
|
+
Default is True.
|
|
749
759
|
|
|
750
760
|
Returns:
|
|
751
|
-
A `SpotifyConnectDevice` object for the specified device name / id
|
|
761
|
+
A `SpotifyConnectDevice` object for the specified device name / id if found;
|
|
762
|
+
otherwise, null.
|
|
752
763
|
|
|
753
764
|
Raises:
|
|
765
|
+
SpotifyConnectDeviceNotFound:
|
|
766
|
+
If the `raiseExceptionIfNotFound` argument value is True, and the specified
|
|
767
|
+
device value was not found or there was no default device found.
|
|
754
768
|
SpotifyApiError:
|
|
755
|
-
If the specified device value was not found.
|
|
756
|
-
If there was no defaualt device found.
|
|
757
769
|
If an error occured while obtaining current Spotify Web API Player device data.
|
|
758
770
|
|
|
759
|
-
|
|
760
|
-
to the copy do not affect the internal master device entry.
|
|
771
|
+
If a SpotifyConnectDevice object is returned, it will be a copy of the internal master
|
|
772
|
+
device entry; any changes made to the copy do not affect the internal master device entry.
|
|
761
773
|
|
|
762
774
|
<details>
|
|
763
775
|
<summary>Sample Code</summary>
|
|
@@ -788,6 +800,8 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
788
800
|
value = None
|
|
789
801
|
if (not isinstance(refreshDynamicDevices, bool)):
|
|
790
802
|
refreshDynamicDevices = True
|
|
803
|
+
if (not isinstance(raiseExceptionIfNotFound, bool)):
|
|
804
|
+
raiseExceptionIfNotFound = True
|
|
791
805
|
valueOriginal:str = value
|
|
792
806
|
|
|
793
807
|
# get currently active player device.
|
|
@@ -804,6 +818,10 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
804
818
|
_logsi.LogObject(SILevel.Verbose, "Spotify Player device \"%s\" (%s) was found in the Spotify Connect Devices collection (by Active PlayerState)" % (scActiveDevice.Name, scActiveDevice.Id), scActiveDevice, excludeNonPublic=True)
|
|
805
819
|
return scActiveDevice
|
|
806
820
|
|
|
821
|
+
# if no active player device, then let's use the default device value.
|
|
822
|
+
_logsi.LogVerbose("Spotify Player has no active device; defaulting device selection to use DefaultDeviceId: \"%s\"" % (self.SpotifyClientInstance.DefaultDeviceId))
|
|
823
|
+
value = self.SpotifyClientInstance.DefaultDeviceId
|
|
824
|
+
|
|
807
825
|
# was a default device value specified?
|
|
808
826
|
# if so, then use the `defaultDeviceId` value; if the `defaultDeviceId` value is not in the device list,
|
|
809
827
|
# then we will catch it with the `GetDeviceById` / `GetDeviceByName` logic.
|
|
@@ -822,7 +840,7 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
822
840
|
_logsi.LogObject(SILevel.Verbose, "Spotify Player default device (*) was not configured; using active player device: %s" % (scActiveDevice.Title), scActiveDevice, excludeNonPublic=True)
|
|
823
841
|
return scActiveDevice
|
|
824
842
|
# if no default device and no active player, then it's an error!
|
|
825
|
-
raise SpotifyApiError("Spotify Player default device (*) was not configured, and there is no active Spotify Player device", logsi=_logsi)
|
|
843
|
+
#raise SpotifyApiError("Spotify Player default device (*) was not configured, and there is no active Spotify Player device", logsi=_logsi)
|
|
826
844
|
|
|
827
845
|
# assign default device value.
|
|
828
846
|
_logsi.LogVerbose("Spotify Player device default \"%s\" will be used for selecting a device (by default *)" % (defaultDeviceId))
|
|
@@ -858,8 +876,13 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
858
876
|
_logsi.LogObject(SILevel.Verbose, "Spotify Player default device \"%s\" was not found in the Spotify Connect Devices collection; using active player device: %s" % (value, scActiveDevice.Title), scActiveDevice, excludeNonPublic=True)
|
|
859
877
|
return scActiveDevice
|
|
860
878
|
|
|
861
|
-
# at this point we could not resolve the device name / id
|
|
862
|
-
raise
|
|
879
|
+
# at this point we could not resolve the device name / id, and there is no active player
|
|
880
|
+
# available; raise exception / return null as requested by the caller.
|
|
881
|
+
if (raiseExceptionIfNotFound):
|
|
882
|
+
raise SpotifyConnectDeviceNotFound("Spotify Player device \"%s\" was not found, and there is no active Spotify player" % (value))
|
|
883
|
+
else:
|
|
884
|
+
_logsi.LogVerbose("Spotify Player device \"%s\" was not found, and there is no active Spotify player" % (value))
|
|
885
|
+
return None
|
|
863
886
|
|
|
864
887
|
except SpotifyApiError: raise # pass handled exceptions on thru
|
|
865
888
|
except Exception as ex:
|
|
@@ -957,6 +980,50 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
957
980
|
return result
|
|
958
981
|
|
|
959
982
|
|
|
983
|
+
def GetSonosPlayer(
|
|
984
|
+
self,
|
|
985
|
+
device:SpotifyConnectDevice,
|
|
986
|
+
) -> SoCo:
|
|
987
|
+
"""
|
|
988
|
+
Returns the Sonos Controller instance for the specified Spotify Connect device.
|
|
989
|
+
Returns the Sonos player instance for the specified Spotify Connect Sonos device.
|
|
990
|
+
|
|
991
|
+
Args:
|
|
992
|
+
device (SpotifyConnectDevice):
|
|
993
|
+
Spotify Connect device instance used to identify the Sonos player.
|
|
994
|
+
|
|
995
|
+
Returns:
|
|
996
|
+
The Sonos Controller instance for the specified Spotify Connect device.
|
|
997
|
+
|
|
998
|
+
Raises:
|
|
999
|
+
SpotifyApiError:
|
|
1000
|
+
If a Sonos Controller instance could not be found for the device id.
|
|
1001
|
+
|
|
1002
|
+
You should invoke "if (scDevice.IsSonos):" logic prior to calling this method, as
|
|
1003
|
+
a Sonos Controller instance will not be created for non-Sonos devices and an exception
|
|
1004
|
+
will be raised!
|
|
1005
|
+
"""
|
|
1006
|
+
apiMethodName:str = "GetSonosPlayer"
|
|
1007
|
+
|
|
1008
|
+
# syncronize access via lock, as we are accessing the collection.
|
|
1009
|
+
with self._SpotifyConnectDevices_RLock:
|
|
1010
|
+
|
|
1011
|
+
result:SpotifyConnectDevice = None
|
|
1012
|
+
|
|
1013
|
+
# validations.
|
|
1014
|
+
if (device is None):
|
|
1015
|
+
raise SpotifyApiError(SAAppMessages.ARGUMENT_REQUIRED_ERROR % (apiMethodName, 'device'), logsi=_logsi)
|
|
1016
|
+
|
|
1017
|
+
# get Sonos Controller instance for device name.
|
|
1018
|
+
sonosPlayer:SoCo = self._SonosPlayers.get(device.DiscoveryResult.HostIpAddress, None)
|
|
1019
|
+
|
|
1020
|
+
# if not found then it's an error.
|
|
1021
|
+
if (sonosPlayer is None):
|
|
1022
|
+
raise SpotifyApiError("Could not find Sonos Controller instance for device: %s" % (device.Title), None, logsi=_logsi)
|
|
1023
|
+
|
|
1024
|
+
return sonosPlayer
|
|
1025
|
+
|
|
1026
|
+
|
|
960
1027
|
def GetSpotifyDeviceIDFromName(
|
|
961
1028
|
self,
|
|
962
1029
|
name:str
|
|
@@ -1013,9 +1080,9 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
1013
1080
|
|
|
1014
1081
|
# trace.
|
|
1015
1082
|
if (scDevice is None):
|
|
1016
|
-
_logsi.LogVerbose("Spotify Player playstate
|
|
1083
|
+
_logsi.LogVerbose("Spotify Player playstate device is not present; no active device")
|
|
1017
1084
|
else:
|
|
1018
|
-
_logsi.LogObject(SILevel.Verbose, "Spotify Player playstate active device instance %s" % (scDevice.Title), scDevice, excludeNonPublic=True)
|
|
1085
|
+
_logsi.LogObject(SILevel.Verbose, "Spotify Player playstate active device instance: %s" % (scDevice.Title), scDevice, excludeNonPublic=True)
|
|
1019
1086
|
|
|
1020
1087
|
# return real-time active Spotify Player device.
|
|
1021
1088
|
return scDevice
|
|
@@ -1738,6 +1805,21 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
1738
1805
|
if (len(self._SpotifyConnectDevices.Items) > 0):
|
|
1739
1806
|
self._SpotifyConnectDevices.Items.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
|
|
1740
1807
|
|
|
1808
|
+
try:
|
|
1809
|
+
|
|
1810
|
+
# if new device is a Sonos, then create a Sonos Controller instance for the device.
|
|
1811
|
+
# use device ip address as the key, as Spotify Web API reports id=null for restricted devices in playerstate!
|
|
1812
|
+
if (scDevice.IsSonos):
|
|
1813
|
+
_logsi.LogVerbose("Sonos device detected; creating Sonos Controller instance for device: %s (ip=%s)" % (scDevice.Title, zeroconfDiscoveryResult.HostIpAddress))
|
|
1814
|
+
self._SonosPlayers[zeroconfDiscoveryResult.HostIpAddress] = SoCo(zeroconfDiscoveryResult.HostIpAddress)
|
|
1815
|
+
|
|
1816
|
+
except:
|
|
1817
|
+
|
|
1818
|
+
# trace.
|
|
1819
|
+
_logsi.LogException("%s - Could not create Sonos Control API reference: %s" % (self.name, str(ex)), ex, logToSystemLogger=False)
|
|
1820
|
+
|
|
1821
|
+
# ignore exceptions, as there is nothing we can do at this point.
|
|
1822
|
+
|
|
1741
1823
|
# raise event.
|
|
1742
1824
|
self._RaiseDeviceAdded(scDevice)
|
|
1743
1825
|
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# our package imports.
|
|
2
|
+
from spotifywebapipython import SpotifyApiError
|
|
3
|
+
|
|
4
|
+
|
|
1
5
|
class SpotifyConnectZeroconfLaunchError(Exception):
|
|
2
6
|
"""
|
|
3
7
|
Exception raised when a cast app fails to launch.
|
|
@@ -8,3 +12,9 @@ class SpotifyConnectZeroconfPlaybackTransferError(Exception):
|
|
|
8
12
|
"""
|
|
9
13
|
Exception raised when a cast app fails to receive transfer of playback control.
|
|
10
14
|
"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class SpotifyConnectDeviceNotFound(SpotifyApiError):
|
|
18
|
+
"""
|
|
19
|
+
Exception raised when a Spotify Connect device could not be resolved.
|
|
20
|
+
"""
|
|
File without changes
|
|
File without changes
|
{spotifywebapiPython-1.0.150.dist-info → spotifywebapiPython-1.0.152.dist-info}/top_level.txt
RENAMED
|
File without changes
|