Author Topic: Spotify API with OAuth2 (WIP) Windows Only  (Read 3653 times)

0 Members and 1 Guest are viewing this topic.

Offline SpriggsySpriggs

  • Forum Resident
  • Posts: 1145
  • Larger than life
    • View Profile
    • GitHub
Spotify API with OAuth2 (WIP) Windows Only
« on: February 24, 2022, 10:43:58 pm »
I'm currently working on a project for the Spotify API. The project is still in its infancy. Right now, you can see the album art, song info, and playback timestamp in real-time. This program will eventually have buttons and a trackbar to control playback. I'll track the progress for the project here. The main reason why I wanted to do this project was because I had never been able to do OAuth2 before in QB64. I had no idea how to do it. The most I had done with online API was just simple GETs and POSTs. Now I have figured out the proper way to do OAuth2 and authorize a QB64 program for more advanced API like this Spotify API. I accomplished the OAuth2 authorization using a slightly edited version of Luke's HTTP server code. Obviously, you will need a Spotify account in order to use this program. It is also designed to run while you are playing music on Spotify. You can play Spotify from anywhere and this will track it. You don't have to use your computer to play the music.

Here is a short video showing how it works:


Code: QB64 $NOPREFIX: [Select]
  1. '$Console:Only
  2.  
  3. On Error GoTo errorhandler
  4.  
  5. Const INTERNET_OPEN_TYPE_DIRECT = 1
  6.  
  7. Const INTERNET_DEFAULT_HTTP_PORT = 80
  8. Const INTERNET_DEFAULT_HTTPS_PORT = 443
  9.  
  10. Const INTERNET_SERVICE_HTTP = 3
  11.  
  12. Const INTERNET_FLAG_SECURE = &H00800000
  13. Const INTERNET_FLAG_RELOAD = &H80000000
  14.  
  15. Const HTTP_QUERY_CONTENT_LENGTH = 5
  16.  
  17. Const TRUE = 1
  18. Const FALSE = 0
  19.  
  20. Const CLIENT_ID = "43b28a744c8947babd5766c3674e0a13"
  21. Const CLIENT_SECRET = "965f8e02e48a48ad9063e89bf5b0995f"
  22. Const REDIRECT_URI = "http://localhost:8888/"
  23.  
  24. Const SW_SHOWNORMAL = 1
  25.  
  26.     Function InternetOpen%& Alias "InternetOpenA" (ByVal lpszAgent As Offset, Byval dwAccessType As Unsigned Long, Byval lpszProxy As Offset, Byval lpszProxyBypass As Offset, Byval dwFlags As Unsigned Long)
  27.     Function InternetConnect%& Alias "InternetConnectA" (ByVal hInternet As Offset, Byval lpszServerName As Offset, Byval nServerPort As Unsigned Long, Byval lpszUserName As Offset, Byval lpszPassword As Offset, Byval dwService As Unsigned Long, Byval dwFlags As Unsigned Long, Byval dwContext As Unsigned Long)
  28.     Function HttpOpenRequest%& Alias "HttpOpenRequestA" (ByVal hConnect As Offset, Byval lpszVerb As Offset, Byval lpszObjectName As Offset, Byval lpszVersion As Offset, Byval lpszReferer As Offset, Byval lplpszAcceptTypes As Offset, Byval dwFlags As Unsigned Long, Byval dwContext As Unsigned Offset)
  29.     Function HttpSendRequest& Alias "HttpSendRequestA" (ByVal hRequest As Offset, Byval lpszHeaders As Offset, Byval dwHeadersLength As Unsigned Long, Byval lpOptional As Offset, Byval dwOptionalLength As Unsigned Long)
  30.     Function HttpQueryInfo& Alias "HttpQueryInfoA" (ByVal hRequest As Offset, Byval dwInfoLevel As Unsigned Long, Byval lpBuffer As Offset, Byval lpdwBufferLength As Offset, Byval lpdwIndex As Offset)
  31.     Sub InternetReadFile (ByVal hFile As Offset, Byval lpBuffer As Offset, Byval dwNumberOfBytesToRead As Unsigned Long, Byval lpdwNumberOfBytesRead As Offset)
  32.     Sub InternetCloseHandle (ByVal hInternet As Offset)
  33.  
  34. '$Include:'httpserv.BI'
  35.  
  36. $ExeIcon:'Spotify_icon.ico'
  37.  
  38. Dim Shared As String code, refreshtoken
  39.  
  40. Login
  41. If code <> "" Then
  42.     Screen NewImage(640, 640, 32)
  43.     'Print code
  44.     'ReDim As Long albumart(1 To 3)
  45.     'ReDim As String albumarturl(0)
  46.     Dim As Long albumart
  47.     Dim As String albumartstring, oldart, oldsong
  48.     Dim As String token
  49.     Dim As String playbackstate
  50.     Dim As String playing
  51.     Dim As Long songlength, position, cseconds, cminutes, chours, dseconds, dminutes, dhours
  52.     token = GetToken
  53.     'Print token
  54.     'Print "refresh_token:"; refreshtoken
  55.     Do
  56.  
  57.         'Dim As String current: current = SpotifyAPI("https://api.spotify.com/v1/me/player/currently-playing?market=US", token)
  58.         playbackstate = SpotifyAPI("https://api.spotify.com/v1/me/player?market=US", token)
  59.         albumartstring = GetKey(playbackstate, "url")
  60.         'albumart(1) = OnlineImage(albumarturl(1))
  61.         'albumart(2) = OnlineImage(albumarturl(2))
  62.         'albumart(3) = OnlineImage(albumarturl(3))
  63.         If GetKey2(playbackstate, "is_playing") = "true" Then playing = "Playing" Else playing = "Paused"
  64.         ReDim As String names(0)
  65.         GetAllKey playbackstate, "name", names()
  66.         If oldart <> albumartstring Or oldsong <> names((UBound(names))) Then
  67.             token = GetRefreshedToken
  68.             FreeImage albumart
  69.             oldart = albumartstring
  70.             oldsong = names((UBound(names)))
  71.             albumart = OnlineImage(albumartstring)
  72.             Title "Playing - " + names(UBound(names)) + " by " + names(2)
  73.             songlength = Val(GetKey(playbackstate, "duration_ms"))
  74.             dseconds = Int(songlength \ 1000) Mod 60
  75.             dminutes = Int((songlength \ (1000 * 60)) Mod 60)
  76.             dhours = Int((songlength \ (1000 * 60 * 60)) Mod 24)
  77.         End If
  78.         Cls
  79.         PutImage , albumart, 0
  80.         Print "Artist: "; names(2)
  81.         Print "Album : "; names(3)
  82.         Print "Song  : "; names((UBound(names)))
  83.         Print playing
  84.         position = Val(GetKey(playbackstate, "progress_ms"))
  85.         cseconds = Int(position \ 1000) Mod 60
  86.         cminutes = Int((position \ (1000 * 60)) Mod 60)
  87.         chours = Int((position \ (1000 * 60 * 60)) Mod 24)
  88.         If chours < 10 Then
  89.             Print "0"; LTrim$(Str$(chours)); ":";
  90.         Else
  91.             Print LTrim$(Str$(chours)); ":";
  92.         End If
  93.         If cminutes < 10 Then
  94.             Print "0"; LTrim$(Str$(cminutes)); ":";
  95.         Else
  96.             Print LTrim$(Str$(cminutes)); ":";
  97.         End If
  98.         If cseconds < 10 Then
  99.             Print "0"; LTrim$(Str$(cseconds)); "/";
  100.         Else
  101.             Print LTrim$(Str$(cseconds)); "/";
  102.         End If
  103.         If dhours < 10 Then
  104.             Print "0"; LTrim$(Str$(dhours)); ":";
  105.         Else
  106.             Print LTrim$(Str$(dhours)); ":";
  107.         End If
  108.         If dminutes < 10 Then
  109.             Print "0"; LTrim$(Str$(dminutes)); ":";
  110.         Else
  111.             Print LTrim$(Str$(dminutes)); ":";
  112.         End If
  113.         If dseconds < 10 Then
  114.             Print "0"; LTrim$(Str$(dseconds))
  115.         Else
  116.             Print LTrim$(Str$(dseconds))
  117.         End If
  118.  
  119.         Display
  120.         Limit 60
  121.     Loop
  122.  
  123. errorhandler:
  124.  
  125. Sub Login ()
  126.     Declare Dynamic Library "Shell32"
  127.         Sub ShellExecute Alias "ShellExecuteA" (ByVal hwnd As Offset, lpOperation As String, lpFile As String, Byval lpParameters As Offset, Byval lpDirectory As Offset, Byval nShowCmd As Long)
  128.     End Declare
  129.     Dim As String URL: URL = "https://accounts.spotify.com/authorize?response_type=code&client_id=" + CLIENT_ID + "&scope=user-modify-playback-state%20user-read-playback-state%20user-read-currently-playing%20user-read-recently-played&state=cAzgzTDzXnVYqbAM&show_dialog=true&redirect_uri=" + REDIRECT_URI
  130.     ShellExecute 0, "open" + Chr$(0), URL + Chr$(0), 0, 0, SW_SHOWNORMAL
  131.     OAuth2ServerStart
  132.  
  133. Function GetKey2$ (JSON As String, jkey As String)
  134.     Dim As String outj
  135.     outj = Mid$(JSON, InStr(JSON, Chr$(34) + jkey + Chr$(34) + " : ") + Len(Chr$(34) + jkey + Chr$(34) + " : "))
  136.     If Mid$(outj, 1, 1) = Chr$(34) Then outj = Mid$(outj, 2)
  137.     If Mid$(outj, Len(outj), 1) = Chr$(34) Then outj = Mid$(outj, Len(outj) - 1)
  138.     outj = Mid$(outj, 1, Len(outj) - 2)
  139.     GetKey2 = outj
  140.  
  141. Function GetRefreshedToken$ ()
  142.     Dim As String URL: URL = "https://accounts.spotify.com/api/token"
  143.     Dim As String server, apipath
  144.     server = Mid$(URL, InStr(URL, "/") + 2)
  145.     server = Mid$(server, 1, InStr(server, "/") - 1)
  146.     apipath = Mid$(URL, InStr(URL, server) + Len(server)) + Chr$(0)
  147.     server = server + Chr$(0)
  148.     Dim As Offset hInternet: hInternet = InternetOpen(0, INTERNET_OPEN_TYPE_DIRECT, 0, 0, 0)
  149.     If hInternet = 0 Then
  150.         Exit Function
  151.     End If
  152.     Dim As Offset hConnect: hConnect = InternetConnect(hInternet, Offset(server), INTERNET_DEFAULT_HTTPS_PORT, 0, 0, INTERNET_SERVICE_HTTP, 0, 0)
  153.     If hConnect = 0 Then
  154.         InternetCloseHandle hInternet
  155.         Exit Function
  156.     End If
  157.     Dim As String sessiontype, accepttypes
  158.     sessiontype = "POST" + Chr$(0)
  159.     accepttypes = "application/json" + Chr$(0)
  160.     Dim As Offset hRequest: hRequest = HttpOpenRequest(hConnect, Offset(sessiontype), Offset(apipath), 0, 0, Offset(accepttypes), INTERNET_FLAG_RELOAD Or INTERNET_FLAG_SECURE, 0)
  161.     If hRequest = 0 Then
  162.         InternetCloseHandle hConnect
  163.         InternetCloseHandle hInternet
  164.         Exit Function
  165.     End If
  166.     Dim As String opt: opt = "grant_type=refresh_token&refresh_token=" + refreshtoken
  167.     Dim As String headers: headers = "Authorization: Basic " + encodeBase64(CLIENT_ID + ":" + CLIENT_SECRET) + Chr$(13) + Chr$(10) + "Content-Type: application/x-www-form-urlencoded" + Chr$(0)
  168.     If HttpSendRequest(hRequest, Offset(headers), -1, Offset(opt), Len(opt)) <> TRUE Then
  169.         InternetCloseHandle hRequest
  170.         InternetCloseHandle hConnect
  171.         InternetCloseHandle hInternet
  172.         Exit Function
  173.     End If
  174.     Dim As String queryinfo: queryinfo = Space$(1024)
  175.     Dim As Unsigned Long querylen: querylen = Len(queryinfo) - 1
  176.  
  177.     If HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH, Offset(queryinfo), Offset(querylen), 0) <> TRUE Then
  178.         InternetCloseHandle hRequest
  179.         InternetCloseHandle hConnect
  180.         InternetCloseHandle hInternet
  181.         Exit Function
  182.     End If
  183.  
  184.     Dim As String szBuffer: szBuffer = Space$(4097)
  185.     Dim As String response
  186.     Dim As Unsigned Long dwRead
  187.     Do
  188.         InternetReadFile hRequest, Offset(szBuffer), Len(szBuffer) - 1, Offset(dwRead)
  189.         If dwRead > 0 Then response = response + Mid$(szBuffer, 1, dwRead)
  190.     Loop While dwRead
  191.     InternetCloseHandle hRequest
  192.     InternetCloseHandle hConnect
  193.     InternetCloseHandle hInternet
  194.     'refreshtoken = GetKey(response, "refresh_token")
  195.     GetRefreshedToken = GetKey(response, "access_token")
  196.  
  197. Function GetToken$ ()
  198.     Dim As String URL: URL = "https://accounts.spotify.com/api/token"
  199.     Dim As String server, apipath
  200.     server = Mid$(URL, InStr(URL, "/") + 2)
  201.     server = Mid$(server, 1, InStr(server, "/") - 1)
  202.     apipath = Mid$(URL, InStr(URL, server) + Len(server)) + Chr$(0)
  203.     server = server + Chr$(0)
  204.     Dim As Offset hInternet: hInternet = InternetOpen(0, INTERNET_OPEN_TYPE_DIRECT, 0, 0, 0)
  205.     If hInternet = 0 Then
  206.         Exit Function
  207.     End If
  208.     Dim As Offset hConnect: hConnect = InternetConnect(hInternet, Offset(server), INTERNET_DEFAULT_HTTPS_PORT, 0, 0, INTERNET_SERVICE_HTTP, 0, 0)
  209.     If hConnect = 0 Then
  210.         InternetCloseHandle hInternet
  211.         Exit Function
  212.     End If
  213.     Dim As String sessiontype, accepttypes
  214.     sessiontype = "POST" + Chr$(0)
  215.     accepttypes = "application/json" + Chr$(0)
  216.     Dim As Offset hRequest: hRequest = HttpOpenRequest(hConnect, Offset(sessiontype), Offset(apipath), 0, 0, Offset(accepttypes), INTERNET_FLAG_RELOAD Or INTERNET_FLAG_SECURE, 0)
  217.     If hRequest = 0 Then
  218.         InternetCloseHandle hConnect
  219.         InternetCloseHandle hInternet
  220.         Exit Function
  221.     End If
  222.     Dim As String opt: opt = "grant_type=authorization_code&code=" + code + "&redirect_uri=http://localhost:8888/"
  223.     Dim As String headers: headers = "Authorization: Basic " + encodeBase64(CLIENT_ID + ":" + CLIENT_SECRET) + Chr$(13) + Chr$(10) + "Content-Type: application/x-www-form-urlencoded" + Chr$(0)
  224.     If HttpSendRequest(hRequest, Offset(headers), -1, Offset(opt), Len(opt)) <> TRUE Then
  225.         InternetCloseHandle hRequest
  226.         InternetCloseHandle hConnect
  227.         InternetCloseHandle hInternet
  228.         Exit Function
  229.     End If
  230.     Dim As String queryinfo: queryinfo = Space$(1024)
  231.     Dim As Unsigned Long querylen: querylen = Len(queryinfo) - 1
  232.  
  233.     If HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH, Offset(queryinfo), Offset(querylen), 0) <> TRUE Then
  234.         InternetCloseHandle hRequest
  235.         InternetCloseHandle hConnect
  236.         InternetCloseHandle hInternet
  237.         Exit Function
  238.     End If
  239.  
  240.     Dim As String szBuffer: szBuffer = Space$(4097)
  241.     Dim As String response
  242.     Dim As Unsigned Long dwRead
  243.     Do
  244.         InternetReadFile hRequest, Offset(szBuffer), Len(szBuffer) - 1, Offset(dwRead)
  245.         If dwRead > 0 Then response = response + Mid$(szBuffer, 1, dwRead)
  246.     Loop While dwRead
  247.     InternetCloseHandle hRequest
  248.     InternetCloseHandle hConnect
  249.     InternetCloseHandle hInternet
  250.     refreshtoken = GetKey(response, "refresh_token")
  251.     GetToken = GetKey(response, "access_token")
  252.  
  253. Function SpotifyAPI$ (URL As String, token As String)
  254.     Dim As String server, apipath
  255.     server = Mid$(URL, InStr(URL, "/") + 2)
  256.     server = Mid$(server, 1, InStr(server, "/") - 1)
  257.     apipath = Mid$(URL, InStr(URL, server) + Len(server)) + Chr$(0)
  258.     server = server + Chr$(0)
  259.     Dim As Offset hInternet: hInternet = InternetOpen(0, INTERNET_OPEN_TYPE_DIRECT, 0, 0, 0)
  260.     If hInternet = 0 Then
  261.         Exit Function
  262.     End If
  263.     Dim As Offset hConnect: hConnect = InternetConnect(hInternet, Offset(server), INTERNET_DEFAULT_HTTPS_PORT, 0, 0, INTERNET_SERVICE_HTTP, 0, 0)
  264.     If hConnect = 0 Then
  265.         InternetCloseHandle hInternet
  266.         Exit Function
  267.     End If
  268.     Dim As String sessiontype, accepttypes
  269.     sessiontype = "GET" + Chr$(0)
  270.     accepttypes = "application/json" + Chr$(0)
  271.     Dim As Offset hRequest: hRequest = HttpOpenRequest(hConnect, Offset(sessiontype), Offset(apipath), 0, 0, Offset(accepttypes), INTERNET_FLAG_RELOAD Or INTERNET_FLAG_SECURE, 0)
  272.     If hRequest = 0 Then
  273.         InternetCloseHandle hConnect
  274.         InternetCloseHandle hInternet
  275.         Exit Function
  276.     End If
  277.     Dim As String headers: headers = "Authorization: Bearer " + token + Chr$(0)
  278.     If HttpSendRequest(hRequest, Offset(headers), -1, 0, 0) <> TRUE Then
  279.         InternetCloseHandle hRequest
  280.         InternetCloseHandle hConnect
  281.         InternetCloseHandle hInternet
  282.         Exit Function
  283.     End If
  284.     Dim As String queryinfo: queryinfo = Space$(1024)
  285.     Dim As Unsigned Long querylen: querylen = Len(queryinfo) - 1
  286.  
  287.     If HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH, Offset(queryinfo), Offset(querylen), 0) <> TRUE Then
  288.         InternetCloseHandle hRequest
  289.         InternetCloseHandle hConnect
  290.         InternetCloseHandle hInternet
  291.         Exit Function
  292.     End If
  293.  
  294.     Dim As String szBuffer: szBuffer = Space$(4097)
  295.     Dim As String response
  296.     Dim As Unsigned Long dwRead
  297.     Do
  298.         InternetReadFile hRequest, Offset(szBuffer), Len(szBuffer) - 1, Offset(dwRead)
  299.         If dwRead > 0 Then response = response + Mid$(szBuffer, 1, dwRead)
  300.     Loop While dwRead
  301.     InternetCloseHandle hRequest
  302.     InternetCloseHandle hConnect
  303.     InternetCloseHandle hInternet
  304.     SpotifyAPI = response
  305.  
  306. Function GetKey$ (JSON As String, keyname As String)
  307.     Dim jkey As String
  308.     jkey = JSON
  309.     If InStr(jkey, Chr$(34) + keyname + Chr$(34)) Then
  310.         jkey = Mid$(jkey, InStr(jkey, Chr$(34) + keyname + Chr$(34)) + Len(keyname))
  311.         jkey = Mid$(jkey, InStr(jkey, ":") + 2)
  312.         jkey = String.Replace(jkey, "\" + Chr$(34), "'")
  313.         If Mid$(jkey, 1, 1) = Chr$(34) Then
  314.             jkey = Mid$(jkey, 2)
  315.         End If
  316.         jkey = Mid$(jkey, 1, InStr(jkey, Chr$(34)) - 1)
  317.         If Right$(jkey, 1) = "," Then
  318.             jkey = Mid$(jkey, 1, Len(jkey) - 1)
  319.         End If
  320.     Else
  321.         GetKey = ""
  322.     End If
  323.     GetKey = jkey
  324.  
  325. Sub GetAllKey (JSON As String, keyname As String, ParseKey() As String)
  326.     Dim unchangejson As String
  327.     Dim jkey As String
  328.     Dim x
  329.     unchangejson = JSON
  330.     Do
  331.         If InStr(unchangejson, Chr$(34) + keyname + Chr$(34)) Then
  332.             x = x + 1
  333.             ReDim _Preserve ParseKey(x) As String
  334.             unchangejson = Mid$(unchangejson, InStr(unchangejson, Chr$(34) + keyname + Chr$(34)) + Len(keyname))
  335.             jkey = unchangejson
  336.             jkey = Mid$(jkey, InStr(jkey, ":") + 2)
  337.             jkey = String.Replace(jkey, "\" + Chr$(34), "'")
  338.             If Mid$(jkey, 1, 1) = Chr$(34) Then
  339.                 jkey = Mid$(jkey, 2)
  340.             End If
  341.             jkey = Mid$(jkey, 1, InStr(jkey, Chr$(34)) - 1)
  342.             If Right$(jkey, 1) = "," Then
  343.                 jkey = Mid$(jkey, 1, Len(jkey) - 1)
  344.             End If
  345.             ParseKey(x) = jkey
  346.         End If
  347.     Loop Until InStr(unchangejson, Chr$(34) + keyname + Chr$(34)) = 0
  348.  
  349. Function String.Replace$ (a As String, b As String, c As String)
  350.     Dim j
  351.     Dim r
  352.     Dim r$
  353.     j = InStr(a, b)
  354.     If j > 0 Then
  355.         r$ = Left$(a, j - 1) + c + String.Replace(Right$(a, Len(a) - j + 1 - Len(b)), b, c)
  356.     Else
  357.         r$ = a
  358.     End If
  359.     String.Replace = r$
  360.  
  361. Function encodeBase64$ (encode As String)
  362.     Declare Dynamic Library "Crypt32"
  363.         Function CryptBinaryToString& Alias "CryptBinaryToStringA" (ByVal pbBinary As Offset, Byval cbBinary As Unsigned Long, Byval dwFlags As Unsigned Long, Byval pszString As Offset, Byval pcchString As Offset)
  364.     End Declare
  365.     Const CRYPT_STRING_NOCRLF = &H40000000
  366.     Const CRYPT_STRING_BASE64 = &H00000001
  367.     Dim As String encoded
  368.     Dim As Unsigned Long lenEncoded
  369.     If CryptBinaryToString(Offset(encode), Len(encode), CRYPT_STRING_BASE64 Or CRYPT_STRING_NOCRLF, 0, Offset(lenEncoded)) <> FALSE Then
  370.         encoded = Space$(lenEncoded)
  371.     Else
  372.         encodeBase64 = ""
  373.         Exit Function
  374.     End If
  375.     If CryptBinaryToString(Offset(encode), Len(encode), CRYPT_STRING_BASE64 Or CRYPT_STRING_NOCRLF, Offset(encoded), Offset(lenEncoded)) <> FALSE Then
  376.         encodeBase64 = Mid$(encoded, 1, lenEncoded)
  377.     Else
  378.         encodeBase64 = ""
  379.     End If
  380.  
  381. Sub OAuth2ServerStart
  382.     Dim i
  383.     Dim num_active_connections
  384.     Dim server_handle
  385.     server_handle = _OpenHost("TCP/IP:" + LTrim$(Str$(PORT)))
  386.     Do
  387.         If num_active_connections < MAX_CONNECTIONS Then
  388.             Dim new_connection
  389.             new_connection = _OpenConnection(server_handle)
  390.             If new_connection Then
  391.                 num_active_connections = num_active_connections + 1
  392.                 For i = 1 To MAX_CONNECTIONS
  393.                     If Connections(i).handle = 0 Then
  394.                         Dim empty_connection As connection_t
  395.                         Connections(i) = empty_connection
  396.                         Connections(i).handle = new_connection
  397.                         Exit For
  398.                     End If
  399.                 Next i
  400.             End If
  401.         End If
  402.  
  403.         For i = 1 To MAX_CONNECTIONS
  404.             If Connections(i).handle Then
  405.                 Dim buf$
  406.                 Get #Connections(i).handle, , buf$
  407.                 If buf$ <> "" Then
  408.                     Connections(i).read_buf = Connections(i).read_buf + buf$
  409.                     process_request i
  410.                     http_error_complete:
  411.                 End If
  412.             End If
  413.         Next i
  414.         _Limit 240
  415.     Loop Until InStr(code, "code=") Or InStr(code, "error=")
  416.     If InStr(code, "code=") Then
  417.         code = Mid$(code, Len("?/code=") + 1)
  418.         code = Mid$(code, 1, InStr(code, "&state") - 1)
  419.     Else
  420.         code = ""
  421.     End If
  422.  
  423. '$Include:'httpserv.BM'
  424. Function OnlineImage& (URL As String)
  425.         Function GetTempFileName~& (ByVal lpPathName As Offset, Byval lpPrefixString As Offset, Byval uUnique As Unsigned Long, Byval lpTempFileName As Offset)
  426.         Function GetTempPath~& (ByVal nBufferLength As Unsigned Long, Byval lpBuffer As Offset)
  427.     End Declare
  428.     Dim getpath As Long
  429.     Dim getfile As _Unsigned Long
  430.  
  431.     Dim path As String
  432.     path = Space$(260 + 1)
  433.     getpath = GetTempPath(Len(path), _Offset(path))
  434.  
  435.     path = _Trim$(path)
  436.  
  437.     Dim file As String
  438.     Dim prefix As String
  439.     Dim unique As _Unsigned Integer
  440.     unique = Int(Rnd * 999) + 1
  441.     prefix = "spr" + Chr$(0)
  442.     Dim tempfile As String
  443.     tempfile = Space$(260 + 1)
  444.  
  445.     getfile = GetTempFileName(_Offset(path), _Offset(prefix), unique, _Offset(tempfile))
  446.  
  447.     tempfile = _Trim$(tempfile)
  448.  
  449.     URL = Mid$(URL, InStr(URL, "https://") + 8)
  450.     Dim location As String
  451.     location = Mid$(URL, InStr(URL, "/")) + Chr$(0)
  452.     URL = Mid$(URL, 1, InStr(URL, "/") - 1) + Chr$(0)
  453.     Dim As _Offset hsession, httpsession, httprequest
  454.     hsession = InternetOpen(0, INTERNET_OPEN_TYPE_DIRECT, 0, 0, 0)
  455.  
  456.     httpsession = InternetConnect(hsession, _Offset(URL), INTERNET_DEFAULT_HTTPS_PORT, 0, 0, INTERNET_SERVICE_HTTP, 0, 0)
  457.  
  458.     Dim sessiontype As String
  459.     sessiontype = "GET" + Chr$(0)
  460.     httprequest = HttpOpenRequest(httpsession, _Offset(sessiontype), _Offset(location), 0, 0, 0, INTERNET_FLAG_RELOAD Or INTERNET_FLAG_SECURE, 0)
  461.  
  462.     Dim sendrequest As Long
  463.     sendrequest = HttpSendRequest(httprequest, 0, 0, 0, 0)
  464.     Dim szBuffer As String
  465.     szBuffer = Space$(2048)
  466.     Dim dwRead As _Unsigned Long
  467.     Dim picfile As String
  468.     Open tempfile For Binary As #1
  469.     Do
  470.         InternetReadFile httprequest, _Offset(szBuffer), Len(szBuffer), _Offset(dwRead)
  471.         If dwRead > 0 Then picfile = picfile + Mid$(szBuffer, 1, dwRead)
  472.     Loop While dwRead
  473.     Put #1, , picfile
  474.     Close #1
  475.     InternetCloseHandle hsession
  476.     OnlineImage = _LoadImage(tempfile, 32)
  477.     Kill tempfile
* httpserv.BI (Filesize: 0.66 KB, Downloads: 228)
* httpserv.BM (Filesize: 6.7 KB, Downloads: 216)

* Spotify_icon.ico (Filesize: 4.06 KB, Dimensions: 31x32, Views: 467)
« Last Edit: February 24, 2022, 10:50:49 pm by SpriggsySpriggs »
Shuwatch!

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Spotify API with OAuth2 (WIP) Windows Only
« Reply #1 on: February 24, 2022, 11:01:32 pm »
Hi Indy,

I see your avatar has changed, or did you just get a haircut? :D Anyway, nice work! One question about the error handler. I had to trap time out errors in the past, with website apps, where a resume 0 was needed instead of a resume next. I would time the trap so if the internet connection was lost or the site was unavailable, the program would then break out of the trap and issue a report. It could be started again or exited with user response. I'm not sure if your app would need or could benefit from such a routine.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline SpriggsySpriggs

  • Forum Resident
  • Posts: 1145
  • Larger than life
    • View Profile
    • GitHub
Re: Spotify API with OAuth2 (WIP) Windows Only
« Reply #2 on: February 24, 2022, 11:08:12 pm »
@Pete I'm intentionally ignoring errors in this iteration while it is still in this phase of testing. Sometimes the API doesn't respond as fast as QB64 would like and would cause it to have invalid handles. It seems better to just ignore and keep working. It's been rather stable so far but I won't keep it with the errors turned off like that when I get closer to the final product. I do trap whether or not authentication was successful, however.
Shuwatch!

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Spotify API with OAuth2 (WIP) Windows Only
« Reply #3 on: February 24, 2022, 11:23:35 pm »
Nice! almost makes me want to jump back into programming again.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/