spotifywebapiPython 1.0.50__py3-none-any.whl → 1.0.52__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.

Files changed (27) hide show
  1. {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.52.dist-info}/METADATA +1 -1
  2. {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.52.dist-info}/RECORD +27 -25
  3. spotifywebapipython/const.py +1 -1
  4. spotifywebapipython/docs/__init__.html +14 -2
  5. spotifywebapipython/docs/index.html +2 -2
  6. spotifywebapipython/docs/search.js +1 -1
  7. spotifywebapipython/docs/spotifywebapiPython/const.html +3 -3
  8. spotifywebapipython/docs/spotifywebapiPython/saappmessages.html +2 -2
  9. spotifywebapipython/docs/spotifywebapiPython/sautils.html +2 -2
  10. spotifywebapipython/docs/spotifywebapiPython/spotifyapierror.html +2 -2
  11. spotifywebapipython/docs/spotifywebapiPython/spotifyapimessage.html +2 -2
  12. spotifywebapipython/docs/spotifywebapiPython/spotifyauthtoken.html +2 -2
  13. spotifywebapipython/docs/spotifywebapiPython/spotifyclient.html +111 -3
  14. spotifywebapipython/docs/spotifywebapiPython/spotifydiscovery.html +2 -2
  15. spotifywebapipython/docs/spotifywebapiPython/spotifywebapiauthenticationerror.html +2 -2
  16. spotifywebapipython/docs/spotifywebapiPython/spotifywebapierror.html +2 -2
  17. spotifywebapipython/models/__init__.py +2 -0
  18. spotifywebapipython/models/device.py +50 -0
  19. spotifywebapipython/models/spotifyconnectdevice.py +93 -0
  20. spotifywebapipython/models/spotifyconnectdevices.py +240 -0
  21. spotifywebapipython/models/zeroconfdiscoveryresult.py +13 -5
  22. spotifywebapipython/spotifyclient.py +144 -36
  23. spotifywebapipython/zeroconfapi/zeroconfgetinfo.py +32 -0
  24. spotifywebapipython/zeroconfapi/zeroconfresponse.py +24 -0
  25. {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.52.dist-info}/LICENSE +0 -0
  26. {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.52.dist-info}/WHEEL +0 -0
  27. {spotifywebapiPython-1.0.50.dist-info → spotifywebapiPython-1.0.52.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,240 @@
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 .zeroconfdiscoveryresult import ZeroconfDiscoveryResult
9
+ from spotifywebapipython.zeroconfapi import ZeroconfGetInfo, ZeroconfGetInfoAlias
10
+
11
+ @export
12
+ class SpotifyConnectDevices():
13
+ """
14
+ Spotify Connect Devices collection.
15
+ """
16
+
17
+ def __init__(self) -> None:
18
+ """
19
+ Initializes a new instance of the class.
20
+ """
21
+ self._Items:list[SpotifyConnectDevice] = []
22
+
23
+
24
+ def __getitem__(self, key) -> SpotifyConnectDevice:
25
+ return self._Presets[key]
26
+
27
+
28
+ def __iter__(self) -> Iterator:
29
+ return iter(self._Items)
30
+
31
+
32
+ def __len__(self) -> int:
33
+ return len(self._Items)
34
+
35
+
36
+ def __repr__(self) -> str:
37
+ return self.ToString()
38
+
39
+
40
+ def __str__(self) -> str:
41
+ return self.ToString()
42
+
43
+
44
+ @property
45
+ def Items(self) -> list[SpotifyConnectDevice]:
46
+ """
47
+ Array of `SpotifyConnectDevice` objects.
48
+ """
49
+ return self._Items
50
+
51
+
52
+ @property
53
+ def ItemsCount(self) -> int:
54
+ """
55
+ Number of objects in the `Items` property array.
56
+ """
57
+ if self._Items is not None:
58
+ return len(self._Items)
59
+ return 0
60
+
61
+
62
+ def AddDynamicDevice(self, device:Device, activeUser:str) -> None:
63
+ """
64
+ Adds a new dynamic device entry to the `Items` collection.
65
+
66
+ Dynamic devices are Spotify Connect devices that are not found in Zeroconf discovery
67
+ process, but still exist in the player device list. These are usually devices in
68
+ a Spotify Connect web or mobile player.
69
+ """
70
+ # validations.
71
+ if (device is None) or (not isinstance(device, Device)):
72
+ return
73
+
74
+ # build zeroconf discovery result with what we can.
75
+ discoverResult:ZeroconfDiscoveryResult = ZeroconfDiscoveryResult()
76
+ discoverResult.DeviceName = device.Name
77
+ discoverResult.HostIpv4Address = '127.0.0.1'
78
+ discoverResult.HostIpPort = 0
79
+ discoverResult.Name = device.Name
80
+ discoverResult.SpotifyConnectCPath = '/zc'
81
+ discoverResult.SpotifyConnectVersion = '1.0'
82
+
83
+ # build zeroconf getinfo result with what we can.
84
+ info:ZeroconfGetInfo = ZeroconfGetInfo()
85
+ info.ActiveUser = activeUser
86
+ info.DeviceId = device.Id
87
+ info.DeviceType = device.Type
88
+ info.RemoteName = device.Name
89
+ info.SpotifyError = 0
90
+ info.Status = 101
91
+ info.StatusString = 'OK'
92
+
93
+ # add the device.
94
+ scDevice:SpotifyConnectDevice = SpotifyConnectDevice()
95
+ scDevice.DeviceInfo = info
96
+ scDevice.DiscoveryResult = discoverResult
97
+ self._Items.append(scDevice)
98
+
99
+
100
+ def ContainsDeviceId(self, value:str) -> bool:
101
+ """
102
+ Returns True if the `Items` collection contains the specified device id value;
103
+ otherwise, False.
104
+
105
+ Alias entries (if any) are also compared.
106
+ """
107
+ result:bool = False
108
+ if value is None:
109
+ return result
110
+
111
+ # convert case for comparison.
112
+ value = value.lower()
113
+
114
+ # process all discovered devices.
115
+ scDevice:SpotifyConnectDevice
116
+ for scDevice in self._Items:
117
+ if (scDevice.DeviceInfo.HasAliases):
118
+ scAlias:ZeroconfGetInfoAlias
119
+ for scAlias in scDevice.DeviceInfo.Aliases:
120
+ if (scAlias.Id.lower() == value):
121
+ result = True
122
+ break
123
+ if result:
124
+ break
125
+ else:
126
+ if (scDevice.DeviceInfo.DeviceId.lower() == value):
127
+ result = True
128
+ break
129
+ return result
130
+
131
+
132
+ def ContainsDeviceName(self, value:str) -> bool:
133
+ """
134
+ Returns True if the `Items` collection contains the specified device name value;
135
+ otherwise, False.
136
+
137
+ Alias entries (if any) are also compared.
138
+ """
139
+ result:bool = False
140
+ if value is None:
141
+ return result
142
+
143
+ # convert case for comparison.
144
+ value = value.lower()
145
+
146
+ # process all discovered devices.
147
+ scDevice:SpotifyConnectDevice
148
+ for scDevice in self._Items:
149
+ if (scDevice.DeviceInfo.HasAliases):
150
+ scAlias:ZeroconfGetInfoAlias
151
+ for scAlias in scDevice.DeviceInfo.Aliases:
152
+ if (scAlias.Name.lower() == value):
153
+ result = True
154
+ break
155
+ if result:
156
+ break
157
+ else:
158
+ if (scDevice.DeviceInfo.RemoteName.lower() == value):
159
+ result = True
160
+ break
161
+ return result
162
+
163
+
164
+ def GetDeviceList(self) -> list[Device]:
165
+ """
166
+ Returns a list of `Device` objects that can be used to build a selection list
167
+ of available devices.
168
+
169
+ Note that the `Device` object has the following properties populated:
170
+ Id, Name, IsActive, Type.
171
+ """
172
+ result:list[Device] = []
173
+
174
+ # process all discovered devices.
175
+ scDevice:SpotifyConnectDevice
176
+ for scDevice in self._Items:
177
+
178
+ # map device information details.
179
+ info:ZeroconfGetInfo = scDevice.DeviceInfo
180
+
181
+ # create new mock device.
182
+ device = Device()
183
+ device.IsActive = info.HasActiveUser
184
+ device.Type = info.DeviceType
185
+
186
+ # are aliases being used (RemoteName is null if so)?
187
+ if info.RemoteName is None:
188
+
189
+ # if aliases are defined, then use the alias details.
190
+ infoAlias:ZeroconfGetInfoAlias
191
+ for infoAlias in info.Aliases:
192
+ device.Id = infoAlias.Id
193
+ device.Name = infoAlias.Name
194
+
195
+ else:
196
+
197
+ # if no aliases then use the remote name and id.
198
+ device.Id = info.DeviceId
199
+ device.Name = info.RemoteName
200
+
201
+ # append device to results.
202
+ result.append(device)
203
+
204
+ # sort items on Name property, ascending order.
205
+ if len(result) > 0:
206
+ result.sort(key=lambda x: (x.Name or "").lower(), reverse=False)
207
+
208
+ return result
209
+
210
+
211
+ def ToDictionary(self) -> dict:
212
+ """
213
+ Returns a dictionary representation of the class.
214
+ """
215
+ result:dict = \
216
+ {
217
+ 'ItemsCount': self.ItemsCount,
218
+ 'Items': [ item.ToDictionary() for item in self._Items ],
219
+ }
220
+
221
+ return result
222
+
223
+
224
+ def ToString(self, includeItems:bool=False) -> str:
225
+ """
226
+ Returns a displayable string representation of the class.
227
+
228
+ Args:
229
+ includeItems (bool):
230
+ True to include the Items collection of objects; otherwise, False
231
+ to only return base properties.
232
+ """
233
+ msg:str = 'Items Count=%s' % (str(self.ItemsCount))
234
+
235
+ if (includeItems):
236
+ item:SpotifyConnectDevice
237
+ for item in self._Items:
238
+ msg = "%s\n- %s" % (msg, item.ToString(True))
239
+
240
+ 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 = '.'
@@ -132,6 +127,19 @@ class ZeroconfDiscoveryResult:
132
127
  self._HostTTL = value
133
128
 
134
129
 
130
+ @property
131
+ def IsDynamicDevice(self) -> bool:
132
+ """
133
+ Returns True if the device is a dynamic device;
134
+ otherwise, False.
135
+
136
+ Dynamic devices are Spotify Connect devices that are not found in Zeroconf discovery
137
+ process, but still exist in the player device list. These are usually Spotify Connect
138
+ web or mobile players with temporary device id's.
139
+ """
140
+ return (self._HostIpPort == 0)
141
+
142
+
135
143
  @property
136
144
  def Key(self) -> str:
137
145
  """