Last active
August 25, 2021 05:23
-
-
Save tmplinshi/b81e135a87c778a5ed16d9e83017c703 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; Google Drive API test | |
#NoEnv | |
SetWorkingDir %A_ScriptDir% | |
SetBatchLines, -1 | |
; http://www.howtosolvenow.com/how-to-create-your-google-drive-api-keys/ | |
; http://www.howtosolvenow.com/how-to-get-refresh-token-for-google-drive-api/ | |
client_id := "xxxxxxxxxxx" | |
client_secret := "xxxxxxxxxxx" | |
refresh_token := "xxxxxxxxxxx" | |
client := new gdrive(client_id, client_secret, refresh_token) | |
; client.proxy := "localhost:1080" | |
msgbox % client.getAccessToken() | |
; MsgBox % client.get("/about?fields=*") | |
; MsgBox % client.get("/about?fields=user") | |
MsgBox % client.get("/files") | |
; MsgBox % client.get("/files?q=name = 'temp.xlsx'") | |
; MsgBox % client.get("/files?q=name contains 'test'&pageSize=2") | |
; MsgBox % client.getFileId("test.png") | |
; MsgBox % client.downloadByName("test.png") | |
; MsgBox % client.upload("C:\Users\weich\Desktop\test.png") | |
; MsgBox % client.upload("C:\Users\weich\Desktop\test.png", {name: "new-name.png"}) | |
; MsgBox % client.updateFile("1Jva1qXDEDIR8bTvSc_EkJOBY1660aoG5", "C:\Users\weich\Desktop\test.png") | |
ExitApp | |
; https://developers.google.com/drive/api/v3/reference | |
class gdrive | |
{ | |
whr := ComObjCreate("WinHttp.WinHttpRequest.5.1") | |
baseUrl := "https://www.googleapis.com/drive/v3" | |
__New(client_id, client_secret, refresh_token) | |
{ | |
this.client_id := client_id | |
this.client_secret := client_secret | |
this.refresh_token := refresh_token | |
} | |
getAccessToken() | |
{ | |
body := { "client_id": this.client_id | |
, "client_secret": this.client_secret | |
, "refresh_token": this.refresh_token | |
, "grant_type": "refresh_token" } | |
result := this.http( "POST" | |
, "https://www.googleapis.com/oauth2/v4/token" | |
, Jxon_Dump(body) | |
, {"Content-Type": "application/json"} ) | |
return this.access_token := Jxon_Load(result).access_token | |
/* | |
{ | |
"access_token": "xxxxxxxxxxxxxxxxx", | |
"expires_in": 3599, | |
"scope": "https://www.googleapis.com/auth/drive", | |
"token_type": "Bearer" | |
} | |
*/ | |
} | |
get(resource) | |
{ | |
return this.http("GET", this.baseUrl . resource) | |
} | |
post(resource, data, oHeaders := "") | |
{ | |
return this.http("POST", this.baseUrl . resource, data, oHeaders) | |
} | |
simpileUpload(fileName) | |
{ | |
url := "https://www.googleapis.com/upload/drive/v3/files?uploadType=media" | |
return this.http("POST", url, this.FileToSafeArray(fileName)) | |
} | |
updateFile(fileId, fileName) | |
{ | |
url := "https://www.googleapis.com/upload/drive/v3/files/" fileId "?uploadType=media" | |
return this.http("PATCH", url, this.FileToSafeArray(fileName)) | |
} | |
getFileId(name) | |
{ | |
res := "/files?pageSize=1&q=" this.URIEncode("name='" name "' or name contains '" name "'") | |
out := Jxon_Load( this.get(res) ) | |
return out.files.1.id | |
} | |
upload(fileName, obj_Metadata := "") | |
{ | |
if !FileExist(fileName) | |
throw | |
if !IsObject(obj_Metadata) | |
{ | |
fName := RegExReplace(fileName, ".*[\\/]") | |
obj_Metadata := {name: fName} | |
} | |
url := "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart" | |
obj := { "whatever": [fileName] | |
, "i_am_json": {json: Jxon_Dump(obj_Metadata)} } | |
CreateFormData(retData, retHeader, obj) | |
return this.http("POST", url, retData, {"Content-Type": retHeader}) | |
} | |
downloadByName(name) | |
{ | |
res := "/files?pageSize=1&q=" this.URIEncode("name='" name "' or name contains '" name "'") | |
out := Jxon_Load( this.get(res) ) | |
if (out.files.1.id) | |
return this.downloadById(out.files.1.id, out.files.1.name) | |
} | |
downloadById(fileId, fileName := "") | |
{ | |
if (fileName = "") | |
fileName := Jxon_Load( this.get("/files/" fileId) ).files.1.name | |
this.get("/files/" fileId "?alt=media") | |
this.StreamToFile(this.whr.ResponseStream, fileName) | |
return fileName | |
} | |
http(method, url, postData="", obj_headers="") | |
{ | |
whr := this.whr | |
whr.Open(method, url, true) | |
if (this.proxy) | |
whr.SetProxy(2, this.proxy) | |
for k, v in obj_headers { | |
whr.SetRequestHeader(k, v) | |
} | |
if (this.access_token) { | |
whr.SetRequestHeader("Authorization", "Bearer " . this.access_token) | |
} | |
if (method = "POST") && !obj_headers.HasKey("Content-Type") { | |
whr.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded") | |
} | |
whr.Send(postData) | |
whr.WaitForResponse() | |
if (whr.Status = 200) | |
return whr.ResponseText | |
else | |
throw whr.Status " " whr.StatusText "`n" whr.GetAllResponseHeaders() "`n`n" whr.ResponseText | |
} | |
FileToSafeArray(fileName) { | |
File := FileOpen(FileName, "r") | |
safeArr := ComObjArray(0x11, File.length) ; Create SAFEARRAY = VT_ARRAY|VT_UI1 | |
File.RawRead(NumGet(ComObjValue(safeArr) + 8 + A_PtrSize), File.length) ; read raw data | |
File.Close() | |
return safeArr | |
} | |
; https://autohotkey.com/board/topic/65701-urldownloadtofile-saving-download-to-default-name/?p=650775 | |
; StreamToFile(whr.ResponseStream, "fileName") | |
StreamToFile(Stream, fileName) { | |
If (ComObjType(Stream) != 0xD) | |
Return 0 | |
pIStream := ComObjQuery(Stream, "{0000000c-0000-0000-C000-000000000046}") | |
oFile := FileOpen(fileName, "w") | |
While (cbRead != 0) | |
VarSetCapacity(Buffer, 8192) | |
, DllCall(NumGet(NumGet(pIStream + 0) + 3 * A_PtrSize) | |
, "ptr", pIStream, "ptr", &Buffer, "uint", 8192, "ptr*", cbRead) | |
, oFile.RawWrite(&Buffer, cbRead) | |
Return 1, ObjRelease(pIStream), oFile.Close() | |
} | |
; https://www.autohotkey.com/boards/viewtopic.php?t=63835 | |
URIEncode(str, encoding := "UTF-8") { | |
VarSetCapacity(var, StrPut(str, encoding)) | |
StrPut(str, &var, encoding) | |
While code := NumGet(Var, A_Index - 1, "UChar") { | |
bool := (code > 0x7F || code < 0x30 || code = 0x3D) | |
UrlStr .= bool ? "%" . Format("{:02X}", code) : Chr(code) | |
} | |
Return UrlStr | |
} | |
} | |
; =============================================================================== | |
; CreateFormData | |
; 2020-06-08 - Added a temporary approach to handling the json content-type | |
; example: objParam := { "key": {json: "{'k':'v'}"} } | |
; | |
/* | |
CreateFormData - Creates "multipart/form-data" for http post | |
https://www.autohotkey.com/boards/viewtopic.php?t=7647 | |
Usage: CreateFormData(ByRef retData, ByRef retHeader, objParam) | |
retData - (out) Data used for HTTP POST. | |
retHeader - (out) Content-Type header used for HTTP POST. | |
objParam - (in) An object defines the form parameters. | |
To specify files, use array as the value. Example: | |
objParam := { "key1": "value1" | |
, "upload[]": ["1.png", "2.png"] } | |
Requirements: BinArr.ahk -- https://gist.github.com/tmplinshi/a97d9a99b9aa5a65fd20 | |
Version : / 2020-06-08 - Added a temporary approach to handling the json content-type | |
example: objParam := { "key": {json: "{'k':'v'}"} } | |
1.30 / 2019-01-13 - The file parameters are now placed at the end of the retData | |
1.20 / 2016-06-17 - Added CreateFormData_WinInet(), which can be used for VxE's HTTPRequest(). | |
1.10 / 2015-06-23 - Fixed a bug | |
1.00 / 2015-05-14 | |
*/ | |
; Used for WinHttp.WinHttpRequest.5.1, Msxml2.XMLHTTP ... | |
CreateFormData(ByRef retData, ByRef retHeader, objParam) { | |
New CreateFormData(retData, retHeader, objParam) | |
} | |
; Used for WinInet | |
CreateFormData_WinInet(ByRef retData, ByRef retHeader, objParam) { | |
New CreateFormData(safeArr, retHeader, objParam) | |
size := safeArr.MaxIndex() + 1 | |
VarSetCapacity(retData, size, 1) | |
DllCall("oleaut32\SafeArrayAccessData", "ptr", ComObjValue(safeArr), "ptr*", pdata) | |
DllCall("RtlMoveMemory", "ptr", &retData, "ptr", pdata, "ptr", size) | |
DllCall("oleaut32\SafeArrayUnaccessData", "ptr", ComObjValue(safeArr)) | |
} | |
Class CreateFormData { | |
__New(ByRef retData, ByRef retHeader, objParam) { | |
CRLF := "`r`n" | |
Boundary := this.RandomBoundary() | |
BoundaryLine := "------------------------------" . Boundary | |
; Loop input paramters | |
binArrs := [] | |
fileArrs := [] | |
For k, v in objParam | |
{ | |
If IsObject(v) { | |
if v.HasKey("json") | |
{ | |
str := BoundaryLine . CRLF | |
. "Content-Type: application/json" . CRLF . CRLF | |
. v.json . CRLF | |
binArrs.Push( BinArr_FromString(str) ) | |
} | |
else | |
{ | |
For i, FileName in v | |
{ | |
str := BoundaryLine . CRLF | |
. "Content-Disposition: form-data; name=""" . k . """; filename=""" . FileName . """" . CRLF | |
. "Content-Type: " . this.MimeType(FileName) . CRLF . CRLF | |
fileArrs.Push( BinArr_FromString(str) ) | |
fileArrs.Push( BinArr_FromFile(FileName) ) | |
fileArrs.Push( BinArr_FromString(CRLF) ) | |
} | |
} | |
} Else { | |
str := BoundaryLine . CRLF | |
. "Content-Disposition: form-data; name=""" . k """" . CRLF . CRLF | |
. v . CRLF | |
binArrs.Push( BinArr_FromString(str) ) | |
} | |
} | |
binArrs.push( fileArrs* ) | |
str := BoundaryLine . "--" . CRLF | |
binArrs.Push( BinArr_FromString(str) ) | |
retData := BinArr_Join(binArrs*) | |
retHeader := "multipart/form-data; boundary=----------------------------" . Boundary | |
} | |
RandomBoundary() { | |
str := "0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z" | |
Sort, str, D| Random | |
str := StrReplace(str, "|") | |
Return SubStr(str, 1, 12) | |
} | |
MimeType(FileName) { | |
n := FileOpen(FileName, "r").ReadUInt() | |
Return (n = 0x474E5089) ? "image/png" | |
: (n = 0x38464947) ? "image/gif" | |
: (n&0xFFFF = 0x4D42 ) ? "image/bmp" | |
: (n&0xFFFF = 0xD8FF ) ? "image/jpeg" | |
: (n&0xFFFF = 0x4949 ) ? "image/tiff" | |
: (n&0xFFFF = 0x4D4D ) ? "image/tiff" | |
: "application/octet-stream" | |
} | |
} | |
; =============================================================================== | |
BinArr_FromString(str) { | |
oADO := ComObjCreate("ADODB.Stream") | |
oADO.Type := 2 ; adTypeText | |
oADO.Mode := 3 ; adModeReadWrite | |
oADO.Open | |
oADO.Charset := "UTF-8" | |
oADO.WriteText(str) | |
oADO.Position := 0 | |
oADO.Type := 1 ; adTypeBinary | |
oADO.Position := 3 ; Skip UTF-8 BOM | |
return oADO.Read, oADO.Close | |
} | |
BinArr_FromFile(FileName) { | |
oADO := ComObjCreate("ADODB.Stream") | |
oADO.Type := 1 ; adTypeBinary | |
oADO.Open | |
oADO.LoadFromFile(FileName) | |
return oADO.Read, oADO.Close | |
} | |
BinArr_Join(Arrays*) { | |
oADO := ComObjCreate("ADODB.Stream") | |
oADO.Type := 1 ; adTypeBinary | |
oADO.Mode := 3 ; adModeReadWrite | |
oADO.Open | |
For i, arr in Arrays | |
oADO.Write(arr) | |
oADO.Position := 0 | |
return oADO.Read, oADO.Close | |
} | |
BinArr_ToString(BinArr, Encoding := "UTF-8") { | |
oADO := ComObjCreate("ADODB.Stream") | |
oADO.Type := 1 ; adTypeBinary | |
oADO.Mode := 3 ; adModeReadWrite | |
oADO.Open | |
oADO.Write(BinArr) | |
oADO.Position := 0 | |
oADO.Type := 2 ; adTypeText | |
oADO.Charset := Encoding | |
return oADO.ReadText, oADO.Close | |
} | |
BinArr_ToFile(BinArr, FileName) { | |
oADO := ComObjCreate("ADODB.Stream") | |
oADO.Type := 1 ; adTypeBinary | |
oADO.Open | |
oADO.Write(BinArr) | |
oADO.SaveToFile(FileName, 2) | |
oADO.Close | |
} | |
; ================================================================================== | |
; by Coco, https://www.autohotkey.com/boards/viewtopic.php?t=627 | |
Jxon_Load(ByRef src, args*) | |
{ | |
static q := Chr(34) | |
key := "", is_key := false | |
stack := [ tree := [] ] | |
is_arr := { (tree): 1 } | |
next := q . "{[01234567890-tfn" | |
pos := 0 | |
while ( (ch := SubStr(src, ++pos, 1)) != "" ) | |
{ | |
if InStr(" `t`n`r", ch) | |
continue | |
if !InStr(next, ch, true) | |
{ | |
ln := ObjLength(StrSplit(SubStr(src, 1, pos), "`n")) | |
col := pos - InStr(src, "`n",, -(StrLen(src)-pos+1)) | |
msg := Format("{}: line {} col {} (char {})" | |
, (next == "") ? ["Extra data", ch := SubStr(src, pos)][1] | |
: (next == "'") ? "Unterminated string starting at" | |
: (next == "\") ? "Invalid \escape" | |
: (next == ":") ? "Expecting ':' delimiter" | |
: (next == q) ? "Expecting object key enclosed in double quotes" | |
: (next == q . "}") ? "Expecting object key enclosed in double quotes or object closing '}'" | |
: (next == ",}") ? "Expecting ',' delimiter or object closing '}'" | |
: (next == ",]") ? "Expecting ',' delimiter or array closing ']'" | |
: [ "Expecting JSON value(string, number, [true, false, null], object or array)" | |
, ch := SubStr(src, pos, (SubStr(src, pos)~="[\]\},\s]|$")-1) ][1] | |
, ln, col, pos) | |
throw Exception(msg, -1, ch) | |
} | |
is_array := is_arr[obj := stack[1]] | |
if i := InStr("{[", ch) | |
{ | |
val := (proto := args[i]) ? new proto : {} | |
is_array? ObjPush(obj, val) : obj[key] := val | |
ObjInsertAt(stack, 1, val) | |
is_arr[val] := !(is_key := ch == "{") | |
next := q . (is_key ? "}" : "{[]0123456789-tfn") | |
} | |
else if InStr("}]", ch) | |
{ | |
ObjRemoveAt(stack, 1) | |
next := stack[1]==tree ? "" : is_arr[stack[1]] ? ",]" : ",}" | |
} | |
else if InStr(",:", ch) | |
{ | |
is_key := (!is_array && ch == ",") | |
next := is_key ? q : q . "{[0123456789-tfn" | |
} | |
else ; string | number | true | false | null | |
{ | |
if (ch == q) ; string | |
{ | |
i := pos | |
while i := InStr(src, q,, i+1) | |
{ | |
val := StrReplace(SubStr(src, pos+1, i-pos-1), "\\", "\u005C") | |
static end := A_AhkVersion<"2" ? 0 : -1 | |
if (SubStr(val, end) != "\") | |
break | |
} | |
if !i ? (pos--, next := "'") : 0 | |
continue | |
pos := i ; update pos | |
val := StrReplace(val, "\/", "/") | |
, val := StrReplace(val, "\" . q, q) | |
, val := StrReplace(val, "\b", "`b") | |
, val := StrReplace(val, "\f", "`f") | |
, val := StrReplace(val, "\n", "`n") | |
, val := StrReplace(val, "\r", "`r") | |
, val := StrReplace(val, "\t", "`t") | |
i := 0 | |
while i := InStr(val, "\",, i+1) | |
{ | |
if (SubStr(val, i+1, 1) != "u") ? (pos -= StrLen(SubStr(val, i)), next := "\") : 0 | |
continue 2 | |
; \uXXXX - JSON unicode escape sequence | |
xxxx := Abs("0x" . SubStr(val, i+2, 4)) | |
if (A_IsUnicode || xxxx < 0x100) | |
val := SubStr(val, 1, i-1) . Chr(xxxx) . SubStr(val, i+6) | |
} | |
if is_key | |
{ | |
key := val, next := ":" | |
continue | |
} | |
} | |
else ; number | true | false | null | |
{ | |
val := SubStr(src, pos, i := RegExMatch(src, "[\]\},\s]|$",, pos)-pos) | |
; For numerical values, numerify integers and keep floats as is. | |
; I'm not yet sure if I should numerify floats in v2.0-a ... | |
static number := "number", integer := "integer" | |
if val is %number% | |
{ | |
if val is %integer% | |
val += 0 | |
} | |
; in v1.1, true,false,A_PtrSize,A_IsUnicode,A_Index,A_EventInfo, | |
; SOMETIMES return strings due to certain optimizations. Since it | |
; is just 'SOMETIMES', numerify to be consistent w/ v2.0-a | |
else if (val == "true" || val == "false") | |
val := %val% + 0 | |
; AHK_H has built-in null, can't do 'val := %value%' where value == "null" | |
; as it would raise an exception in AHK_H(overriding built-in var) | |
else if (val == "null") | |
val := "" | |
; any other values are invalid, continue to trigger error | |
else if (pos--, next := "#") | |
continue | |
pos += i-1 | |
} | |
is_array? ObjPush(obj, val) : obj[key] := val | |
next := obj==tree ? "" : is_array ? ",]" : ",}" | |
} | |
} | |
return tree[1] | |
} | |
Jxon_Dump(obj, indent:="", lvl:=1) | |
{ | |
static q := Chr(34) | |
if IsObject(obj) | |
{ | |
static Type := Func("Type") | |
if Type ? (Type.Call(obj) != "Object") : (ObjGetCapacity(obj) == "") | |
throw Exception("Object type not supported.", -1, Format("<Object at 0x{:p}>", &obj)) | |
is_array := 0 | |
for k in obj | |
is_array := k == A_Index | |
until !is_array | |
static integer := "integer" | |
if indent is %integer% | |
{ | |
if (indent < 0) | |
throw Exception("Indent parameter must be a postive integer.", -1, indent) | |
spaces := indent, indent := "" | |
Loop % spaces | |
indent .= " " | |
} | |
indt := "" | |
Loop, % indent ? lvl : 0 | |
indt .= indent | |
lvl += 1, out := "" ; Make #Warn happy | |
for k, v in obj | |
{ | |
if IsObject(k) || (k == "") | |
throw Exception("Invalid object key.", -1, k ? Format("<Object at 0x{:p}>", &obj) : "<blank>") | |
if !is_array | |
out .= ( ObjGetCapacity([k], 1) ? Jxon_Dump(k) : q . k . q ) ;// key | |
. ( indent ? ": " : ":" ) ; token + padding | |
out .= Jxon_Dump(v, indent, lvl) ; value | |
. ( indent ? ",`n" . indt : "," ) ; token + indent | |
} | |
if (out != "") | |
{ | |
out := Trim(out, ",`n" . indent) | |
if (indent != "") | |
out := "`n" . indt . out . "`n" . SubStr(indt, StrLen(indent)+1) | |
} | |
return is_array ? "[" . out . "]" : "{" . out . "}" | |
} | |
; Number | |
else if (ObjGetCapacity([obj], 1) == "") | |
return obj | |
; String (null -> not supported by AHK) | |
if (obj != "") | |
{ | |
obj := StrReplace(obj, "\", "\\") | |
, obj := StrReplace(obj, "/", "\/") | |
, obj := StrReplace(obj, q, "\" . q) | |
, obj := StrReplace(obj, "`b", "\b") | |
, obj := StrReplace(obj, "`f", "\f") | |
, obj := StrReplace(obj, "`n", "\n") | |
, obj := StrReplace(obj, "`r", "\r") | |
, obj := StrReplace(obj, "`t", "\t") | |
static needle := (A_AhkVersion<"2" ? "O)" : "") . "[^\x20-\x7e]" | |
while RegExMatch(obj, needle, m) | |
obj := StrReplace(obj, m[0], Format("\u{:04X}", Ord(m[0]))) | |
} | |
return q . obj . q | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment