I want to use AHK to create a small UI for querying an API. The API generates a random UUID for each download & I just need to know the name of the file which I've downloaded.
The problem is that URLDownloadToFile forces you to specify the filename upon downloading. Is it possible to get the file name as it was originally named by the server & not by AHK?
URLDownloadToFile with original file name?
Re: URLDownloadToFile with original file name?
example
Code: Select all
url:="http://www.replicaradio.ro/audio/billboard/1960//02.Jim%20Reeves-He'll%20Have%20To%20Go.mp3"
SplitPath, url, name, dir, ext, name_no_ext, drive
F1=%a_desktop%\%name%
urldownloadtofile,%url%,%f1%
return
Re: URLDownloadToFile with original file name?
Thanks Garry.
I just want to reiterate that it is an API & I do not know at the time of the request what the filename of the response will be. So my request is a lot like this:
And the response file is named:
I just want to reiterate that it is an API & I do not know at the time of the request what the filename of the response will be. So my request is a lot like this:
Code: Select all
http://thesite.com/api/foo?paramter=bar
Code: Select all
74bfb59b-8410-42a7-83ad-fca268a5b49c.xlsx
Re: URLDownloadToFile with original file name?
If you use a http request ( or similar request object ),
the filename may or may not be in the response header.
You can 1st test this by returning and viewing the entire response header:If you see the file name within the header,
you can use it's `item name` in the GetResponseHeader() method to return the specific name, for instance:
You can then stream/save the response body to a file using a ADODB stream object.
just an idea...
the filename may or may not be in the response header.
You can 1st test this by returning and viewing the entire response header:
Code: Select all
url = http://thesite.com/api/foo?paramter=bar
ReqObj := ComObjCreate( "WinHttp.WinHttpRequest.5.1" )
ReqObj.Open( "GET", url ), ReqObj.Send()
msgbox % ReqObj.GetAllResponseHeaders()
you can use it's `item name` in the GetResponseHeader() method to return the specific name, for instance:
In this case you'd use msgbox % ReqObj.GetResponseHeader("Content-Disposition")EXAMPLE RESPONSE HEADER:
Connection: Keep-Alive
Date: Tue, 27 Sep 2016 18:35:41 GMT
Keep-Alive: timeout=5, max=100
Content-Length: 100
Content-Type: text/plain
Content-Disposition: 74bfb59b-8410-42a7-83ad-fca268a5b49c.xlsx
Last-Modified: Tue, 27 Sep 2016 18:30:39 GMT
Accept-Ranges: bytes
ETag: "9-123456789"
Server: Some Server Type
You can then stream/save the response body to a file using a ADODB stream object.
just an idea...
Re: URLDownloadToFile with original file name?
The other case is the url redirect to another url.
Code: Select all
MsgBox, % GetUrlFilename("https://autohotkey.com/download/ahk-install.exe") ; The url redirect to another url
MsgBox, % GetUrlFilename("https://wordpress.org/latest.zip") ; The filename specified in the Content-Disposition response header
GetUrlFilename(url) {
whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
whr.Open("HEAD", url)
whr.Send()
try {
RegExMatch( whr.GetResponseHeader("Content-Disposition"), "filename=\K.+", m )
} catch {
RegExMatch( whr.Option(1), "[^/]+$", m ) ; 1 = WinHttpRequestOption_URL
}
return m
}
Code: Select all
WinHttp_UrlDownloadToFile(URL, Filename := "") {
WHR := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WHR.Open("GET", url, true)
WHR.Send()
WHR.WaitForResponse()
if (Filename ~= "^\s*$") {
try {
RegExMatch( WHR.GetResponseHeader("Content-Disposition"), "filename=\K.+", Filename )
} catch {
RegExMatch( WHR.Option(1), "[^/]+$", Filename ) ; 1 = WinHttpRequestOption_URL
}
}
ADO := ComObjCreate("ADODB.Stream")
ADO.Type := 1 ; adTypeBinary
ADO.Open()
ADO.Write(WHR.ResponseBody)
ADO.SaveToFile(FileName, 2)
ADO.Close()
}
Re: URLDownloadToFile with original file name?
ahh WinHttpRequestOption_URL is very nicetmplinshi wrote:The other case is the url redirect to another url.
On a side-note I'm lurking the spec to figure out if `Content-Disposition` is returned in a fixed order.
That way something like StrSplit() can be used over RegEx. Just a thought.
Re: URLDownloadToFile with original file name?
But the delimiter = may appear in the filename.TLM wrote:On a side-note I'm lurking the spec to figure out if `Content-Disposition` is returned in a fixed order.
That way something like StrSplit() can be used over RegEx. Just a thought.
StrSplit is actually a little slower than RegExMatch.
Running 10,000 times time-consuming (seconds):
0.004214 <- RegExMatch
0.008914 <- StrSplit
Code: Select all
#NoEnv
SetBatchLines, -1
str := "Content-Disposition: attachment; filename=wordpress-4.6.1.zip"
QPX(true)
Loop, 10000 {
RegExMatch(str, "filename=\K.+", m)
}
time_RegExMatch := QPX(false)
QPX(true)
Loop, 10000 {
m := StrSplit(str, "=")[2]
}
time_StrSplit := QPX(false)
MsgBox, % time_RegExMatch . " <- RegExMatch" . "`n"
. time_StrSplit . " <- StrSplit"
QPX( N=0 ) { ; Wrapper for QueryPerformanceCounter()by SKAN | CD: 06/Dec/2009
Static F,A,Q,P,X ; www.autohotkey.com/forum/viewtopic.php?t=52083 | LM: 10/Dec/2009
If ( N && !P )
Return DllCall("QueryPerformanceFrequency",Int64P,F) + (X:=A:=0) + DllCall("QueryPerformanceCounter",Int64P,P)
DllCall("QueryPerformanceCounter",Int64P,Q), A:=A+Q-P, P:=Q, X:=X+1
Return ( N && X=N ) ? (X:=X-1)<<64 : ( N=0 && (R:=A/X/F) ) ? ( R + (A:=P:=X:=0) ) : 1
}
Re: URLDownloadToFile with original file name?
Redirects like 302 are a pain, because generated headers of non-existent files will download as files without the error being easily trapped.
If the file to be downloaded is not text/html content-type, then at least an invalid file will be picked up as one of those.
If the file to be downloaded is not text/html content-type, then at least an invalid file will be picked up as one of those.
itros "ylbbub eht tuO kaerB" a ni kcuts m'I pleH
- Delta Pythagorean
- Posts: 627
- Joined: 13 Feb 2017, 13:44
- Location: Somewhere in the US
- Contact:
Re: URLDownloadToFile with original file name?
(To be honest I didn't read everything, I only know what I've read in the title.)
This might be of some help.
This might be of some help.
Code: Select all
$F1::
FileSelectFolder, Location
Location := RegExReplace(Location, "\\$")
InputBox, Link, URL, Please input a url to download.
UrlDownloadToFile, % Link, Location "\" SplitPath(Clipboard).FileName
Return
SplitPath(File) {
If (IsObject(File)) {
Files := []
For Each, Item in File {
SplitPath, Item, F, D, E, N, D_
Files[Each] := {FileName: F, Dir: D, Ext: E, NameNoExt: N, Drive: D_}
}
Return, Files
} Else {
SplitPath, File, F, D, E, N, D_
Return, {FileName: F, Dir: D, Ext: E, NameNoExt: N, Drive: D_}
}
}
[AHK]......: v2.0.12 | 64-bit
[OS].......: Windows 11 | 23H2 (OS Build: 22621.3296)
[GITHUB]...: github.com/DelPyth
[PAYPAL]...: paypal.me/DelPyth
[DISCORD]..: tophatcat
Re: URLDownloadToFile with original file name?
easy example if no redirect
combined good REDIRECT example from tmplinshi & TLM ( see above )
Code: Select all
url :="http://www.replicaradio.ro/audio/billboard/1960//02.Jim%20Reeves-He'll%20Have%20To%20Go.mp3"
urla:= uriDecode(url) ;- remove %20 etc
SplitPath, urla, name, dir, ext, name_no_ext, drive
F1=%a_desktop%\%name%
urldownloadtofile,%url%,%f1%
ifexist,%f1%
run,%f1%
return
uriDecode(str) {
Loop
If RegExMatch(str, "i)(?<=%)[\da-f]{1,2}", hex)
StringReplace, str, str, `%%hex%, % Chr("0x" . hex), All
Else Break
Return, str
}
combined good REDIRECT example from tmplinshi & TLM ( see above )
Code: Select all
;--- redirect example tmplinshi / TLM ---------------
f1:="https://autohotkey.com/download/ahk-install.exe"
f2:="https://wordpress.org/latest.zip"
fd:=a_desktop ;- save here
;----------------------------------------------------
whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
whr.SetTimeouts(3000,3000,3000,3000)
global whr,fd
;-- see header TLM ( if needed ) -------
whr.Open( "GET", f1 ), whr.Send()
rh1:=whr.GetAllResponseHeaders()
;whr.Open( "GET", f2 ), whr.Send()
; rh2:=whr.GetAllResponseHeaders()
;---------------------------------------
a1:=GetUrlFilename(f1)
a2:=GetUrlFilename(f2)
msgbox,%f1%`n%a1%`n-------------------`n%f2%`n%a2%`n`n-------HEADER from %f1%-------------`n%rh1%`n------------------------`n%rh2%
url:=WinHttp_UrlDownloadToFile(F1)
msgbox,downloaded file=`n%f1%`n%fd%\%a1%
;url:=WinHttp_UrlDownloadToFile(F2)
;msgbox,downloaded second file =`n%f2%`n%fd%\%a2%
;run,%fd% ;- open folder
return
;------------- tmplinshi --------------------------------------
GetUrlFilename(url) {
;whr := ComObjCreate("WinHttp.WinHttpRequest.5.1")
whr.Open("HEAD", url)
whr.Send()
try {
RegExMatch( whr.GetResponseHeader("Content-Disposition"), "filename=\K.+", m )
} catch {
RegExMatch( whr.Option(1), "[^/]+$", m ) ;- 1 = WinHttpRequestOption_URL
}
return m
}
;------------ urldownloadtofile --------------------------------
WinHttp_UrlDownloadToFile(URL, Filename := "") {
;WHR := ComObjCreate("WinHttp.WinHttpRequest.5.1")
WHR.Open("GET", url, true)
WHR.Send()
WHR.WaitForResponse()
if (Filename ~= "^\s*$") {
try {
RegExMatch( WHR.GetResponseHeader("Content-Disposition"), "filename=\K.+", Filename )
} catch {
RegExMatch( WHR.Option(1), "[^/]+$", Filename ) ;- 1 = WinHttpRequestOption_URL
}
}
ADO := ComObjCreate("ADODB.Stream")
ADO.Type := 1 ; adTypeBinary
ADO.Open()
ADO.Write(WHR.ResponseBody)
ADO.SaveToFile(fd . "\" . FileName, 2)
ADO.Close()
}
;========================================================================
Who is online
Users browsing this forum: CrowexBR, Google [Bot] and 270 guests