commit affb086e09ba989f11407f38c6ec25a9f52af546 Author: yuriy Date: Sat Jul 1 01:00:58 2023 -0400 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e073ba7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/Backups \ No newline at end of file diff --git a/Libs/RunCMD.ahk b/Libs/RunCMD.ahk new file mode 100644 index 0000000..d4f5d7d --- /dev/null +++ b/Libs/RunCMD.ahk @@ -0,0 +1,50 @@ + ; PowerShell +; https://www.autohotkey.com/boards/viewtopic.php?p=341237#p341237 + + +RunCMD(CmdLine, WorkingDir:="", Codepage:="CP0", Fn:="RunCMD_Output") { ; RunCMD v0.94 +Local ; RunCMD v0.94 by SKAN on D34E/D37C @ autohotkey.com/boards/viewtopic.php?t=74647 +Global A_Args ; Based on StdOutToVar.ahk by Sean @ autohotkey.com/board/topic/15455-stdouttovar + + Fn := IsFunc(Fn) ? Func(Fn) : 0 +, DllCall("CreatePipe", "PtrP",hPipeR:=0, "PtrP",hPipeW:=0, "Ptr",0, "Int",0) +, DllCall("SetHandleInformation", "Ptr",hPipeW, "Int",1, "Int",1) +, DllCall("SetNamedPipeHandleState","Ptr",hPipeR, "UIntP",PIPE_NOWAIT:=1, "Ptr",0, "Ptr",0) + +, P8 := (A_PtrSize=8) +, VarSetCapacity(SI, P8 ? 104 : 68, 0) ; STARTUPINFO structure +, NumPut(P8 ? 104 : 68, SI) ; size of STARTUPINFO +, NumPut(STARTF_USESTDHANDLES:=0x100, SI, P8 ? 60 : 44,"UInt") ; dwFlags +, NumPut(hPipeW, SI, P8 ? 88 : 60) ; hStdOutput +, NumPut(hPipeW, SI, P8 ? 96 : 64) ; hStdError +, VarSetCapacity(PI, P8 ? 24 : 16) ; PROCESS_INFORMATION structure + + If not DllCall("CreateProcess", "Ptr",0, "Str",CmdLine, "Ptr",0, "Int",0, "Int",True + ,"Int",0x08000000 | DllCall("GetPriorityClass", "Ptr",-1, "UInt"), "Int",0 + ,"Ptr",WorkingDir ? &WorkingDir : 0, "Ptr",&SI, "Ptr",&PI) + Return Format("{1:}", "", ErrorLevel := -1 + ,DllCall("CloseHandle", "Ptr",hPipeW), DllCall("CloseHandle", "Ptr",hPipeR)) + + DllCall("CloseHandle", "Ptr",hPipeW) +, A_Args.RunCMD := { "PID": NumGet(PI, P8? 16 : 8, "UInt") } +, File := FileOpen(hPipeR, "h", Codepage) + +, LineNum := 1, sOutput := "" + While (A_Args.RunCMD.PID + DllCall("Sleep", "Int",0)) + and DllCall("PeekNamedPipe", "Ptr",hPipeR, "Ptr",0, "Int",0, "Ptr",0, "Ptr",0, "Ptr",0) + While A_Args.RunCMD.PID and (Line := File.ReadLine()) + sOutput .= Fn ? Fn.Call(Line, LineNum++) : Line + + A_Args.RunCMD.PID := 0 +, hProcess := NumGet(PI, 0) +, hThread := NumGet(PI, A_PtrSize) + +, DllCall("GetExitCodeProcess", "Ptr",hProcess, "PtrP",ExitCode:=0) +, DllCall("CloseHandle", "Ptr",hProcess) +, DllCall("CloseHandle", "Ptr",hThread) +, DllCall("CloseHandle", "Ptr",hPipeR) + +, ErrorLevel := ExitCode + +Return sOutput +} diff --git a/Libs/wallabag-add-article.exe b/Libs/wallabag-add-article.exe new file mode 100644 index 0000000..634e322 Binary files /dev/null and b/Libs/wallabag-add-article.exe differ diff --git a/Libs/wallabag-add-article.url b/Libs/wallabag-add-article.url new file mode 100644 index 0000000..e8866d1 --- /dev/null +++ b/Libs/wallabag-add-article.url @@ -0,0 +1,2 @@ +[InternetShortcut] +URL=https://codeberg.org/strubbl/wallabag-add-article diff --git a/README.md b/README.md new file mode 100644 index 0000000..2e6e9e3 --- /dev/null +++ b/README.md @@ -0,0 +1,110 @@ +# Open Current Browser Tab WITH + +A simple Autohotkey script that adds keyboard shortcuts for executing various actions on your active browser tab, including: + +- Open with different browser (Chrome, Firefox, Brave, etc) +- Open on different device through KDE-Connect +- Save to Pocket +- Send to a Telegram channel using a bot + - handy for saving a page for later without getting forgotten in bookmarks +- Quick copy URL to clipboard +- Open Archived version through Archive.org +- Download Video or Audio using yt-dlp + +![Preview](https://gitlab.com/yman84/open-with-browser/uploads/6be99a4dca865cefbc008136d68846c8/Preview.gif) + +## Default Keyboard Shortcuts + +##### (Can be customized by editing the .ahk file) + +- Alt + M: Send to Telegram Channel + +- Alt + P: Save Page to Pocket + +- Alt + X: Copy URL to Clipboard + +- Open Tab in Another Browser + + - Alt + F: Firefox + + - Alt + Shift + F: Firefox Private + + - Alt + C: Chrome + + - Alt + Shift + C: Chrome Incognito + + - Alt + B: Brave + + - Alt + Shift + B: Brave Incognito + +- Open Archived Version Through Archive.org + + - Alt + A: Open in same Same Tab + + - Alt + Shift + A: Open Page in New Tab + +- Open on Different Device using KDE-Connect + + - Alt + O: Open with KDE-Connect Device One + + - Alt + Shift + O: Open with KDE-Connect Device One + +- Download Video using yt-dlp + + - Alt + Y: Download Video + + - Alt + Shift + Y: Download Video's Audio + +# Installation + +1) Make sure you have [autohotkey](https://www.autohotkey.com/) installed + +2) If you have git installed: + +        `git clone https://gitlab.com/yman84/open-with-browser.git` + +      Otherwise: + +        Click Download and then select zip + +# Extended Functionality Configuration + +## Open Tab on Different Device(s) using KDE-Connect + +- Install KDE-Connect: https://kdeconnect.kde.org/download.html +- Get device IDs by running the following in Comamnd Prompt: + ``"C:\Program Files\KDE Connect\bin\kdeconnect-cli.exe" -l`` +- Set the KDEConnectDeviceOne\Two\Three in `KDE Connect Settings` section of the .ahk script to the device ID of each device you want to send to + +## Save Tab URL to Pocket + +- Obtain an Access Token and Consumer Key by following the Pocket docs: + - https://getpocket.com/developer/docs/authentication +- Input both the Token and Key into the `Pocket Settings` section of the .ahk script + +## Send Tab URL to a Telegram Channel + +- Create a Telegram Bot by following the Telegram docs + - https://core.telegram.org/bots#6-botfather +- Obtain your chatID by following the guide here + - https://stackoverflow.com/questions/32423837/telegram-bot-how-to-get-a-group-chat-id +- Input both numbers into the `Telegram Settings` section of the .ahk script + +## Download Video with [yt-dlp](https://github.com/yt-dlp/yt-dlp) + +- Install yt-dlp + + - Using Chocolatey: ``choco install yt-dlp`` + + - OR [Manually](https://github.com/yt-dlp/yt-dlp/releases/latest) + +- Update the `yt-dlp Settings` section of the .ahk script to match your video/audio quality preferences + + - By default video is 720p and audio is "BEST" + +## Add Another Browser to Open Tabs With + +- Add your browser's filepath to the `Filepaths of Browsers` section below the others +- Add your browser's ahk_exe info below the other browsers in `Trigger Within Applications` section by using Window Spy.ahk (comes installed with Autohotkey) +- Change the function call to reflect your new browser + - eg: `OpenWithBrowser(Firefox)` >> `OpenWithBrowser(YourCustomBrowser)` \ No newline at end of file diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000..bf06a5d Binary files /dev/null and b/icon.ico differ diff --git a/open-browser-tab-with.ahk b/open-browser-tab-with.ahk new file mode 100644 index 0000000..12571fb --- /dev/null +++ b/open-browser-tab-with.ahk @@ -0,0 +1,579 @@ +; ENVIRONMENT +;------------------------------------------------ +#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. +;#Warn ; Enable warnings to assist with detecting common errors. +;DetectHiddenWindows, On +#SingleInstance, Force +SendMode Input ; Recommended for new scripts due to its superior speed and reliability. +SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. +;SetKeyDelay, 500 +CoordMode, ToolTip, Screen +CoordMode, Mouse, Screen +; #NoTrayIcon + +; MyGlobalVars() ; import custom global variables +;Menu, Tray, Icon, %A_AHKSyncthingDir%\Icons\ICONNAMEHERE + +; Notes/Extra Info/#Includes +;------------------------------------------------ +#Include %A_scriptdir%\Libs\RunCMD.ahk + + +; ENVIRONMENT +;------------------------------------------------ +#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. +#SingleInstance, Force +SendMode Input ; Recommended for new scripts due to its superior speed and reliability. +SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. + +Argument = %1% + +; Icon taken from: https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/tree/master/Papirus +Menu, Tray, Icon, %A_scriptdir%/icon.ico + +;------------------------------------------------ +; SETTINGS AND VARIABLES +;------------------------------------------------ +; Filepaths of Browsers + +Brave = C:\Users\%A_Username%\AppData\Local\BraveSoftware\Brave-Browser\Application\brave.exe +BraveIncognito = %Brave% --incognito + +Chrome = C:\Program Files\Iridium\iridium.exe +ChromeIncognito = %Chrome% --incognito + +; IniRead, Chromium, C:\Program Files\Iridium\iridium.exe +; Msgbox % "Chromium: " Chromium +Chromium = C:\Program Files\Iridium\iridium.exe +ChromiumIncognito = %Chromium% --incognito + +Firefox = C:\Program Files\Mozilla Firefox\firefox.exe +FirefoxPrivate = %Firefox% -private-window + +Librewolf = C:\Program Files\LibreWolf\librewolf.exe +LibrewolfPrivate = %Librewolf% -private-window + +; https://codeberg.org/strubbl/wallabag-add-article +WallabagAddArticleExe = %A_scriptdir%\Libs\wallabag-add-article.exe + + +; Pocket Settings +PocketAccessToken= +PocketConsumerKey= + +; Telegram Settings +TelegramChatID= +TelegramBotToken= + + +; KDE Connect Settings +KDEConnectCLIExeFilepath=C:\Program Files\KDE Connect\bin\kdeconnect-cli.exe +KDEConnectDeviceOne=OP7 +KDEConnectDeviceTwo=S4 +KDEConnectDeviceThree= + +; yt-dlp Settings +AudioDownloadFolder = C:\Users\%A_UserName%\Downloads +VideoDownloadFolder = C:\Users\%A_UserName%\Downloads +VideoResolution = 720 +AudioQuality = Best ; Best OR MP3 + + +; Todo.txt filepath +todotxtFilepath = C:\Users\%A_UserName%\Syncthing\WhiteMountain\Todo\WMT-todo.txt + + +; Trigger Within These Applications Only +GroupAdd, GroupOfBrowsers, ahk_exe firefox.exe +GroupAdd, GroupOfBrowsers, ahk_exe chrome.exe +GroupAdd, GroupOfBrowsers, ahk_exe brave.exe +GroupAdd, GroupOfBrowsers, ahk_exe librewolf.exe +GroupAdd, GroupOfBrowsers, ahk_exe iridium.exe + +#IfWinActive, ahk_group GroupOfBrowsers + + +; Key Shortcuts: +;Complete List can be found at: +; https://autohotkey.com/docs/KeyList.htm#Advanced_buttons +;# : Windows +;+ : Shift +;^ : Ctrl +;! : Alt + +; Open with Browser +; Function arguments should match the variable that contains your browser filepath +!f::OpenWithBrowser(Firefox) +!+f::OpenWithBrowser(FirefoxPrivate) + +!b::OpenWithBrowser(Brave) +!+b::OpenWithBrowser(BraveIncognito) + +; !+c::OpenWithBrowser(Chromium) +!c::OpenWithBrowser(ChromiumIncognito) + +; Open with Archive.org +!a::OpenWithArchiveOrg("SameTab") +!+a::OpenWithArchiveOrg("NewTab") + +; KDE Connect +!o::OpenOnKDEConnectDevice(KDEConnectDeviceOne, KDEConnectCLIExeFilepath) +!+o::OpenOnKDEConnectDevice(KDEConnectDeviceTwo, KDEConnectCLIExeFilepath) + +; yt-dlp +!y::YouTubeDL("Video", VideoResolution, VideoDownloadFolder) +!+y::YouTubeDL("Audio", AudioQuality, AudioDownloadFolder) + +; pocket +; !p::SavePageToPocket(PocketConsumerKey, PocketAccessToken) + +; Wallabag +!p::SavePageToWallabag(WallabagAddArticleExe) + +!d::SaveToLinkDing() + +; Telegram +!m::SaveToTelegram(TelegramBotToken, TelegramChatID) + +!+m::SaveToTelegram(TelegramBotToken, TelegramChatID) + +!t::SaveToTelegram(TelegramBotToken, TelegramChatID) + + +; Clipboard +!x::CopyURLToClipboard() + + +!q::EmailWithOutlook() +#if + + +; Functions +;------------------------------------------------ +EmailWithOutlook(){ + TabURL := GetURLofActiveTab() + if(TabURL = "") + Return + + WindowTitle := GetTitleofActiveTab() + + ; If outlook is NOT currently open, start it + If !WinExist("ahk_class rctrl_renwnd32") ; + { + run, Outlook + WinWait, ahk_class rctrl_renwnd32 + sleep, 500 ; Wait for animation to catch up + } + + ; Create outlook COM connection + Ol := ComObjCreate("Outlook.Application").CreateItem(0) ;Connect to Outlook object + ; Ol.TO := "test@gmail.com" ;Send to Variable content that resides within "Email" + + Ol.Subject := WindowTitle + + Ol.HTMLBody := TabURL + Ol.Display ; Create gui window of Outlook message + ; Ol.Send() ;Sends the email + + ; CenterTooltipOnScreen("URL Emailed with Outlook", 1000) + + Return +} + + +CopyURLToClipboard(){ + TabURL := GetURLofActiveTab() + if(TabURL = "") + Return + + Clipboard := TabURL + + CenterTooltipOnScreen("Tab URL Copied to Clipboard Successfully", 1000) + ; ShowTooltip("Tab URL Copied to Clipboard Successfully", 1000) + return +} + + +AppendToDoTxt(todotxtFilepath){ + TabURL := GetURLofActiveTab() + if(TabURL = "") + Return + + WindowTitle := GetTitleofActiveTab() + + InputBox, WindowTitle, Note Title: , Please Input Note Title:,,,,,,,,%WindowTitle% + if ErrorLevel + return + + FormatTime, todaydate,,yyyy-MM-dd + FileAppend, `n%todaydate% %WindowTitle%: %TabURL% @rl,%todotxtFilepath% + + return +} + + +YouTubeDL(Type, Quality, DownloadFolder){ + ; Requires yt-dlp to be installed + ; https://github.com/yt-dlp/yt-dlp + + TabURL := GetURLofActiveTab() + if(TabURL = "") + Return + + if(Type = "Video") + Command = yt-dlp -f "bestvideo[height<=%Quality%]+bestaudio" --embed-thumbnail --add-metadata --no-mtime -o `"%DownloadFolder%\`%(title)s.`%(ext)s`" %TabURL% + if(Type = "Audio"){ + if(Quality = "Best") + command = yt-dlp -f bestaudio --extract-audio --embed-thumbnail --add-metadata --no-mtime -o `"%DownloadFolder%\`%(title)s.`%(ext)s`" %TabURL% + else, + command = yt-dlp --extract-audio --audio-format mp3 --audio-quality 5 --no-mtime -o `"%DownloadFolder%\`%(title)s.`%(ext)s`" %TabURL% + } + + run, %comspec% /C %command% + Return +} + + +OpenWithArchiveOrg(TabOption){ + TabURL := GetURLofActiveTab() + if(TabURL = "") + Return + + NewURL = https://web.archive.org/web/2/%TabURL% + + if(TabOption = "SameTab"){ + send, %NewURL% + send, {Enter} + } + + if(TabOption = "NewTab"){ + send, ^t ; new tab + sleep, 250 + send, %NewURL% + send, {Enter} + } + return +} + +SaveToTelegram(TelegramBotToken, TelegramChatID){ + TabURL := GetURLofActiveTab() + if(TabURL = "") + Return + + PostURL = https://api.telegram.org/bot%TelegramBotToken%/sendmessage?chat_id=%TelegramChatID%&text=%TabURL% + PostStatus := URLDownloadToVar(PostURL) + + SuccessString = "message_id" + if(!InStr(PostStatus, SuccessString)){ + MsgBox, Failed to Submit Post + return + } + + ; MsgBox + CenterTooltipOnScreen("Tab Posted to Telegram Successfully", 1000) + ; TrayTip, Browser Tab, Tap Posted to Telegram Successfully, 5 ;, Seconds, Options] + ; msgbox + ; ShowTooltip("Tab Posted to Telegram Successfully", 1000) + return +} + + +SaveToLinkDing(){ + ; Requires linkding extension to be installed + ; https://addons.mozilla.org/en-US/firefox/addon/linkding-extension/ + + ; TabURL := GetURLofActiveTab() + TabTitle := GetTitleofActiveTab() + Clipboard := TabTitle + + send, !+l + + return +} + + + +SavePageToWallabag(WallabagAddArticleExe){ + ; requires + ; https://codeberg.org/strubbl/wallabag-add-article + + TabURL := GetURLofActiveTab() + if(TabURL = "") + Return + + ; Msgbox % "TabURL: " TabURL + command = "%WallabagAddArticleExe%" %TabURL% + Status := RunCMD(command) + + TrayTip, Browser Tab, Tap Posted to wallabag Successfully, 5 ;, Seconds, Options] + + ; Clipboard := command + ; run, %comspec% /k "%WallabagAddArticleExe%" %TabURL% + ; msgbox + ; run, %WallabagAddArticleExe% %TabURL% + ; msgbox +} + + +SavePageToPocket(PocketConsumerKey, PocketAccessToken){ + ; https://getpocket.com/developer/docs/v3/add + TabURL := GetURLofActiveTab() + if(TabURL = "") + Return + + url_str := "https://getpocket.com/v3/add" + objParam := { "url" : TabURL + ,"consumer_key" : PocketConsumerKey + ,"access_token" : PocketAccessToken } + + Status := SubmitJsonObject(url_str, objParam) + + SuccessStatusCode = response_code":"200" + if(!InStr(Status, SuccessStatusCode)){ + MsgBox, Failed to Submit to Pocket + return + } + + CenterTooltipOnScreen("Tab Saved to Pocket Successfully", 1000) + return +} + +ShowTooltip(Text, LengthOfTime){ + ToolTip, %Text% + sleep, %LengthOfTime% + ToolTip + return +} + +OpenOnKDEConnectDevice(DeviceID, KDEConnectCLIExeFilepath){ + TabURL := GetURLofActiveTab() + if(TabURL = "") + Return + + command = "%KDEConnectCLIExeFilepath%" -n "%DeviceID%" --share "%TabURL%" + ; Clipboard := command + Status := RunCMD(command) + + if(InStr(Status, "error") OR InStr(Status, "Couldn't find device")){ + MsgBox, Failed to Send URL.`nIs Device Connected? + return + } + CenterTooltipOnScreen("Tab Sent Successfully", 1000) + + return +} + + +OpenWithBrowser(BrowserFilepath){ + TabURL := GetURLofActiveTab() + if(TabURL = "") + Return + + run, %BrowserFilepath% %TabURL% +} + + +GetURLofActiveTab(){ + ClipBackup := ClipboardAll ; Backup the clipboard contents + Clipboard := ; Empty clipboard + send, {Escape} ; send the escape key to click out of ALT menu in case user is using an ALT+Letter shortcut + + Loop, 5 { + send, ^l ; Send control + l ; Default shortcut to select URL bar in most browsers + sleep, 250 + send, ^c ; send control + c + ClipWait, .5 ; Wait for clipboard to get contents + if(ErrorLevel){ ; if error, wait .5 seconds and try sending control + c again + sleep, 500 + Continue + } + else, + break + } + send, {Escape} ; escape out of url bar activation + + TabURL := Clipboard + + Clipboard := ClipBackup ; restore clipboard contents + Return TabURL +} + +GetTitleofActiveTab(){ + WinGetTitle, WindowTitle, A + WindowTitle := StrReplace(WindowTitle, "LibreWolf", "") + ; StrReplace(Haystack, SearchText [, ReplaceText, OutputVarCount, Limit := -1]) + WindowTitle := StrReplace(WindowTitle, "Brave", "") + WindowTitle := StrReplace(WindowTitle, "Chromium", "") + WindowTitle := StrReplace(WindowTitle, "Chrome", "") + WindowTitle := StrReplace(WindowTitle, "GitHub - ", "") + TitleLen := StrLen(WindowTitle) + TitleLen := TitleLen - 3 + WindowTitle := SubStr(WindowTitle, 1, TitleLen) + ; WindowTitle := StrReplace(WindowTitle, "—", "") + ; Msgbox % "WindowTitle: " WindowTitle + + return WindowTitle +} + + + +; ------------------------------- +; CreateFormData - Creates "multipart/form-data" for http post +; Needed for Pocket Posting +; ------------------------------- +SubmitJsonObject(url_str, objParam){ + CreateFormData(postData, hdr_ContentType, objParam) + whr := ComObjCreate("WinHttp.WinHttpRequest.5.1") + whr.Open("POST", url_str, true) + whr.SetRequestHeader("Content-Type", hdr_ContentType) + ; whr.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko") ; ??????? + whr.Option(6) := False ; No auto redirect + whr.Send(postData) + whr.WaitForResponse() + json_resp := whr.ResponseText + whr := + + ; Clipboard := json_resp ; free COM object + return json_resp + + ; if(InStr(json_resp, "error_code")) + ; Return json_resp +} + +; 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 := [] + For k, v in objParam + { + If IsObject(v) { + For i, FileName in v + { + str := BoundaryLine . CRLF + . "Content-Disposition: form-data; name=""" . k . """; filename=""" . FileName . """" . CRLF + . "Content-Type: " . this.MimeType(FileName) . CRLF . CRLF + binArrs.Push( BinArr_FromString(str) ) + binArrs.Push( BinArr_FromFile(FileName) ) + binArrs.Push( BinArr_FromString(CRLF) ) + } + } + Else { + str := BoundaryLine . CRLF + . "Content-Disposition: form-data; name=""" . k """" . CRLF . CRLF + . v . CRLF + binArrs.Push( BinArr_FromString(str) ) + } + } + + 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" + } + +} +;############################################################################################################# +; Update: 2015-6-4 - Added BinArr_ToFile() + +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 +} +; -------------------------------/CreateFormData - Creates "multipart/form-data" for http post-------------------------------