spotifywebapiPython 1.0.114__py3-none-any.whl → 1.0.116__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of spotifywebapiPython might be problematic. Click here for more details.
- {spotifywebapiPython-1.0.114.dist-info → spotifywebapiPython-1.0.116.dist-info}/METADATA +1 -1
- {spotifywebapiPython-1.0.114.dist-info → spotifywebapiPython-1.0.116.dist-info}/RECORD +25 -25
- spotifywebapipython/const.py +1 -1
- spotifywebapipython/docs/__init__.html +17 -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 +7 -5
- spotifywebapipython/docs/spotifywebapipython/spotifydiscovery.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebapiauthenticationerror.html +2 -2
- spotifywebapipython/docs/spotifywebapipython/spotifywebapierror.html +2 -2
- spotifywebapipython/models/artistinfo.py +20 -1
- spotifywebapipython/models/artistinfotourevent.py +19 -0
- spotifywebapipython/models/category.py +15 -0
- spotifywebapipython/models/pageobject.py +1 -4
- spotifywebapipython/models/playerqueueinfo.py +27 -0
- spotifywebapipython/spotifyclient.py +194 -142
- {spotifywebapiPython-1.0.114.dist-info → spotifywebapiPython-1.0.116.dist-info}/LICENSE +0 -0
- {spotifywebapiPython-1.0.114.dist-info → spotifywebapiPython-1.0.116.dist-info}/WHEEL +0 -0
- {spotifywebapiPython-1.0.114.dist-info → spotifywebapiPython-1.0.116.dist-info}/top_level.txt +0 -0
|
@@ -50,6 +50,8 @@ CACHE_SOURCE_CURRENT:str = "current"
|
|
|
50
50
|
|
|
51
51
|
SPOTIFY_DJ_PLAYLIST_ID = "37i9dqzf1eykqdzj48dyyq"
|
|
52
52
|
|
|
53
|
+
SPOTIFY_ONLINE_LINK_PREFIX = "https://open.spotify.com"
|
|
54
|
+
|
|
53
55
|
# get smartinspect logger reference; create a new session for this module name.
|
|
54
56
|
from smartinspectpython.siauto import SIAuto, SILevel, SISession, SIMethodParmListContext, SISourceId
|
|
55
57
|
import logging
|
|
@@ -423,10 +425,16 @@ class SpotifyClient:
|
|
|
423
425
|
False if there are no more pages to process;
|
|
424
426
|
otherwise, True to safely process the next page of results.
|
|
425
427
|
"""
|
|
426
|
-
# anymore page results?
|
|
428
|
+
# anymore page results for non-cursor paging types?
|
|
427
429
|
if (pageObj.Next is None) or (resultItemsCount >= limitTotal):
|
|
428
430
|
# no - all pages were processed, or limit total reached.
|
|
429
431
|
return False
|
|
432
|
+
|
|
433
|
+
# anymore page results for cursor paging types?
|
|
434
|
+
if (pageObj.IsCursor and pageObj.CursorAfter is None and pageObj.CursorBefore is None) \
|
|
435
|
+
or (resultItemsCount >= limitTotal):
|
|
436
|
+
# no - all pages were processed, or limit total reached.
|
|
437
|
+
return False
|
|
430
438
|
|
|
431
439
|
# modify paging-related request parameters for next page of items.
|
|
432
440
|
urlParms['limit'] = pageObj.Limit
|
|
@@ -434,7 +442,7 @@ class SpotifyClient:
|
|
|
434
442
|
urlParms['after'] = pageObj.CursorAfter
|
|
435
443
|
else:
|
|
436
444
|
urlParms['before'] = pageObj.CursorBefore
|
|
437
|
-
|
|
445
|
+
|
|
438
446
|
# just in case spotify doesn't return what is expected, and to prevent
|
|
439
447
|
# an endless loop
|
|
440
448
|
if pageObj.ItemsCount == 0:
|
|
@@ -3658,162 +3666,205 @@ class SpotifyClient:
|
|
|
3658
3666
|
|
|
3659
3667
|
# was a Spotify external url specified for the artist? if not then we are done.
|
|
3660
3668
|
if artist.ExternalUrls is None or artist.ExternalUrls.Spotify is None:
|
|
3661
|
-
|
|
3669
|
+
_logsi.LogVerbose("Spotify ExternalUrl not present for artist details page")
|
|
3670
|
+
return result
|
|
3662
3671
|
|
|
3663
|
-
|
|
3664
|
-
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, artist.ExternalUrls.Spotify)
|
|
3665
|
-
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
3666
|
-
self.MakeRequest('GET', msg)
|
|
3672
|
+
try:
|
|
3667
3673
|
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3674
|
+
# retrieve artist details page.
|
|
3675
|
+
msg:SpotifyApiMessage = SpotifyApiMessage(apiMethodName, artist.ExternalUrls.Spotify)
|
|
3676
|
+
msg.RequestHeaders[self.AuthToken.HeaderKey] = self.AuthToken.HeaderValue
|
|
3677
|
+
self.MakeRequest('GET', msg)
|
|
3671
3678
|
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
_logsi.
|
|
3675
|
-
return result
|
|
3679
|
+
# log html response.
|
|
3680
|
+
#_logsi.LogHtml(SILevel.Verbose, "GetArtistInfo response HTML", msg.ResponseData)
|
|
3681
|
+
_logsi.LogSource(SILevel.Verbose, "GetArtistInfo response Text", msg.ResponseData, SISourceId.Html)
|
|
3676
3682
|
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
if html is None:
|
|
3681
|
-
return result
|
|
3682
|
-
if not html.startswith('<html'):
|
|
3683
|
-
idx:int = html.find('<html')
|
|
3684
|
-
if idx == -1:
|
|
3685
|
-
_logsi.LogVerbose("<html> tag could not be found for artist details page: '%s'" % (artist.ExternalUrls.Spotify))
|
|
3683
|
+
# if no response data then we are done.
|
|
3684
|
+
if not msg.HasResponseData:
|
|
3685
|
+
_logsi.LogVerbose("No html returned for artist details page: '%s'" % (artist.ExternalUrls.Spotify))
|
|
3686
3686
|
return result
|
|
3687
|
-
|
|
3688
|
-
|
|
3687
|
+
|
|
3688
|
+
# find the starting <html> tag.
|
|
3689
|
+
# ElementTree fromstring method will fail if initial tag is "<!doctype html>".
|
|
3690
|
+
html:str = msg.ResponseData
|
|
3691
|
+
if html is None:
|
|
3692
|
+
return result
|
|
3693
|
+
if not html.startswith('<html'):
|
|
3694
|
+
idx:int = html.find('<html')
|
|
3695
|
+
if idx == -1:
|
|
3696
|
+
_logsi.LogVerbose("<html> tag could not be found for artist details page: '%s'" % (artist.ExternalUrls.Spotify))
|
|
3697
|
+
return result
|
|
3698
|
+
html = html[idx:]
|
|
3699
|
+
_logsi.LogSource(SILevel.Verbose, "GetArtistInfo response Text (starting from '<html')", html, SISourceId.Html)
|
|
3689
3700
|
|
|
3690
|
-
|
|
3691
|
-
|
|
3701
|
+
# log formatted html response.
|
|
3702
|
+
_logsi.LogXml(SILevel.Verbose, "GetArtistInfo response Text (formatted)", html, prettyPrint=True)
|
|
3692
3703
|
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3704
|
+
# load html element tree so we can parse it.
|
|
3705
|
+
doc:Element = fromstring(html)
|
|
3706
|
+
_logsi.LogObject(SILevel.Verbose, "doc Element object", doc)
|
|
3696
3707
|
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3708
|
+
attrXPath:str = None
|
|
3709
|
+
elm:Element = None
|
|
3710
|
+
elmChild:Element = None
|
|
3711
|
+
innerText:str = None
|
|
3712
|
+
|
|
3713
|
+
# about information - image (button / bio page):
|
|
3714
|
+
attrXPath = './/button[@type="button"]/descendant-or-self::img'
|
|
3715
|
+
_logsi.LogVerbose("Element search 'image button': '%s'" % attrXPath)
|
|
3716
|
+
attrElements:list[Element] = doc.xpath(attrXPath)
|
|
3717
|
+
for elm in attrElements:
|
|
3718
|
+
_logsi.LogObject(SILevel.Verbose, "Element match: '%s'" % attrXPath, elm)
|
|
3719
|
+
attrValue:str = elm.get('src', None)
|
|
3720
|
+
if attrValue is not None:
|
|
3721
|
+
result.ImageUrl = attrValue
|
|
3722
|
+
break
|
|
3712
3723
|
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3724
|
+
# about information - image (entity-id):
|
|
3725
|
+
# use the internal `_ImageUrl` attribute value to check, as the `ImageUrl` property
|
|
3726
|
+
# will return the `ImageUrlDefault` if `_ImageUrl` attribute was not set.
|
|
3727
|
+
# <img data-testid="artist-entity-image" src="https://i.scdn.co/image/ab6761610000517446196125b56397cd4e0d9c4b" />
|
|
3728
|
+
if result._ImageUrl is None:
|
|
3729
|
+
attrXPath = './/attribute::data-testid[contains(., "artist-entity-image")]/../@src'
|
|
3730
|
+
_logsi.LogVerbose("Element search 'image entity': '%s'" % attrXPath)
|
|
3731
|
+
elmChild = doc.xpath(attrXPath)
|
|
3732
|
+
if elmChild is not None:
|
|
3733
|
+
_logsi.LogVerbose("Element match: '%s'" % elmChild[0])
|
|
3734
|
+
result.ImageUrl = elmChild[0]
|
|
3735
|
+
|
|
3736
|
+
# about information - monthly listeners:
|
|
3737
|
+
# <div data-testid="monthly-listeners-label">2,707,252 monthly listeners</div>
|
|
3738
|
+
attrXPath = './/attribute::data-testid[contains(., "monthly-listeners-label")]/../text()'
|
|
3739
|
+
_logsi.LogVerbose("Element search 'monthly listeners': '%s'" % attrXPath)
|
|
3720
3740
|
elmChild = doc.xpath(attrXPath)
|
|
3721
3741
|
if elmChild is not None:
|
|
3722
3742
|
_logsi.LogVerbose("Element match: '%s'" % elmChild[0])
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
if innerTextLCase.startswith('view all upcoming concerts'):
|
|
3779
|
-
break;
|
|
3743
|
+
attrValue = elmChild[0].replace(ABOUT_MONTHLY_LISTENERS,'')
|
|
3744
|
+
attrValue = attrValue.replace(',','')
|
|
3745
|
+
attrValue = attrValue.strip()
|
|
3746
|
+
if attrValue.isnumeric:
|
|
3747
|
+
result.MonthlyListeners = int(attrValue)
|
|
3748
|
+
|
|
3749
|
+
# about information - bio:
|
|
3750
|
+
# <div data-testid="expandable-description">
|
|
3751
|
+
# <div>
|
|
3752
|
+
# <div>
|
|
3753
|
+
# <span>xxxxx is a contemporary music band ...</span>
|
|
3754
|
+
# </div>
|
|
3755
|
+
# </div>
|
|
3756
|
+
# </div>
|
|
3757
|
+
attrXPath = './/attribute::data-testid[contains(., "expandable-description")]/..'
|
|
3758
|
+
_logsi.LogVerbose("Element search 'bio': '%s'" % attrXPath)
|
|
3759
|
+
attrElements:list[Element] = doc.xpath(attrXPath)
|
|
3760
|
+
for elm in attrElements:
|
|
3761
|
+
innerText = _xmlGetInnerText(elm)
|
|
3762
|
+
_logsi.LogObject(SILevel.Verbose, "Element match: '%s' (innerText=%s)" % (attrXPath, innerText), elm)
|
|
3763
|
+
|
|
3764
|
+
# replace "see more" suffix with spotify link.
|
|
3765
|
+
SEE_MORE:str = "see more"
|
|
3766
|
+
if (innerText) and (innerText.endswith(SEE_MORE)):
|
|
3767
|
+
innerText = innerText.removesuffix(SEE_MORE)
|
|
3768
|
+
innerText += "<a href=\"%s\" target=\"_blank\">%s</a>" % (artist.ExternalUrls.Spotify, SEE_MORE)
|
|
3769
|
+
|
|
3770
|
+
result.Bio = innerText
|
|
3771
|
+
|
|
3772
|
+
# remove various html attributes from sub-elements.
|
|
3773
|
+
for elmDIV in elm.findall(".//*[@class]"):
|
|
3774
|
+
del elmDIV.attrib["class"]
|
|
3775
|
+
for elmDIV in elm.findall(".//*[@data-testid]"):
|
|
3776
|
+
del elmDIV.attrib["data-testid"]
|
|
3777
|
+
for elmDIV in elm.findall(".//*[@data-encore-id]"):
|
|
3778
|
+
del elmDIV.attrib["data-encore-id"]
|
|
3779
|
+
for elmDIV in elm.findall(".//*[@draggable]"):
|
|
3780
|
+
del elmDIV.attrib["draggable"]
|
|
3781
|
+
|
|
3782
|
+
# modify anchor link relative references in sub-elements.
|
|
3783
|
+
for elmDIV in elm.findall(".//a[@href]"):
|
|
3784
|
+
value:str = elmDIV.attrib["href"]
|
|
3785
|
+
if (value.startswith("/")):
|
|
3786
|
+
value = SPOTIFY_ONLINE_LINK_PREFIX + value
|
|
3787
|
+
elmDIV.attrib["href"] = value
|
|
3788
|
+
|
|
3789
|
+
# drop the parent DIV element, convert to html, and update result property.
|
|
3790
|
+
xml_string = etree.tostring(elm[0], pretty_print=True, encoding="utf-8")
|
|
3791
|
+
xml_decoded = xml_string.decode("utf-8")
|
|
3792
|
+
xml_decoded = xml_decoded.replace("\n","<br/>") # add <br> tags in place of newlines
|
|
3793
|
+
xml_decoded = xml_decoded.replace("<div><br/> ","<div>") # trim leading line breaks
|
|
3794
|
+
result.BioHtml = xml_decoded
|
|
3795
|
+
_logsi.LogHtml(SILevel.Verbose, "GetArtistInfo result BioHtml", result.BioHtml)
|
|
3796
|
+
|
|
3797
|
+
break
|
|
3780
3798
|
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3799
|
+
# about information - on tour dates:
|
|
3800
|
+
# <h2>On tour</h2>
|
|
3801
|
+
# <div><ul><li>
|
|
3802
|
+
# <a draggable="false" class="kZAjDLOBaUEUgIh0u_ar" href="/concert/35nHWo11uitgmm5XSkd8CU">
|
|
3803
|
+
# <time class="jqymLdIlkUVKl8shJfKZ" dateTime="2024-11-09T19:00-05:00">
|
|
3804
|
+
# <div class="encore-text encore-text-marginal-bold diaCgR2BgDJgHboSPS1S" data-encore-id="text">Nov</div>
|
|
3805
|
+
# <div class="encore-text encore-text-title-small RjfBbWVLuXMzwFtTXDL0" data-encore-id="text">9</div>
|
|
3806
|
+
# </time>
|
|
3807
|
+
# <div class="ymKJ1kNm06pnfmgmATrg">
|
|
3808
|
+
# <div class="encore-text encore-text-body-medium-bold encore-internal-color-text-base UmCMpZhcC2lll241N1NU" data-encore-id="text">Danny Gokey with Mac Powell and Seph Schlueter</div>
|
|
3809
|
+
# <p class="encore-text encore-text-body-small bk3jsOor2S1AwKPihqwM" data-encore-id="text">
|
|
3810
|
+
# <time class="cR3tL5CgXmgwfJDDKQ2A">Sat, Nov 9</time>Hobart Arena, Troy</p>
|
|
3811
|
+
# </div>
|
|
3812
|
+
# </a>
|
|
3813
|
+
# </li></ul></div>
|
|
3814
|
+
|
|
3815
|
+
attrXPath = './/h2[text()="On tour"]/following-sibling::*/descendant-or-self::a'
|
|
3816
|
+
_logsi.LogVerbose("Element search 'On tour': '%s'" % attrXPath)
|
|
3817
|
+
attrElements:list[Element] = doc.xpath(attrXPath)
|
|
3818
|
+
for elm in attrElements:
|
|
3819
|
+
event:ArtistInfoTourEvent = ArtistInfoTourEvent()
|
|
3820
|
+
|
|
3821
|
+
# process event more info link.
|
|
3822
|
+
attrValue = elm.attrib["href"]
|
|
3823
|
+
if (attrValue):
|
|
3824
|
+
event.Href = SPOTIFY_ONLINE_LINK_PREFIX + attrValue
|
|
3825
|
+
|
|
3826
|
+
# process event datetime.
|
|
3827
|
+
for elmDT in elm.findall(".//*[@dateTime]"):
|
|
3828
|
+
attrValue = elmDT.attrib["dateTime"]
|
|
3792
3829
|
idx:int = attrValue.rfind('-')
|
|
3793
3830
|
if idx > 15: # drop timezone portion of the datetime.
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3831
|
+
try:
|
|
3832
|
+
event.EventDateTime = datetime.fromisoformat(attrValue[:idx])
|
|
3833
|
+
except Exception as ex:
|
|
3834
|
+
_logsi.LogException("Element value '%s' (%s) could not be parsed to a datetime object" % (elmDT, attrValue), ex, logToSystemLogger=False)
|
|
3835
|
+
event.EventDateTime = None
|
|
3836
|
+
break
|
|
3837
|
+
|
|
3838
|
+
# process event venue.
|
|
3839
|
+
# we will remove the <time> element, leaving only the innerText of the <p> element.
|
|
3840
|
+
for elmPT in elm.findall(".//p/time"):
|
|
3841
|
+
#xml_string_before = etree.tostring(elm, pretty_print=True, encoding="utf-8")
|
|
3842
|
+
elmPT.text = "" # remove <time> text value
|
|
3843
|
+
#xml_string_after = etree.tostring(elm, pretty_print=True, encoding="utf-8")
|
|
3844
|
+
break
|
|
3845
|
+
for elmP in elm.findall(".//p"):
|
|
3846
|
+
event.VenueName = _xmlGetInnerText(elmP)
|
|
3847
|
+
break
|
|
3803
3848
|
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3849
|
+
# process event title.
|
|
3850
|
+
for elmDIV in elm.findall(".//div/div"):
|
|
3851
|
+
event.Title = _xmlGetInnerText(elmDIV)
|
|
3852
|
+
break
|
|
3808
3853
|
|
|
3809
|
-
|
|
3810
|
-
|
|
3854
|
+
# append event info to events collection.
|
|
3855
|
+
result.TourEvents.append(event)
|
|
3856
|
+
_logsi.LogObject(SILevel.Verbose, '%s: "%s" (%s)' % (type(event).__name__, event.Title, event.EventDateTime), event, excludeNonPublic=True)
|
|
3811
3857
|
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3858
|
+
# about information - links.
|
|
3859
|
+
result.AboutUrlFacebook = self._GetArtistInfoAboutLink(doc,"Facebook")
|
|
3860
|
+
result.AboutUrlInstagram = self._GetArtistInfoAboutLink(doc,"Instagram")
|
|
3861
|
+
result.AboutUrlTwitter = self._GetArtistInfoAboutLink(doc,"Twitter")
|
|
3862
|
+
result.AboutUrlWikipedia = self._GetArtistInfoAboutLink(doc,"Wikipedia")
|
|
3863
|
+
|
|
3864
|
+
except Exception as ex:
|
|
3865
|
+
|
|
3866
|
+
# trace parsing exceptions.
|
|
3867
|
+
_logsi.LogException(str(ex), ex, logToSystemLogger=False)
|
|
3817
3868
|
|
|
3818
3869
|
# trace.
|
|
3819
3870
|
_logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
|
|
@@ -4968,7 +5019,7 @@ class SpotifyClient:
|
|
|
4968
5019
|
sortResult:bool=True,
|
|
4969
5020
|
) -> CategoryPage:
|
|
4970
5021
|
"""
|
|
4971
|
-
Get
|
|
5022
|
+
Get categories used to tag items in Spotify.
|
|
4972
5023
|
|
|
4973
5024
|
Args:
|
|
4974
5025
|
limit (int):
|
|
@@ -7376,6 +7427,7 @@ class SpotifyClient:
|
|
|
7376
7427
|
|
|
7377
7428
|
# process results.
|
|
7378
7429
|
result = PlayerQueueInfo(root=msg.ResponseData)
|
|
7430
|
+
result.DateLastRefreshed = datetime.utcnow().timestamp()
|
|
7379
7431
|
|
|
7380
7432
|
# trace.
|
|
7381
7433
|
_logsi.LogObject(SILevel.Verbose, TRACE_METHOD_RESULT_TYPE % (apiMethodName, type(result).__name__), result, excludeNonPublic=True)
|
|
@@ -7680,7 +7732,7 @@ class SpotifyClient:
|
|
|
7680
7732
|
result = Playlist()
|
|
7681
7733
|
result._Collaborative = False
|
|
7682
7734
|
result._Description = 'Spotify DJ Playlist'
|
|
7683
|
-
result._ExternalUrls._Spotify =
|
|
7735
|
+
result._ExternalUrls._Spotify = SPOTIFY_ONLINE_LINK_PREFIX + "/playlist/" + playlistId
|
|
7684
7736
|
result._Id = playlistId
|
|
7685
7737
|
result._Name = 'DJ'
|
|
7686
7738
|
result._Public = False
|
|
File without changes
|
|
File without changes
|
{spotifywebapiPython-1.0.114.dist-info → spotifywebapiPython-1.0.116.dist-info}/top_level.txt
RENAMED
|
File without changes
|