spotifywebapiPython 1.0.294__py3-none-any.whl → 1.0.296__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/const.py +1 -1
- spotifywebapipython/docs/__init__.html +16 -2
- spotifywebapipython/docs/index.html +2 -2
- spotifywebapipython/docs/search.js +1 -1
- spotifywebapipython/docs/spotifywebapipython/const.html +3 -3
- spotifywebapipython/docs/spotifywebapipython/saappmessages.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/sautils.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifyclient.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifymediatypes.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifytypeprefixes.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html +2 -2
- spotifywebapipython/spotifyclient.py +1 -1
- spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py +126 -104
- spotifywebapipython/zeroconfapi/zeroconfconnect.py +128 -0
- spotifywebapipython/zeroconfapi/zeroconfgetinfo.py +25 -0
- {spotifywebapipython-1.0.294.dist-info → spotifywebapipython-1.0.296.dist-info}/METADATA +1 -1
- {spotifywebapipython-1.0.294.dist-info → spotifywebapipython-1.0.296.dist-info}/RECORD +26 -26
- {spotifywebapipython-1.0.294.dist-info → spotifywebapipython-1.0.296.dist-info}/LICENSE +0 -0
- {spotifywebapipython-1.0.294.dist-info → spotifywebapipython-1.0.296.dist-info}/WHEEL +0 -0
- {spotifywebapipython-1.0.294.dist-info → spotifywebapipython-1.0.296.dist-info}/top_level.txt +0 -0
|
@@ -692,6 +692,7 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
692
692
|
transferPlayback:bool=False,
|
|
693
693
|
timeoutActivation:float=15.0,
|
|
694
694
|
timeoutTransfer:float=10.0,
|
|
695
|
+
activateAppMediaReceiverOnGroupMembers:bool=False,
|
|
695
696
|
) -> str:
|
|
696
697
|
"""
|
|
697
698
|
Activates the Spotify Cast Application on the specified Chromecast device.
|
|
@@ -712,18 +713,22 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
712
713
|
|
|
713
714
|
Args:
|
|
714
715
|
deviceName (str):
|
|
715
|
-
Chromecast device friendly name (or device id) to activate.
|
|
716
|
+
Chromecast device friendly name (or device id) to activate.
|
|
716
717
|
transferPlayback (bool):
|
|
717
718
|
True to transfer playback to the device; otherwise, False to just activate
|
|
718
|
-
the Spotify Cast App on the device.
|
|
719
|
+
the Spotify Cast App on the device.
|
|
719
720
|
timeoutActivation (float):
|
|
720
721
|
Amount of time to wait (in seconds) for the Spotify Cast App to be fully activated,
|
|
721
722
|
the user logged in, and ready for transfer of playback.
|
|
722
|
-
Default is 15 seconds.
|
|
723
|
+
Default is 15 seconds.
|
|
723
724
|
timeoutTransfer (float):
|
|
724
725
|
If `transferPlayback` argument is True, the amount of time to wait (in seconds)
|
|
725
726
|
for the transfer to complete; otherwise, argument is ignored.
|
|
726
|
-
Default is 10 seconds.
|
|
727
|
+
Default is 10 seconds.
|
|
728
|
+
activateAppMediaReceiverOnGroupMembers (bool):
|
|
729
|
+
True to force start the APP_MEDIA_RECEIVER on each group member cast device prior
|
|
730
|
+
to activating the Spotify Cast App; otherwise, False (default) to not start the
|
|
731
|
+
APP_MEDIA_RECEIVER on any group devices.
|
|
727
732
|
|
|
728
733
|
Returns:
|
|
729
734
|
The deviceId that was activated.
|
|
@@ -739,6 +744,7 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
739
744
|
apiMethodParms.AppendKeyValue("transferPlayback", transferPlayback)
|
|
740
745
|
apiMethodParms.AppendKeyValue("timeoutActivation", timeoutActivation)
|
|
741
746
|
apiMethodParms.AppendKeyValue("timeoutTransfer", timeoutTransfer)
|
|
747
|
+
apiMethodParms.AppendKeyValue("activateAppMediaReceiverOnGroupMembers", activateAppMediaReceiverOnGroupMembers)
|
|
742
748
|
_logsi.LogMethodParmList(SILevel.Verbose, "Activating Spotify App on Chromecast device: \"%s\"" % (deviceName), apiMethodParms)
|
|
743
749
|
|
|
744
750
|
# validations.
|
|
@@ -829,13 +835,13 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
829
835
|
|
|
830
836
|
# for groups, the SpotifyAppTask must be activated on the group leader (e.g. coordinator).
|
|
831
837
|
# the cast zeroconf info may not contain the group leader host info, as it is constantly
|
|
832
|
-
# being updated as devices are added / removed from the group.
|
|
833
|
-
#
|
|
834
|
-
#
|
|
835
|
-
#
|
|
836
|
-
#
|
|
837
|
-
#
|
|
838
|
-
#
|
|
838
|
+
# being updated as devices are added / removed from the group. the resolution of the group
|
|
839
|
+
# leader should have been handled by the `_VerifyMultizoneGroupLeader` call above.
|
|
840
|
+
#
|
|
841
|
+
# if this the the second attempt at activating the Spotify Cast App, then we will try
|
|
842
|
+
# starting the APP_MEDIA_RECEIVER on each group member device, as well as calling the
|
|
843
|
+
# `get_multizone_status` function again to verify the status of the zone before trying to
|
|
844
|
+
# start the Spotify Cast App.
|
|
839
845
|
|
|
840
846
|
# trace.
|
|
841
847
|
if (_logsi.IsOn(SILevel.Verbose)):
|
|
@@ -845,102 +851,109 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
845
851
|
groupHost:str = scDevice.DiscoveryResult.HostIpAddress
|
|
846
852
|
groupPort:int = scDevice.DiscoveryResult.HostIpPort
|
|
847
853
|
|
|
848
|
-
|
|
854
|
+
# are we starting the APP_MEDIA_RECEIVER on each group member?
|
|
855
|
+
if (activateAppMediaReceiverOnGroupMembers != True):
|
|
849
856
|
|
|
850
|
-
|
|
851
|
-
# note that this will just send a request to the cast group device for its
|
|
852
|
-
# status, which will then update the members list via event listener callbacks.
|
|
853
|
-
castMultizoneController:MultizoneController = self._CastMultiZoneControllers.get(str(castInfo.uuid), None)
|
|
854
|
-
if (castMultizoneController) and (castMultizoneController._socket_client):
|
|
855
|
-
castMultizoneController.update_members()
|
|
856
|
-
time.sleep(2.0) # give controller some time to update member list.
|
|
857
|
-
|
|
858
|
-
# activate media receiver app for each member in the group.
|
|
859
|
-
# process all device members in the group / zone.
|
|
860
|
-
for zone_member_uuid in castMultizoneController.members:
|
|
861
|
-
|
|
862
|
-
# get castInfo instance so we can connect to the device.
|
|
863
|
-
zone_member_castInfo = self._CastBrowser.devices.get(UUID(zone_member_uuid))
|
|
864
|
-
if zone_member_castInfo is not None:
|
|
865
|
-
|
|
866
|
-
# get cast device instance.
|
|
867
|
-
zone_member_castDevice = get_chromecast_from_cast_info(
|
|
868
|
-
cast_info=zone_member_castInfo,
|
|
869
|
-
zconf=self._ZeroconfInstance,
|
|
870
|
-
tries=2,
|
|
871
|
-
retry_wait=0.5,
|
|
872
|
-
timeout=5)
|
|
873
|
-
|
|
874
|
-
# wait for the cast device to provide an initial status.
|
|
875
|
-
zone_member_castDevice.wait(10)
|
|
876
|
-
|
|
877
|
-
# formulate title for trace messages.
|
|
878
|
-
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)
|
|
879
|
-
|
|
880
|
-
# trace.
|
|
881
|
-
_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)
|
|
882
|
-
|
|
883
|
-
# if current app is APP_SPOTIFY, then stop the app before starting the media receiver.
|
|
884
|
-
if (zone_member_castDevice.status) and (zone_member_castDevice.status.app_id == APP_SPOTIFY):
|
|
885
|
-
_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)
|
|
886
|
-
zone_member_castDevice.quit_app(timeout=5.0)
|
|
887
|
-
elif (zone_member_castDevice.status) and (zone_member_castDevice.status.app_id == APP_SPOTIFY_CONNECT):
|
|
888
|
-
_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)
|
|
889
|
-
zone_member_castDevice.quit_app(timeout=5.0)
|
|
890
|
-
|
|
891
|
-
# start the media receiver app.
|
|
892
|
-
# this will stabilize routing for the group using the Default Media Receiver.
|
|
893
|
-
_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)
|
|
894
|
-
zone_member_castDevice.start_app(APP_MEDIA_RECEIVER, force_launch=True, timeout=10.0)
|
|
895
|
-
|
|
896
|
-
# start the connection worker thread, if needed.
|
|
897
|
-
# failure to do this will result in the following exception being thrown when
|
|
898
|
-
# the `launch_app()` method is called:
|
|
899
|
-
# - `pychromecast.error.NotConnected: Chromecast unknown:8009 is connecting...`
|
|
900
|
-
if (zone_member_castDevice.is_idle):
|
|
901
|
-
if (zone_member_castDevice.socket_client is not None) and (zone_member_castDevice.socket_client.first_connection):
|
|
902
|
-
_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)
|
|
903
|
-
zone_member_castDevice.start()
|
|
904
|
-
zone_member_castDevice.wait(timeout=5.0)
|
|
905
|
-
|
|
906
|
-
# media receiver app needs time to start.
|
|
907
|
-
time.sleep(2.0)
|
|
857
|
+
_logsi.LogVerbose("Bypassing start of APP_MEDIA_RECEIVER for group: %s" % (scDevice.Title), colorValue=SIColors.Coral)
|
|
908
858
|
|
|
909
|
-
|
|
859
|
+
else:
|
|
860
|
+
|
|
861
|
+
try:
|
|
862
|
+
|
|
863
|
+
# request a multizone group member update.
|
|
864
|
+
# note that this will just send a request to the cast group device for its
|
|
865
|
+
# status, which will then update the members list via event listener callbacks.
|
|
866
|
+
castMultizoneController:MultizoneController = self._CastMultiZoneControllers.get(str(castInfo.uuid), None)
|
|
867
|
+
if (castMultizoneController) and (castMultizoneController._socket_client):
|
|
868
|
+
castMultizoneController.update_members()
|
|
869
|
+
time.sleep(2.0) # give controller some time to update member list.
|
|
870
|
+
|
|
871
|
+
# activate media receiver app for each member in the group.
|
|
872
|
+
# process all device members in the group / zone.
|
|
873
|
+
for zone_member_uuid in castMultizoneController.members:
|
|
874
|
+
|
|
875
|
+
# get castInfo instance so we can connect to the device.
|
|
876
|
+
zone_member_castInfo = self._CastBrowser.devices.get(UUID(zone_member_uuid))
|
|
877
|
+
if zone_member_castInfo is not None:
|
|
878
|
+
|
|
879
|
+
# get cast device instance.
|
|
880
|
+
zone_member_castDevice = get_chromecast_from_cast_info(
|
|
881
|
+
cast_info=zone_member_castInfo,
|
|
882
|
+
zconf=self._ZeroconfInstance,
|
|
883
|
+
tries=2,
|
|
884
|
+
retry_wait=0.5,
|
|
885
|
+
timeout=5)
|
|
886
|
+
|
|
887
|
+
# wait for the cast device to provide an initial status.
|
|
888
|
+
zone_member_castDevice.wait(10)
|
|
889
|
+
|
|
890
|
+
# formulate title for trace messages.
|
|
891
|
+
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)
|
|
892
|
+
|
|
893
|
+
# trace.
|
|
894
|
+
_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)
|
|
895
|
+
|
|
896
|
+
# if current app is APP_SPOTIFY, then stop the app before starting the media receiver.
|
|
897
|
+
if (zone_member_castDevice.status) and (zone_member_castDevice.status.app_id == APP_SPOTIFY):
|
|
898
|
+
_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)
|
|
899
|
+
zone_member_castDevice.quit_app(timeout=5.0)
|
|
900
|
+
elif (zone_member_castDevice.status) and (zone_member_castDevice.status.app_id == APP_SPOTIFY_CONNECT):
|
|
901
|
+
_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)
|
|
902
|
+
zone_member_castDevice.quit_app(timeout=5.0)
|
|
903
|
+
|
|
904
|
+
# start the media receiver app.
|
|
905
|
+
# this will stabilize routing for the group using the Default Media Receiver.
|
|
906
|
+
_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)
|
|
907
|
+
zone_member_castDevice.start_app(APP_MEDIA_RECEIVER, force_launch=True, timeout=10.0)
|
|
908
|
+
|
|
909
|
+
# start the connection worker thread, if needed.
|
|
910
|
+
# failure to do this will result in the following exception being thrown when
|
|
911
|
+
# the `launch_app()` method is called:
|
|
912
|
+
# - `pychromecast.error.NotConnected: Chromecast unknown:8009 is connecting...`
|
|
913
|
+
if (zone_member_castDevice.is_idle):
|
|
914
|
+
if (zone_member_castDevice.socket_client is not None) and (zone_member_castDevice.socket_client.first_connection):
|
|
915
|
+
_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)
|
|
916
|
+
zone_member_castDevice.start()
|
|
917
|
+
zone_member_castDevice.wait(timeout=5.0)
|
|
918
|
+
|
|
919
|
+
# media receiver app needs time to start.
|
|
920
|
+
time.sleep(2.0)
|
|
921
|
+
|
|
922
|
+
except Exception as ex:
|
|
910
923
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
924
|
+
# trace.
|
|
925
|
+
_logsi.LogException("Chromecast Multizone group update_members exception: %s" % (str(ex)), ex, logToSystemLogger=False)
|
|
926
|
+
# ignore exception, as nothing can be done about it.
|
|
927
|
+
|
|
928
|
+
# get current multizone status for all groups.
|
|
929
|
+
castMultiZoneStatus:MultizoneStatus = get_multizone_status(castInfo.host, castInfo.services, self.ZeroconfInstance, 5)
|
|
930
|
+
_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)
|
|
931
|
+
|
|
932
|
+
# ensure group device is still on the network;
|
|
933
|
+
# if group device dropped off the network, then we can't query it!
|
|
934
|
+
if (castMultiZoneStatus is not None):
|
|
935
|
+
|
|
936
|
+
# find the group coordinator for the selected device.
|
|
937
|
+
zoneInfo:MultizoneInfo = None
|
|
938
|
+
for zoneInfo in castMultiZoneStatus.groups:
|
|
939
|
+
|
|
940
|
+
# is this our group?
|
|
941
|
+
if (str(zoneInfo.uuid) == scDevice.DiscoveryResult.Key):
|
|
942
|
+
|
|
943
|
+
# yes - get host info to use for the device.
|
|
944
|
+
# we will use the device discovery result HostIpAddress instead of the zoneInfo.host
|
|
945
|
+
# value here, as the zoneInfo MAY contain an IPV6 formatted address, which was causing
|
|
946
|
+
# issues if the device was originally activated using an IPV4 address!
|
|
947
|
+
groupHost = scDevice.DiscoveryResult.HostIpAddress
|
|
948
|
+
groupPort = scDevice.DiscoveryResult.HostIpPort
|
|
949
|
+
break
|
|
937
950
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
951
|
+
# connect to the device and build a Chromecast instance from group coordinator host info.
|
|
952
|
+
castDevice = get_chromecast_from_host(
|
|
953
|
+
host=(groupHost, groupPort, castInfo.uuid, castInfo.model_name, castInfo.friendly_name),
|
|
954
|
+
tries=2,
|
|
955
|
+
retry_wait=0.5,
|
|
956
|
+
timeout=10)
|
|
944
957
|
|
|
945
958
|
# trace.
|
|
946
959
|
_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)
|
|
@@ -1535,12 +1548,21 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
1535
1548
|
returnCoordinator = True
|
|
1536
1549
|
|
|
1537
1550
|
# get Sonos Controller instance for device name.
|
|
1538
|
-
|
|
1551
|
+
hostIpAddress:str = device.DiscoveryResult.HostIpAddress
|
|
1552
|
+
sonosPlayer:SoCo = self._SonosPlayers.get(hostIpAddress, None)
|
|
1539
1553
|
|
|
1540
1554
|
# if not found then it's an error.
|
|
1541
1555
|
if (sonosPlayer is None):
|
|
1542
1556
|
raise SpotifyApiError("Could not find Sonos Controller instance for device: %s" % (device.Title), None, logsi=_logsi)
|
|
1543
1557
|
|
|
1558
|
+
# Another integration (e.g. Home Assistant Sonos) can call soco_reset().
|
|
1559
|
+
# Our cached reference then outlives the SoCo singleton registry, and
|
|
1560
|
+
# topology updates only reach the current instance. Reacquire it before
|
|
1561
|
+
# inspecting its coordinator role or group. Without a reset this returns
|
|
1562
|
+
# the same instance, preserving the normal SoCo topology cache.
|
|
1563
|
+
sonosPlayer = SoCo(hostIpAddress)
|
|
1564
|
+
self._SonosPlayers[hostIpAddress] = sonosPlayer
|
|
1565
|
+
|
|
1544
1566
|
# trace.
|
|
1545
1567
|
_logsi.LogDictionary(SILevel.Verbose, "Sonos Controller instance for device: %s (speaker_info)" % (device.Title), sonosPlayer.speaker_info)
|
|
1546
1568
|
|
|
@@ -648,6 +648,134 @@ class ZeroconfConnect:
|
|
|
648
648
|
# formulate the blob.
|
|
649
649
|
blob = builder.build()
|
|
650
650
|
|
|
651
|
+
# special processing for Spotify Soloist client:
|
|
652
|
+
elif (infoModelDisplayName in ["soloist"]):
|
|
653
|
+
|
|
654
|
+
# have not figured out how the Spotify Soloist initial session is created.
|
|
655
|
+
raise SpotifyWebApiError(404, "Spotify Soloist initial session has not been created for loginId \"%s\"; use an authorized Spotify App to connect to Soloist for this loginId first" % (loginId), apiMethodName, "Soloist Initial Session Not Created", _logsi)
|
|
656
|
+
|
|
657
|
+
# The following Soloist log info is generated by a successful connection from an authorized Spotify App:
|
|
658
|
+
# 20:30:15.371 I [f:379] getAuthInfo: success
|
|
659
|
+
# 20:30:15.371 I [f:302] zeroconf: received getInfo
|
|
660
|
+
# 20:30:18.700 I [f:379] getAuthInfo: success
|
|
661
|
+
# 20:30:18.700 I [f:302] zeroconf: received getInfo
|
|
662
|
+
# 20:30:18.939 I [f:186] zeroconf: received addUser
|
|
663
|
+
# 20:30:18.939 I [f:280] loginAuthToken
|
|
664
|
+
# 20:30:18.939 I [f:273] SpeakerAuth: Login state changed: LOGGED_OUT -> LOGGING_IN
|
|
665
|
+
# 20:30:18.939 I [f:53 ] Creating session via Connect
|
|
666
|
+
# 20:30:19.275 I [f:263] High request latency: https://accounts.spotify.com/api took 185 ms
|
|
667
|
+
# 20:30:19.275 I [f:218] Auth code grant token exchange succeeded
|
|
668
|
+
# 20:30:19.277 I [f:72 ] Session created via Connect, session: [session:31l77y2al5lnn7mxfrmd4bpfhqke]
|
|
669
|
+
# 20:30:19.278 I [f:808] Connect session created successfully, received AuthenticatedSession
|
|
670
|
+
|
|
671
|
+
# left the following code in for now - still trying to work out how to create the
|
|
672
|
+
# initial Soloist session if one has not been established yet.
|
|
673
|
+
|
|
674
|
+
# # special processing for Spotify Soloist client:
|
|
675
|
+
# elif (infoModelDisplayName in ["soloist"]):
|
|
676
|
+
|
|
677
|
+
# # trace.
|
|
678
|
+
# _logsi.LogVerbose("Spotify Connect token type is '%s' - using soloist authorization credentials to connect: '%s' (ip=%s)" % (info.TokenType, info.RemoteName, self._HostIpAddress))
|
|
679
|
+
|
|
680
|
+
# # validations.
|
|
681
|
+
# # note that userid and password are not needed by soloist, as both of those
|
|
682
|
+
# # are contained in the soloist credentials object. we only need the loginId
|
|
683
|
+
# # value for the credentials lookup.
|
|
684
|
+
# if (loginId is None) or (not isinstance(loginId,str)):
|
|
685
|
+
# raise SpotifyApiError(SAAppMessages.MSG_SPOTIFY_ACTIVATE_CREDENTIAL_REQUIRED % ("SpotifyConnectLoginId"), logsi=_logsi)
|
|
686
|
+
|
|
687
|
+
# # we will use credentials from a librespot credentials.json file.
|
|
688
|
+
# # this requires that the user copy the "credentials.json" file from the
|
|
689
|
+
# # librespot cache location (e.g. "/home/user/.cache/spotifyd/credentials.json", etc)
|
|
690
|
+
# # and place it in the same folder as the token storage file with a new name
|
|
691
|
+
# # of "SpotifyWebApiPython_librespot_credentials.json".
|
|
692
|
+
|
|
693
|
+
# # get credentials from librespot credentials file.
|
|
694
|
+
# credentials:dict = self._LoadLibrespotCredentials(loginId)
|
|
695
|
+
|
|
696
|
+
# # create credentials and builder objects.
|
|
697
|
+
# librespot_username = credentials.get('username','')
|
|
698
|
+
# librespot_password = b64str_to_bytes(credentials.get('auth_data',''))
|
|
699
|
+
# credentials:Credentials = Credentials(librespot_username, librespot_password, AuthenticationTypes.STORED_SPOTIFY_CREDENTIALS)
|
|
700
|
+
# builder = BlobBuilder(credentials, info.DeviceId, info.PublicKey)
|
|
701
|
+
|
|
702
|
+
# # set defaults used by this token type:
|
|
703
|
+
# # - clientKey should be the getInfo response PublicKey (base64 encoded).
|
|
704
|
+
# # - include origin device information in the addUser request.
|
|
705
|
+
# # - tokenType should be set to '' (not used by librespot).
|
|
706
|
+
# clientKey:str = ''
|
|
707
|
+
# includeOriginDeviceInfo = True
|
|
708
|
+
# tokenType = 'auth_token'
|
|
709
|
+
|
|
710
|
+
# # formulate the blob.
|
|
711
|
+
# blob = builder.build()
|
|
712
|
+
|
|
713
|
+
# The following Soloist log errors are generated for this auth method if an authorized Spotify App
|
|
714
|
+
# has not yet connected to the Soloist instance.
|
|
715
|
+
# The above code passes pre-configured LIBRESPOT credentials to the Spotify Connect zeroconf process.
|
|
716
|
+
# Note that playback transfer is successful if an authorized Spotify App HAS connected to
|
|
717
|
+
# the Soloist instance, as the device is in the Spotify Web API device list (dynamic device); in
|
|
718
|
+
# this instance, the `_ConnectAddUser` method is not even called!
|
|
719
|
+
# 20:18:17.491 I [f:379] getAuthInfo: success
|
|
720
|
+
# 20:18:17.491 I [f:302] zeroconf: received getInfo
|
|
721
|
+
# 20:18:44.731 I [f:379] getAuthInfo: success
|
|
722
|
+
# 20:18:44.731 I [f:302] zeroconf: received getInfo
|
|
723
|
+
# 20:18:47.458 I [f:186] zeroconf: received addUser
|
|
724
|
+
# 20:18:47.458 I [f:280] loginAuthToken
|
|
725
|
+
# 20:18:47.459 I [f:273] SpeakerAuth: Login state changed: LOGGED_OUT -> LOGGING_IN
|
|
726
|
+
# 20:18:47.459 I [f:53 ] Creating session via Connect
|
|
727
|
+
# 20:18:47.459 E [f:78 ] Session creation via Connect failed, error: session_invalid_connect_auth_token
|
|
728
|
+
# 20:18:47.459 E [f:813] Connect session creation failed: session_invalid_connect_auth_token
|
|
729
|
+
# 20:18:47.459 I [f:273] SpeakerAuth: Login state changed: LOGGING_IN -> LOGGED_OUT
|
|
730
|
+
|
|
731
|
+
# # special processing for Spotify Soloist client:
|
|
732
|
+
# elif (infoModelDisplayName in ["soloist"]):
|
|
733
|
+
|
|
734
|
+
# # trace.
|
|
735
|
+
# _logsi.LogVerbose("Spotify Connect token type is '%s' - using Spotify Desktop Client OAuth2 token to connect to Soloist: '%s' (ip=%s)" % (info.TokenType, info.RemoteName, self._HostIpAddress))
|
|
736
|
+
|
|
737
|
+
# # validations.
|
|
738
|
+
# if (loginId is None) or (not isinstance(loginId,str)):
|
|
739
|
+
# raise SpotifyApiError(SAAppMessages.MSG_SPOTIFY_ACTIVATE_CREDENTIAL_REQUIRED % ("SpotifyConnectLoginId"), logsi=_logsi)
|
|
740
|
+
# if (username is None) or (not isinstance(username,str)):
|
|
741
|
+
# raise SpotifyApiError(SAAppMessages.MSG_SPOTIFY_ACTIVATE_CREDENTIAL_REQUIRED % ("SpotifyConnectUsername"), logsi=_logsi)
|
|
742
|
+
# if (password is None) or (not isinstance(password,str)):
|
|
743
|
+
# raise SpotifyApiError(SAAppMessages.MSG_SPOTIFY_ACTIVATE_CREDENTIAL_REQUIRED % ("SpotifyConnectPassword"), logsi=_logsi)
|
|
744
|
+
|
|
745
|
+
# # create credentials and builder objects.
|
|
746
|
+
# credentials:Credentials = Credentials(loginId, password, AuthenticationTypes.SPOTIFY_TOKEN)
|
|
747
|
+
# #credentials:Credentials = Credentials(username, password, AuthenticationTypes.SPOTIFY_TOKEN)
|
|
748
|
+
# builder = BlobBuilder(credentials, info.DeviceId, info.PublicKey)
|
|
749
|
+
|
|
750
|
+
# # set defaults used by Soloist client.
|
|
751
|
+
# # - clientKey not required.
|
|
752
|
+
# # - include origin device information in the addUser request.
|
|
753
|
+
# # - use tokenType of "auth_token".
|
|
754
|
+
# clientKey = ''
|
|
755
|
+
# includeOriginDeviceInfo = True
|
|
756
|
+
# tokenType = 'auth_token'
|
|
757
|
+
|
|
758
|
+
# # get access token.
|
|
759
|
+
# blob:str = self._GetSpotifyConnectAccessToken(info, loginId=loginId)
|
|
760
|
+
|
|
761
|
+
# The following Soloist log errors are generated for this auth method if an authorized Spotify App
|
|
762
|
+
# has not yet connected to the Soloist instance.
|
|
763
|
+
# The above code passes pre-configured Spotify Desktop App credentials to the Spotify Connect zeroconf process.
|
|
764
|
+
# Note that playback transfer is successful if an authorized Spotify App HAS connected to
|
|
765
|
+
# the Soloist instance, as the device is in the Spotify Web API device list (dynamic device); in
|
|
766
|
+
# this instance, the `_ConnectAddUser` method is not even called!
|
|
767
|
+
# 20:14:33.640 I [f:379] getAuthInfo: success
|
|
768
|
+
# 20:14:33.640 I [f:302] zeroconf: received getInfo
|
|
769
|
+
# 20:14:36.579 I [f:186] zeroconf: received addUser
|
|
770
|
+
# 20:14:36.579 I [f:280] loginAuthToken
|
|
771
|
+
# 20:14:36.579 I [f:273] SpeakerAuth: Login state changed: LOGGED_OUT -> LOGGING_IN
|
|
772
|
+
# 20:14:36.579 I [f:53 ] Creating session via Connect
|
|
773
|
+
# 20:14:36.579 E [f:78 ] Session creation via Connect failed, error: session_invalid_connect_auth_token
|
|
774
|
+
# 20:14:36.579 E [f:813] Connect session creation failed: session_invalid_connect_auth_token
|
|
775
|
+
# 20:14:36.579 I [f:273] SpeakerAuth: Login state changed: LOGGING_IN -> LOGGED_OUT
|
|
776
|
+
# 20:14:36.579 W [f:552] login failed while API key is configured (action_id=1)
|
|
777
|
+
# 20:14:36.579 W [f:553] login failed: make sure --api-key is valid
|
|
778
|
+
|
|
651
779
|
# special processing for tokenType "authorization_code":
|
|
652
780
|
elif info.TokenType == 'authorization_code':
|
|
653
781
|
|
|
@@ -28,6 +28,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
28
28
|
self._AccountReq:str = None
|
|
29
29
|
self._ActiveUser:str = ""
|
|
30
30
|
self._Aliases:list[ZeroconfGetInfoAlias] = []
|
|
31
|
+
self._AuthInfo:str = ""
|
|
31
32
|
self._Availability:str = ""
|
|
32
33
|
self._BrandDisplayName:str = None
|
|
33
34
|
self._ClientId:str = None
|
|
@@ -55,6 +56,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
55
56
|
|
|
56
57
|
self._AccountReq = root.get('accountReq', None)
|
|
57
58
|
self._ActiveUser = root.get('activeUser', "")
|
|
59
|
+
self._AuthInfo = root.get('authInfo', None)
|
|
58
60
|
self._Availability = root.get('availability', "")
|
|
59
61
|
self._BrandDisplayName = root.get('brandDisplayName', None)
|
|
60
62
|
self._ClientId = root.get('clientID', None)
|
|
@@ -137,6 +139,27 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
137
139
|
return self._Aliases
|
|
138
140
|
|
|
139
141
|
|
|
142
|
+
@property
|
|
143
|
+
def AuthInfo(self) -> str:
|
|
144
|
+
"""
|
|
145
|
+
This variable is not documented by the Spotify Web API.
|
|
146
|
+
|
|
147
|
+
It appears to be structured authentication information associated with the Soloist
|
|
148
|
+
client/device, in base64-encoded / protobuf format (e.g. "CiQyZjA2M ... BVE9NWmU5RQ==").
|
|
149
|
+
|
|
150
|
+
The maximum length of the auth Info string is unknown.
|
|
151
|
+
"""
|
|
152
|
+
return self._AuthInfo
|
|
153
|
+
|
|
154
|
+
@AuthInfo.setter
|
|
155
|
+
def AuthInfo(self, value:str):
|
|
156
|
+
"""
|
|
157
|
+
Sets the AuthInfo property value.
|
|
158
|
+
"""
|
|
159
|
+
if (isinstance(value, str)) or (value is None):
|
|
160
|
+
self._AuthInfo = value
|
|
161
|
+
|
|
162
|
+
|
|
140
163
|
@property
|
|
141
164
|
def Availability(self) -> str:
|
|
142
165
|
"""
|
|
@@ -526,6 +549,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
526
549
|
'AccountReq': self._AccountReq,
|
|
527
550
|
'ActiveUser': self._ActiveUser,
|
|
528
551
|
'Aliases': [ item.ToDictionary() for item in self._Aliases ],
|
|
552
|
+
'AuthInfo': self._AuthInfo,
|
|
529
553
|
'Availability': self._Availability,
|
|
530
554
|
'BrandDisplayName': self._BrandDisplayName,
|
|
531
555
|
'ClientId': self._ClientId,
|
|
@@ -577,6 +601,7 @@ class ZeroconfGetInfo(ZeroconfResponse):
|
|
|
577
601
|
if self._AccountReq is not None: msg = '%s\n AccountReq="%s"' % (msg, str(self._AccountReq))
|
|
578
602
|
if self._ActiveUser is not None: msg = '%s\n ActiveUser="%s"' % (msg, str(self._ActiveUser))
|
|
579
603
|
if self._Aliases is not None: msg = '%s\n Aliases=%s' % (msg, str(self._Aliases))
|
|
604
|
+
if self._AuthInfo is not None: msg = '%s\n AuthInfo="%s"' % (msg, str(self._AuthInfo))
|
|
580
605
|
if self._Availability is not None: msg = '%s\n Availability="%s"' % (msg, str(self._Availability))
|
|
581
606
|
if self._BrandDisplayName is not None: msg = '%s\n BrandDisplayName="%s"' % (msg, str(self._BrandDisplayName))
|
|
582
607
|
if self._ClientId is not None: msg = '%s\n ClientId="%s"' % (msg, str(self._ClientId))
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
spotifywebapipython/__init__.py,sha256=ka7F2AsT-UU7KSYKBnfgl5Trojcep5aQspLutg8D-2k,1306
|
|
2
|
-
spotifywebapipython/const.py,sha256=
|
|
2
|
+
spotifywebapipython/const.py,sha256=50BHoLMJDRh4KnIBHjbpaYqfixgOHxMMl8lF_qZlktA,4100
|
|
3
3
|
spotifywebapipython/saappmessages.py,sha256=mVprjpd5CdD8kYeAkLzRvMvIQPmaYtH4UCP5my3QhSk,5065
|
|
4
4
|
spotifywebapipython/sautils.py,sha256=LZF3UvxaBK35WIg1hO37nbW8j1y-M-oOxRbi1dPR39w,8746
|
|
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=hya2_fpOpP9Qyg6_wuWlUmlPwquTT_8-KcDF3Eiwx08,928655
|
|
9
9
|
spotifywebapipython/spotifydiscovery.py,sha256=cyysxl8PQj9yGHVbaqhSF3SStlrp-NvfGAudM-dDmg0,20290
|
|
10
10
|
spotifywebapipython/spotifymediatypes.py,sha256=hMjkxhbfTtks0_P8BKmY7qg3EmB2zhH3RT0DbEpb_2s,1628
|
|
11
11
|
spotifywebapipython/spotifytypeprefixes.py,sha256=3yfpxKF7jF694qBuo-PbKYvm70YwwdBoGj9enOpWsAg,1375
|
|
12
12
|
spotifywebapipython/spotifywebapiauthenticationerror.py,sha256=5A0MKvYo3Ypv0ZeSSfLHuFLwzoUUu044bBoUgMfNXNw,3940
|
|
13
13
|
spotifywebapipython/spotifywebapierror.py,sha256=ctYFvkBPlFFEoM_geP6hzwTyC2mPcrYR_zCCNvsmpwc,3870
|
|
14
14
|
spotifywebapipython/spotifywebplayertoken.py,sha256=axj1j1lM7COiiZfpElkJRdnk4AmE6bAQcjKshUIz1Nk,35813
|
|
15
|
-
spotifywebapipython/docs/__init__.html,sha256=
|
|
15
|
+
spotifywebapipython/docs/__init__.html,sha256=2F9ndL51ND0rePvMs3q1AOaJB6jksyMo82YoBePSgOQ,200803
|
|
16
16
|
spotifywebapipython/docs/codecopy.js,sha256=ryuoZwLIL03YitjjFzn49UO5ta7-OBos6LNA3qHhFzs,3120
|
|
17
|
-
spotifywebapipython/docs/index.html,sha256=
|
|
18
|
-
spotifywebapipython/docs/search.js,sha256=
|
|
17
|
+
spotifywebapipython/docs/index.html,sha256=OGv36bUHX26oGcS2HmgUEpMVSUOVAVSNhqfYOeDcfRw,48779
|
|
18
|
+
spotifywebapipython/docs/search.js,sha256=wdg_LJOjbdrkNQchItK23zLj9CiU-3uVBqFjue7v4k4,9289882
|
|
19
19
|
spotifywebapipython/docs/spotifywebapipython.ico,sha256=YImj39fqqSPSuB2-sMDlUYDd6YwRfQeJRtq4FjwWglg,16410
|
|
20
20
|
spotifywebapipython/docs/spotifywebapipython_OLD.ico,sha256=YIv5LjcD4bTIJQSOr8jjwbWaeB3QkElRwkTOePiGbZo,14904
|
|
21
|
-
spotifywebapipython/docs/spotifywebapipython/const.html,sha256=
|
|
22
|
-
spotifywebapipython/docs/spotifywebapipython/saappmessages.html,sha256=
|
|
23
|
-
spotifywebapipython/docs/spotifywebapipython/sautils.html,sha256
|
|
24
|
-
spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html,sha256=
|
|
25
|
-
spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html,sha256=
|
|
26
|
-
spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html,sha256=
|
|
27
|
-
spotifywebapipython/docs/spotifywebapipython/spotifyclient.html,sha256=
|
|
28
|
-
spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html,sha256=
|
|
29
|
-
spotifywebapipython/docs/spotifywebapipython/spotifymediatypes.html,sha256=
|
|
30
|
-
spotifywebapipython/docs/spotifywebapipython/spotifytypeprefixes.html,sha256=
|
|
31
|
-
spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html,sha256=
|
|
32
|
-
spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html,sha256=
|
|
33
|
-
spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html,sha256=
|
|
21
|
+
spotifywebapipython/docs/spotifywebapipython/const.html,sha256=lHX8fMlg1Wd6MOAj9QABn9UtA3AWYFf6WTC2YOU6dsI,60537
|
|
22
|
+
spotifywebapipython/docs/spotifywebapipython/saappmessages.html,sha256=8Z2OMN1jlwhsYyORHZysY-ECDOfhPCiS91huz43ceHQ,62358
|
|
23
|
+
spotifywebapipython/docs/spotifywebapipython/sautils.html,sha256=BERvm-lHcFYo4-MIXhi_dfOpvlF4GHr8Ke_QGqx0Ecs,62031
|
|
24
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html,sha256=8vXg0qZ5kH9nAfKJeAjrv9JLR2t5E_DMDQsbguIX1ZQ,48054
|
|
25
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html,sha256=2UlqgTeZKQzT-wFuCjLq5zvSpcimnd5ojMYvDYhNt3M,59210
|
|
26
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html,sha256=MdmU34FdYdsn4h4glGd7cZJ70TSPTkjMq2LoI-0PmZk,59256
|
|
27
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyclient.html,sha256=oikPy0hqH3rbmcWoVHMCbcnFpvzjfie7yAoACBYedMM,1677607
|
|
28
|
+
spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html,sha256=lcs4bqdzMxbptqGL8ElmPNvsGhFCgoNVdCmWnqblMOY,57662
|
|
29
|
+
spotifywebapipython/docs/spotifywebapipython/spotifymediatypes.html,sha256=2VUSFazpMxjWW7xBSqo2zE0ncMBPttNGrZqlmf5-sMA,51532
|
|
30
|
+
spotifywebapipython/docs/spotifywebapipython/spotifytypeprefixes.html,sha256=Fgypo08rN1oCBeSxlIBlOKYK6la14WUv78KgT_ri7jc,52401
|
|
31
|
+
spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html,sha256=POs3Fp9loNh4Vpp7IHu3VUGcMS8XD0UH__39bZtzJdI,52174
|
|
32
|
+
spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html,sha256=hNHWZzM2MUf4J6KEmpuNXRCbkfOx-GVeh6EnCSkbL8M,51484
|
|
33
|
+
spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html,sha256=z8FBtuJ5ytOuNBvcRG5Nq9b9A-ZXHdHyl9P00eiEbjc,62204
|
|
34
34
|
spotifywebapipython/models/__init__.py,sha256=RwRQhUX-6EUs8XvStVFpR8EPwoqIAz9K6ref-28qHKI,4423
|
|
35
35
|
spotifywebapipython/models/album.py,sha256=U3Pdw0-EL33LdkeiN31fjZ23rlLk6DNGV8jRmZU7EyQ,5170
|
|
36
36
|
spotifywebapipython/models/albumpagesaved.py,sha256=SBYMhkh5ZsMrRAXl-cm9zsxMDh8gO190ENq6Py2TyGY,2417
|
|
@@ -110,7 +110,7 @@ spotifywebapipython/oauthcli/__init__.py,sha256=K37XTxYAKT0n8otCNzWbjgJ10fAPN4WL
|
|
|
110
110
|
spotifywebapipython/oauthcli/authclient.py,sha256=qGKa4FLBHHZQyP5ho1sIM_mNmyshQd720YwKcUFQJAw,56207
|
|
111
111
|
spotifywebapipython/spotifyconnect/__init__.py,sha256=9Xl5KiJFvWLbsdb4YQ0xmF67i36ybpXCCXrWeNsKEvc,1108
|
|
112
112
|
spotifywebapipython/spotifyconnect/spotifyconnectdeviceeventargs.py,sha256=35hKa0FAaPgy7W8D6MFXmga667pjwXITo8jSj1TDfE8,1988
|
|
113
|
-
spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py,sha256=
|
|
113
|
+
spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py,sha256=RUXj875jstz_zRuZHn0TAn-gN59x4eA8yRRgmwTnK6Y,169688
|
|
114
114
|
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastapptask.py,sha256=jArxsjAGntTcQD9L9yVuey1L8pw0KvshlNXIBA7PqiI,23367
|
|
115
115
|
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastcontroller.py,sha256=e2wLmFq4393IdVa51w8X5UQl4KfnHRh34DMlxZfl9-g,34218
|
|
116
116
|
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastlistener.py,sha256=e7vKob2xim8H3BkxbgPj-eymftKvWgT71tzpskd0sn0,16720
|
|
@@ -132,13 +132,13 @@ spotifywebapipython/zeroconfapi/credentials.py,sha256=MIXqZvFNDjoICpZGNXPveHNl9G
|
|
|
132
132
|
spotifywebapipython/zeroconfapi/cryptodiffiehellman.py,sha256=k-nMR68GtzODYsQrwCpvFE2XNxv-XUFbMemplldtwp4,3340
|
|
133
133
|
spotifywebapipython/zeroconfapi/helpers.py,sha256=9lJFOuKYrk-e7SbU94WmFv5oiBq4k5gMS8wE1it4Wbc,1429
|
|
134
134
|
spotifywebapipython/zeroconfapi/spotifyzeroconfapierror.py,sha256=rTwIrr1qV0UiQS_zBufboyZ3A3yGrdCsTAOiVA5dvzY,3031
|
|
135
|
-
spotifywebapipython/zeroconfapi/zeroconfconnect.py,sha256=
|
|
136
|
-
spotifywebapipython/zeroconfapi/zeroconfgetinfo.py,sha256=
|
|
135
|
+
spotifywebapipython/zeroconfapi/zeroconfconnect.py,sha256=8SxKNnzBiDtL7Mjrs5K7v67j-qr20ixS-2jwpvsiutw,88286
|
|
136
|
+
spotifywebapipython/zeroconfapi/zeroconfgetinfo.py,sha256=J8Oab4JJJ_OuNR5Q4cywTAYHUPUtarTGmmBjAzcUdq4,23135
|
|
137
137
|
spotifywebapipython/zeroconfapi/zeroconfgetinfoalias.py,sha256=FZJM23HIPJSfhXIC3-EuS1XhawheoG5maSp7__k4yBo,2932
|
|
138
138
|
spotifywebapipython/zeroconfapi/zeroconfgetinfodrmmediaformat.py,sha256=c5uk8ljsIuBK3w2jahHKQuoWvm245LOjUBitetXx5Mo,2347
|
|
139
139
|
spotifywebapipython/zeroconfapi/zeroconfresponse.py,sha256=mAPIDj5MG53x8peiScrp7OJblwy_o_Sto4wqE0rGujU,6445
|
|
140
|
-
spotifywebapipython-1.0.
|
|
141
|
-
spotifywebapipython-1.0.
|
|
142
|
-
spotifywebapipython-1.0.
|
|
143
|
-
spotifywebapipython-1.0.
|
|
144
|
-
spotifywebapipython-1.0.
|
|
140
|
+
spotifywebapipython-1.0.296.dist-info/LICENSE,sha256=KGcc9g0zwqNLcWnSn_ezv1UtKyhMENFhvtixpxUPNsE,1177
|
|
141
|
+
spotifywebapipython-1.0.296.dist-info/METADATA,sha256=RgTFqUYbGNKScjkYOnpf66c1p-DFjUk9QMMyLBvTzaw,11644
|
|
142
|
+
spotifywebapipython-1.0.296.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
143
|
+
spotifywebapipython-1.0.296.dist-info/top_level.txt,sha256=jTBLFlijKTesYh2dteAz4vb17qjaqWKeDjpnnwTcrjs,20
|
|
144
|
+
spotifywebapipython-1.0.296.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{spotifywebapipython-1.0.294.dist-info → spotifywebapipython-1.0.296.dist-info}/top_level.txt
RENAMED
|
File without changes
|