Jump to content

Spotify Grab Now Playing and Track Elapsed/Duration


Bilgus
 Share

Recommended Posts

Thanks to LarsJ's excellent UIASpy application I was able to grab the now playing and track elapsed / duration from Spotify in about 15 minutes

https://www.autoitscript.com/forum/topic/196833-uiaspy-ui-automation-spy-tool/

You will need junkew's CUIAutomation2.au3 from the above UDF

 

Spoiler
#include "CUIAutomation2.au3"
Global Enum $eSpotify_Elapsed = 0, $eSpotify_Duration, $eSpotify_NowPlaying, $eSpotify_Elems
Example()

Func Example()
    Local $a_oSpotify = Spotify_InitInterface()
    Local $iErr = @error
    Local $sErr = @extended
    If $iErr Then
        MsgBox(16, "Error", "Unable to parse Spotify App " & @CRLF & "Error (" & $iErr & ") " & $a_oSpotify)
        Return
    EndIf

    Local $sElapsed, $sDuration
    Local $sNowPlaying = ""
    Local $iElapsed = 0, $iDuration = 0

    For $j = 0 To 120
        If $iElapsed = 0 Then
            $a_oSpotify[$eSpotify_NowPlaying].GetCurrentPropertyValue($UIA_NamePropertyId, $sNowPlaying)
            $sNowPlaying = NowPlaying_Proper($sNowPlaying)
            $a_oSpotify[$eSpotify_Duration].GetCurrentPropertyValue($UIA_NamePropertyId, $sDuration)
            $iDuration = TimeStringtoSeconds($sDuration)
        EndIf

        $a_oSpotify[$eSpotify_Elapsed].GetCurrentPropertyValue($UIA_NamePropertyId, $sElapsed)
        $iElapsed = TimeStringtoSeconds($sElapsed)
        ToolTip($sNowPlaying & @CRLF & $iElapsed & " / " & $iDuration & "s")
        Sleep(500)
    Next

EndFunc   ;==>Example

Func TimeStringtoSeconds($sHMS)
    Local $aTime = StringSplit($sHMS, ":")
    Local $iMultiplier = 1
    Local $iSeconds = 0
    If IsArray($aTime) Then
        For $i = $aTime[0] To 1 Step -1
            $iSeconds += $aTime[$i] * $iMultiplier
            $iMultiplier *= 60
        Next
    EndIf
    Return $iSeconds
EndFunc   ;==>TimeStringtoSeconds

Func NowPlaying_Proper($sNowPlaying)
    Local Const $sSearchNowPlaying = "Now Playing: "
    Local Const $sDelim = " by "
    Local $sProper = ""
    Local $sRes = StringReplace($sNowPlaying, $sSearchNowPlaying, "")
    Local $aRes = StringSplit($sRes, $sDelim, 2 + 1) ;$STR_ENTIRESPLIT (1), $STR_NOCOUNT (2)

    If IsArray($aRes) Then $sProper = $aRes[1] & " - " & $aRes[0]

    Return $sProper
EndFunc   ;==>NowPlaying_Proper

Func Spotify_InitInterface()
    ;Thanks LarsJ
    ;https://www.autoitscript.com/forum/topic/196833-uiaspy-ui-automation-spy-tool/
    Local Const $sSearchNowPlaying = "Now Playing: "
    Local $a_oSpotify[$eSpotify_Elems]
    Local $iErr = 1
    Local $sErr = "Unable to create $oUIAutomation object"
    Local $oAutomationElementArray, $iLength, $pElements
    Local $pTextField, $oTextField, $sTextField
    Local $oNowPlaying = 0
    ; Open Spotify

    ; Create UI Automation object
    Local $oUIAutomation = ObjCreateInterface($sCLSID_CUIAutomation, $sIID_IUIAutomation, $dtagIUIAutomation)
    While IsObj($oUIAutomation)
        $iErr = 0
        $sErr = "SUCCESS"
        ; Get Desktop element
        Local $pDesktop, $oDesktop
        $oUIAutomation.GetRootElement($pDesktop)
        $oDesktop = ObjCreateInterface($pDesktop, $sIID_IUIAutomationElement, $dtagIUIAutomationElement)
        If Not IsObj($oDesktop) Then
            $iErr = 2
            $sErr = "Unable to create $oDesktop object"
            ExitLoop
        EndIf

        ; --- Spotify window ---
        Local $pCondition_Spotify
        $oUIAutomation.CreatePropertyCondition($UIA_ValueValuePropertyId, "https://zlink.app.spotify.com/index.html", $pCondition_Spotify)
        If Not $pCondition_Spotify Then
            $iErr = 3
            $sErr = "Unable to create $pCondition_Spotify pointer"
            ExitLoop
        EndIf

        Local $pSpotify, $oSpotify
        $oDesktop.FindFirst($TreeScope_Descendants, $pCondition_Spotify, $pSpotify)
        $oSpotify = ObjCreateInterface($pSpotify, $sIID_IUIAutomationElement, $dtagIUIAutomationElement)
        If Not IsObj($oSpotify) Then
            ;Fallback
            $oUIAutomation.CreatePropertyConditionEx($UIA_ClassNamePropertyId, "Chrome_RenderWidgetHostHWND", $PropertyConditionFlags_IgnoreCase, $pCondition_Spotify)
            If Not $pCondition_Spotify Then
                $iErr = 4
                $sErr = "Unable to create $pCondition_Spotify pointer"
                ExitLoop
            EndIf
            $oDesktop.FindFirst($TreeScope_Descendants, $pCondition_Spotify, $pSpotify)
            $oSpotify = ObjCreateInterface($pSpotify, $sIID_IUIAutomationElement, $dtagIUIAutomationElement)

            If Not IsObj($oSpotify) Then
                $iErr = 5
                $sErr = "Unable to create $oSpotify object"
                ExitLoop
            EndIf
        EndIf

        ; --- Find Track / Artist ---
        Local $pCondition_Hyperlink
        $oUIAutomation.CreatePropertyCondition($UIA_ControlTypePropertyId, $UIA_HyperlinkControlTypeId, $pCondition_Hyperlink)
        If Not $pCondition_Hyperlink Then
            $iErr = 6
            $sErr = "Unable to create $pCondition_Hyperlink pointer"
            ExitLoop
        EndIf

        $oSpotify.FindAll($TreeScope_Descendants, $pCondition_Hyperlink, $pElements)
        If Not $pElements Then
            $iErr = 7
            $sErr = "Unable to find $pCondition_Hyperlink"
            ExitLoop
        EndIf

        $oAutomationElementArray = ObjCreateInterface($pElements, $sIID_IUIAutomationElementArray, $dtagIUIAutomationElementArray)
        $oAutomationElementArray.Length($iLength)
        If Not $iLength Then
            $iErr = 8
            $sErr = "Unable to find Now Playing object"
            ExitLoop
        EndIf

        For $i = 0 To $iLength - 1
            $oAutomationElementArray.GetElement($i, $pTextField)
            $oTextField = ObjCreateInterface($pTextField, $sIID_IUIAutomationElement, $dtagIUIAutomationElement)
            $oTextField.GetCurrentPropertyValue($UIA_NamePropertyId, $sTextField)
            ;;ConsoleWrite($sTextField & @CRLF)
            If StringRegExp($sTextField, "(?i)^" & $sSearchNowPlaying) Then ;Caseless match at beginning of string
                $oNowPlaying = $oTextField
                ExitLoop
            EndIf
        Next

        If Not IsObj($oNowPlaying) Then
            $iErr = 9
            $sErr = "Unable to find Now Playing object"
            ExitLoop
        EndIf

        ; --- Find Player controls ---
        Local $pCondition_PlayerControls
        $oUIAutomation.CreatePropertyConditionEx($UIA_NamePropertyId, "Player Controls", $PropertyConditionFlags_IgnoreCase, $pCondition_PlayerControls)
        If Not $pCondition_PlayerControls Then
            $iErr = 10
            $sErr = "Unable to create $pCondition_PlayerControls pointer"
            ExitLoop
        EndIf

        Local $iTries = 10
        While $iTries > 0
            Local $pPlayerControls, $oPlayerControls = 0
            $oSpotify.FindFirst($TreeScope_Subtree, $pCondition_PlayerControls, $pPlayerControls)
            If $pPlayerControls Then
                $oPlayerControls = ObjCreateInterface($pPlayerControls, $sIID_IUIAutomationElement, $dtagIUIAutomationElement)
            EndIf
            If Not IsObj($oPlayerControls) Then
                Sleep(1000)
                $iTries -= 1
            Else
                ExitLoop
            EndIf
        WEnd

        If Not IsObj($oPlayerControls) Then
            $iErr = 11
            $sErr = "Unable to create $oPlayerControls object"
            ExitLoop
        EndIf

        ; --- Find elapsed / duration ---
        Local $pCondition_TextControls
        $oUIAutomation.CreatePropertyCondition($UIA_ControlTypePropertyId, $UIA_TextControlTypeId, $pCondition_TextControls)
        If Not $pCondition_TextControls Then
            $iErr = 12
            $sErr = "Unable to create $pCondition_TextControls pointer"
            ExitLoop
        EndIf

        $oPlayerControls.FindAll($TreeScope_Descendants, $pCondition_TextControls, $pElements)
        If Not $pElements Then
            $iErr = 13
            $sErr = "Unable to find $pCondition_TextControls"
            ExitLoop
        EndIf

        $oAutomationElementArray = ObjCreateInterface($pElements, $sIID_IUIAutomationElementArray, $dtagIUIAutomationElementArray)
        $oAutomationElementArray.Length($iLength)
        If $iLength < $eSpotify_Elems - 1 Then
            $iErr = 14
            $sErr = "Unable to find elapsed or duration"
            ExitLoop
        EndIf

        For $i = 0 To $eSpotify_Elems - 2
            $oAutomationElementArray.GetElement($i, $pTextField)
            $oTextField = ObjCreateInterface($pTextField, $sIID_IUIAutomationElement, $dtagIUIAutomationElement)
            $a_oSpotify[$i] = $oTextField
        Next
        $a_oSpotify[$eSpotify_NowPlaying] = $oNowPlaying
        ExitLoop
    WEnd
    $oUIAutomation = 0
    $oAutomationElementArray = 0
    $oTextField = 0

    If $iErr Then
        Return SetError($iErr, 0, $sErr)
    Else
        Return $a_oSpotify
    EndIf
EndFunc   ;==>Spotify_InitInterface

 

 

Edited by Bilgus
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...