spotifywebapiPython 1.0.243__py3-none-any.whl → 1.0.251__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.
Files changed (33) hide show
  1. spotifywebapipython/const.py +1 -1
  2. spotifywebapipython/docs/__init__.html +56 -2
  3. spotifywebapipython/docs/index.html +5 -2
  4. spotifywebapipython/docs/search.js +1 -1
  5. spotifywebapipython/docs/spotifywebapipython/const.html +3 -3
  6. spotifywebapipython/docs/spotifywebapipython/saappmessages.html +2 -2
  7. spotifywebapipython/docs/spotifywebapipython/sautils.html +2 -2
  8. spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html +2 -2
  9. spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html +2 -2
  10. spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html +2 -2
  11. spotifywebapipython/docs/spotifywebapipython/spotifyclient.html +235 -4
  12. spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html +2 -2
  13. spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html +2 -2
  14. spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html +2 -2
  15. spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html +2 -2
  16. spotifywebapipython/models/__init__.py +2 -0
  17. spotifywebapipython/models/episodesimplified.py +41 -0
  18. spotifywebapipython/models/imagepalettecolors.py +111 -0
  19. spotifywebapipython/models/imagevibrantcolors.py +2 -0
  20. spotifywebapipython/models/pageobject.py +1 -0
  21. spotifywebapipython/spotifyclient.py +219 -6
  22. spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py +227 -76
  23. spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastcontroller.py +2 -2
  24. spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastmultizonecontrollerlistener.py +247 -0
  25. spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastmultizonemanagerlistener.py +384 -0
  26. spotifywebapipython/vibrant/__init__.py +2 -0
  27. spotifywebapipython/vibrant/colorthieffast.py +626 -0
  28. {spotifywebapipython-1.0.243.dist-info → spotifywebapipython-1.0.251.dist-info}/METADATA +3 -2
  29. {spotifywebapipython-1.0.243.dist-info → spotifywebapipython-1.0.251.dist-info}/RECORD +32 -29
  30. spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastmultizonelistener.py +0 -212
  31. {spotifywebapipython-1.0.243.dist-info → spotifywebapipython-1.0.251.dist-info}/LICENSE +0 -0
  32. {spotifywebapipython-1.0.243.dist-info → spotifywebapipython-1.0.251.dist-info}/WHEEL +0 -0
  33. {spotifywebapipython-1.0.243.dist-info → spotifywebapipython-1.0.251.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,247 @@
1
+ # external package imports.
2
+ from pychromecast.controllers.multizone import MultizoneController, MultiZoneControllerListener
3
+ from pychromecast.dial import MultizoneStatus, get_multizone_status
4
+ from pychromecast import Chromecast
5
+ import pychromecast
6
+ import threading
7
+ from uuid import UUID
8
+ from zeroconf import Zeroconf
9
+
10
+ # our package imports.
11
+ from spotifywebapipython.models import SpotifyConnectDevice, ZeroconfDiscoveryResult
12
+ # note - cannot reference `SpotifyConnectDirectoryTask` due to circular import!
13
+ # from .spotifyconnectdirectorytask import SpotifyConnectDirectoryTask
14
+
15
+ # get smartinspect logger reference; create a new session for this module name.
16
+ from smartinspectpython.siauto import SIAuto, SILevel, SISession, SIMethodParmListContext, SIColors
17
+ import logging
18
+
19
+ _logsi:SISession = SIAuto.Si.GetSession(__name__)
20
+ if (_logsi == None):
21
+ _logsi = SIAuto.Si.AddSession(__name__, True)
22
+ _logsi.SystemLogger = logging.getLogger(__name__)
23
+
24
+
25
+ class SpotifyConnectZeroconfCastMultiZoneControllerListener(MultiZoneControllerListener):
26
+ """
27
+ Google Chromecast Zeroconf MultiZone Listener class.
28
+
29
+ Listens for Chromecast device multi-zone status updates for devices that
30
+ support multi-zone / group functionality.
31
+
32
+ This class should only be added as a listener to Chromecast group devices.
33
+ """
34
+
35
+ UNHANDLED_EXCEPTION_MSG:str = "Unhandled exception occured while processing Chromecast MultiZoneController notification (%s)"
36
+ """
37
+ Unhandled exception occured while processing Chromecast MultiZoneController notification (%s)
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ parentDirectory,
43
+ zeroconfInstance:Zeroconf,
44
+ zeroconf_RLock:threading.RLock,
45
+ castMultizoneController:MultizoneController,
46
+ castDevice:Chromecast,
47
+ ) -> None:
48
+ """
49
+ Initializes a new instance of the class.
50
+
51
+ Args:
52
+ parentDirectory (SpotifyConnectDirectoryTask):
53
+ Parent SpotifyConnectDirectoryTask instance.
54
+ zeroconfInstance (Zeroconf):
55
+ Zeroconf instance used to query zeroconf.
56
+ zeroconf_RLock (threading.RLock):
57
+ Lock object used to enforce thread-safe updates.
58
+ castMultizoneController (MultizoneController)
59
+ MultizoneController parent instance.
60
+ castDevice (Chromecast):
61
+ Chromecast device object.
62
+ """
63
+ # invoke base class method.
64
+ super().__init__()
65
+
66
+ # initialize storage.
67
+ self._CastMultizoneController:MultizoneController = castMultizoneController
68
+ self._CastDevice = castDevice
69
+ """ Cast group device that received the multizone notification. """
70
+ self._ParentDirectory = parentDirectory
71
+ self._ZeroconfInstance:Zeroconf = zeroconfInstance
72
+ self._Zeroconf_RLock:threading.RLock = zeroconf_RLock
73
+
74
+
75
+ def multizone_member_added(
76
+ self,
77
+ member_uuid:str,
78
+ ) -> None:
79
+ """
80
+ Called when cast device identified by `member_uuid` has been added to a group.
81
+ """
82
+ # use lock, as multiple threads could be calling this method simultaneously.
83
+ with self._Zeroconf_RLock:
84
+
85
+ # copy passed parameters to thread-safe storage.
86
+ argsMemberUuid:UUID = member_uuid
87
+
88
+ apiMethodName:str = "multizone_member_added (MultiZoneControllerListener)"
89
+ apiMethodParms:SIMethodParmListContext = None
90
+
91
+ try:
92
+
93
+ # trace.
94
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
95
+ apiMethodParms.AppendKeyValue("member_uuid", argsMemberUuid)
96
+ _logsi.LogMethodParmList(SILevel.Debug, "Chromecast multizone controller notification was received for Cast device key \"%s\"" % (argsMemberUuid), apiMethodParms, colorValue=SIColors.Lavender)
97
+
98
+ # trace.
99
+ if (_logsi.IsOn(SILevel.Verbose)):
100
+
101
+ # get device instance.
102
+ scDevice:SpotifyConnectDevice = self._ParentDirectory._SpotifyConnectDevices.GetDeviceByDiscoveryKey(str(argsMemberUuid))
103
+ if (scDevice is None):
104
+
105
+ # trace.
106
+ _logsi.LogVerbose("Could not find SpotifyConnectDevices instance for Cast device key: \"%s\"" % (str(argsMemberUuid)), colorValue=SIColors.Lavender)
107
+
108
+ else:
109
+
110
+ _logsi.LogVerbose("Chromecast multizone controller for group \"%s\" added member device: %s" % (self._CastDevice.cast_info.friendly_name, scDevice.Title), colorValue=SIColors.Lavender)
111
+
112
+ # get multizone controller reference for the group device, so we can get it's members.
113
+ castMultizoneController:MultizoneController = self._ParentDirectory._CastMultiZoneControllers.get(str(self._CastDevice.uuid), None)
114
+ if (castMultizoneController is not None):
115
+ membersSummary:list[str] = []
116
+ for member in castMultizoneController.members:
117
+ scMemberDevice:SpotifyConnectDevice = self._ParentDirectory._SpotifyConnectDevices.GetDeviceByDiscoveryKey(member)
118
+ if (scMemberDevice is None):
119
+ membersSummary.append(str(member))
120
+ else:
121
+ membersSummary.append("%s [ip=%s]" % (scMemberDevice.Title, scMemberDevice.DiscoveryResult.HostIpTitle))
122
+ _logsi.LogArray(SILevel.Verbose, "Chromecast multizone controller members for group: \"%s\" (count=%d)" % (self._CastDevice.cast_info.friendly_name, len(membersSummary)), membersSummary, colorValue=SIColors.Lavender)
123
+
124
+ except Exception as ex:
125
+
126
+ # trace.
127
+ _logsi.LogException(SpotifyConnectZeroconfCastMultiZoneControllerListener.UNHANDLED_EXCEPTION_MSG % (apiMethodName), ex, logToSystemLogger=False)
128
+
129
+ # ignore exception, as nothing can be done about it.
130
+
131
+ finally:
132
+
133
+ # trace.
134
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
135
+
136
+
137
+ def multizone_member_removed(
138
+ self,
139
+ member_uuid,
140
+ ) -> None:
141
+ """
142
+ Called when cast device identified by `member_uuid` has been removed from a group.
143
+ """
144
+ # use lock, as multiple threads could be calling this method simultaneously.
145
+ with self._Zeroconf_RLock:
146
+
147
+ # copy passed parameters to thread-safe storage.
148
+ argsMemberUuid:UUID = member_uuid
149
+
150
+ apiMethodName:str = "multizone_member_removed (MultiZoneControllerListener)"
151
+ apiMethodParms:SIMethodParmListContext = None
152
+
153
+ try:
154
+
155
+ # trace.
156
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
157
+ apiMethodParms.AppendKeyValue("member_uuid", argsMemberUuid)
158
+ _logsi.LogMethodParmList(SILevel.Debug, "Chromecast multizone controller notification was received for Cast device key \"%s\"" % (argsMemberUuid), apiMethodParms, colorValue=SIColors.Lavender)
159
+
160
+ # trace.
161
+ if (_logsi.IsOn(SILevel.Verbose)):
162
+
163
+ # get device instance.
164
+ scDevice:SpotifyConnectDevice = self._ParentDirectory._SpotifyConnectDevices.GetDeviceByDiscoveryKey(str(argsMemberUuid))
165
+ if (scDevice is None):
166
+
167
+ # trace.
168
+ _logsi.LogVerbose("Could not find SpotifyConnectDevices instance for Cast device key: \"%s\"" % (str(argsMemberUuid)), colorValue=SIColors.Lavender)
169
+
170
+ else:
171
+
172
+ _logsi.LogVerbose("Chromecast multizone controller for group \"%s\" removed member device: %s" % (self._CastDevice.cast_info.friendly_name, scDevice.Title), colorValue=SIColors.Lavender)
173
+
174
+ # get multizone controller reference for the group device, so we can get it's members.
175
+ castMultizoneController:MultizoneController = self._ParentDirectory._CastMultiZoneControllers.get(str(self._CastDevice.uuid), None)
176
+ if (castMultizoneController is not None):
177
+ membersSummary:list[str] = []
178
+ for member in castMultizoneController.members:
179
+ scMemberDevice:SpotifyConnectDevice = self._ParentDirectory._SpotifyConnectDevices.GetDeviceByDiscoveryKey(member)
180
+ if (scMemberDevice is None):
181
+ membersSummary.append(str(member))
182
+ else:
183
+ membersSummary.append("%s [ip=%s]" % (scMemberDevice.Title, scMemberDevice.DiscoveryResult.HostIpTitle))
184
+ _logsi.LogArray(SILevel.Verbose, "Chromecast multizone controller members for group: \"%s\" (count=%d)" % (self._CastDevice.cast_info.friendly_name, len(membersSummary)), membersSummary, colorValue=SIColors.Lavender)
185
+
186
+ except Exception as ex:
187
+
188
+ # trace.
189
+ _logsi.LogException(SpotifyConnectZeroconfCastMultiZoneControllerListener.UNHANDLED_EXCEPTION_MSG % (apiMethodName), ex, logToSystemLogger=False)
190
+
191
+ # ignore exception, as nothing can be done about it.
192
+
193
+ finally:
194
+
195
+ # trace.
196
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
197
+
198
+
199
+ def multizone_status_received(
200
+ self,
201
+ ) -> None:
202
+ """
203
+ Called when Multizone status has been updated.
204
+ """
205
+ # use lock, as multiple threads could be calling this method simultaneously.
206
+ with self._Zeroconf_RLock:
207
+
208
+ # copy passed parameters to thread-safe storage.
209
+ # n/a
210
+
211
+ apiMethodName:str = "multizone_status_received (MultiZoneControllerListener)"
212
+ apiMethodParms:SIMethodParmListContext = None
213
+
214
+ try:
215
+
216
+ # trace.
217
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
218
+ _logsi.LogMethodParmList(SILevel.Debug, "Chromecast multizone controller status has been updated for group: \"%s\"" % (self._CastDevice.cast_info.friendly_name), apiMethodParms, colorValue=SIColors.Lavender)
219
+
220
+ # trace.
221
+ if (_logsi.IsOn(SILevel.Verbose)):
222
+
223
+ # trace.
224
+ _logsi.LogObject(SILevel.Verbose, "Chromecast multizone controller group status: \"%s\"" % (self._CastDevice.cast_info.friendly_name), self._CastDevice.status, colorValue=SIColors.Lavender)
225
+
226
+ # build member list with friendly names.
227
+ membersSummary:list[str] = []
228
+ member:str = None
229
+ for member in self._CastMultizoneController.members:
230
+ scMemberDevice:SpotifyConnectDevice = self._ParentDirectory._SpotifyConnectDevices.GetDeviceByDiscoveryKey(member)
231
+ if (scMemberDevice is None):
232
+ membersSummary.append(str(member))
233
+ else:
234
+ membersSummary.append("%s [ip=%s]" % (scMemberDevice.Title, scMemberDevice.DiscoveryResult.HostIpTitle))
235
+ _logsi.LogArray(SILevel.Verbose, "Chromecast multizone controller group members: \"%s\" (count=%d)" % (self._CastDevice.cast_info.friendly_name, len(membersSummary)), membersSummary, colorValue=SIColors.Lavender)
236
+
237
+ except Exception as ex:
238
+
239
+ # trace.
240
+ _logsi.LogException(SpotifyConnectZeroconfCastMultiZoneControllerListener.UNHANDLED_EXCEPTION_MSG % (apiMethodName), ex, logToSystemLogger=False)
241
+
242
+ # ignore exception, as nothing can be done about it.
243
+
244
+ finally:
245
+
246
+ # trace.
247
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
@@ -0,0 +1,384 @@
1
+
2
+ # external package imports.
3
+ from pychromecast.controllers.media import MediaStatus
4
+ from pychromecast.controllers.multizone import MultizoneController, MultizoneManager, MultiZoneManagerListener, GroupInfo
5
+ from pychromecast.controllers.receiver import CastStatus
6
+ from pychromecast.dial import MultizoneStatus, get_multizone_status
7
+ from pychromecast import Chromecast
8
+ import pychromecast
9
+ import threading
10
+ from uuid import UUID
11
+ from zeroconf import Zeroconf
12
+
13
+ # our package imports.
14
+ from spotifywebapipython.models import SpotifyConnectDevice
15
+ # note - cannot reference `SpotifyConnectDirectoryTask` due to circular import!
16
+ # from .spotifyconnectdirectorytask import SpotifyConnectDirectoryTask
17
+
18
+ # get smartinspect logger reference; create a new session for this module name.
19
+ from smartinspectpython.siauto import SIAuto, SILevel, SISession, SIMethodParmListContext, SIColors
20
+ import logging
21
+
22
+ _logsi:SISession = SIAuto.Si.GetSession(__name__)
23
+ if (_logsi == None):
24
+ _logsi = SIAuto.Si.AddSession(__name__, True)
25
+ _logsi.SystemLogger = logging.getLogger(__name__)
26
+
27
+
28
+ class SpotifyConnectZeroconfCastMultiZoneManagerListener(MultiZoneManagerListener):
29
+ """
30
+ Google Chromecast Zeroconf MultiZone Listener class.
31
+
32
+ Listens for Chromecast device multi-zone status updates for devices that
33
+ support multi-zone / group functionality.
34
+
35
+ This class should be added as a listener to all Chromecast devices.
36
+ """
37
+
38
+ UNHANDLED_EXCEPTION_MSG:str = "Unhandled exception occured while processing Chromecast MultizoneManager notification (%s)"
39
+ """
40
+ Unhandled exception occured while processing Chromecast MultizoneManager notification (%s)
41
+ """
42
+
43
+ def __init__(
44
+ self,
45
+ parentDirectory,
46
+ zeroconfInstance:Zeroconf,
47
+ zeroconf_RLock:threading.RLock,
48
+ castMultizoneManager:MultizoneManager,
49
+ castDevice:Chromecast,
50
+ ) -> None:
51
+ """
52
+ Initializes a new instance of the class.
53
+
54
+ Args:
55
+ parentDirectory (SpotifyConnectDirectoryTask):
56
+ Parent SpotifyConnectDirectoryTask instance.
57
+ zeroconfInstance (Zeroconf):
58
+ Zeroconf instance used to query zeroconf.
59
+ zeroconf_RLock (threading.RLock):
60
+ Lock object used to enforce thread-safe updates.
61
+ castMultizoneManager (MultizoneManager)
62
+ MultizoneManager parent instance.
63
+ castDevice (Chromecast):
64
+ Chromecast device object.
65
+ """
66
+ # invoke base class method.
67
+ super().__init__()
68
+
69
+ # initialize storage.
70
+ self._CastMultizoneManager:MultizoneManager = castMultizoneManager
71
+ self._CastDevice = castDevice
72
+ """ Cast group device that received the multizone notification. """
73
+ self._ParentDirectory = parentDirectory
74
+ self._ZeroconfInstance:Zeroconf = zeroconfInstance
75
+ self._Zeroconf_RLock:threading.RLock = zeroconf_RLock
76
+
77
+
78
+ def added_to_multizone(
79
+ self,
80
+ group_uuid:str,
81
+ ) -> None:
82
+ """
83
+ Called when cast has been added to group identified by group_uuid.
84
+ """
85
+ # use lock, as multiple threads could be calling this method simultaneously.
86
+ with self._Zeroconf_RLock:
87
+
88
+ # copy passed parameters to thread-safe storage.
89
+ argsGroupUuid:UUID = group_uuid
90
+
91
+ apiMethodName:str = "added_to_multizone (MultiZoneManagerListener)"
92
+ apiMethodParms:SIMethodParmListContext = None
93
+
94
+ try:
95
+
96
+ # trace.
97
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
98
+ apiMethodParms.AppendKeyValue("group_uuid", argsGroupUuid)
99
+ _logsi.LogMethodParmList(SILevel.Debug, "Chromecast multizone manager notification was received for group \"%s\"" % (argsGroupUuid), apiMethodParms, colorValue=SIColors.Lavender)
100
+
101
+ # trace.
102
+ if (_logsi.IsOn(SILevel.Verbose)):
103
+
104
+ # get group device instance.
105
+ scDevice:SpotifyConnectDevice = self._ParentDirectory._SpotifyConnectDevices.GetDeviceByDiscoveryKey(str(argsGroupUuid))
106
+ if (scDevice is None):
107
+
108
+ # trace.
109
+ _logsi.LogVerbose("Could not find SpotifyConnectDevices instance for Cast device key: \"%s\"" % (str(argsGroupUuid)), colorValue=SIColors.Lavender)
110
+
111
+ else:
112
+
113
+ # trace.
114
+ _logsi.LogVerbose("Chromecast multizone manager added device \"%s\" to multizone group %s" % (self._CastDevice.cast_info.friendly_name, scDevice.Title), colorValue=SIColors.Lavender)
115
+
116
+ # # get the current multizone status.
117
+ # castMultiZoneStatus:MultizoneStatus = get_multizone_status(scDevice.DiscoveryResult.HostIpAddress, self._CastDevice.cast_info.services, self._ZeroconfInstance, 5)
118
+ # _logsi.LogObject(SILevel.Verbose, "Chromecast multizone manager status for group: %s [%s] (get_multizone_status)" % (scDevice.Title, scDevice.DiscoveryResult.HostIpTitle), castMultiZoneStatus, colorValue=SIColors.Lavender)
119
+
120
+ # # build member list with friendly names.
121
+ # result:list[str] = []
122
+ # member:GroupInfo = None
123
+ # for key, member in self._CastMultizoneManager._groups.items():
124
+ # memberName:str = member["chromecast"].cast_info.friendly_name
125
+ # result.append(memberName + ": " + str(member))
126
+ # _logsi.LogArray(SILevel.Verbose, "Chromecast multizone group \"%s\" groups (count=%d)" % (scDevice.Title, len(result)), result, colorValue=SIColors.Lavender)
127
+
128
+ # # build member list with friendly names.
129
+ # result:list[str] = []
130
+ # member:GroupInfo = None
131
+ # for key, member in self._CastMultizoneManager._casts.items():
132
+ # group_members:str = member["group_memberships"]
133
+ # if (len(group_members) > 0):
134
+ # result.append(str(member))
135
+ # _logsi.LogArray(SILevel.Verbose, "Chromecast multizone group \"%s\" casts (count=%d)" % (scDevice.Title, len(result)), result, colorValue=SIColors.Lavender)
136
+
137
+ except Exception as ex:
138
+
139
+ # trace.
140
+ _logsi.LogException(SpotifyConnectZeroconfCastMultiZoneManagerListener.UNHANDLED_EXCEPTION_MSG % (apiMethodName), ex, logToSystemLogger=False)
141
+
142
+ # ignore exception, as nothing can be done about it.
143
+
144
+ finally:
145
+
146
+ # trace.
147
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
148
+
149
+
150
+ def removed_from_multizone(
151
+ self,
152
+ group_uuid,
153
+ ) -> None:
154
+ """
155
+ Called when cast has been removed from group identified by group_uuid.
156
+ """
157
+ # use lock, as multiple threads could be calling this method simultaneously.
158
+ with self._Zeroconf_RLock:
159
+
160
+ # copy passed parameters to thread-safe storage.
161
+ argsGroupUuid:UUID = group_uuid
162
+
163
+ apiMethodName:str = "removed_from_multizone (MultiZoneManagerListener)"
164
+ apiMethodParms:SIMethodParmListContext = None
165
+
166
+ try:
167
+
168
+ # trace.
169
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
170
+ apiMethodParms.AppendKeyValue("group_uuid", argsGroupUuid)
171
+ _logsi.LogMethodParmList(SILevel.Debug, "Chromecast multizone manager notification was received for group \"%s\"" % (argsGroupUuid), apiMethodParms, colorValue=SIColors.Lavender)
172
+
173
+ # trace.
174
+ if (_logsi.IsOn(SILevel.Verbose)):
175
+
176
+ # get group device instance.
177
+ scDevice:SpotifyConnectDevice = self._ParentDirectory._SpotifyConnectDevices.GetDeviceByDiscoveryKey(str(argsGroupUuid))
178
+ if (scDevice is None):
179
+
180
+ # trace.
181
+ _logsi.LogVerbose("Could not find SpotifyConnectDevices instance for Cast device key: \"%s\"" % (str(argsGroupUuid)), colorValue=SIColors.Lavender)
182
+
183
+ else:
184
+
185
+ # trace.
186
+ _logsi.LogVerbose("Chromecast multizone manager removed device \"%s\" from multizone group %s" % (self._CastDevice.cast_info.friendly_name, scDevice.Title), colorValue=SIColors.Lavender)
187
+
188
+ # # get the current multizone status.
189
+ # castMultiZoneStatus:MultizoneStatus = get_multizone_status(scDevice.DiscoveryResult.HostIpAddress, self._CastDevice.cast_info.services, self._ZeroconfInstance, 5)
190
+ # _logsi.LogObject(SILevel.Verbose, "Chromecast multizone manager status for group: %s [%s] (get_multizone_status)" % (scDevice.Title, scDevice.DiscoveryResult.HostIpTitle), castMultiZoneStatus, colorValue=SIColors.Lavender)
191
+
192
+ # # build member list with friendly names.
193
+ # result:list[str] = []
194
+ # member:GroupInfo = None
195
+ # for key, member in self._CastMultizoneManager._groups.items():
196
+ # memberName:str = member["chromecast"].cast_info.friendly_name
197
+ # result.append(memberName + ": " + str(member))
198
+ # _logsi.LogArray(SILevel.Verbose, "Chromecast multizone group \"%s\" groups (count=%d)" % (scDevice.Title, len(result)), result, colorValue=SIColors.Lavender)
199
+
200
+ # # build member list with friendly names.
201
+ # result:list[str] = []
202
+ # member:GroupInfo = None
203
+ # for key, member in self._CastMultizoneManager._casts.items():
204
+ # group_members:str = member["group_memberships"]
205
+ # if (len(group_members) > 0):
206
+ # result.append(str(member))
207
+ # _logsi.LogArray(SILevel.Verbose, "Chromecast multizone group \"%s\" casts (count=%d)" % (scDevice.Title, len(result)), result, colorValue=SIColors.Lavender)
208
+
209
+ except Exception as ex:
210
+
211
+ # trace.
212
+ _logsi.LogException(SpotifyConnectZeroconfCastMultiZoneManagerListener.UNHANDLED_EXCEPTION_MSG % (apiMethodName), ex, logToSystemLogger=False)
213
+
214
+ # ignore exception, as nothing can be done about it.
215
+
216
+ finally:
217
+
218
+ # trace.
219
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
220
+
221
+
222
+ def multizone_new_media_status(
223
+ self,
224
+ group_uuid: str,
225
+ media_status: MediaStatus
226
+ ) -> None:
227
+ """
228
+ Called when the group identified by group_uuid, of which the cast is a member, has new media status.
229
+ """
230
+
231
+ # Commented out this code, as we do not use it.
232
+ # Left it in place, in case it's required in the future.
233
+ pass
234
+
235
+ # # use lock, as multiple threads could be calling this method simultaneously.
236
+ # with self._Zeroconf_RLock:
237
+
238
+ # # copy passed parameters to thread-safe storage.
239
+ # argsGroupUuid:UUID = group_uuid
240
+ # argsMediaStatus:MediaStatus = media_status
241
+
242
+ # apiMethodName:str = "multizone_new_media_status (MultiZoneManagerListener)"
243
+ # apiMethodParms:SIMethodParmListContext = None
244
+
245
+ # try:
246
+
247
+ # # trace.
248
+ # apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
249
+ # apiMethodParms.AppendKeyValue("group_uuid", argsGroupUuid)
250
+ # apiMethodParms.AppendKeyValue("media_status", argsMediaStatus)
251
+ # _logsi.LogMethodParmList(SILevel.Debug, "Chromecast multizone manager media status has been updated for group: \"%s\"" % (argsGroupUuid), apiMethodParms, colorValue=SIColors.Lavender)
252
+
253
+ # # example - MediaStatus:
254
+ # # {
255
+ # # 'metadata_type': 3,
256
+ # # 'title': 'Fire And Ice',
257
+ # # 'series_title': None,
258
+ # # 'season': None,
259
+ # # 'episode': None,
260
+ # # 'artist': 'Steve Camp',
261
+ # # 'album_name': 'Fire And Ice',
262
+ # # 'album_artist': None,
263
+ # # 'track': None,
264
+ # # 'subtitle_tracks': [],
265
+ # # 'images': [MediaImage(url = 'https://i.scdn.co/image/ab67 ...')],
266
+ # # 'content_id': 'spotify:track:4M7fCbUaDpYWNKSEZfLpSb',
267
+ # # 'content_type': 'application/x-spotify.track',
268
+ # # ... <==== truncated for brevity; see developer docs for more details
269
+ # # }
270
+
271
+ # # trace.
272
+ # if (_logsi.IsOn(SILevel.Verbose)):
273
+
274
+ # # get group device instance.
275
+ # scDevice:SpotifyConnectDevice = self._ParentDirectory._SpotifyConnectDevices.GetDeviceByDiscoveryKey(str(argsGroupUuid))
276
+ # if (scDevice is None):
277
+
278
+ # # trace.
279
+ # _logsi.LogVerbose("Could not find SpotifyConnectDevices instance for Cast device key: \"%s\"" % (str(argsGroupUuid)), colorValue=SIColors.Lavender)
280
+
281
+ # else:
282
+
283
+ # # formulate current status.
284
+ # statusText:str = "unknown"
285
+ # if (argsMediaStatus):
286
+ # statusText = "%s (%s)" % (argsMediaStatus.title or "null", argsMediaStatus.artist or "null")
287
+
288
+ # # trace.
289
+ # _logsi.LogObject(SILevel.Verbose, "Chromecast multizone manager group MediaStatus: %s [%s] - %s" % (scDevice.Title, scDevice.DiscoveryResult.HostIpTitle, statusText), argsMediaStatus, colorValue=SIColors.Lavender)
290
+
291
+ # except Exception as ex:
292
+
293
+ # # trace.
294
+ # _logsi.LogException(SpotifyConnectZeroconfCastMultiZoneManagerListener.UNHANDLED_EXCEPTION_MSG % (apiMethodName), ex, logToSystemLogger=False)
295
+
296
+ # # ignore exception, as nothing can be done about it.
297
+
298
+ # finally:
299
+
300
+ # # trace.
301
+ # _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
302
+
303
+
304
+ def multizone_new_cast_status(
305
+ self,
306
+ group_uuid: str,
307
+ cast_status: CastStatus
308
+ ) -> None:
309
+ """
310
+ Called when the group identified by group_uuid, of which the cast is a member, has new status.
311
+ """
312
+ # Commented out this code, as we do not use it.
313
+ # Left it in place, in case it's required in the future.
314
+ #pass
315
+
316
+ # use lock, as multiple threads could be calling this method simultaneously.
317
+ with self._Zeroconf_RLock:
318
+
319
+ # copy passed parameters to thread-safe storage.
320
+ argsGroupUuid:UUID = group_uuid
321
+ argsCastStatus:CastStatus = cast_status
322
+
323
+ apiMethodName:str = "multizone_new_cast_status (MultiZoneManagerListener)"
324
+ apiMethodParms:SIMethodParmListContext = None
325
+
326
+ try:
327
+
328
+ # trace.
329
+ apiMethodParms = _logsi.EnterMethodParmList(SILevel.Debug, apiMethodName)
330
+ apiMethodParms.AppendKeyValue("group_uuid", argsGroupUuid)
331
+ apiMethodParms.AppendKeyValue("cast_status", argsCastStatus)
332
+ _logsi.LogMethodParmList(SILevel.Debug, "Chromecast multizone manager cast status has been updated for group: \"%s\"" % (argsGroupUuid), apiMethodParms, colorValue=SIColors.Lavender)
333
+
334
+ # example - CastStatus:
335
+ # {
336
+ # "is_active_input": "None",
337
+ # "is_stand_by": "None",
338
+ # "volume_level": "0.10000763088464737",
339
+ # "volume_muted": "False",
340
+ # "app_id": "CC32E753",
341
+ # "display_name": "Spotify",
342
+ # "namespaces": ['urn:x-cast:com.google.cast.debugoverlay',
343
+ # 'urn:x-cast:com.google.cast.cac',
344
+ # 'urn:x-cast:com.spotify.chromecast.secure.v1',
345
+ # 'urn:x-cast:com.google.cast.media'
346
+ # ],
347
+ # "session_id": "690a6e31-647d-4808-97f1-cc65cf2eb473",
348
+ # "transport_id": "690a6e31-647d-4808-97f1-cc65cf2eb473",
349
+ # "status_text": "Casting: Strong Enough",
350
+ # "icon_url": "https://lh3.googleusercontent.com/oodettwQnQA4LTRxkeyqf93S8J6gbWu9r8DPsiVsDoiTffNV2xhiSeNnFCQ8zh5I4xGaAH_xyLzLx3E6",
351
+ # "volume_control_type": "master"
352
+ # }
353
+
354
+ # trace.
355
+ if (_logsi.IsOn(SILevel.Verbose)):
356
+
357
+ # get group device instance.
358
+ scDevice:SpotifyConnectDevice = self._ParentDirectory._SpotifyConnectDevices.GetDeviceByDiscoveryKey(str(argsGroupUuid))
359
+ if (scDevice is None):
360
+
361
+ # trace.
362
+ _logsi.LogVerbose("Could not find SpotifyConnectDevices instance for Cast device key: \"%s\"" % (str(argsGroupUuid)), colorValue=SIColors.Lavender)
363
+
364
+ else:
365
+
366
+ # formulate current status.
367
+ statusText:str = "unknown"
368
+ if (argsCastStatus):
369
+ statusText = "%s: %s" % (argsCastStatus.display_name or "null", argsCastStatus.status_text or "null")
370
+
371
+ # trace.
372
+ _logsi.LogObject(SILevel.Verbose, "Chromecast multizone manager group CastStatus: %s [%s] - %s" % (scDevice.Title, scDevice.DiscoveryResult.HostIpTitle, statusText), argsCastStatus, colorValue=SIColors.Lavender)
373
+
374
+ except Exception as ex:
375
+
376
+ # trace.
377
+ _logsi.LogException(SpotifyConnectZeroconfCastMultiZoneManagerListener.UNHANDLED_EXCEPTION_MSG % (apiMethodName), ex, logToSystemLogger=False)
378
+
379
+ # ignore exception, as nothing can be done about it.
380
+
381
+ finally:
382
+
383
+ # trace.
384
+ _logsi.LeaveMethod(SILevel.Debug, apiMethodName)
@@ -7,6 +7,7 @@ from .image import VibrantImage
7
7
  from .main import Vibrant
8
8
  from .models import Palette, Props, Swatch
9
9
  from .utils import hsl_to_rgb, rgb_to_hsl
10
+ from .colorthieffast import ColorThiefFast
10
11
 
11
12
  # all classes to import when "import *" is specified.
12
13
  __all__ = [
@@ -14,4 +15,5 @@ __all__ = [
14
15
  'Vibrant',
15
16
  'Palette',
16
17
  'Swatch',
18
+ 'ColorThiefFast',
17
19
  ]