spotifywebapiPython 1.0.50__py3-none-any.whl → 1.0.51__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.50.dist-info → spotifywebapiPython-1.0.51.dist-info}/METADATA +1 -1
- {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.51.dist-info}/RECORD +25 -23
- 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 +99 -2
- spotifywebapipython/docs/spotifywebapiPython/spotifydiscovery.html +2 -2
- spotifywebapipython/docs/spotifywebapiPython/spotifywebapiauthenticationerror.html +2 -2
- spotifywebapipython/docs/spotifywebapiPython/spotifywebapierror.html +2 -2
- spotifywebapipython/models/__init__.py +2 -0
- spotifywebapipython/models/device.py +50 -0
- spotifywebapipython/models/spotifyconnectdevice.py +93 -0
- spotifywebapipython/models/spotifyconnectdevices.py +137 -0
- spotifywebapipython/models/zeroconfdiscoveryresult.py +0 -5
- spotifywebapipython/spotifyclient.py +81 -0
- {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.51.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.51.dist-info}/WHEEL +0 -0
- {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.51.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# external package imports.
|
|
2
|
+
from zeroconf import ServiceInfo
|
|
3
|
+
|
|
4
|
+
# our package imports.
|
|
5
|
+
from ..sautils import export
|
|
6
|
+
from .zeroconfdiscoveryresult import ZeroconfDiscoveryResult
|
|
7
|
+
from spotifywebapipython.zeroconfapi.zeroconfgetinfo import ZeroconfGetInfo
|
|
8
|
+
|
|
9
|
+
@export
|
|
10
|
+
class SpotifyConnectDevice():
|
|
11
|
+
"""
|
|
12
|
+
Spotify Connect Device object.
|
|
13
|
+
|
|
14
|
+
Information about the Spotify Connect device, which is a combination of the
|
|
15
|
+
`ZeroconfDiscoveryResult` and `ZeroconfGetInfo` classes.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self) -> None:
|
|
19
|
+
"""
|
|
20
|
+
Initializes a new instance of the class.
|
|
21
|
+
"""
|
|
22
|
+
self._DiscoveryResult:ZeroconfDiscoveryResult = None
|
|
23
|
+
self._DeviceInfo:ZeroconfGetInfo = None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def __repr__(self) -> str:
|
|
27
|
+
return self.ToString()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def __str__(self) -> str:
|
|
31
|
+
return self.ToString()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def DiscoveryResult(self) -> ZeroconfDiscoveryResult:
|
|
36
|
+
"""
|
|
37
|
+
Information about the Zeroconf entry for a SpotifyConnect device as found by Zeroconf (mDNS).
|
|
38
|
+
"""
|
|
39
|
+
return self._DiscoveryResult
|
|
40
|
+
|
|
41
|
+
@DiscoveryResult.setter
|
|
42
|
+
def DiscoveryResult(self, value:ZeroconfDiscoveryResult):
|
|
43
|
+
"""
|
|
44
|
+
Sets the DiscoveryResult property value.
|
|
45
|
+
"""
|
|
46
|
+
if isinstance(value, ZeroconfDiscoveryResult):
|
|
47
|
+
self._DiscoveryResult = value
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def DeviceInfo(self) -> ZeroconfGetInfo:
|
|
52
|
+
"""
|
|
53
|
+
Spotify Zeroconf API GetInfo response object.
|
|
54
|
+
"""
|
|
55
|
+
return self._DeviceInfo
|
|
56
|
+
|
|
57
|
+
@DeviceInfo.setter
|
|
58
|
+
def DeviceInfo(self, value:ZeroconfGetInfo):
|
|
59
|
+
"""
|
|
60
|
+
Sets the DeviceInfo property value.
|
|
61
|
+
"""
|
|
62
|
+
if isinstance(value, ZeroconfGetInfo):
|
|
63
|
+
self._DeviceInfo = value
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def ToDictionary(self) -> dict:
|
|
67
|
+
"""
|
|
68
|
+
Returns a dictionary representation of the class.
|
|
69
|
+
"""
|
|
70
|
+
result:dict = \
|
|
71
|
+
{
|
|
72
|
+
'DeviceInfo': self._DeviceInfo.ToDictionary(),
|
|
73
|
+
'DiscoveryResult': self._DiscoveryResult.ToDictionary(),
|
|
74
|
+
}
|
|
75
|
+
return result
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def ToString(self, includeTitle:bool=True) -> str:
|
|
79
|
+
"""
|
|
80
|
+
Returns a displayable string representation of the class.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
includeTitle (str):
|
|
84
|
+
True to include the class name title prefix.
|
|
85
|
+
"""
|
|
86
|
+
msg:str = ''
|
|
87
|
+
if includeTitle:
|
|
88
|
+
msg = 'Device: "%s" (%s)' % (self._DiscoveryResult.DeviceName, self._DeviceInfo.DeviceId)
|
|
89
|
+
|
|
90
|
+
# build result.
|
|
91
|
+
msg = '%s\n %s\n' % (msg, str(self._DeviceInfo.ToString(True)))
|
|
92
|
+
msg = '%s\n %s\n' % (msg, str(self._DiscoveryResult.ToString(True)))
|
|
93
|
+
return msg
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# external package imports.
|
|
2
|
+
from typing import Iterator
|
|
3
|
+
|
|
4
|
+
# our package imports.
|
|
5
|
+
from ..sautils import export
|
|
6
|
+
from .device import Device
|
|
7
|
+
from .spotifyconnectdevice import SpotifyConnectDevice
|
|
8
|
+
from spotifywebapipython.zeroconfapi import ZeroconfGetInfo, ZeroconfGetInfoAlias
|
|
9
|
+
|
|
10
|
+
@export
|
|
11
|
+
class SpotifyConnectDevices():
|
|
12
|
+
"""
|
|
13
|
+
Spotify Connect Devices collection.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self) -> None:
|
|
17
|
+
"""
|
|
18
|
+
Initializes a new instance of the class.
|
|
19
|
+
"""
|
|
20
|
+
self._Items:list[SpotifyConnectDevice] = []
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def __getitem__(self, key) -> SpotifyConnectDevice:
|
|
24
|
+
return self._Presets[key]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def __iter__(self) -> Iterator:
|
|
28
|
+
return iter(self._Items)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def __len__(self) -> int:
|
|
32
|
+
return len(self._Items)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def __repr__(self) -> str:
|
|
36
|
+
return self.ToString()
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def __str__(self) -> str:
|
|
40
|
+
return self.ToString()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def Items(self) -> list[SpotifyConnectDevice]:
|
|
45
|
+
"""
|
|
46
|
+
Array of `SpotifyConnectDevice` objects.
|
|
47
|
+
"""
|
|
48
|
+
return self._Items
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def ItemsCount(self) -> int:
|
|
53
|
+
"""
|
|
54
|
+
Number of objects in the `Items` property array.
|
|
55
|
+
"""
|
|
56
|
+
if self._Items is not None:
|
|
57
|
+
return len(self._Items)
|
|
58
|
+
return 0
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def GetDeviceList(self) -> list[Device]:
|
|
62
|
+
"""
|
|
63
|
+
Returns a list of `Device` objects that can be used to build a selection list
|
|
64
|
+
of available devices.
|
|
65
|
+
|
|
66
|
+
Note that the `Device` object has the following properties populated:
|
|
67
|
+
Id, Name, IsActive, Type.
|
|
68
|
+
"""
|
|
69
|
+
result:list[Device] = []
|
|
70
|
+
|
|
71
|
+
# process all discovered devices.
|
|
72
|
+
scDevice:SpotifyConnectDevice
|
|
73
|
+
for scDevice in self._Items:
|
|
74
|
+
|
|
75
|
+
# map device information details.
|
|
76
|
+
info:ZeroconfGetInfo = scDevice.DeviceInfo
|
|
77
|
+
|
|
78
|
+
# create new mock device.
|
|
79
|
+
device = Device()
|
|
80
|
+
device.IsActive = info.HasActiveUser
|
|
81
|
+
device.Type = info.DeviceType
|
|
82
|
+
|
|
83
|
+
# are aliases being used (RemoteName is null if so)?
|
|
84
|
+
if info.RemoteName is None:
|
|
85
|
+
|
|
86
|
+
# if aliases are defined, then use the alias details.
|
|
87
|
+
infoAlias:ZeroconfGetInfoAlias
|
|
88
|
+
for infoAlias in info.Aliases:
|
|
89
|
+
device.Id = infoAlias.Id
|
|
90
|
+
device.Name = infoAlias.Name
|
|
91
|
+
|
|
92
|
+
else:
|
|
93
|
+
|
|
94
|
+
# if no aliases then use the remote name and id.
|
|
95
|
+
device.Id = info.DeviceId
|
|
96
|
+
device.Name = info.RemoteName
|
|
97
|
+
|
|
98
|
+
# append device to results.
|
|
99
|
+
result.append(device)
|
|
100
|
+
|
|
101
|
+
# sort items on Name property, ascending order.
|
|
102
|
+
if len(result) > 0:
|
|
103
|
+
result.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
|
|
104
|
+
|
|
105
|
+
return result
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def ToDictionary(self) -> dict:
|
|
109
|
+
"""
|
|
110
|
+
Returns a dictionary representation of the class.
|
|
111
|
+
"""
|
|
112
|
+
result:dict = \
|
|
113
|
+
{
|
|
114
|
+
'ItemsCount': self.ItemsCount,
|
|
115
|
+
'Items': [ item.ToDictionary() for item in self._Items ],
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return result
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def ToString(self, includeItems:bool=False) -> str:
|
|
122
|
+
"""
|
|
123
|
+
Returns a displayable string representation of the class.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
includeItems (bool):
|
|
127
|
+
True to include the Items collection of objects; otherwise, False
|
|
128
|
+
to only return base properties.
|
|
129
|
+
"""
|
|
130
|
+
msg:str = 'Items Count=%s' % (str(self.ItemsCount))
|
|
131
|
+
|
|
132
|
+
if (includeItems):
|
|
133
|
+
item:SpotifyConnectDevice
|
|
134
|
+
for item in self._Items:
|
|
135
|
+
msg = "%s\n- %s" % (msg, item.ToString(True))
|
|
136
|
+
|
|
137
|
+
return msg
|
|
@@ -16,11 +16,6 @@ class ZeroconfDiscoveryResult:
|
|
|
16
16
|
def __init__(self) -> None:
|
|
17
17
|
"""
|
|
18
18
|
Initializes a new instance of the class.
|
|
19
|
-
|
|
20
|
-
Args:
|
|
21
|
-
root (dict):
|
|
22
|
-
Spotify Web API JSON response in dictionary format, used to load object
|
|
23
|
-
attributes; otherwise, None to not load attributes.
|
|
24
19
|
"""
|
|
25
20
|
self._DeviceName:str = None
|
|
26
21
|
self._Domain:str = '.'
|
|
@@ -7890,6 +7890,87 @@ class SpotifyClient:
|
|
|
7890
7890
|
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
7891
7891
|
|
|
7892
7892
|
|
|
7893
|
+
def GetSpotifyConnectDevices(
|
|
7894
|
+
self,
|
|
7895
|
+
) -> SpotifyConnectDevices:
|
|
7896
|
+
"""
|
|
7897
|
+
Get information about all available Spotify Connect player devices.
|
|
7898
|
+
|
|
7899
|
+
Returns:
|
|
7900
|
+
A `SpotifyConnectDevices` object that contain the discovery results
|
|
7901
|
+
as well as the `getInfo` result for each found device.
|
|
7902
|
+
|
|
7903
|
+
Raises:
|
|
7904
|
+
SpotifyWebApiError:
|
|
7905
|
+
If the Spotify Web API request was for a non-authorization service
|
|
7906
|
+
and the response contains error information.
|
|
7907
|
+
SpotifyZeroconfApiError:
|
|
7908
|
+
If the Spotify Zeroconf API request faild for any reason.
|
|
7909
|
+
SpotifApiError:
|
|
7910
|
+
If the method fails for any other reason.
|
|
7911
|
+
|
|
7912
|
+
This method is similar to the `GetPlayerDevices` method, but it contains ALL
|
|
7913
|
+
available Spotify Connect devices that are known to the local network (versus
|
|
7914
|
+
just the devices known to a specific user).
|
|
7915
|
+
|
|
7916
|
+
<details>
|
|
7917
|
+
<summary>Sample Code</summary>
|
|
7918
|
+
```python
|
|
7919
|
+
.. include:: ../docs/include/samplecode/SpotifyClient/GetSpotifyConnectDevices.py
|
|
7920
|
+
```
|
|
7921
|
+
</details>
|
|
7922
|
+
"""
|
|
7923
|
+
apiMethodName:str = 'GetSpotifyConnectDevices'
|
|
7924
|
+
result:SpotifyConnectDevices = SpotifyConnectDevices()
|
|
7925
|
+
|
|
7926
|
+
try:
|
|
7927
|
+
|
|
7928
|
+
# trace.
|
|
7929
|
+
_logsi.EnterMethod(SILevel.Debug, apiMethodName)
|
|
7930
|
+
_logsi.LogVerbose("Get all available Spotify Connect devices")
|
|
7931
|
+
|
|
7932
|
+
# discover Spotify Connect devices on the network, waiting up to the specified timeout
|
|
7933
|
+
# for all devices to be discovered. this will return all Spotify Connect devices that
|
|
7934
|
+
# are currently powered on, and are registered to Zeroconf / mDNS.
|
|
7935
|
+
_logsi.LogVerbose("Discovering Spotify Connect devices on the local network")
|
|
7936
|
+
discovery:SpotifyDiscovery = SpotifyDiscovery(self._ZeroconfClient, printToConsole=False)
|
|
7937
|
+
discovery.DiscoverDevices(timeout=self._SpotifyConnectDiscoveryTimeout)
|
|
7938
|
+
|
|
7939
|
+
# process all discovered devices.
|
|
7940
|
+
discoverResult:ZeroconfDiscoveryResult
|
|
7941
|
+
for discoverResult in discovery.DiscoveryResults:
|
|
7942
|
+
|
|
7943
|
+
# get the id from the device via the zeroconf API getInfo endpoint, as the id is not
|
|
7944
|
+
# returned in the zeroconf discovery result.
|
|
7945
|
+
zconn:ZeroconfConnect = ZeroconfConnect(discoverResult.HostIpv4Address,
|
|
7946
|
+
discoverResult.HostIpPort,
|
|
7947
|
+
discoverResult.SpotifyConnectCPath,
|
|
7948
|
+
useSSL=False)
|
|
7949
|
+
info:ZeroconfGetInfo = zconn.GetInformation()
|
|
7950
|
+
|
|
7951
|
+
# create new spotify connect device object.
|
|
7952
|
+
scDevice:SpotifyConnectDevice = SpotifyConnectDevice()
|
|
7953
|
+
scDevice.DiscoveryResult = discoverResult
|
|
7954
|
+
scDevice.DeviceInfo = info
|
|
7955
|
+
result.Items.append(scDevice)
|
|
7956
|
+
|
|
7957
|
+
# trace.
|
|
7958
|
+
_logsi.LogArray(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result)
|
|
7959
|
+
return result
|
|
7960
|
+
|
|
7961
|
+
except SpotifyZeroconfApiError: raise # pass handled exceptions on thru
|
|
7962
|
+
except SpotifyApiError: raise # pass handled exceptions on thru
|
|
7963
|
+
except Exception as ex:
|
|
7964
|
+
|
|
7965
|
+
# format unhandled exception.
|
|
7966
|
+
raise SpotifyApiError(SAAppMessages.UNHANDLED_EXCEPTION.format(apiMethodName, str(ex)), ex, logsi=_logsi)
|
|
7967
|
+
|
|
7968
|
+
finally:
|
|
7969
|
+
|
|
7970
|
+
# trace.
|
|
7971
|
+
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
7972
|
+
|
|
7973
|
+
|
|
7893
7974
|
def GetTrack(self,
|
|
7894
7975
|
trackId:str,
|
|
7895
7976
|
) -> Track:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|