spotifywebapiPython 1.0.49__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.49.dist-info → spotifywebapiPython-1.0.51.dist-info}/METADATA +1 -1
- {spotifywebapiPython-1.0.49.dist-info → spotifywebapiPython-1.0.51.dist-info}/RECORD +26 -24
- spotifywebapipython/const.py +1 -1
- spotifywebapipython/docs/__init__.html +16 -3
- 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 +115 -2
- spotifywebapipython/docs/spotifywebapiPython/spotifydiscovery.html +18 -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 +93 -4
- spotifywebapipython/spotifydiscovery.py +10 -2
- {spotifywebapiPython-1.0.49.dist-info → spotifywebapiPython-1.0.51.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.49.dist-info → spotifywebapiPython-1.0.51.dist-info}/WHEEL +0 -0
- {spotifywebapiPython-1.0.49.dist-info → spotifywebapiPython-1.0.51.dist-info}/top_level.txt +0 -0
|
@@ -64,6 +64,24 @@ class Device:
|
|
|
64
64
|
return self.ToString()
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
# implement sorting support.
|
|
68
|
+
def __eq__(self, other):
|
|
69
|
+
try:
|
|
70
|
+
return self.Name == other.Name
|
|
71
|
+
except Exception as ex:
|
|
72
|
+
if (isinstance(self, Device )) and (isinstance(other, Device )):
|
|
73
|
+
return self.Name == other.Name
|
|
74
|
+
return False
|
|
75
|
+
|
|
76
|
+
def __lt__(self, other):
|
|
77
|
+
try:
|
|
78
|
+
return self.Name < other.Name
|
|
79
|
+
except Exception as ex:
|
|
80
|
+
if (isinstance(self, Device )) and (isinstance(other, Device )):
|
|
81
|
+
return self.Name < other.Name
|
|
82
|
+
return False
|
|
83
|
+
|
|
84
|
+
|
|
67
85
|
@property
|
|
68
86
|
def Id(self) -> str:
|
|
69
87
|
"""
|
|
@@ -74,6 +92,14 @@ class Device:
|
|
|
74
92
|
"""
|
|
75
93
|
return self._Id
|
|
76
94
|
|
|
95
|
+
@Id.setter
|
|
96
|
+
def Id(self, value:str):
|
|
97
|
+
"""
|
|
98
|
+
Sets the Id property value.
|
|
99
|
+
"""
|
|
100
|
+
if isinstance(value, str):
|
|
101
|
+
self._Id = value
|
|
102
|
+
|
|
77
103
|
|
|
78
104
|
@property
|
|
79
105
|
def IsActive(self) -> bool:
|
|
@@ -82,6 +108,14 @@ class Device:
|
|
|
82
108
|
"""
|
|
83
109
|
return self._IsActive
|
|
84
110
|
|
|
111
|
+
@IsActive.setter
|
|
112
|
+
def IsActive(self, value:bool):
|
|
113
|
+
"""
|
|
114
|
+
Sets the IsActive property value.
|
|
115
|
+
"""
|
|
116
|
+
if isinstance(value, bool):
|
|
117
|
+
self._IsActive = value
|
|
118
|
+
|
|
85
119
|
|
|
86
120
|
@property
|
|
87
121
|
def IsMuted(self) -> bool:
|
|
@@ -122,6 +156,14 @@ class Device:
|
|
|
122
156
|
"""
|
|
123
157
|
return self._Name
|
|
124
158
|
|
|
159
|
+
@Name.setter
|
|
160
|
+
def Name(self, value:str):
|
|
161
|
+
"""
|
|
162
|
+
Sets the Name property value.
|
|
163
|
+
"""
|
|
164
|
+
if isinstance(value, str):
|
|
165
|
+
self._Name = value
|
|
166
|
+
|
|
125
167
|
|
|
126
168
|
@property
|
|
127
169
|
def SelectItemNameAndId(self) -> str:
|
|
@@ -151,6 +193,14 @@ class Device:
|
|
|
151
193
|
"""
|
|
152
194
|
return self._Type
|
|
153
195
|
|
|
196
|
+
@Type.setter
|
|
197
|
+
def Type(self, value:str):
|
|
198
|
+
"""
|
|
199
|
+
Sets the Type property value.
|
|
200
|
+
"""
|
|
201
|
+
if isinstance(value, str):
|
|
202
|
+
self._Type = value
|
|
203
|
+
|
|
154
204
|
|
|
155
205
|
@property
|
|
156
206
|
def VolumePercent(self) -> int:
|
|
@@ -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 = '.'
|
|
@@ -146,7 +146,7 @@ class SpotifyClient:
|
|
|
146
146
|
self._TokenStorageDir:str = tokenStorageDir
|
|
147
147
|
self._TokenUpdater:Callable = tokenUpdater
|
|
148
148
|
self._UserProfile:UserProfile = None
|
|
149
|
-
self.
|
|
149
|
+
self._ZeroconfClient = zeroconfClient
|
|
150
150
|
|
|
151
151
|
# if pool manager instance is none or not a PoolManager instance, then create one.
|
|
152
152
|
# we increase the maximum number of connections to keep in the pool (maxsize=) to avoid the following warnings:
|
|
@@ -165,7 +165,7 @@ class SpotifyClient:
|
|
|
165
165
|
# create the zeroconf client if one was not specified.
|
|
166
166
|
if zeroconfClient is None:
|
|
167
167
|
_logsi.LogVerbose("Creating new Zeroconf instance for discovery")
|
|
168
|
-
self.
|
|
168
|
+
self._ZeroconfClient = Zeroconf()
|
|
169
169
|
else:
|
|
170
170
|
_logsi.LogObject(SILevel.Verbose, "Using existing Zeroconf instance for discovery", zeroconfClient)
|
|
171
171
|
|
|
@@ -299,6 +299,14 @@ class SpotifyClient:
|
|
|
299
299
|
return self._UserProfile
|
|
300
300
|
|
|
301
301
|
|
|
302
|
+
@property
|
|
303
|
+
def ZeroconfClient(self) -> Zeroconf:
|
|
304
|
+
"""
|
|
305
|
+
Zeroconf client instance that will be used to discover Spotify Connect devices.
|
|
306
|
+
"""
|
|
307
|
+
return self._ZeroconfClient
|
|
308
|
+
|
|
309
|
+
|
|
302
310
|
def _CheckForNextPageWithOffset(self,
|
|
303
311
|
pageObj:PageObject,
|
|
304
312
|
resultItemsCount,
|
|
@@ -6012,7 +6020,7 @@ class SpotifyClient:
|
|
|
6012
6020
|
# for all devices to be discovered. this will return all Spotify Connect devices that
|
|
6013
6021
|
# are currently powered on, and are registered to Zeroconf / mDNS.
|
|
6014
6022
|
_logsi.LogVerbose("Discovering Spotify Connect devices on the local network")
|
|
6015
|
-
discovery:SpotifyDiscovery = SpotifyDiscovery(self.
|
|
6023
|
+
discovery:SpotifyDiscovery = SpotifyDiscovery(self._ZeroconfClient, printToConsole=False)
|
|
6016
6024
|
discovery.DiscoverDevices(timeout=self._SpotifyConnectDiscoveryTimeout)
|
|
6017
6025
|
|
|
6018
6026
|
# process all discovered devices.
|
|
@@ -7882,6 +7890,87 @@ class SpotifyClient:
|
|
|
7882
7890
|
_logsi.LeaveMethod(SILevel.Debug, apiMethodName)
|
|
7883
7891
|
|
|
7884
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
|
+
|
|
7885
7974
|
def GetTrack(self,
|
|
7886
7975
|
trackId:str,
|
|
7887
7976
|
) -> Track:
|
|
@@ -10184,7 +10273,7 @@ class SpotifyClient:
|
|
|
10184
10273
|
# for all devices to be discovered. this will return all Spotify Connect devices that
|
|
10185
10274
|
# are currently powered on, and are registered to Zeroconf / mDNS.
|
|
10186
10275
|
_logsi.LogVerbose("Discovering Spotify Connect devices on the local network")
|
|
10187
|
-
discovery:SpotifyDiscovery = SpotifyDiscovery(self.
|
|
10276
|
+
discovery:SpotifyDiscovery = SpotifyDiscovery(self._ZeroconfClient, printToConsole=False)
|
|
10188
10277
|
discovery.DiscoverDevices(timeout=self._SpotifyConnectDiscoveryTimeout)
|
|
10189
10278
|
|
|
10190
10279
|
# process all discovered devices.
|
|
@@ -65,7 +65,7 @@ class SpotifyDiscovery:
|
|
|
65
65
|
self._DiscoveredDeviceNames:dict = {}
|
|
66
66
|
self._DiscoveryResults:list[ZeroconfDiscoveryResult] = []
|
|
67
67
|
self._PrintToConsole:bool = printToConsole
|
|
68
|
-
self.
|
|
68
|
+
self._ZeroconfClient = zeroconfClient
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
def __getitem__(self, key):
|
|
@@ -113,6 +113,14 @@ class SpotifyDiscovery:
|
|
|
113
113
|
return self._DiscoveryResults
|
|
114
114
|
|
|
115
115
|
|
|
116
|
+
@property
|
|
117
|
+
def ZeroconfClient(self) -> Zeroconf:
|
|
118
|
+
"""
|
|
119
|
+
Zeroconf client instance that will be used to discover Spotify Connect devices.
|
|
120
|
+
"""
|
|
121
|
+
return self._ZeroconfClient
|
|
122
|
+
|
|
123
|
+
|
|
116
124
|
def _OnServiceStateChange(self,
|
|
117
125
|
zeroconf:Zeroconf,
|
|
118
126
|
service_type:str,
|
|
@@ -234,7 +242,7 @@ class SpotifyDiscovery:
|
|
|
234
242
|
|
|
235
243
|
# create the zeroconf service browser that will start device discovery.
|
|
236
244
|
_logsi.LogVerbose("Discovery of Spotify Connect devices via Zeroconf is starting ...")
|
|
237
|
-
ServiceBrowser(self.
|
|
245
|
+
ServiceBrowser(self._ZeroconfClient, "_spotify-connect._tcp.local.", handlers=[self._OnServiceStateChange])
|
|
238
246
|
|
|
239
247
|
try:
|
|
240
248
|
# give the ServiceBrowser time to discover
|
|
File without changes
|
|
File without changes
|
|
File without changes
|