Setting up an asynchronous download in AutoHotkey is a pain, but this is is necessary if you want to run some code during the download, like for example updating progress bar.
So the question is:
Is there a short and simple way of downloading a file with a progress bar, without including huge 1000+ lines libraries?
I came up with that code quite some time ago and you can still find it on the AHK forums, however, why not share it with the Stackoverflow community:
DownloadFile(UrlToFile, SaveFileAs, Overwrite := True, UseProgressBar := True, ExpectedFileSize := 0) {
;Check if the file already exists and if we must not overwrite it
If (!Overwrite && FileExist(SaveFileAs))
Return
;Check if the user wants a progressbar
If (UseProgressBar) {
;Initialize the WinHttpRequest Object
WebRequest := ComObjCreate("WinHttp.WinHttpRequest.5.1")
;Download the headers
WebRequest.Open("HEAD", UrlToFile)
WebRequest.Send()
try {
;Store the header which holds the file size in a variable:
FinalSize := WebRequest.GetResponseHeader("Content-Length")
} catch e {
; Cannot get "Content-Length" header
FinalSize := ExpectedFileSize
}
;Create the progressbar and the timer
Progress, , , Downloading..., %UrlToFile%
LastSizeTick := 0
LastSize := 0
; Enable progress bar updating if the system knows file size
SetTimer, __UpdateProgressBar, 1500
}
;Download the file
UrlDownloadToFile, %UrlToFile%, %SaveFileAs%
;Remove the timer and the progressbar because the download has finished
If (UseProgressBar) {
Progress, Off
SetTimer, __UpdateProgressBar, Off
}
Return
;The label that updates the progressbar
__UpdateProgressBar:
;Get the current filesize and tick
CurrentSize := FileOpen(SaveFileAs, "r").Length ;FileGetSize wouldn't return reliable results
CurrentSizeTick := A_TickCount
;Calculate the downloadspeed
SpeedOrig := Round((CurrentSize/1024-LastSize/1024)/((CurrentSizeTick-LastSizeTick)/1000))
SpeedUnit := "KB/s"
Speed := SpeedOrig
if (Speed > 1024) {
; Convert to megabytes
SpeedUnit := "MB/s"
Speed := Round(Speed/1024, 2)
}
SpeedText := Speed . " " . SpeedUnit
;Save the current filesize and tick for the next time
LastSizeTick := CurrentSizeTick
LastSize := FileOpen(SaveFileAs, "r").Length
if FinalSize = 0
{
PercentDone := 50
} else {
;Calculate percent done
PercentDone := Round(CurrentSize/FinalSize*100)
SpeedText := SpeedText . ", " . Round((FinalSize - CurrentSize) / SpeedOrig / 1024) . "s left"
}
;Update the ProgressBar
Progress, %PercentDone%, %PercentDone%`% (%SpeedText%), Downloading..., Downloading %SaveFileAs% (%PercentDone%`%)
Return
}
Here are some examples:
Example 1 - Download a firefox setup with a progressbar and overwrite it if it already exists on the disk:
DownloadFile("http://download-installer.cdn.mozilla.net/pub/firefox/releases/26.0/win32/en-US/Firefox%20Setup%2026.0.exe", "firefox_setup.exe")
Example 2 - Download Autohotkey with a progressbar and don't overwrite it if it already exists:
Url = http://ahkscript.org/download/ahk-install.exe
DownloadAs = AutoHotkey_L Installer.exe
Overwrite := False
UseProgressBar := True
DownloadFile(Url, DownloadAs, Overwrite, UseProgressBar)
Example 3 - Download a CCleaner setup and open a Save As dialog, asking the user where to save the file, overwriting it if already exists:
FileSelectFile, SaveAs, S, ccsetup410.exe
DownloadFile("http://download.piriform.com/ccsetup410.exe", SaveAs, True, True)
Related
I am new to AutoHotKey usage. I am using Version 1 syntax.
I want to watch a text file for any changes/modifications and if the text file is modified then I want to copy the contents of the Text file to clipboard.
When I run the below script then I don't see any errors but the clipboard is not working. What am I doing wrong here?
#SingleInstance
#Persistent
global ClipboardFile := "C:\\Users\\Username\\OneDrive - Folder\\clipboard.txt"
global Timestamp
FileGetTime, Timestamp, ClipboardFile, M
SetTimer , isFileModified, 1000
return
isFileModified() {
FileGetTime, TimestampModified, ClipboardFile, M
if ( Timestamp < TimestampModified ) {
global Timestamp := TimestampModified
FileRead, ClipboardText, ClipboardFile
ClipboardText := StrReplace(ClipboardText, "`n", "`r`n")
clipboard := ClipboardText
TrayTip , "Clipboard is updated successfully"
}
}
myFile := "C:\Users\user\myFileName.txt"
SetTimer, isFileModified, 1000
Return
isFileModified()
{
Global
ToolTip
FileGetTime, myNewTime, % myFile
If(myOldTime = "")
myOldTime := myNewTime, Return
If(myOldTime = myNewTime)
Return
myOldTime := myNewTime
SoundBeep, 444, 999
MsgBox % "Modified.."
}
I'm building Autohotkey script in order to take a backup of opened File Explorer windows list.
I'm looking for a way in order to get starting time of each window (time when I've opened the window).
I've this function:
list_opened_folders(byref file_explorer_windows) {
; file_explorer_windows := [] ; array of file_explorer_windows
for window in ComObjCreate("Shell.Application").Windows {
file_explorer_windows[a_index] := {}
file_explorer_windows[a_index].path := window.Document.Folder.Self.Path
file_explorer_windows[a_index].id := window.HWND
file_explorer_windows[a_index].started_time := window.Document.Folder.Self.Time ; Line I'm trying to add (I know this is invalid but to illustrate my idea)
}
}
Try:
#Persistent
DetectHiddenWindows, On
SetTitleMatchMode, 2
file_explorer_windows := {}
SetTimer, GetExplorer, 100
GetExplorer:
Process, Exist, Explorer.exe
If ErrorLevel
{
for window in ComObjCreate("Shell.Application").Windows {
if (file_explorer_windows[window.HWND]["id"] == "") {
file_explorer_windows[window.HWND] := {id: window.HWND
, path: window.Document.Folder.Self.Path
, start: A_NowUTC}
}
}
}
Return
It is supposed to put an entry in a text file each time a new window is active, instead it constantly loops and puts thousands of entries while the window is active, if anyone is capable of rectifying this I would be grateful.
loop
{
if new_window = %window_title%
new_window = diff
else
{
WinGetActiveTitle, window_title
fileappend, %window_title%`n, C:\mydirectory\myname.txt
new_window = %window_title%
}
}
Any help able to be provided would be more than welcome.
This uses a timer to check for a new window every 0.5 seconds.
#Persistent
prev_window := ""
settimer, check_window, 500
return
check_window:
WinGetActiveTitle, active_window
if (active_window != prev_window) {
fileappend, %active_window%`n, myname.txt
prev_window := active_window
}
return
The same could be accomplished in a loop:
prev_window := ""
loop
{
WinGetActiveTitle, active_window
if (active_window != prev_window) {
fileappend, %active_window%`n, myname.txt
prev_window := active_window
}
sleep, 500
}
return
You should probably put a SetTimer that checks active window title in some time interval (100ms or something) and compare to previously checked window tile - and if it has changed then write to file.
In Media Player Classic I found a way to jump to a point in a video/audio programmatically, avoiding the Go To... box.
The jump distances are available at Options → Tweaks,
and HKEY_CURRENT_USER\Software\MPC-HC\MPC-HC\Settings
(JumpDistL/JumpDistM/JumpDistS).
What I do is find the jump distances in the address space of Media Player Classic, and set the value of the large jump distance such
that if you applied it to the elapsed time you would get the desired time.
I then send a WM_COMMAND message with parameter 903/904 (all via AutoHotkey. I get the elapsed time by retrieving/parsing the contents of the Edit control.)
Because the jump is relative to the current point, it is imprecise,
and arrives within a second of the right time, but doesn't arrive
at exactly the same point each time.
Is there a more direct way of accomplishing this and if not,
would any Media Player Classic users/programmers
consider discussing on the forum, introducing new WM_COMMAND messages
that allow jump to point (in milliseconds),
or that retrieve the numerical values listed here
(state, position, duration, volumelevel, muted, playbackrate, reloadtime).
(The method found here is too slow to get the time accurately, and requires special options be set).
Thanks to the message from wOxxOm, below the question,
I have been able to create this AutoHotkey script,
which solves my original problem:
to set the elapsed time in Media Player Classic programmatically,
directly, without using the Go To... box.
It also solves the problem of retrieving
information about the video.
The hotkeys are:
- Ctrl+Q to start the MPC API,
- Ctrl+W to retrieve information,
- the number keys to jump partway through the video.
;==================================================
^q:: ;start MPC API
hWnd := A_ScriptHwnd+0
OnMessage(WM_COPYDATA:=74, "On_WM_COPYDATA")
;64-bit
Run, "C:\Program Files (x86)\K-Lite Codec Pack\MPC-HC64\mpc-hc64.exe" /slave %hWnd%
;32-bit
;Run, "C:\Program Files (x86)\K-Lite Codec Pack\MPC-HC\mpc-hc.exe" /slave %hWnd%
Return
;==================================================
^w:: ;display information
Send(vMPCApiHWnd, 0xA0003004, "") ;CMD_GETCURRENTPOSITION := 0xA0003004
vElapsed := 19990101
vDuration := 19990101
vElapsed += vMPCApiCurrent, S
vDuration += vMPCApiDuration, S
if (vMPCApiCurrent >= 3600) OR (vMPCApiDuration >= 3600)
vFormat := "HH:mm:ss"
else
vFormat := "mm:ss"
FormatTime, vElapsed, %vElapsed%, %vFormat%
FormatTime, vDuration, %vDuration%, %vFormat%
SplitPath, vMPCApiPath, vName, vDir, vExt, vNameNoExt, vDrive
vText = ;continuation section
(
title: %vMPCApiTitle%
author: %vMPCApiAuthor%
description: %vMPCApiDesc%
name: %vName%
path: %vMPCApiPath%
elapsed: %vElapsed% (%vMPCApiCurrent%)
duration: %vDuration% (%vMPCApiDuration%)
)
MsgBox %vText%
Return
;==================================================
#IfWinActive, ahk_class MediaPlayerClassicW
0:: ;skip to point
1::
2::
3::
4::
5::
6::
7::
8::
9::
vNum := SubStr(A_ThisHotkey, 1-1)
vElapsed2 := Round(vMPCApiDuration*(vNum/10))
Send(vMPCApiHWnd, 0xA0002000, "" vElapsed2) ;CMD_SETPOSITION := 0xA0002000
Return
#IfWinActive
;==================================================
On_WM_COPYDATA(wParam, lParam, msg, hwnd)
{
global vMPCApiHWnd
global vMPCApiTitle
global vMPCApiAuthor
global vMPCApiDesc
global vMPCApiPath
global vMPCApiDuration
global vMPCApiCurrent
dwData := NumGet(lParam+0, 0)
cbData := NumGet(lParam+A_PtrSize)
lpData := NumGet(lParam + 2*A_PtrSize)
lpData := StrGet(lpData)
if (dwData = 0x50000000) ;CMD_CONNECT := 0x50000000
{
vMPCApiHWnd := lpData
WinGetClass, vWinClass, ahk_id %vMPCApiHWnd%
if (vWinClass = "MediaPlayerClassicW")
MsgBox, , , MPC API on, 3
}
if (dwData = 0x50000003) ;CMD_NOWPLAYING := 0x50000003
{
StringSplit, lpData, lpData, |
vMPCApiTitle := lpData1
vMPCApiAuthor := lpData2
vMPCApiDesc := lpData3
vMPCApiPath := lpData4
vMPCApiDuration := lpData5
}
if (dwData = 0x50000007) ;CMD_CURRENTPOSITION := 0x50000007
vMPCApiCurrent := lpData
Return true
}
;==================================================
Send(Hwnd, dwData, lpData)
{
static WM_COPYDATA := 0x4a
VarSetCapacity(COPYDATASTRUCT, 3*A_PtrSize, 0)
cbData := (StrLen(lpData) + 1) * (A_IsUnicode ? 2 : 1)
NumPut(dwData, COPYDATASTRUCT, 0)
NumPut(cbData, COPYDATASTRUCT, A_PtrSize)
NumPut(&lpData, COPYDATASTRUCT, 2*A_PtrSize)
SendMessage, % WM_COPYDATA, % A_ScriptHwnd , ©DATASTRUCT,, % "ahk_id " Hwnd
return ErrorLevel == "FAIL" ? false : true
}
;==================================================
;USEFUL LINKS
;Sending Strings Via SendMessage - Ask for Help - AutoHotkey Community
;https://autohotkey.com/board/topic/98334-sending-strings-via-sendmessage/
;Media Player Classic - Homecinema MPC remote API (via WM_COPYDATA) - AutoIt Example Scripts - AutoIt Forums
;https://www.autoitscript.com/forum/topic/85354-media-player-classic-homecinema-mpc-remote-api-via-wm_copydata/
;mpcapi.h
;https://raw.githubusercontent.com/jeeb/mpc-be/master/src/apps/mplayerc/mpcapi.h
;winapi - media player classic - jump to point in video/audio programmatically - Stack Overflow
;http://stackoverflow.com/questions/41310778/media-player-classic-jump-to-point-in-video-audio-programmatically
;==================================================
USEFUL LINKS:
Sending Strings Via SendMessage - Ask for Help - AutoHotkey Community
https://autohotkey.com/board/topic/98334-sending-strings-via-sendmessage/
Media Player Classic - Homecinema MPC remote API (via WM_COPYDATA) - AutoIt Example Scripts - AutoIt Forums
https://www.autoitscript.com/forum/topic/85354-media-player-classic-homecinema-mpc-remote-api-via-wm_copydata/
mpcapi.h
https://raw.githubusercontent.com/jeeb/mpc-be/master/src/apps/mplayerc/mpcapi.h
I spent last few hours trying to figure out how to use Autohotkey shortcut to switch between specific Chrome windows.
I have two monitors. Left side monitor (nr 1) is split vertically between Chrome localhost window and Vim editor. Right side monitor (nr 2) has Chrome fullscreen with my gmail, search tabs etc.
I would like to switch between the windows with ahk shortcuts e.g. Alt+1 (localhost monitor nr 1), Alt+2 (Chrome window monitor nr 2).
It's easy to do if windows have different title. I tried with titles, text, ahk_id, ahk_class, sysget (to change focus monitor), mouse clicks(covered by other windows) etc. Nothing seems to work consistently and couldn't google any sensible answer.
Any ideas?
This code should work for you. One hotkey to activate the leftmost chrome window. The other to active the rightmost
CoordMode, Pixel, Screen
!1::
ChromeList := GetWinListByClass("Chrome_WidgetWin_1")
LeftmostPos := 9999
LeftmostId := ""
Loop, % ChromeList.MaxIndex()
{
currentId := ChromeList[A_Index][1]
currentX := ChromeList[A_Index][2]
if (currentX < LeftmostPos)
{
LeftmostPos := currentX
LeftmostId := currentId
}
}
WinActivate, % "ahk_id" LeftmostId
Return
!2::
ChromeList := GetWinListByClass("Chrome_WidgetWin_1")
RightmostPos := -9999
RightmostId := ""
Loop, % ChromeList.MaxIndex()
{
currentId := ChromeList[A_Index][1]
currentX := ChromeList[A_Index][2]
if (currentX > RightmostPos)
{
RightmostPos := currentX
RightmostId := currentId
}
}
WinActivate, % "ahk_id" RightmostId
Return
GetWinListByClass(filterClass)
{
WinGet, all, list
ChromeList := {}
winCount := 1
Loop, %all%
{
WinGetClass, WClass, % "ahk_id " all%A_Index%
if (WClass = filterClass)
{
winId := all%A_Index%
WinGetPos, X, Y, W, H, % "ahk_id " winId
ChromeList[winCount] := [winId, X]
winCount++
}
}
return ChromeList
}