spotifywebapiPython 1.0.259__py3-none-any.whl → 1.0.261__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.
- spotifywebapipython/__init__.py +2 -0
- spotifywebapipython/const.py +1 -1
- spotifywebapipython/docs/__init__.html +23 -2
- spotifywebapipython/docs/index.html +8 -2
- spotifywebapipython/docs/search.js +1 -1
- spotifywebapipython/docs/spotifywebapipython/const.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/saappmessages.html +26 -8
- 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 +494 -82
- spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifymediatypes.html +441 -0
- spotifywebapipython/docs/spotifywebapipython/spotifytypeprefixes.html +458 -0
- spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html +2 -2
- spotifywebapipython/models/zeroconfdiscoveryresult.py +1 -1
- spotifywebapipython/saappmessages.py +6 -1
- spotifywebapipython/spotifyclient.py +1020 -344
- spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py +64 -7
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastapptask.py +6 -0
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastcontroller.py +42 -13
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastlistener.py +12 -0
- spotifywebapipython/spotifymediatypes.py +10 -10
- spotifywebapipython/spotifytypeprefixes.py +65 -0
- {spotifywebapipython-1.0.259.dist-info → spotifywebapipython-1.0.261.dist-info}/METADATA +1 -1
- {spotifywebapipython-1.0.259.dist-info → spotifywebapipython-1.0.261.dist-info}/RECORD +32 -29
- {spotifywebapipython-1.0.259.dist-info → spotifywebapipython-1.0.261.dist-info}/LICENSE +0 -0
- {spotifywebapipython-1.0.259.dist-info → spotifywebapipython-1.0.261.dist-info}/WHEEL +0 -0
- {spotifywebapipython-1.0.259.dist-info → spotifywebapipython-1.0.261.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,7 @@ from abc import abstractmethod
|
|
|
3
3
|
import copy
|
|
4
4
|
from datetime import datetime
|
|
5
5
|
import hashlib
|
|
6
|
-
from pychromecast import CastBrowser, CastInfo, Chromecast, get_chromecast_from_cast_info, get_chromecast_from_host
|
|
6
|
+
from pychromecast import APP_MEDIA_RECEIVER, CastBrowser, CastInfo, Chromecast, get_chromecast_from_cast_info, get_chromecast_from_host
|
|
7
7
|
from pychromecast.dial import MultizoneInfo, MultizoneStatus, get_multizone_status
|
|
8
8
|
from pychromecast.controllers.multizone import MultiZoneManagerListener, MultizoneController, MultizoneManager
|
|
9
9
|
from pychromecast.const import CAST_TYPE_GROUP
|
|
@@ -23,6 +23,8 @@ from .spotifyconnectzeroconfcastmultizonemanagerlistener import SpotifyConnectZe
|
|
|
23
23
|
from .spotifyconnectdeviceeventargs import SpotifyConnectDeviceEventArgs
|
|
24
24
|
from .spotifyconnectzeroconflistener import ZEROCONF_SERVICETYPE_SPOTIFYCONNECT, SpotifyConnectZeroconfListener
|
|
25
25
|
from .spotifyconnectzeroconfcastcontroller import (
|
|
26
|
+
APP_SPOTIFY,
|
|
27
|
+
APP_SPOTIFY_CONNECT,
|
|
26
28
|
TYPE_ADD_USER_RESPONSE,
|
|
27
29
|
TYPE_ADD_USER_ERROR,
|
|
28
30
|
TYPE_GET_INFO_ERROR,
|
|
@@ -667,6 +669,58 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
667
669
|
castMultizoneController:MultizoneController = self._CastMultiZoneControllers.get(str(castInfo.uuid), None)
|
|
668
670
|
if (castMultizoneController) and (castMultizoneController._socket_client):
|
|
669
671
|
castMultizoneController.update_members()
|
|
672
|
+
time.sleep(2.0) # give controller some time to update member list.
|
|
673
|
+
|
|
674
|
+
# activate media receiver app for each member in the group.
|
|
675
|
+
# process all device members in the group / zone.
|
|
676
|
+
for zone_member_uuid in castMultizoneController.members:
|
|
677
|
+
|
|
678
|
+
# get castInfo instance so we can connect to the device.
|
|
679
|
+
zone_member_castInfo = self._CastBrowser.devices.get(UUID(zone_member_uuid))
|
|
680
|
+
if zone_member_castInfo is not None:
|
|
681
|
+
|
|
682
|
+
# get cast device instance.
|
|
683
|
+
zone_member_castDevice = get_chromecast_from_cast_info(
|
|
684
|
+
cast_info=zone_member_castInfo,
|
|
685
|
+
zconf=self._ZeroconfInstance,
|
|
686
|
+
tries=2,
|
|
687
|
+
retry_wait=0.5,
|
|
688
|
+
timeout=5)
|
|
689
|
+
|
|
690
|
+
# wait for the cast device to provide an initial status.
|
|
691
|
+
zone_member_castDevice.wait(10)
|
|
692
|
+
|
|
693
|
+
# formulate title for trace messages.
|
|
694
|
+
trc_zone_member_title:str = "\"%s\" [ip=%s:%s]" % (zone_member_castDevice.cast_info.friendly_name, zone_member_castDevice.socket_client.host, zone_member_castDevice.socket_client.port)
|
|
695
|
+
|
|
696
|
+
# trace.
|
|
697
|
+
_logsi.LogObject(SILevel.Verbose, "%s - Cast group \"%s\" member Chromecast device status: %s" % (self.name, castInfo.friendly_name, trc_zone_member_title), zone_member_castDevice.status, colorValue=SIColors.Coral)
|
|
698
|
+
|
|
699
|
+
# if current app is APP_SPOTIFY, then stop the app before starting the media receiver.
|
|
700
|
+
if (zone_member_castDevice.status) and (zone_member_castDevice.status.app_id == APP_SPOTIFY):
|
|
701
|
+
_logsi.LogVerbose("%s - Issuing quit_app (APP_SPOTIFY) for group \"%s\" member device: %s" % (self.name, castInfo.friendly_name, trc_zone_member_title), colorValue=SIColors.Coral)
|
|
702
|
+
zone_member_castDevice.quit_app(timeout=5.0)
|
|
703
|
+
elif (zone_member_castDevice.status) and (zone_member_castDevice.status.app_id == APP_SPOTIFY_CONNECT):
|
|
704
|
+
_logsi.LogVerbose("%s - Issuing quit_app (APP_SPOTIFY_CONNECT) for group \"%s\" member device: %s" % (self.name, castInfo.friendly_name, trc_zone_member_title), colorValue=SIColors.Coral)
|
|
705
|
+
zone_member_castDevice.quit_app(timeout=5.0)
|
|
706
|
+
|
|
707
|
+
# start the media receiver app.
|
|
708
|
+
# this will stabilize routing for the group using the Default Media Receiver.
|
|
709
|
+
_logsi.LogVerbose("%s - Starting Chromecast default APP_MEDIA_RECEIVER for group \"%s\" member device: %s" % (self.name, castInfo.friendly_name, trc_zone_member_title), colorValue=SIColors.Coral)
|
|
710
|
+
zone_member_castDevice.start_app(APP_MEDIA_RECEIVER, force_launch=True, timeout=10.0)
|
|
711
|
+
|
|
712
|
+
# start the connection worker thread, if needed.
|
|
713
|
+
# failure to do this will result in the following exception being thrown when
|
|
714
|
+
# the `launch_app()` method is called:
|
|
715
|
+
# - `pychromecast.error.NotConnected: Chromecast unknown:8009 is connecting...`
|
|
716
|
+
if (zone_member_castDevice.is_idle):
|
|
717
|
+
if (zone_member_castDevice.socket_client is not None) and (zone_member_castDevice.socket_client.first_connection):
|
|
718
|
+
_logsi.LogVerbose("%s - Starting Chromecast default APP_MEDIA_RECEIVER connection worker thread for group \"%s\" member device: %s" % (self.name, castInfo.friendly_name, trc_zone_member_title), colorValue=SIColors.Coral)
|
|
719
|
+
zone_member_castDevice.start()
|
|
720
|
+
zone_member_castDevice.wait(timeout=5.0)
|
|
721
|
+
|
|
722
|
+
# media receiver app needs time to start.
|
|
723
|
+
time.sleep(2.0)
|
|
670
724
|
|
|
671
725
|
except Exception as ex:
|
|
672
726
|
|
|
@@ -678,6 +732,7 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
678
732
|
castMultiZoneStatus:MultizoneStatus = get_multizone_status(castInfo.host, castInfo.services, self.ZeroconfInstance, 5)
|
|
679
733
|
_logsi.LogObject(SILevel.Verbose, "%s - Chromecast group multizone status for device: %s [ip=%s:%s]" % (self.name, scDevice.Title, castInfo.host, castInfo.port), castMultiZoneStatus, colorValue=SIColors.Coral)
|
|
680
734
|
|
|
735
|
+
# ensure group device is still on the network;
|
|
681
736
|
# if group device dropped off the network, then we can't query it!
|
|
682
737
|
if (castMultiZoneStatus is not None):
|
|
683
738
|
|
|
@@ -703,11 +758,13 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
703
758
|
retry_wait=0.5,
|
|
704
759
|
timeout=10)
|
|
705
760
|
|
|
706
|
-
#
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
761
|
+
# don't need this anymore, since we are activating media receiver on each group member.
|
|
762
|
+
# left it in here just in case we change our mind.
|
|
763
|
+
# # calculate wait timeout for devices to become active, based on number of devices in group.
|
|
764
|
+
# if (castMultiZoneStatus.groups is not None):
|
|
765
|
+
# groupCount:int = len(castMultiZoneStatus.groups)
|
|
766
|
+
# if (groupCount > 1):
|
|
767
|
+
# deviceWaitTimeoutSecs = (groupCount * 5.0)
|
|
711
768
|
|
|
712
769
|
# trace.
|
|
713
770
|
_logsi.LogVerbose("%s - Waiting %d seconds max for Chromecast group multizone device to activate: %s [ip=%s:%s]" % (self.name, deviceWaitTimeoutSecs, scDevice.Title, groupHost, groupPort), colorValue=SIColors.Coral)
|
|
@@ -740,7 +797,7 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
740
797
|
# trace.
|
|
741
798
|
if (_logsi.IsOn(SILevel.Verbose)):
|
|
742
799
|
_logsi.LogObject(SILevel.Verbose, "%s - Chromecast device object: \"%s\" (ip=%s:%s)" % (self.name, castInfo.friendly_name, castDevice.socket_client.host, castDevice.socket_client.port), castDevice)
|
|
743
|
-
_logsi.LogObject(SILevel.Verbose, "%s - Chromecast device status: %s [ip=%s:%s]" % (self.name, scDevice.Title, castDevice.socket_client.host, castDevice.socket_client.port), castDevice.status)
|
|
800
|
+
_logsi.LogObject(SILevel.Verbose, "%s - Chromecast device status: %s [ip=%s:%s]" % (self.name, scDevice.Title, castDevice.socket_client.host, castDevice.socket_client.port), castDevice.status, colorValue=SIColors.Coral)
|
|
744
801
|
self._TraceMultizoneGroupMembers(str(castInfo.uuid), castInfo.friendly_name)
|
|
745
802
|
|
|
746
803
|
# verify multizone controller instance is registered for cast group device.
|
|
@@ -221,6 +221,9 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
221
221
|
self._CastDevice.start()
|
|
222
222
|
self._CastDevice.wait(10)
|
|
223
223
|
|
|
224
|
+
# trace.
|
|
225
|
+
_logsi.LogObject(SILevel.Verbose, "%s - Chromecast device status: %s (castAppTask pre-launch)" % (self.name, self._CastDevice.cast_info.friendly_name), self._CastDevice.status)
|
|
226
|
+
|
|
224
227
|
# get spotify desktop authorization token.
|
|
225
228
|
_logsi.LogVerbose("%s - Retrieving Spotify Desktop authorization token for loginId \"%s\"" % (self.name, self.SpotifyClientInstance.SpotifyConnectLoginId), colorValue=SIColors.Gold)
|
|
226
229
|
tokenSP:SpotifyAuthToken = self._GetSpotifyDesktopAuthorizationToken(self.SpotifyClientInstance.SpotifyConnectLoginId)
|
|
@@ -245,6 +248,9 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
245
248
|
# at this point the cast app should be either fully launched, or an error
|
|
246
249
|
# occured while trying to launch.
|
|
247
250
|
|
|
251
|
+
# trace.
|
|
252
|
+
_logsi.LogObject(SILevel.Verbose, "%s - Chromecast device status: %s (castAppTask post-launch)" % (self.name, self._CastDevice.cast_info.friendly_name), self._CastDevice.status)
|
|
253
|
+
|
|
248
254
|
# did an error occur?
|
|
249
255
|
if (not self._SpotifyConnectZeroconfCastController.isLaunched):
|
|
250
256
|
|
|
@@ -32,9 +32,14 @@ if (_logsi == None):
|
|
|
32
32
|
_logsi = SIAuto.Si.AddSession(__name__, True)
|
|
33
33
|
_logsi.SystemLogger = logging.getLogger(__name__)
|
|
34
34
|
|
|
35
|
+
# constants - cast app identifiers.
|
|
36
|
+
APP_GOOGLE_INTERNAL_RECEIVER = "705D30C6" # Google Internal Receiver
|
|
37
|
+
APP_SPOTIFY_CONNECT = "531A4F84" # Spotify Connect
|
|
38
|
+
APP_SPOTIFY = "CC32E753" # Spotify (legacy / classic cast)
|
|
39
|
+
APP_SPOTIFY_NAMESPACE = "urn:x-cast:com.spotify.chromecast.secure.v1"
|
|
40
|
+
APP_SPOTIFY_LAUNCH_TIMEOUT = 20.0 # Amount of time to wait for Spotify App launch.
|
|
41
|
+
|
|
35
42
|
# constants.
|
|
36
|
-
APP_SPOTIFY = "CC32E753"
|
|
37
|
-
APP_NAMESPACE = "urn:x-cast:com.spotify.chromecast.secure.v1"
|
|
38
43
|
TYPE_GET_INFO = "getInfo"
|
|
39
44
|
TYPE_GET_INFO_ERROR = "getInfoError"
|
|
40
45
|
TYPE_GET_INFO_RESPONSE = "getInfoResponse"
|
|
@@ -78,7 +83,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
78
83
|
"""
|
|
79
84
|
|
|
80
85
|
# invoke base class method.
|
|
81
|
-
super().__init__(
|
|
86
|
+
super().__init__(APP_SPOTIFY_NAMESPACE, APP_SPOTIFY)
|
|
82
87
|
|
|
83
88
|
# initialize storage.
|
|
84
89
|
self.accessToken:str = accessToken
|
|
@@ -88,6 +93,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
88
93
|
self.deviceId:str = None
|
|
89
94
|
self.isAddUserError:bool = False
|
|
90
95
|
self.isGetInfoError:bool = False
|
|
96
|
+
self.isLaunchError:bool = False
|
|
91
97
|
self.isLaunched:bool = False
|
|
92
98
|
self.isPlaybackTransferError:bool = False
|
|
93
99
|
self.isMessageException:bool = False
|
|
@@ -141,6 +147,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
141
147
|
self.isLaunched = False
|
|
142
148
|
self.isAddUserError = False
|
|
143
149
|
self.isGetInfoError = False
|
|
150
|
+
self.isLaunchError = False
|
|
144
151
|
self.isPlaybackTransferError = False
|
|
145
152
|
self.isMessageException = False
|
|
146
153
|
self.waitAddUser.clear()
|
|
@@ -186,6 +193,8 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
186
193
|
raise SpotifyZeroconfApiError(self.zeroconfResponse.Status, "AddUser request failed", "launch_app", self.zeroconfResponse.StatusString)
|
|
187
194
|
if (self.isGetInfoError):
|
|
188
195
|
raise SpotifyZeroconfApiError(self.zeroconfResponse.Status, "GetInformation request failed", "launch_app", self.zeroconfResponse.StatusString)
|
|
196
|
+
if (self.isLaunchError):
|
|
197
|
+
raise SpotifyZeroconfApiError(self.zeroconfResponse.Status, "Launch request failed", "launch_app", self.zeroconfResponse.StatusString)
|
|
189
198
|
if (not self.isLaunched):
|
|
190
199
|
raise SpotifyConnectZeroconfLaunchError("Spotify Cast App could not be launched")
|
|
191
200
|
|
|
@@ -244,7 +253,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
244
253
|
try:
|
|
245
254
|
|
|
246
255
|
# trace.
|
|
247
|
-
_logsi.LogDictionary(SILevel.Verbose, "Chromecast Message payload received: %s" % message, data, prettyPrint=True)
|
|
256
|
+
_logsi.LogDictionary(SILevel.Verbose, "Chromecast Message payload received: %s" % message, data, prettyPrint=True, colorValue=SIColors.Tan)
|
|
248
257
|
|
|
249
258
|
# message argument example: "getInfoResponse"
|
|
250
259
|
# protocol_version: CASTV2_1_0
|
|
@@ -317,7 +326,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
317
326
|
self.zeroconfGetInfo.ResponseSource = payloadDataType
|
|
318
327
|
|
|
319
328
|
# trace.
|
|
320
|
-
_logsi.LogObject(SILevel.Verbose, "GetInformation result (ZeroconfGetInfo) - \"%s\" (%s)" % (self.zeroconfGetInfo.RemoteName, self.zeroconfGetInfo.DeviceId), self.zeroconfGetInfo, excludeNonPublic=True)
|
|
329
|
+
_logsi.LogObject(SILevel.Verbose, "GetInformation result (ZeroconfGetInfo) - \"%s\" (%s)" % (self.zeroconfGetInfo.RemoteName, self.zeroconfGetInfo.DeviceId), self.zeroconfGetInfo, excludeNonPublic=True, colorValue=SIColors.Tan)
|
|
321
330
|
|
|
322
331
|
# getInfo response received from the initial launch.
|
|
323
332
|
self.deviceId = self.zeroconfGetInfo.DeviceId
|
|
@@ -448,7 +457,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
448
457
|
return True
|
|
449
458
|
|
|
450
459
|
# trace.
|
|
451
|
-
_logsi.LogDictionary(SILevel.Verbose, "Chromecast Message ignored - payload type value not recognized: \"%s\"" % (payloadDataType), message, prettyPrint=True)
|
|
460
|
+
_logsi.LogDictionary(SILevel.Verbose, "Chromecast Message ignored - payload type value not recognized: \"%s\"" % (payloadDataType), message, prettyPrint=True, colorValue=SIColors.Tan)
|
|
452
461
|
|
|
453
462
|
return True
|
|
454
463
|
|
|
@@ -463,7 +472,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
463
472
|
self.zeroconfResponse = response
|
|
464
473
|
|
|
465
474
|
# trace.
|
|
466
|
-
_logsi.LogException(SAAppMessages.UNHANDLED_EXCEPTION.format("receive_message", str(ex)), ex, logToSystemLogger=False)
|
|
475
|
+
_logsi.LogException(SAAppMessages.UNHANDLED_EXCEPTION.format("receive_message", str(ex)), ex, logToSystemLogger=False, colorValue=SIColors.Tan)
|
|
467
476
|
|
|
468
477
|
# ignore exceptions, as there is nothing we can do at this point.
|
|
469
478
|
|
|
@@ -571,7 +580,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
571
580
|
"blob": json_resp["accessToken"],
|
|
572
581
|
},
|
|
573
582
|
}
|
|
574
|
-
_logsi.LogDictionary(SILevel.Debug, "Sending Spotify Connect Zeroconf AddUser Chromecast Message payload to Chromecast device (ip=%s:%s)" % (self.castDevice.socket_client.host, self.castDevice.socket_client.port), castMsg, prettyPrint=True)
|
|
583
|
+
_logsi.LogDictionary(SILevel.Debug, "Sending Spotify Connect Zeroconf AddUser Chromecast Message payload to Chromecast device (ip=%s:%s)" % (self.castDevice.socket_client.host, self.castDevice.socket_client.port), castMsg, prettyPrint=True, colorValue=SIColors.Tan)
|
|
575
584
|
self.send_message(castMsg)
|
|
576
585
|
|
|
577
586
|
# if we are in the process of launching, then we will wait for a response in the
|
|
@@ -589,7 +598,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
589
598
|
if (counter >= timeout):
|
|
590
599
|
raise SpotifyZeroconfApiError(0, "Timed out while waiting for a response", "AddUser", "timeout")
|
|
591
600
|
counter += WAIT_INTERVAL
|
|
592
|
-
_logsi.LogVerbose("Waiting for addUserResponse Chromecast Message payload (%f seconds from initial request)" % (counter))
|
|
601
|
+
_logsi.LogVerbose("Waiting for addUserResponse Chromecast Message payload (%f seconds from initial request)" % (counter), colorValue=SIColors.Tan)
|
|
593
602
|
|
|
594
603
|
# if we make it here, then addUser request was processed successfully.
|
|
595
604
|
return
|
|
@@ -665,7 +674,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
665
674
|
"interactionIDs": [self.interactionID],
|
|
666
675
|
},
|
|
667
676
|
}
|
|
668
|
-
_logsi.LogDictionary(SILevel.Debug, "Sending Spotify Connect Zeroconf Getinformation Chromecast Message payload to Chromecast device (ip=%s:%s)" % (self.castDevice.socket_client.host, self.castDevice.socket_client.port), castMsg, prettyPrint=True)
|
|
677
|
+
_logsi.LogDictionary(SILevel.Debug, "Sending Spotify Connect Zeroconf Getinformation Chromecast Message payload to Chromecast device (ip=%s:%s)" % (self.castDevice.socket_client.host, self.castDevice.socket_client.port), castMsg, prettyPrint=True, colorValue=SIColors.Tan)
|
|
669
678
|
self.send_message(castMsg)
|
|
670
679
|
|
|
671
680
|
# if we are in the process of launching, then we will wait for a response in the
|
|
@@ -683,7 +692,7 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
683
692
|
if (counter >= timeout):
|
|
684
693
|
raise SpotifyZeroconfApiError(0, "Timed out while waiting for a response", "GetInformation", "timeout")
|
|
685
694
|
counter += WAIT_INTERVAL
|
|
686
|
-
_logsi.LogVerbose("Waiting for getInfoResponse Chromecast Message payload (%f seconds from initial request)" % (counter))
|
|
695
|
+
_logsi.LogVerbose("Waiting for getInfoResponse Chromecast Message payload (%f seconds from initial request)" % (counter), colorValue=SIColors.Tan)
|
|
687
696
|
|
|
688
697
|
# if we make it here, then getInfo request was processed successfully.
|
|
689
698
|
# return response to the caller.
|
|
@@ -691,9 +700,29 @@ class SpotifyConnectZeroconfCastController(BaseController):
|
|
|
691
700
|
|
|
692
701
|
except SpotifyZeroconfApiError: raise # pass handled exceptions on thru
|
|
693
702
|
except Exception as ex:
|
|
703
|
+
|
|
704
|
+
# pychromecast ControllerNotRegistered can occur when launching to cast group devices
|
|
705
|
+
# that contain a Google Mini (legacy) device.
|
|
706
|
+
|
|
707
|
+
# indicate launch error.
|
|
708
|
+
self.isLaunchError = True
|
|
694
709
|
|
|
695
|
-
#
|
|
696
|
-
|
|
710
|
+
# load zeroconfResponse instance with exception information.
|
|
711
|
+
response: ZeroconfResponse = ZeroconfResponse()
|
|
712
|
+
response.SpotifyError = 0
|
|
713
|
+
response.Status = 1001
|
|
714
|
+
response.StatusString = "ERROR-PYCHROMECAST-%s" % (type(ex).__name__.upper())
|
|
715
|
+
response.ResponseSource = "SpotifyConnectZeroconfCastController"
|
|
716
|
+
self.zeroconfResponse = response
|
|
717
|
+
|
|
718
|
+
# trace.
|
|
719
|
+
_logsi.LogException(SAAppMessages.UNHANDLED_EXCEPTION.format("GetInformation", str(ex)), ex, logToSystemLogger=False, colorValue=SIColors.Tan)
|
|
720
|
+
|
|
721
|
+
# if app is not launched, then init is waiting on the `waitAddUser` event!
|
|
722
|
+
if (not self.isLaunched):
|
|
723
|
+
self.waitAddUser.set()
|
|
724
|
+
|
|
725
|
+
# ignore exceptions, as there is nothing we can do at this point.
|
|
697
726
|
|
|
698
727
|
finally:
|
|
699
728
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# external package imports.
|
|
2
2
|
from pychromecast import CastInfo, HostServiceInfo
|
|
3
3
|
from pychromecast.discovery import AbstractCastListener
|
|
4
|
+
import ipaddress
|
|
4
5
|
import threading
|
|
5
6
|
from uuid import UUID
|
|
6
7
|
|
|
@@ -145,6 +146,17 @@ class SpotifyConnectZeroconfCastListener(AbstractCastListener):
|
|
|
145
146
|
if (not (castType in [CAST_TYPE_AUDIO, CAST_TYPE_GROUP, CAST_TYPE_CHROMECAST, CAST_TYPE_NONE])):
|
|
146
147
|
_logsi.LogDebug("Chromecast device cast_type of \"%s\" is not supported; ignoring: \"%s\" (%s)" % (castType, castInfo.friendly_name, serviceName), colorValue=SIColors.Coral)
|
|
147
148
|
return None
|
|
149
|
+
|
|
150
|
+
# ensure IPV4 connection - ignore if IPV6.
|
|
151
|
+
# Windows OS does not support dual-stack socket handling IPv4 (224.0.0.251) and IPv6 (ff02::fb).
|
|
152
|
+
ip = ipaddress.ip_address(castInfo.host)
|
|
153
|
+
if (ip.version == 6):
|
|
154
|
+
_logsi.LogDebug("Chromecast IPV6 device addresses are not supported; device could cause problems: \"%s\" (%s)" % (castInfo.friendly_name, serviceName), colorValue=SIColors.Red)
|
|
155
|
+
|
|
156
|
+
# will still allow this for now, but we might want to ignore IPV6 devices
|
|
157
|
+
# in the future! To do so, just uncomment the following, which will
|
|
158
|
+
# ignore the device.
|
|
159
|
+
#return None
|
|
148
160
|
|
|
149
161
|
# create new discovery result instance.
|
|
150
162
|
result:ZeroconfDiscoveryResult = ZeroconfDiscoveryResult()
|
|
@@ -60,13 +60,13 @@ class SpotifyMediaTypes(StrEnum):
|
|
|
60
60
|
"""
|
|
61
61
|
|
|
62
62
|
|
|
63
|
-
def __eq__(self, other):
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
63
|
+
# def __eq__(self, other):
|
|
64
|
+
# """
|
|
65
|
+
# Override __eq__ so that we can compare enum members directly to their raw values
|
|
66
|
+
# without explicitly accessing the ".value".
|
|
67
|
+
# """
|
|
68
|
+
# if isinstance(other, self.__class__):
|
|
69
|
+
# return self is other
|
|
70
|
+
# elif isinstance(other, type(self.value)):
|
|
71
|
+
# return self.value == other
|
|
72
|
+
# return False
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from enum import StrEnum
|
|
2
|
+
|
|
3
|
+
class SpotifyTypePrefixes(StrEnum):
|
|
4
|
+
"""
|
|
5
|
+
Spotify media type prefixes enumeration.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
ALBUM = "spotify:album:"
|
|
9
|
+
"""
|
|
10
|
+
Album media type.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
ARTIST = "spotify:artist:"
|
|
14
|
+
"""
|
|
15
|
+
Artist media type.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
AUDIOBOOK = "spotify:audiobook:"
|
|
19
|
+
"""
|
|
20
|
+
Audiobook media type.
|
|
21
|
+
|
|
22
|
+
This value is not part of the Spotify Web API specification.
|
|
23
|
+
It is loaded from our API so that the type of item can be determined programatically.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
EPISODE = "spotify:episode:"
|
|
27
|
+
"""
|
|
28
|
+
Episode media type.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
PLAYLIST = "spotify:playlist:"
|
|
32
|
+
"""
|
|
33
|
+
Playlist media type.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
PODCAST = "spotify:podcast:"
|
|
37
|
+
"""
|
|
38
|
+
Podcast episode type.
|
|
39
|
+
|
|
40
|
+
This value is not part of the Spotify Web API specification.
|
|
41
|
+
It is loaded from our API so that the type of item can be determined programatically.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
SHOW = "spotify:show:"
|
|
45
|
+
"""
|
|
46
|
+
Show media type.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
TRACK = "spotify:track:"
|
|
50
|
+
"""
|
|
51
|
+
Track media type.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
USER = "spotify:user:"
|
|
55
|
+
"""
|
|
56
|
+
Track media type.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
UNKNOWN = "spotify:unknown:"
|
|
60
|
+
"""
|
|
61
|
+
Unknown media type.
|
|
62
|
+
|
|
63
|
+
This value is not part of the Spotify Web API specification.
|
|
64
|
+
It is loaded from our API so that the type of item can be determined programatically.
|
|
65
|
+
"""
|
|
@@ -1,33 +1,36 @@
|
|
|
1
|
-
spotifywebapipython/__init__.py,sha256=
|
|
2
|
-
spotifywebapipython/const.py,sha256=
|
|
3
|
-
spotifywebapipython/saappmessages.py,sha256=
|
|
1
|
+
spotifywebapipython/__init__.py,sha256=ka7F2AsT-UU7KSYKBnfgl5Trojcep5aQspLutg8D-2k,1306
|
|
2
|
+
spotifywebapipython/const.py,sha256=3mSxDa97aItq_ektUA1qfK4_bBoI7krNApvUrWnP9pE,3923
|
|
3
|
+
spotifywebapipython/saappmessages.py,sha256=mVprjpd5CdD8kYeAkLzRvMvIQPmaYtH4UCP5my3QhSk,5065
|
|
4
4
|
spotifywebapipython/sautils.py,sha256=j3f_Lu3Tb5D7-Gd2rJ2Ep901W-4XDp6Vq6XXVl8DX5I,8098
|
|
5
5
|
spotifywebapipython/spotifyapierror.py,sha256=23_CYlxWN0BceYYCLpBpunl55vEwPr_wFf34l74xzeA,1855
|
|
6
6
|
spotifywebapipython/spotifyapimessage.py,sha256=wCnW8jYMLS3x9kjyXPgXXZqaf1HeMTTXzU8u_Dm5pfA,8447
|
|
7
7
|
spotifywebapipython/spotifyauthtoken.py,sha256=iVg2Pa5mfMqYe4qgc5H8td6JzJlaDqk4vMEhH5LmtfI,9289
|
|
8
|
-
spotifywebapipython/spotifyclient.py,sha256=
|
|
8
|
+
spotifywebapipython/spotifyclient.py,sha256=h3Oizin4YG7U-KPDSINdSf50ZtThmAdld6WYR86w8so,893394
|
|
9
9
|
spotifywebapipython/spotifydiscovery.py,sha256=cyysxl8PQj9yGHVbaqhSF3SStlrp-NvfGAudM-dDmg0,20290
|
|
10
|
-
spotifywebapipython/spotifymediatypes.py,sha256=
|
|
10
|
+
spotifywebapipython/spotifymediatypes.py,sha256=hMjkxhbfTtks0_P8BKmY7qg3EmB2zhH3RT0DbEpb_2s,1628
|
|
11
|
+
spotifywebapipython/spotifytypeprefixes.py,sha256=3yfpxKF7jF694qBuo-PbKYvm70YwwdBoGj9enOpWsAg,1375
|
|
11
12
|
spotifywebapipython/spotifywebapiauthenticationerror.py,sha256=5A0MKvYo3Ypv0ZeSSfLHuFLwzoUUu044bBoUgMfNXNw,3940
|
|
12
13
|
spotifywebapipython/spotifywebapierror.py,sha256=5cga9213J_nFQ0UX4vSn3dpyinASKTRiH0wAR4nLjvs,3147
|
|
13
14
|
spotifywebapipython/spotifywebplayertoken.py,sha256=axj1j1lM7COiiZfpElkJRdnk4AmE6bAQcjKshUIz1Nk,35813
|
|
14
|
-
spotifywebapipython/docs/__init__.html,sha256=
|
|
15
|
+
spotifywebapipython/docs/__init__.html,sha256=B7Ca0_PI5g3P7uYtVRn3bcSGXnH-Zl9dPjCy4NeXFFM,185587
|
|
15
16
|
spotifywebapipython/docs/codecopy.js,sha256=ryuoZwLIL03YitjjFzn49UO5ta7-OBos6LNA3qHhFzs,3120
|
|
16
|
-
spotifywebapipython/docs/index.html,sha256=
|
|
17
|
-
spotifywebapipython/docs/search.js,sha256=
|
|
17
|
+
spotifywebapipython/docs/index.html,sha256=21MQnmOy1a2EjDM8ve8OcarjzJX19o1n0anNZUmzplM,48779
|
|
18
|
+
spotifywebapipython/docs/search.js,sha256=U41gKtSu_T-vtyoPskKxtNbBmLJnWkP1efWob6_vSa0,9147897
|
|
18
19
|
spotifywebapipython/docs/spotifywebapipython.ico,sha256=YImj39fqqSPSuB2-sMDlUYDd6YwRfQeJRtq4FjwWglg,16410
|
|
19
20
|
spotifywebapipython/docs/spotifywebapipython_OLD.ico,sha256=YIv5LjcD4bTIJQSOr8jjwbWaeB3QkElRwkTOePiGbZo,14904
|
|
20
|
-
spotifywebapipython/docs/spotifywebapipython/const.html,sha256=
|
|
21
|
-
spotifywebapipython/docs/spotifywebapipython/saappmessages.html,sha256=
|
|
22
|
-
spotifywebapipython/docs/spotifywebapipython/sautils.html,sha256=
|
|
23
|
-
spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html,sha256=
|
|
24
|
-
spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html,sha256=
|
|
25
|
-
spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html,sha256=
|
|
26
|
-
spotifywebapipython/docs/spotifywebapipython/spotifyclient.html,sha256=
|
|
27
|
-
spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html,sha256=
|
|
28
|
-
spotifywebapipython/docs/spotifywebapipython/
|
|
29
|
-
spotifywebapipython/docs/spotifywebapipython/
|
|
30
|
-
spotifywebapipython/docs/spotifywebapipython/
|
|
21
|
+
spotifywebapipython/docs/spotifywebapipython/const.html,sha256=qRx7QtpuIPmYMCfZydIi7QDaXcN-hjiefUAvooUjtHU,59805
|
|
22
|
+
spotifywebapipython/docs/spotifywebapipython/saappmessages.html,sha256=JNl5KbQi1aufV741xNAxNAgI525kaD06VdBo-wOjbhg,62358
|
|
23
|
+
spotifywebapipython/docs/spotifywebapipython/sautils.html,sha256=xnOj756AW4mh3VvQ8R7sP7w8GxHDCqAVox2QCYecfNc,61063
|
|
24
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html,sha256=heHmJmlRL9hLQwio3zgw_jO8xzA5TCD5e1Q3Tdqmlso,48054
|
|
25
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html,sha256=H0qgCuYoEgWL_U1dVI_UjMrQqIu564GC8kRo8mXX_4s,59210
|
|
26
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html,sha256=ZmFqfnuGobSaUDNHp4QCu2GjuX3YS6MF0zqYAHdWqFM,59256
|
|
27
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyclient.html,sha256=ffSAZSFgSXzATQ2idss3qNlo8HQ_7z_njWwrZyiGhW4,1670808
|
|
28
|
+
spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html,sha256=ZA3pKOs5ZVT1B55xXupoSTmVzTjbjt7DrC9AV18Xsu0,57662
|
|
29
|
+
spotifywebapipython/docs/spotifywebapipython/spotifymediatypes.html,sha256=Xhl_VnCgf0jkalpCviWkzcF2Iy03LYGVXVr3aFqXw3Y,51532
|
|
30
|
+
spotifywebapipython/docs/spotifywebapipython/spotifytypeprefixes.html,sha256=AVq43oAigWYemNz6GSiqnO5PQ8E_sJi77YjI1iKq6O8,52401
|
|
31
|
+
spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html,sha256=O4qBEKOHIMmxduqGVx-0Jwut9g6mOE37LrrboV52dR8,52174
|
|
32
|
+
spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html,sha256=_noX0xAqHDKOpE3lWr-5dwVW_suY-vLobg4Zkk20uEg,50592
|
|
33
|
+
spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html,sha256=ZwIaV5UuVpijHyZywmKie84TyBWx10tyND3i_UCfhgc,62204
|
|
31
34
|
spotifywebapipython/models/__init__.py,sha256=RwRQhUX-6EUs8XvStVFpR8EPwoqIAz9K6ref-28qHKI,4423
|
|
32
35
|
spotifywebapipython/models/album.py,sha256=U3Pdw0-EL33LdkeiN31fjZ23rlLk6DNGV8jRmZU7EyQ,5170
|
|
33
36
|
spotifywebapipython/models/albumpagesaved.py,sha256=SBYMhkh5ZsMrRAXl-cm9zsxMDh8gO190ENq6Py2TyGY,2417
|
|
@@ -101,16 +104,16 @@ spotifywebapipython/models/tracksaved.py,sha256=uwnTpawf7ymXlF_b4p1RyjonUwUFRp0q
|
|
|
101
104
|
spotifywebapipython/models/tracksimplified.py,sha256=fqIH45BsTRPbwq0ytss3r9YTCn1TtJSwBLAelJ2dWJY,13199
|
|
102
105
|
spotifywebapipython/models/userprofile.py,sha256=VXHP-wSWGSIiDebGDuT4fFNBCmx_ME6Hn1NO5QyyBQY,6482
|
|
103
106
|
spotifywebapipython/models/userprofilesimplified.py,sha256=YCEVED8PMeqWkORMHwj0JF_tVNqoTc1k_nce63D6kFY,6919
|
|
104
|
-
spotifywebapipython/models/zeroconfdiscoveryresult.py,sha256=
|
|
107
|
+
spotifywebapipython/models/zeroconfdiscoveryresult.py,sha256=XID2qmaK2WTGJoLTQ54aQjfutLJMLgJ7A1ATwAp06kY,20250
|
|
105
108
|
spotifywebapipython/models/zeroconfproperty.py,sha256=sXGUqbHhFMutCNKFJwJKbNbbQAnBnR7Ob5wNDSePxZk,2141
|
|
106
109
|
spotifywebapipython/oauthcli/__init__.py,sha256=K37XTxYAKT0n8otCNzWbjgJ10fAPN4WL6seEpwvWyo4,168
|
|
107
110
|
spotifywebapipython/oauthcli/authclient.py,sha256=-B_av5cxVHGHOaf8F_Xeo5u-HbOI1ytN86nOBzfW4Sw,56026
|
|
108
111
|
spotifywebapipython/spotifyconnect/__init__.py,sha256=9Xl5KiJFvWLbsdb4YQ0xmF67i36ybpXCCXrWeNsKEvc,1108
|
|
109
112
|
spotifywebapipython/spotifyconnect/spotifyconnectdeviceeventargs.py,sha256=35hKa0FAaPgy7W8D6MFXmga667pjwXITo8jSj1TDfE8,1988
|
|
110
|
-
spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py,sha256=
|
|
111
|
-
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastapptask.py,sha256=
|
|
112
|
-
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastcontroller.py,sha256=
|
|
113
|
-
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastlistener.py,sha256=
|
|
113
|
+
spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py,sha256=QXNpJSqUGuOYxCzvDH63Ka9L9Yo7Bb5iVBRtDhc4ILE,153923
|
|
114
|
+
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastapptask.py,sha256=tCjqU7ubtfzBENdvqwVB0pMDGHRY_0u6N5OYlI5hbj8,23368
|
|
115
|
+
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastcontroller.py,sha256=e2wLmFq4393IdVa51w8X5UQl4KfnHRh34DMlxZfl9-g,34218
|
|
116
|
+
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastlistener.py,sha256=zo0z0edxBwFZxN53su2yRI97krFilIlODPlz4VRyL6s,16645
|
|
114
117
|
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastmultizonecontrollerlistener.py,sha256=AA-XxS6AptJWzyO2zsM9DA5ioCncJBKDTpJkr_aN9IM,12352
|
|
115
118
|
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastmultizonemanagerlistener.py,sha256=k3wMC80Z7jBXYwiw9jq-oixRsum7E_vdHzwEgvcGbiw,18918
|
|
116
119
|
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfexceptions.py,sha256=aesGauxMoKupdTPR5rL2-rXBC3SEvH_9bQQx2Vh-abs,524
|
|
@@ -134,8 +137,8 @@ spotifywebapipython/zeroconfapi/zeroconfgetinfo.py,sha256=APayso_F7lCsdzzrkescgd
|
|
|
134
137
|
spotifywebapipython/zeroconfapi/zeroconfgetinfoalias.py,sha256=FZJM23HIPJSfhXIC3-EuS1XhawheoG5maSp7__k4yBo,2932
|
|
135
138
|
spotifywebapipython/zeroconfapi/zeroconfgetinfodrmmediaformat.py,sha256=c5uk8ljsIuBK3w2jahHKQuoWvm245LOjUBitetXx5Mo,2347
|
|
136
139
|
spotifywebapipython/zeroconfapi/zeroconfresponse.py,sha256=mAPIDj5MG53x8peiScrp7OJblwy_o_Sto4wqE0rGujU,6445
|
|
137
|
-
spotifywebapipython-1.0.
|
|
138
|
-
spotifywebapipython-1.0.
|
|
139
|
-
spotifywebapipython-1.0.
|
|
140
|
-
spotifywebapipython-1.0.
|
|
141
|
-
spotifywebapipython-1.0.
|
|
140
|
+
spotifywebapipython-1.0.261.dist-info/LICENSE,sha256=KGcc9g0zwqNLcWnSn_ezv1UtKyhMENFhvtixpxUPNsE,1177
|
|
141
|
+
spotifywebapipython-1.0.261.dist-info/METADATA,sha256=el6L_FCrM5ZEytJpYSFjlPMk3wXY3vUaN3bO35NCv3g,11644
|
|
142
|
+
spotifywebapipython-1.0.261.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
143
|
+
spotifywebapipython-1.0.261.dist-info/top_level.txt,sha256=jTBLFlijKTesYh2dteAz4vb17qjaqWKeDjpnnwTcrjs,20
|
|
144
|
+
spotifywebapipython-1.0.261.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{spotifywebapipython-1.0.259.dist-info → spotifywebapipython-1.0.261.dist-info}/top_level.txt
RENAMED
|
File without changes
|