Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - SpriggsySpriggs

Pages: [1] 2 3 ... 77
1
Programs / Re: Finger Painting in QBJS
« on: April 10, 2022, 03:39:16 pm »
Awesome, dbox! Exciting stuff! I like how it loads instantly to the running program.

2
Chances are, this would take a registry approach. I have a library for interfacing with the registry. I just wouldn't know which keys to mess with.

3
Programs / Re: Evolving RI (Robot Intelligence) for a room vacuum
« on: February 28, 2022, 09:35:14 pm »
bump n' go cars 2.0

4
QB64 Discussion / Re: Windows Notification sample
« on: February 28, 2022, 03:10:27 pm »
Are you running the code for 64 bit? If so, it most likely won't work. Most, if not all, of the Wiki samples are written specifically for 32 bit. That isn't to say it isn't possible to use in 64 bit. It would just take work. If I remember, I'll look at it and see if I can convert it for you

5
Programs / Re: Spotify API with OAuth2 (WIP) Windows Only
« 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.

6
Programs / 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

7
Programs / Re: Rosie Bot
« on: February 24, 2022, 02:01:11 pm »
Speaking of text to speech, I wonder if you can access the new natural voices in Windows 11 through the command line. The new voices sound really good

8
Programs / Re: Draw any curve using only circles
« on: February 23, 2022, 06:37:14 pm »
I wish I understood math more. This is impressive stuff, Bill!

9
Programs / Re: Split Versus Tokenize
« on: February 01, 2022, 02:49:57 pm »
You're intentionally misinterpreting what I'm saying but that's ok. If you prefer to remain ignorant then by all means, please do.

10
Programs / Re: Split Versus Tokenize
« on: February 01, 2022, 01:37:21 pm »
The reason you weren't preserving blank lines is because you are using tokenize incorrectly. You should pass it either CHR$(13) or CHR$(10) (can't remember which). If you pass both, it'll split by both. It can take a list of delimiters.

11
Programs / Re: Quick Directory Files Listing for Windows Only
« on: February 01, 2022, 03:09:17 am »
But if we're going to stick to using dir commands, I think my way of splitting a string into an array is slightly better:

Code: QB64: [Select]
  1.  
  2. comm = pipecom_lite("DIR *.* /a:-d /b /o:-gen")
  3.  
  4. ReDim As String filelist(0 To 0)
  5. tokenize comm, Chr$(10), filelist()
  6. For i = 0 To UBound(filelist) - 1
  7.     Print i + 1, filelist(i)
  8.  
  9. Function pointerToString$ (pointer As _Offset)
  10.         Function strlen%& (ByVal ptr As _Unsigned _Offset)
  11.     End Declare
  12.     Dim As _Offset length: length = strlen(pointer)
  13.     If length Then
  14.         Dim As _MEM pString: pString = _Mem(pointer, length)
  15.         Dim As String ret: ret = Space$(length)
  16.         _MemGet pString, pString.OFFSET, ret
  17.         _MemFree pString
  18.     End If
  19.     pointerToString = ret
  20.  
  21. Sub tokenize (toTokenize As String, delimiters As String, StorageArray() As String)
  22.         Function strtok%& (ByVal str As _Offset, delimiters As String)
  23.     End Declare
  24.     Dim As _Offset tokenized
  25.     Dim As String tokCopy: tokCopy = toTokenize + Chr$(0)
  26.     Dim As String delCopy: delCopy = delimiters + Chr$(0)
  27.     Dim As _Unsigned Long lowerbound: lowerbound = LBound(StorageArray)
  28.     Dim As _Unsigned Long i: i = lowerbound
  29.     tokenized = strtok(_Offset(tokCopy), delCopy)
  30.     While tokenized <> 0
  31.         ReDim _Preserve StorageArray(lowerbound To UBound(StorageArray) + 1)
  32.         StorageArray(i) = pointerToString(tokenized)
  33.         tokenized = strtok(0, delCopy)
  34.         i = i + 1
  35.     Wend
  36.     ReDim _Preserve StorageArray(UBound(StorageArray) - 1)
  37.  
  38. $If PIPECOM = UNDEFINED Then
  39.     $Let PIPECOM = TRUE
  40.     Function pipecom& (cmd As String, stdout As String, stderr As String)
  41.         stdout = "": stderr = ""
  42.         $If WIN Then
  43.             Type SECURITY_ATTRIBUTES
  44.                 As _Unsigned Long nLength
  45.                 $If 64BIT Then
  46.                     As String * 4 padding
  47.                 $End If
  48.                 As _Offset lpSecurityDescriptor
  49.                 As Long bInheritHandle
  50.                 $If 64BIT Then
  51.                     As String * 4 padding2
  52.                 $End If
  53.             End Type
  54.  
  55.             Type STARTUPINFO
  56.                 As Long cb
  57.                 $If 64BIT Then
  58.                     As String * 4 padding
  59.                 $End If
  60.                 As _Offset lpReserved, lpDesktop, lpTitle
  61.                 As _Unsigned Long dwX, dwY, dwXSize, dwYSize, dwXCountChars, dwYCountChars, dwFillAttribute, dwFlags
  62.                 As _Unsigned Integer wShowWindow, cbReserved2
  63.                 $If 64BIT Then
  64.                     As String * 4 padding2
  65.                 $End If
  66.                 As _Offset lpReserved2, hStdInput, hStdOutput, hStdError
  67.             End Type
  68.  
  69.             Type PROCESS_INFORMATION
  70.                 As _Offset hProcess, hThread
  71.                 As _Unsigned Long dwProcessId
  72.                 $If 64BIT Then
  73.                     As String * 4 padding
  74.                 $End If
  75.             End Type
  76.  
  77.             Const STARTF_USESTDHANDLES = &H00000100
  78.             Const CREATE_NO_WINDOW = &H8000000
  79.  
  80.             Const INFINITE = 4294967295
  81.             Const WAIT_FAILED = &HFFFFFFFF
  82.  
  83.             Declare CustomType Library
  84.                 Function CreatePipe& (ByVal hReadPipe As _Offset, Byval hWritePipe As _Offset, Byval lpPipeAttributes As _Offset, Byval nSize As _Unsigned Long)
  85.                 Function CreateProcess& (ByVal lpApplicationName As _Offset, Byval lpCommandLine As _Offset, Byval lpProcessAttributes As _Offset, Byval lpThreadAttributes As _Offset, Byval bInheritHandles As Long, Byval dwCreationFlags As _Unsigned Long, Byval lpEnvironment As _Offset, Byval lpCurrentDirectory As _Offset, Byval lpStartupInfo As _Offset, Byval lpProcessInformation As _Offset)
  86.                 Function GetExitCodeProcess& (ByVal hProcess As _Offset, Byval lpExitCode As _Offset)
  87.                 Sub HandleClose Alias "CloseHandle" (ByVal hObject As _Offset)
  88.                 Function ReadFile& (ByVal hFile As _Offset, Byval lpBuffer As _Offset, Byval nNumberOfBytesToRead As _Unsigned Long, Byval lpNumberOfBytesRead As _Offset, Byval lpOverlapped As _Offset)
  89.                 Function WaitForSingleObject~& (ByVal hHandle As _Offset, Byval dwMilliseconds As _Unsigned Long)
  90.             End Declare
  91.  
  92.             Dim As Long ok: ok = 1
  93.             Dim As _Offset hStdOutPipeRead, hStdOutPipeWrite, hStdReadPipeError, hStdOutPipeError
  94.             Dim As SECURITY_ATTRIBUTES sa: sa.nLength = Len(sa): sa.lpSecurityDescriptor = 0: sa.bInheritHandle = 1
  95.  
  96.             If CreatePipe(_Offset(hStdOutPipeRead), _Offset(hStdOutPipeWrite), _Offset(sa), 0) = 0 Then
  97.                 pipecom = -1
  98.                 Exit Function
  99.             End If
  100.  
  101.             If CreatePipe(_Offset(hStdReadPipeError), _Offset(hStdOutPipeError), _Offset(sa), 0) = 0 Then
  102.                 pipecom = -1
  103.                 Exit Function
  104.             End If
  105.  
  106.             Dim As STARTUPINFO si
  107.             si.cb = Len(si)
  108.             si.dwFlags = STARTF_USESTDHANDLES
  109.             si.hStdError = hStdOutPipeError
  110.             si.hStdOutput = hStdOutPipeWrite
  111.             si.hStdInput = 0
  112.             Dim As PROCESS_INFORMATION procinfo
  113.             Dim As _Offset lpApplicationName
  114.             Dim As String lpCommandLine: lpCommandLine = "cmd /c " + cmd + Chr$(0)
  115.             Dim As _Offset lpProcessAttributes, lpThreadAttributes
  116.             Dim As Long bInheritHandles: bInheritHandles = 1
  117.             Dim As _Unsigned Long dwCreationFlags: dwCreationFlags = CREATE_NO_WINDOW
  118.             Dim As _Offset lpEnvironment, lpCurrentDirectory
  119.             ok = CreateProcess(lpApplicationName, _Offset(lpCommandLine), lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, _Offset(si), _Offset(procinfo))
  120.  
  121.             If ok = 0 Then
  122.                 pipecom = -1
  123.                 Exit Function
  124.             End If
  125.  
  126.             HandleClose hStdOutPipeWrite
  127.             HandleClose hStdOutPipeError
  128.  
  129.             Dim As String buf: buf = Space$(4096 + 1)
  130.             Dim As _Unsigned Long dwRead
  131.             While ReadFile(hStdOutPipeRead, _Offset(buf), 4096, _Offset(dwRead), 0) <> 0 And dwRead > 0
  132.                 buf = Mid$(buf, 1, dwRead)
  133.                 GoSub RemoveChr13
  134.                 stdout = stdout + buf
  135.                 buf = Space$(4096 + 1)
  136.             Wend
  137.  
  138.             While ReadFile(hStdReadPipeError, _Offset(buf), 4096, _Offset(dwRead), 0) <> 0 And dwRead > 0
  139.                 buf = Mid$(buf, 1, dwRead)
  140.                 GoSub RemoveChr13
  141.                 stderr = stderr + buf
  142.                 buf = Space$(4096 + 1)
  143.             Wend
  144.  
  145.             Dim As Long exit_code, ex_stat
  146.             If WaitForSingleObject(procinfo.hProcess, INFINITE) <> WAIT_FAILED Then
  147.                 If GetExitCodeProcess(procinfo.hProcess, _Offset(exit_code)) Then
  148.                     ex_stat = 1
  149.                 End If
  150.             End If
  151.  
  152.             HandleClose hStdOutPipeRead
  153.             HandleClose hStdReadPipeError
  154.             If ex_stat = 1 Then
  155.                 pipecom = exit_code
  156.             Else
  157.                 pipecom = -1
  158.             End If
  159.  
  160.             Exit Function
  161.  
  162.             RemoveChr13:
  163.             Dim As Long j
  164.             j = InStr(buf, Chr$(13))
  165.             Do While j
  166.                 buf = Left$(buf, j - 1) + Mid$(buf, j + 1)
  167.                 j = InStr(buf, Chr$(13))
  168.             Loop
  169.             Return
  170.         $Else
  171.             Declare CustomType Library
  172.             Function popen%& (cmd As String, readtype As String)
  173.             Function feof& (ByVal stream As _Offset)
  174.             Function fgets$ (str As String, Byval n As Long, Byval stream As _Offset)
  175.             Function pclose& (ByVal stream As _Offset)
  176.             End Declare
  177.  
  178.             Declare Library
  179.             Function WEXITSTATUS& (ByVal stat_val As Long)
  180.             End Declare
  181.  
  182.             Dim As _Offset stream
  183.  
  184.             Dim buffer As String * 4096
  185.             If _FileExists("pipestderr") Then
  186.             Kill "pipestderr"
  187.             End If
  188.             stream = popen(cmd + " 2>pipestderr" + Chr$(0), "r")
  189.             If stream Then
  190.             While feof(stream) = 0
  191.             If fgets(buffer, 4096, stream) <> "" And feof(stream) = 0 Then
  192.             stdout = stdout + Mid$(buffer, 1, InStr(buffer, Chr$(0)) - 1)
  193.             End If
  194.             Wend
  195.             Dim As Long status, exit_code
  196.             status = pclose(stream)
  197.             exit_code = WEXITSTATUS(status)
  198.             If _FileExists("pipestderr") Then
  199.             Dim As Integer errfile
  200.             errfile = FreeFile
  201.             Open "pipestderr" For Binary As #errfile
  202.             If LOF(errfile) > 0 Then
  203.             stderr = Space$(LOF(errfile))
  204.             Get #errfile, , stderr
  205.             End If
  206.             Close #errfile
  207.             Kill "pipestderr"
  208.             End If
  209.             pipecom = exit_code
  210.             Else
  211.             pipecom = -1
  212.             End If
  213.         $End If
  214.  
  215.     Function pipecom_lite$ (cmd As String)
  216.         Dim As Long a
  217.         Dim As String stdout, stderr
  218.         a = pipecom(cmd, stdout, stderr)
  219.         If stderr <> "" Then
  220.             pipecom_lite = stderr
  221.         Else
  222.             pipecom_lite = stdout
  223.         End If
  224.  

12
Programs / Re: Quick Directory Files Listing for Windows Only
« on: February 01, 2022, 02:47:08 am »
Since we're doing Windows only:

Code: QB64: [Select]
  1. Option Explicit
  2.  
  3. Const MAX_PATH = 260
  4.  
  5. Type FILETIME
  6.     As Unsigned Long dwLowDateTime, dwHighDateTime
  7.  
  8. Type WIN32_FIND_DATA
  9.     As Unsigned Long dwFileAttributes
  10.     As FILETIME ftCreationTime, ftLastAccessTime, ftLastWriteTime
  11.     As Unsigned Long nFileSizeHigh, nFileSizeLow, dwReserved0, dwReserved1
  12.     As String * Max_path cFileName
  13.     As String * 14 cAlternateFileName
  14.     As Unsigned Long dwFileType, dwCreatorType
  15.     As Unsigned Integer wFinderFlags
  16.  
  17.     Function FindFirstFile%& (ByVal lpFileName As Offset, Byval lpFindFileData As Offset)
  18.     Function FindNextFile& (ByVal hFindFile As Offset, Byval lpFindFileData As Offset)
  19.  
  20. Dim As String start: start = CWD$ + "\*.bas" + Chr$(0)
  21. Dim As Offset lpFileName: lpFileName = Offset(start)
  22. Dim As WIN32_FIND_DATA find
  23.  
  24. ReDim As String * MAX_PATH filelist(0 To 0)
  25.  
  26. Dim As Offset hFind: hFind = FindFirstFile(lpFileName, Offset(find))
  27.  
  28. If hFind Then
  29.     Dim As Unsigned Integer64 filesize: filesize = SHL(find.nFileSizeHigh, 32) Or find.nFileSizeLow
  30.     filelist(0) = find.cFileName
  31.     Print filelist(0), filesize; "bytes"
  32.     While FindNextFile(hFind, Offset(find))
  33.         filesize = SHL(find.nFileSizeHigh, 32) Or find.nFileSizeLow
  34.         ReDim Preserve As String * 260 filelist(UBound(filelist) + 1)
  35.         filelist(UBound(filelist)) = find.cFileName
  36.         Print filelist(UBound(filelist)), filesize; "bytes"
  37.     Wend
  38.     Print UBound(filelist); "files"

13
Programs / Re: Quick Directory Files Listing for Windows Only
« on: January 31, 2022, 04:35:10 pm »
@bplus That would be incorrect. It's been compatible with all operating systems since release. You might be thinking of a different issue where there was a null character throwing off results. That issue has since been resolved. However, the code you wrote here wasn't designed for Linux so even if my code wasn't compatible with Linux, it has no need to be mentioned here.

14
Programs / Re: Quick Directory Files Listing for Windows Only
« on: January 31, 2022, 03:36:20 pm »
This is basically the same code as what's on the Wiki. I'd change this to use pipecom so you don't use temp files at all.

15
There's another way of doing this that's slightly more intuitive. I'll see if I can find my code for it

Pages: [1] 2 3 ... 77