spotifywebapiPython 1.0.292__py3-none-any.whl → 1.0.294__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 +20 -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/spotifyconnect/spotifyconnectdirectorytask.py +204 -18
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastapptask.py +1 -1
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastlistener.py +4 -4
- spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastmultizonemanagerlistener.py +6 -6
- {spotifywebapipython-1.0.292.dist-info → spotifywebapipython-1.0.294.dist-info}/METADATA +1 -1
- {spotifywebapipython-1.0.292.dist-info → spotifywebapipython-1.0.294.dist-info}/RECORD +26 -26
- {spotifywebapipython-1.0.292.dist-info → spotifywebapipython-1.0.294.dist-info}/LICENSE +0 -0
- {spotifywebapipython-1.0.292.dist-info → spotifywebapipython-1.0.294.dist-info}/WHEEL +0 -0
- {spotifywebapipython-1.0.292.dist-info → spotifywebapipython-1.0.294.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# external package imports.
|
|
2
2
|
from abc import abstractmethod
|
|
3
3
|
import copy
|
|
4
|
+
from collections import Counter
|
|
4
5
|
from datetime import datetime
|
|
5
6
|
import hashlib
|
|
6
7
|
from pychromecast import APP_MEDIA_RECEIVER, CastBrowser, CastInfo, Chromecast, get_chromecast_from_cast_info, get_chromecast_from_host
|
|
@@ -509,6 +510,182 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
509
510
|
# ignore exception, as nothing can be done about it.
|
|
510
511
|
|
|
511
512
|
|
|
513
|
+
def _VerifyMultizoneGroupLeader(
|
|
514
|
+
self,
|
|
515
|
+
scDevice: SpotifyConnectDevice,
|
|
516
|
+
) -> None:
|
|
517
|
+
"""
|
|
518
|
+
Verifies the current leader for a cast group is connected and available.
|
|
519
|
+
|
|
520
|
+
Args:
|
|
521
|
+
scDevice (SpotifyConnectDevice):
|
|
522
|
+
SpotifyConnectDevice object that contains discovery result details.
|
|
523
|
+
|
|
524
|
+
This method should be called from a method that syncronizes access via lock
|
|
525
|
+
(using `self._SpotifyConnectDevices_RLock`), as it could possibly modify the
|
|
526
|
+
SpotifyConnectDevices collection.
|
|
527
|
+
"""
|
|
528
|
+
|
|
529
|
+
member_summary:list[str] = []
|
|
530
|
+
member_hosts:list[str] = []
|
|
531
|
+
timeout:float = 2.0
|
|
532
|
+
group_uuid:UUID = UUID(scDevice.DiscoveryResult.Key)
|
|
533
|
+
|
|
534
|
+
try:
|
|
535
|
+
|
|
536
|
+
# get a list of device IP addresses that are members of the group, and also log
|
|
537
|
+
# a user-friendly trace line for debugging.
|
|
538
|
+
|
|
539
|
+
# trace.
|
|
540
|
+
_logsi.LogObject(SILevel.Verbose, "Verifying Chromecast Multizone group leader for Cast Group: %s [UUID=%s]" % (scDevice.Title, group_uuid), scDevice.DiscoveryResult, excludeNonPublic=True, colorValue=SIColors.Coral)
|
|
541
|
+
|
|
542
|
+
# get multizone controller reference for the group.
|
|
543
|
+
castMultizoneController:MultizoneController = self._CastMultiZoneControllers.get(str(group_uuid), None)
|
|
544
|
+
if (castMultizoneController is not None):
|
|
545
|
+
|
|
546
|
+
# process all members, building a list of their host addresses.
|
|
547
|
+
for member in castMultizoneController.members:
|
|
548
|
+
scMemberDevice:SpotifyConnectDevice = self._SpotifyConnectDevices.GetDeviceByDiscoveryKey(member)
|
|
549
|
+
if (scMemberDevice is None):
|
|
550
|
+
member_summary.append(member)
|
|
551
|
+
else:
|
|
552
|
+
member_summary.append("%s [ip=%s]" % (scMemberDevice.Title, scMemberDevice.DiscoveryResult.HostIpTitle))
|
|
553
|
+
member_hosts.append(scMemberDevice.DiscoveryResult.HostIpAddress)
|
|
554
|
+
|
|
555
|
+
# trace.
|
|
556
|
+
_logsi.LogArray(SILevel.Verbose, "Chromecast Multizone group member summary: \"%s\" (count=%d)" % (scDevice.Title, len(member_summary)), member_summary, colorValue=SIColors.Coral)
|
|
557
|
+
|
|
558
|
+
# process each member in the group, retrieving it's multi-zone status.
|
|
559
|
+
|
|
560
|
+
votes: Counter[str] = Counter()
|
|
561
|
+
port_for: dict[str, int] = {}
|
|
562
|
+
|
|
563
|
+
for host in member_hosts:
|
|
564
|
+
|
|
565
|
+
# trace.
|
|
566
|
+
_logsi.LogVerbose("Retrieving Chromecast Multizone group status for member host: %s" % (host), colorValue=SIColors.Coral)
|
|
567
|
+
|
|
568
|
+
# get multizone status for the specified group member.
|
|
569
|
+
# note that `get_multizone_status` can return both IPV4 (e.g. "192.168.1.97") and IPV6 (e.g. "::ffff:c0a8:161") addresses!
|
|
570
|
+
status = get_multizone_status(host, timeout=timeout)
|
|
571
|
+
|
|
572
|
+
# trace.
|
|
573
|
+
_logsi.LogDictionary(SILevel.Verbose, "Chromecast Multizone group status for member host: %s" % (host), status, prettyPrint=True, colorValue=SIColors.Coral)
|
|
574
|
+
|
|
575
|
+
# if we could not retrieve status, then move on to the next group member.
|
|
576
|
+
if status is None:
|
|
577
|
+
continue
|
|
578
|
+
|
|
579
|
+
# add to the vote count for this host address.
|
|
580
|
+
# a member that is the LEADER answers with its own host and the group's cast_port;
|
|
581
|
+
# a member that is a FOLLOWER answers with the leader's host and no port (pychromecast
|
|
582
|
+
# strips the ':10001' multizone port); right after a re-form, a single member can still
|
|
583
|
+
# say 'self' although it no longer leads, so take the majority.
|
|
584
|
+
for g in status.groups:
|
|
585
|
+
if g.uuid == group_uuid and g.host:
|
|
586
|
+
votes[g.host] += 1
|
|
587
|
+
if g.port:
|
|
588
|
+
port_for[g.host] = g.port
|
|
589
|
+
|
|
590
|
+
# add to the vote count for this host address for dynamic groups as well.
|
|
591
|
+
for g in status.dynamic_groups:
|
|
592
|
+
if g.uuid == group_uuid and g.host:
|
|
593
|
+
votes[g.host] += 1
|
|
594
|
+
if g.port:
|
|
595
|
+
port_for[g.host] = g.port
|
|
596
|
+
|
|
597
|
+
# trace.
|
|
598
|
+
_logsi.LogCollection(SILevel.Verbose, "Chromecast Multizone group leader vote summary for Cast Group: %s [UUID=%s]" % (scDevice.Title, group_uuid), votes.most_common(), colorValue=SIColors.Coral)
|
|
599
|
+
|
|
600
|
+
# we will now verify connectivity to all devices that were resolved
|
|
601
|
+
# as group leaders from the various group members. in most cases, this
|
|
602
|
+
# should be just one device, if they all reported the same leader.
|
|
603
|
+
# if multiple leaders were reported (this can happen while the group is
|
|
604
|
+
# in the midst of reforming), then we will use the host address that was
|
|
605
|
+
# reported the most, using the host address that was reported the least
|
|
606
|
+
# as a fallback in case we could not connect to the most-used address.
|
|
607
|
+
|
|
608
|
+
# process all reported leaders, using most reported host address first.
|
|
609
|
+
for host, _ in votes.most_common():
|
|
610
|
+
|
|
611
|
+
# trace.
|
|
612
|
+
_logsi.LogVerbose("Verifying connectivity to Chromecast Multizone group leader: %s" % (host), colorValue=SIColors.Coral)
|
|
613
|
+
|
|
614
|
+
# ensure we resolved a port for this host.
|
|
615
|
+
port = port_for.get(host)
|
|
616
|
+
if port is None:
|
|
617
|
+
|
|
618
|
+
# if a port was not resolved for this host, then it points at a host we have not
|
|
619
|
+
# retrieved multizone status for yet - ask it for its port.
|
|
620
|
+
|
|
621
|
+
# trace.
|
|
622
|
+
_logsi.LogVerbose("Retrieving Chromecast Multizone group status for member host: %s" % (host), colorValue=SIColors.Coral)
|
|
623
|
+
|
|
624
|
+
# get multizone status for the specified group member.
|
|
625
|
+
# note that `get_multizone_status` can return both IPV4 (e.g. "192.168.1.97") and IPV6 (e.g. "::ffff:c0a8:161") addresses!
|
|
626
|
+
status = get_multizone_status(host, timeout=timeout)
|
|
627
|
+
|
|
628
|
+
# trace.
|
|
629
|
+
_logsi.LogDictionary(SILevel.Verbose, "Chromecast Multizone group status for member host: %s" % (host), status, prettyPrint=True, colorValue=SIColors.Coral)
|
|
630
|
+
|
|
631
|
+
if status:
|
|
632
|
+
for g in status.groups:
|
|
633
|
+
if g.uuid == group_uuid and g.host == host and g.port:
|
|
634
|
+
port = g.port
|
|
635
|
+
for g in status.dynamic_groups:
|
|
636
|
+
if g.uuid == group_uuid and g.host == host and g.port:
|
|
637
|
+
port = g.port
|
|
638
|
+
|
|
639
|
+
# verify connectivity if we have a port for this host.
|
|
640
|
+
if port:
|
|
641
|
+
|
|
642
|
+
try:
|
|
643
|
+
|
|
644
|
+
# trace.
|
|
645
|
+
_logsi.LogVerbose("Verifying connection to Chromecast Multizone group leader host candidate: ip=%s, port=%s" % (host, port), colorValue=SIColors.Coral)
|
|
646
|
+
|
|
647
|
+
# connect to the host on the designated port. this should return almost
|
|
648
|
+
# immediately if the device is found on the local network.
|
|
649
|
+
with socket.create_connection((host, port), timeout=timeout):
|
|
650
|
+
|
|
651
|
+
# if it's a good socket connection, then we will treat this host as the
|
|
652
|
+
# group leader; update the devices collection if the addresses are different.
|
|
653
|
+
if (host != scDevice.DiscoveryResult.HostIpAddress):
|
|
654
|
+
|
|
655
|
+
# note that we only care about IPV4 addresses, as `get_multizone_status`
|
|
656
|
+
# can return both IPV4 and IPV6 addresses.
|
|
657
|
+
if (host.count(":")) > 1: # IPV6 address?
|
|
658
|
+
_logsi.LogVerbose("Ignoring Chromecast Multizone group leader candidate address: %s (IPV6 address)" % (host), colorValue=SIColors.Coral)
|
|
659
|
+
else:
|
|
660
|
+
_logsi.LogObject(SILevel.Verbose, "Cast Group leader IP was changed from [%s] to [%s] for Cast Group \"%s\"" % (scDevice.DiscoveryResult.HostIpAddress, host, scDevice.Name), scDevice.DiscoveryResult, excludeNonPublic=True, colorValue=SIColors.ForestGreen)
|
|
661
|
+
scDevice.DiscoveryResult.HostIpAddress = host
|
|
662
|
+
scDevice.DiscoveryResult.Id = "\"%s\" (%s:%s)" % (scDevice.DiscoveryResult.DeviceName, scDevice.DiscoveryResult.HostIpAddress, scDevice.DiscoveryResult.HostIpPort)
|
|
663
|
+
|
|
664
|
+
# connection was good; we are done here.
|
|
665
|
+
_logsi.LogVerbose("Chromecast Multizone group leader host was verified for Cast Group: \"%s\" [%s:%s]" % (scDevice.Name, host, port), colorValue=SIColors.Coral)
|
|
666
|
+
return
|
|
667
|
+
|
|
668
|
+
except Exception as ex:
|
|
669
|
+
|
|
670
|
+
# trace.
|
|
671
|
+
_logsi.LogException("Chromecast Group member [ip=%s, port=%s] could not be reached; moving on to next host" % (host, port, str(ex)), ex, logToSystemLogger=False)
|
|
672
|
+
# ignore exception and check the next available host
|
|
673
|
+
|
|
674
|
+
else:
|
|
675
|
+
_logsi.LogVerbose("Ignoring Chromecast Multizone group leader address: %s (port not found)" % (host), colorValue=SIColors.Coral)
|
|
676
|
+
|
|
677
|
+
# if we make it here, then the cast group leader could not be verified!
|
|
678
|
+
|
|
679
|
+
# trace.
|
|
680
|
+
_logsi.LogVerbose("Could not verify Chromecast Multizone group leader for Cast Group: %s [UUID=%s] - existing host [ip=%s] will be used" % (scDevice.Title, group_uuid, scDevice.DiscoveryResult.HostIpTitle), colorValue=SIColors.Coral)
|
|
681
|
+
|
|
682
|
+
except Exception as ex:
|
|
683
|
+
|
|
684
|
+
# trace.
|
|
685
|
+
_logsi.LogException("Chromecast Multizone group leader verification exception: %s" % (str(ex)), ex, logToSystemLogger=False)
|
|
686
|
+
# ignore exception, as nothing can be done about it.
|
|
687
|
+
|
|
688
|
+
|
|
512
689
|
def ActivateCastAppSpotify(
|
|
513
690
|
self,
|
|
514
691
|
deviceName:str,
|
|
@@ -586,6 +763,13 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
586
763
|
# match was found; reset device id activated before we activate a device.
|
|
587
764
|
scDevice.DeviceIdActivated = None
|
|
588
765
|
|
|
766
|
+
# is the activation request for a group?
|
|
767
|
+
if (scDevice.DiscoveryResult.IsChromeCastGroup):
|
|
768
|
+
|
|
769
|
+
# verify the current leader of the group.
|
|
770
|
+
# the device collection entry will be updated if a change was detected.
|
|
771
|
+
self._VerifyMultizoneGroupLeader(scDevice)
|
|
772
|
+
|
|
589
773
|
# is this a chromecast device?
|
|
590
774
|
if (not scDevice.IsChromeCast):
|
|
591
775
|
raise SpotifyApiError("Device %s is not a Chromecast device; use TransferPlayback instead." % (scDevice.Title), logsi=_logsi)
|
|
@@ -758,14 +942,6 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
758
942
|
retry_wait=0.5,
|
|
759
943
|
timeout=10)
|
|
760
944
|
|
|
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)
|
|
768
|
-
|
|
769
945
|
# trace.
|
|
770
946
|
_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)
|
|
771
947
|
|
|
@@ -1997,17 +2173,27 @@ class SpotifyConnectDirectoryTask(threading.Thread):
|
|
|
1997
2173
|
scDevice.DeviceInfo.RemoteName = newDeviceName
|
|
1998
2174
|
deviceNameChanged = True
|
|
1999
2175
|
|
|
2000
|
-
# is this a Google Cast Group
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2176
|
+
# is this a Google Cast Group update?
|
|
2177
|
+
if (zeroconfDiscoveryResult.IsChromeCastGroup):
|
|
2178
|
+
|
|
2179
|
+
# is this a Google Cast Group "add_cast" event?
|
|
2180
|
+
# if so, then it's probably a group leadership change that did not issue a call to
|
|
2181
|
+
# "remove_cast" as part of the update. we now have to determine which device in the
|
|
2182
|
+
# group is the new leader, and update the group DiscoveryResult accordingly.
|
|
2183
|
+
if (serviceType == "add_cast"):
|
|
2184
|
+
|
|
2185
|
+
# verify the current leader of the group.
|
|
2186
|
+
# the device collection entry will be updated if a change was detected.
|
|
2187
|
+
self._VerifyMultizoneGroupLeader(scDevice)
|
|
2188
|
+
|
|
2189
|
+
# is this a Google Cast Group "update_cast" event?
|
|
2190
|
+
# if so, AND the device name did not change, then ignore the update since
|
|
2191
|
+
# we will pickup any group leader changes in the ActivateCastAppSpotify method.
|
|
2192
|
+
elif (serviceType == "update_cast") and (not deviceNameChanged):
|
|
2007
2193
|
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2194
|
+
_logsi.LogObject(SILevel.Verbose, "SpotifyConnectDevice info: \"%s\" (ignored; Cast Group device update)" % (scDevice.Name), scDevice.DiscoveryResult, excludeNonPublic=True)
|
|
2195
|
+
_logsi.LogObject(SILevel.Debug, "SpotifyConnectDevice info: %s (NEW DiscoveryResult ignored) [%s]" % (scDevice.Title, zeroconfDiscoveryResult.HostIpTitle), zeroconfDiscoveryResult, excludeNonPublic=True)
|
|
2196
|
+
return
|
|
2011
2197
|
|
|
2012
2198
|
# set zeroconf discovery result properties.
|
|
2013
2199
|
scDevice.DiscoveryResult = zeroconfDiscoveryResult
|
|
@@ -393,7 +393,7 @@ class SpotifyConnectZeroconfCastAppTask(threading.Thread):
|
|
|
393
393
|
loginId:str,
|
|
394
394
|
) -> SpotifyAuthToken:
|
|
395
395
|
"""
|
|
396
|
-
Retrieve Spotify Desktop
|
|
396
|
+
Retrieve Spotify Desktop authorization access token from the token cache file.
|
|
397
397
|
The resulting token will be used to launch the Spotify cast app.
|
|
398
398
|
"""
|
|
399
399
|
apiMethodName:str = '_GetSpotifyDesktopAuthorizationToken'
|
|
@@ -91,10 +91,10 @@ class SpotifyConnectZeroconfCastListener(AbstractCastListener):
|
|
|
91
91
|
|
|
92
92
|
try:
|
|
93
93
|
|
|
94
|
-
# is this an
|
|
95
|
-
# that contain
|
|
94
|
+
# is this an GoogleCast service record? we only want discovery results
|
|
95
|
+
# that contain GoogleCast service information.
|
|
96
96
|
if (serviceName.find(ZEROCONF_SERVICETYPE_GOOGLECAST) == -1):
|
|
97
|
-
_logsi.LogDebug("Chromecast Zeroconf discovery service notification: \"%s\" (%s)" % (serviceName, "ignored; not
|
|
97
|
+
_logsi.LogDebug("Chromecast Zeroconf discovery service notification: \"%s\" (%s)" % (serviceName, "ignored; not GoogleCast service type"))
|
|
98
98
|
return None
|
|
99
99
|
|
|
100
100
|
# get chromecast info.
|
|
@@ -149,7 +149,7 @@ class SpotifyConnectZeroconfCastListener(AbstractCastListener):
|
|
|
149
149
|
|
|
150
150
|
# ensure IPV4 connection - ignore if IPV6.
|
|
151
151
|
# Windows OS does not support dual-stack socket handling IPv4 (224.0.0.251) and IPv6 (ff02::fb).
|
|
152
|
-
if (castInfoHost.count(":")) > 1:
|
|
152
|
+
if (castInfoHost.count(":")) > 1: #IPV6?
|
|
153
153
|
_logsi.LogDebug("Chromecast IPV6 device addresses are not supported; device could cause problems: \"%s\" (%s)" % (castInfo.friendly_name, serviceName), colorValue=SIColors.Red)
|
|
154
154
|
|
|
155
155
|
# will still allow this for now, but we might want to ignore IPV6 devices
|
|
@@ -113,9 +113,9 @@ class SpotifyConnectZeroconfCastMultiZoneManagerListener(MultiZoneManagerListene
|
|
|
113
113
|
# trace.
|
|
114
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
115
|
|
|
116
|
-
#
|
|
117
|
-
|
|
118
|
-
|
|
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
119
|
|
|
120
120
|
# # build member list with friendly names.
|
|
121
121
|
# result:list[str] = []
|
|
@@ -185,9 +185,9 @@ class SpotifyConnectZeroconfCastMultiZoneManagerListener(MultiZoneManagerListene
|
|
|
185
185
|
# trace.
|
|
186
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
187
|
|
|
188
|
-
#
|
|
189
|
-
|
|
190
|
-
|
|
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
191
|
|
|
192
192
|
# # build member list with friendly names.
|
|
193
193
|
# result:list[str] = []
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
spotifywebapipython/__init__.py,sha256=ka7F2AsT-UU7KSYKBnfgl5Trojcep5aQspLutg8D-2k,1306
|
|
2
|
-
spotifywebapipython/const.py,sha256=
|
|
2
|
+
spotifywebapipython/const.py,sha256=oj5dY2U2uxxMLiZWij3jeY2VwZzmbqSiHdm1twX9ATw,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
|
|
@@ -12,25 +12,25 @@ spotifywebapipython/spotifytypeprefixes.py,sha256=3yfpxKF7jF694qBuo-PbKYvm70Ywwd
|
|
|
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=FsnO64WP9HsImXs-AonCUUmUWEOlBajpYqhBYVcjNiE,199713
|
|
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=rNcPZUg3v7qJZSaXOcuFERqwC5CEm260Kc91BEbXoSg,48779
|
|
18
|
+
spotifywebapipython/docs/search.js,sha256=xdiBYN4bciyd6hIKcrC6l9ySbFg0NjJ3bl6aAFns-7E,9277464
|
|
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=IsLvA9DVCXJm0ahAFiFqH5fCP_LDErWOknP4_-fIP0w,60537
|
|
22
|
+
spotifywebapipython/docs/spotifywebapipython/saappmessages.html,sha256=5Q_EVCeeIak4bjbiBmzJt2f1P2u6dpRNq_mKWu9JEIs,62358
|
|
23
|
+
spotifywebapipython/docs/spotifywebapipython/sautils.html,sha256=-yv1l4IM__IVWHIIbzRUjCUC7rQJeR2OmDHQY64fH6U,62031
|
|
24
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyapierror.html,sha256=S_mHY212fy_lMKx_xakhFaNaOAI8nJclAnPpKnbSGLM,48054
|
|
25
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyapimessage.html,sha256=eiFt3S4N5FtErC-lEnU39m3sA_ISEMr2YOU6EIDahTA,59210
|
|
26
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyauthtoken.html,sha256=ALxUxbPz9EUt6GxF3C1wghH3iKj-OCvOi1y5cdasaeE,59256
|
|
27
|
+
spotifywebapipython/docs/spotifywebapipython/spotifyclient.html,sha256=bKgbh_ERKgTKypnQH6Gk-M-YTZgk0ihitAhPJpZkaeo,1677607
|
|
28
|
+
spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html,sha256=Nj2t95BtEXLAoVyzI-unE22CgqbPVzfhu3LEGrnJ5ug,57662
|
|
29
|
+
spotifywebapipython/docs/spotifywebapipython/spotifymediatypes.html,sha256=_Ntks24sCD3968HJtNHkN8IEnpgYW64hH69bY0EN7h0,51532
|
|
30
|
+
spotifywebapipython/docs/spotifywebapipython/spotifytypeprefixes.html,sha256=VccKsPzaqeN00S8Oz91yTetc4VKCfrAxHdm0C3T4ozg,52401
|
|
31
|
+
spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html,sha256=Z6TRDfiZ2ylfCkKaOGDEk5yoAE8-sc7OaX-GPIjeATM,52174
|
|
32
|
+
spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html,sha256=z16KGA-IX21EQBfVLw4woYLCMjJe837_mD3jRyYkwkE,51484
|
|
33
|
+
spotifywebapipython/docs/spotifywebapipython/spotifywebplayertoken.html,sha256=RtDWlyO3C3FlR7us4euXW29Spc99HRAw_JTLhJ52axc,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,12 +110,12 @@ 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=
|
|
114
|
-
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastapptask.py,sha256=
|
|
113
|
+
spotifywebapipython/spotifyconnect/spotifyconnectdirectorytask.py,sha256=Ha5Ht0PDaXNQJQxCcZEbu5SpDvETHcPgqbkr9l8WfhE,168043
|
|
114
|
+
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastapptask.py,sha256=jArxsjAGntTcQD9L9yVuey1L8pw0KvshlNXIBA7PqiI,23367
|
|
115
115
|
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastcontroller.py,sha256=e2wLmFq4393IdVa51w8X5UQl4KfnHRh34DMlxZfl9-g,34218
|
|
116
|
-
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastlistener.py,sha256=
|
|
116
|
+
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastlistener.py,sha256=e7vKob2xim8H3BkxbgPj-eymftKvWgT71tzpskd0sn0,16720
|
|
117
117
|
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastmultizonecontrollerlistener.py,sha256=AA-XxS6AptJWzyO2zsM9DA5ioCncJBKDTpJkr_aN9IM,12352
|
|
118
|
-
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastmultizonemanagerlistener.py,sha256=
|
|
118
|
+
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfcastmultizonemanagerlistener.py,sha256=gA-R7nR5cRbHrLVEGIRQILry72MSVpub4pNW-DZHWRY,18906
|
|
119
119
|
spotifywebapipython/spotifyconnect/spotifyconnectzeroconfexceptions.py,sha256=aesGauxMoKupdTPR5rL2-rXBC3SEvH_9bQQx2Vh-abs,524
|
|
120
120
|
spotifywebapipython/spotifyconnect/spotifyconnectzeroconflistener.py,sha256=ciN31zub2gk9On-1Gf7xDQpOdCEA3mutYIXpVfuA-w0,16583
|
|
121
121
|
spotifywebapipython/vibrant/__init__.py,sha256=x3yGfhH0ydjWTSILADuwQXaoLvpkV2EM0T_gyZ5aX38,712
|
|
@@ -137,8 +137,8 @@ spotifywebapipython/zeroconfapi/zeroconfgetinfo.py,sha256=gTr3J3iVDR_ueP1tg-WHuC
|
|
|
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.294.dist-info/LICENSE,sha256=KGcc9g0zwqNLcWnSn_ezv1UtKyhMENFhvtixpxUPNsE,1177
|
|
141
|
+
spotifywebapipython-1.0.294.dist-info/METADATA,sha256=aNEmx_UG_r6U79DD-SDB6Fnswiu-1OQll8IW_BGmr6c,11644
|
|
142
|
+
spotifywebapipython-1.0.294.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
143
|
+
spotifywebapipython-1.0.294.dist-info/top_level.txt,sha256=jTBLFlijKTesYh2dteAz4vb17qjaqWKeDjpnnwTcrjs,20
|
|
144
|
+
spotifywebapipython-1.0.294.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
{spotifywebapipython-1.0.292.dist-info → spotifywebapipython-1.0.294.dist-info}/top_level.txt
RENAMED
|
File without changes
|