Merge branch 'dev'

This commit is contained in:
知一一 2025-04-27 14:51:09 +08:00
commit 0d21d4c2b8
10 changed files with 2286 additions and 325 deletions

3
.gitignore vendored
View File

@ -1,3 +1,2 @@
*.exe
*.ini
lib/
*.ini

File diff suppressed because it is too large Load Diff

View File

@ -1,100 +1,111 @@
# 免责声明
本项目仅供个人学习研究使用,严禁用于商业用途。除 Github 以外其他任何网站、社交平台中有关本项目的内容**均非本人发布**,若造成侵犯著作权、版权或违反网络安全法规等任何后果,均与本人无关。
# 前言
PC端自用日常任务清理助手DoroHelper
PC 端自用日常任务清理助手DoroHelper。支持国际服和港澳台服客户端。支持多开。
![image](https://github.com/kyokakawaii/DoroHelper/blob/main/preview.png)
### 叠甲:
使用任何脚本程序均有封号风险,请谨慎。
### 再叠甲:
程序是根据我自己的账号进度写的所以可能会有操作不兼容的情况出现纯草台班子代码。第一次使用最好在旁边看着。万一Doro失控请按Ctrl + 1组合键结束进程。
程序是根据我自己的账号进度写的,所以可能会有操作不兼容的情况出现。第一次使用最好在旁边看着。万一 Doro 失控,请按 Ctrl + 1 组合键结束进程或者 Ctrl + 2 组合键暂停进程debug
# 下载
在右边的release里有我编译好的exe文件可以直接用。
在右边的 release 里有我编译好的 exe 文件可以直接用。
不放心的话也可以下载代码安装AutoHotkey V2.0并以管理员模式运行`DoroHelper.ahk`。也可以用任意文本编辑器打开`DoroHelper.ahk`修改(史山)代码以适配自己的情况。
也可以使用Ahk2Exe编译`DoroHelper.ahk`自己生成exe可执行文件。
不放心的话也可以下载代码,安装 AutoHotkey V2.0 并以管理员模式运行`DoroHelper.ahk`。也可以用任意文本编辑器打开`DoroHelper.ahk`修改(史山)代码以适配自己的情况。
也可以使用 Ahk2Exe 编译`DoroHelper.ahk`自己生成 exe 可执行文件。
# 功能介绍
Doro只是想让你少被该死的读条、闪光弹和重复劳动折磨。一键清理多项日常事务包括
Doro 只是想让你少被该死的读条、闪光弹和重复劳动折磨。一键清理多项日常事务(按顺序执行),包括:
- **前哨基地防御**
_1次一举歼灭+2次收菜_
_1 次一举歼灭+2 次收菜_
- **付费商店**
_领取每日、周、月免费钻_
- **免费商店**
_普通商店每天白嫖2次竞技场购买自定义数量的属性技能书购买公司武器熔炉_
_普通商店每天白嫖 2 竞技场购买自定义数量的属性技能书购买公司武器熔炉_
- **派遣远征和收菜**
- **收取赠送好友点数**
- **模拟室5C通关**
- **模拟室 5C 通关**
- **新人竞技场进行自定义数量的战斗**
_顺带收取pjjc囤积超过50%的菜_
_顺带收取 pjjc 囤积超过 50%的菜_
- **进行自定义次数的好感度咨询**
- **光速爬塔失败1次**
_支持补充咨询图鉴_
- **光速爬塔失败 1 次**
_蹭每日任务点数_
完成以上全部事务后每日任务点数为90。此时Doro会自动进入异常拦截战斗页面并停留方便指挥官直接开打。打完以后每日任务点数即来到100。
- **爬企业塔**
- **自动异常拦截**
- **邮箱收取**
- **每日奖励收取**
- **Pass 收取**
# 使用说明
对大多数老玩家来说Doro设置保持默认就好。
对大多数老玩家来说 Doro 设置保持默认就好。
万一Doro失控请按Ctrl + 1组合键结束进程。
万一 Doro 失控,请按 Ctrl + 1 组合键结束进程。
万一Doro失控请按Ctrl + 1组合键结束进程。
万一 Doro 失控,请按 Ctrl + 1 组合键结束进程。
万一Doro失控请按Ctrl + 1组合键结束进程。
万一 Doro 失控,请按 Ctrl + 1 组合键结束进程。
## 要求:
- 【设定-画质-全屏幕模式 + 16:9的显示器比例】 或 【16:9的窗口模式窗口别拉太小否则像素识别可能出现误差
- 【设定-画质-全屏幕模式 + 16:9 的显示器比例】(推荐) 或 【16:9 的窗口模式】(窗口尽量拉大,否则像素识别可能出现误差)
- 设定-画质-开启光晕效果
- 设定-画质-开启颜色分级
- 游戏语言设置为简体中文
- 以**管理员身份**运行DoroHelper
- 以**管理员身份**运行 DoroHelper
- 不要开启 windows HDR 显示
## 步骤:
打开NIKKE启动器。点击启动。等右下角腾讯ACE反作弊系统扫完NIKKE主程序中央SHIFT UP logo出现之后再切出来点击“DORO!”按钮。如果你看到鼠标开始在左下角连点,那就代表启动成功了。不行的话手动点击一下NIKKE让它成为活跃窗口。然后就可以悠闲地去泡一杯咖啡或者刷一会儿手机等待Doro完成工作了。
打开 NIKKE 启动器。点击启动。等右下角腾讯 ACE 反作弊系统扫完NIKKE 主程序中央 SHIFT UP logo 出现之后再切出来点击“DORO!”按钮。如果你看到鼠标开始在左下角连点,那就代表启动成功了。然后就可以悠闲地去泡一杯咖啡,或者刷一会儿手机,等待 Doro 完成工作了。
也可以在游戏处在大厅界面时有看板娘的页面切出来点击“DORO!”按钮启动程序。
游戏需要更新的时候请更新完再使用Doro。
游戏需要更新的时候请更新完再使用 Doro。
## 其他:
不要开其他名叫"NIKKE"的文件夹或者窗口。否则Doro会抓错窗口。因为NIKKE启动器也他妈的叫NIKKE所以有极小概率会抓错成启动器。点一下NIKKE主程序然后Ctrl+1重启Doro即可。
如果出现死循环,提高点击间隔可以解决 80%的问题。
如果出现死循环提高点击间隔可以解决80%的问题
如果你的电脑配置较好的话,可以尝试降低点击间隔
如果你的电脑配置较好的话,或许可以尝试降低点击间隔。
可以尝试设置得和我一样:
![image](https://github.com/kyokakawaii/DoroHelper/blob/67486160e97713900c43cc2c68e176dd65e1f442/img/setting1.png)
![image](https://github.com/kyokakawaii/DoroHelper/blob/67486160e97713900c43cc2c68e176dd65e1f442/img/setting2.png)
# 借物表
<https://github.com/samfisherirl/Github.ahk-API-for-AHKv2>
<https://github.com/samfisherirl/Github.ahk-API-for-AHKv2>

BIN
img/preview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
img/setting1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
img/setting2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

235
lib/_JSONS.ahk Normal file
View File

@ -0,0 +1,235 @@
;;;; AHK v2 - https://github.com/TheArkive/JXON_ahk2
;MIT License
;Copyright (c) 2021 TheArkive
;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
;
; Example ===================================================================================
; ===========================================================================================
; Msgbox "The idea here is to create several nested arrays, save to text with jxon_dump(), and then reload the array with jxon_load(). The resulting array should be the same.`r`n`r`nThis is what this example shows."
; a := Map(), b := Map(), c := Map(), d := Map(), e := Map(), f := Map() ; Object() is more technically correct than {} but both will work.
; d["g"] := 1, d["h"] := 2, d["i"] := ["purple","pink","pippy red"]
; e["g"] := 1, e["h"] := 2, e["i"] := Map("1","test1","2","test2","3","test3")
; f["g"] := 1, f["h"] := 2, f["i"] := [1,2,Map("a",1.0009,"b",2.0003,"c",3.0001)]
; a["test1"] := "test11", a["d"] := d
; b["test3"] := "test33", b["e"] := e
; c["test5"] := "test55", c["f"] := f
; myObj := Map()
; myObj["a"] := a, myObj["b"] := b, myObj["c"] := c, myObj["test7"] := "test77", myObj["test8"] := "test88"
; g := ["blue","green","red"], myObj["h"] := g ; add linear array for testing
; q := Chr(34)
; textData2 := Jxon_dump(myObj,4) ; ===> convert array to JSON
; msgbox "JSON output text:`r`n===========================================`r`n(Should match second output.)`r`n`r`n" textData2
; newObj := Jxon_load(&textData2) ; ===> convert json back to array
; textData3 := Jxon_dump(newObj,4) ; ===> break down array into 2D layout again, should be identical
; msgbox "Second output text:`r`n===========================================`r`n(should be identical to first output)`r`n`r`n" textData3
; msgbox "textData2 = textData3: " ((textData2=textData3) ? "true" : "false")
; ===========================================================================================
; End Example ; =============================================================================
; ===========================================================================================
; originally posted by user coco on AutoHotkey.com
; https://github.com/cocobelgica/AutoHotkey-JSON
class Json
{
static Load(&src, args*) {
key := "", is_key := false
stack := [tree := []]
next := '"{[01234567890-tfn'
pos := 0
while ((ch := SubStr(src, ++pos, 1)) != "") {
if InStr(" `t`n`r", ch)
continue
if !InStr(next, ch, true) {
testArr := StrSplit(SubStr(src, 1, pos), "`n")
ln := testArr.Length
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 == '"') ? "Expecting object key enclosed in double quotes"
: (next == '"}') ? "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 Error(msg, -1, ch)
}
obj := stack[1]
is_array := (obj is Array)
if i := InStr("{[", ch) { ; start new object / map?
val := (i = 1) ? Map() : Array() ; ahk v2
is_array ? obj.Push(val) : obj[key] := val
stack.InsertAt(1, val)
next := '"' ((is_key := (ch == "{")) ? "}" : "{[]0123456789-tfn")
} else if InStr("}]", ch) {
stack.RemoveAt(1)
next := (stack[1] == tree) ? "" : (stack[1] is Array) ? ",]" : ",}"
} else if InStr(",:", ch) {
is_key := (!is_array && ch == ",")
next := is_key ? '"' : '"{[0123456789-tfn'
} else { ; string | number | true | false | null
if (ch == '"') { ; string
i := pos
while i := InStr(src, '"', , i + 1) {
val := StrReplace(SubStr(src, pos + 1, i - pos - 1), "\\", "\u005C")
if (SubStr(val, -1) != "\")
break
}
if !i ? (pos--, next := "'") : 0
continue
pos := i ; update pos
val := StrReplace(val, "\/", "/")
val := StrReplace(val, '\"', '"')
, 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
xxxx := Abs("0x" . SubStr(val, i + 2, 4)) ; \uXXXX - JSON unicode escape sequence
if (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)
if IsInteger(val)
val += 0
else if IsFloat(val)
val += 0
else if (val == "true" || val == "false")
val := (val == "true")
else if (val == "null")
val := ""
else if is_key {
pos--, next := "#"
continue
}
pos += i - 1
}
is_array ? obj.Push(val) : obj[key] := val
next := obj == tree ? "" : is_array ? ",]" : ",}"
}
}
return tree[1]
}
static Dump(obj, indent := "", lvl := 1) {
if IsObject(obj) {
;if !obj.__Class = "Map" {
; convertedObject := Map()
; for k, v in obj.OwnProps() {
; convertedObject.Set(k, v)
; }
; obj := convertedObject
;}
;If !(obj is Array || obj is Map || obj is String || obj is Number)
; throw Error("Object type not supported.", -1, Format("<Object at 0x{:p}>", ObjPtr(obj)))
if IsInteger(indent)
{
if (indent < 0)
throw Error("Indent parameter must be a postive integer.", -1, indent)
spaces := indent, indent := ""
Loop spaces ; ===> changed
indent .= " "
}
indt := ""
Loop indent ? lvl : 0
indt .= indent
is_array := (obj is Array)
lvl += 1, out := "" ; Make #Warn happy
if (obj is Map || obj is Array) {
for k, v in obj {
if IsObject(k) || (k == "")
throw Error("Invalid object key.", -1, k ? Format("<Object at 0x{:p}>", ObjPtr(obj)) : "<blank>")
if !is_array ;// key ; ObjGetCapacity([k], 1)
out .= (ObjGetCapacity([k]) ? json.Dump(k) : escape_str(k)) (indent ? ": " : ":") ; token + padding
out .= json.Dump(v, indent, lvl) ; value
. (indent ? ",`n" . indt : ",") ; token + indent
}
} else if IsObject(obj)
for k, v in obj.OwnProps() {
if IsObject(k) || (k == "")
throw Error("Invalid object key.", -1, k ? Format("<Object at 0x{:p}>", ObjPtr(obj)) : "<blank>")
out .= (ObjGetCapacity([k]) ? json.Dump(k) : escape_str(k)) (indent ? ": " : ":") ; token + padding
out .= json.Dump(v, indent, lvl) ; value
. (indent ? ",`n" . indt : ",") ; token + indent
}
;Error("Object type not supported.", -1, Format("<Object at 0x{:p}>", ObjPtr(obj)))
if (out != "") {
out := Trim(out, ",`n" . indent)
if (indent != "")
out := "`n" . indt . out . "`n" . SubStr(indt, StrLen(indent) + 1)
}
return is_array ? "[" . out . "]" : "{" . out . "}"
} Else If (obj is Number)
return obj
Else ; String
return escape_str(obj)
escape_str(obj) {
obj := StrReplace(obj, "\", "\\")
, obj := StrReplace(obj, "`t", "\t")
, obj := StrReplace(obj, "`r", "\r")
, obj := StrReplace(obj, "`n", "\n")
, obj := StrReplace(obj, "`b", "\b")
, obj := StrReplace(obj, "`f", "\f")
, obj := StrReplace(obj, "/", "\/")
, obj := StrReplace(obj, '"', '\"')
return '"' obj '"'
}
}
static Loads(params*) => Json.Load(params*)
static Dumps(params*) => Json.Dump(params*)
}

278
lib/github.ahk Normal file
View File

@ -0,0 +1,278 @@
;credit: https://github.com/TheArkive/JXON_ahk2
;credit: https://github.com/thqby/ahk2_lib
#Include _JSONS.ahk
#Include requests.ahk
/**
* @filesource https://github.com/samfisherirl/Github.ahk-API-for-AHKv2
*/
/**
* Fetches the latest release information from a GitHub repository.
* @function
* @name Github.latest
* @param {string} Username - The username of the repository owner.
* @param {string} Repository_Name - The name of the repository.
* @returns {Object} An object containing the download URLs, version, change notes, and date of the latest release.
*/
/**
* Fetches the historic release information from a GitHub repository.
* @function
* @name Github.historicReleases
* @param {string} Username - The username of the repository owner.
* @param {string} Repository_Name - The name of the repository.
* @returns {Array.<Object>} An array of objects, each containing the download URL, version, change notes, and date of a historic release.
*/
/**
* Downloads a file from a given URL to a specified path.
* @function
* @name Github.Download
* @param {string} url - The URL of the file to download.
* @param {string} path - The path where the file should be saved.
* @description This function improves on the basic download function by applying the proper extension if the user provides a wrong one, and allowing the user to provide a directory.
* @example
* // Providing A_ScriptDir to Download will throw error
* // Providing A_ScriptDir to Github.Download() will supply Download() with release name
*/
class Github
{
static source_zip := ""
static url := false
static usernamePlusRepo := false
static storage := {
repo: "",
source_zip: ""
}
static data := false
static build(Username, Repository_Name) {
Github.usernamePlusRepo := Trim(Username) "/" Trim(Repository_Name)
Github.source_zip := "https://github.com/" Github.usernamePlusRepo "/archive/refs/heads/main.zip"
return "https://api.github.com/repos/" Github.usernamePlusRepo "/releases"
;filedelete, "1.json"
;this.Filetype := data["assets"][1]["browser_download_url"]
}
/*
return {
downloadURLs: [
"http://github.com/release.zip",
"http://github.com/release.rar"
],
version: "",
change_notes: "",
date: "",
}
*/
static latest(Username := "", Repository_Name := "") {
if (Username != "") & (Repository_Name != "") {
url := Github.build(Username, Repository_Name)
data := Github.processRepo(url)
return Github.latestProp(data)
}
}
/*
static processRepo(url) {
Github.source_zip := "https://github.com/" Github.usernamePlusRepo "/archive/refs/heads/main.zip"
Github.data := Github.jsonDownload(url)
data := Github.data
return json.Load(&data)
}
*/
static processRepo(url) {
Github.source_zip := "https://github.com/" Github.usernamePlusRepo "/archive/refs/heads/main.zip"
data := Github.jsonDownload(url)
return Json.Load(&data)
}
/*
@example
repoArray := Github.historicReleases()
repoArray[1].downloadURL => string | link
repoArray[1].version => string | version data
repoArray[1].change_notes => string | change notes
repoArray[1].date => string | date of release
@returns (array of release objects) => [{
downloadURL: "",
version: "",
change_notes: "",
date: ""
}]
*/
static historicReleases(Username, Repository_Name) {
url := Github.build(Username, Repository_Name)
data := Github.processRepo(url)
repo_storage := []
url := "https://api.github.com/repos/" Github.usernamePlusRepo "/releases"
data := Github.jsonDownload(url)
data := json.Load(&data)
for release in data {
for asset in release["assets"] {
repo_storage.Push(Github.repoDistribution(release, asset))
}
}
return repo_storage
}
static latestProp(data) {
for i in data {
baseData := i
assetMap := i["assets"]
date := i["created_at"]
if i["assets"].Length > 0 {
length := i["assets"].Length
releaseArray := Github.distributeReleaseArray(length, assetMap)
break
}
else {
releaseArray := ["https://github.com/" Github.usernamePlusRepo "/archive/" i["tag_name"] ".zip"]
;source url = f"https://github.com/{repo_owner}/{repo_name}/archive/{release_tag}.zip"
break
}
}
;move release array to first if
;then add source
return {
downloadURLs: releaseArray,
version: baseData["tag_name"],
change_notes: baseData["body"],
date: date
}
}
/*
loop releaseURLCount {
assetArray.Push(JsonData[A_Index]["browser_download_url"])
}
return => assetArray[]
*/
/*
loop releaseURLCount {
assetMap.Set(jsonData[A_Index]["name"], jsonData[A_Index]["browser_download_url"])
}
return => assetMap()
*/
static jsonDownload(URL) {
Http := WinHttpRequest()
Http.Open("GET", URL)
Http.Send()
Http.WaitForResponse()
storage := Http.ResponseText
return storage ;Set the "text" variable to the response
}
static distributeReleaseArray(releaseURLCount, Jdata) {
assetArray := []
if releaseURLCount {
if (releaseURLCount > 1) {
loop releaseURLCount {
assetArray.Push(Jdata[A_Index]["browser_download_url"])
}
}
else {
assetArray.Push(Jdata[1]["browser_download_url"])
}
return assetArray
}
}
/*
download the latest main.zip source zip
*/
static Source(Username, Repository_Name, Pathlocal := A_ScriptDir) {
url := Github.build(Username, Repository_Name)
data := Github.processRepo(url)
Github.Download(URL := Github.source_zip, PathLocal)
}
/*
benefit over download() => handles users path, and applies appropriate extension.
IE: If user provides (Path:=A_ScriptDir "\download.zip") but extension is .7z, extension is modified for the user.
If user provides directory, name for file is applied from the path (download() will not).
Download (
@param URL to download
@param Path where to save locally
)
*/
static Download(URL, PathLocal := A_ScriptDir) {
releaseExtension := Github.downloadExtensionSplit(URL)
pathWithExtension := Github.handleUserPath(PathLocal, releaseExtension)
try {
Download(URL, pathWithExtension)
} catch as e {
MsgBox(e.Message . "`nURL:`n" URL)
}
}
static emptyRepoMap() {
repo := {
downloadURL: "",
version: "",
change_notes: "",
date: "",
name: ""
}
return repo
}
static repoDistribution(release, asset) {
return {
downloadURL: asset["browser_download_url"],
version: release["tag_name"],
change_notes: release["body"],
date: asset["created_at"],
name: asset["name"]
}
}
static downloadExtensionSplit(DL) {
Arrays := StrSplit(DL, ".")
filetype := Trim(Arrays[Arrays.Length])
return filetype
}
static handleUserPath(PathLocal, releaseExtension) {
if InStr(PathLocal, "\") {
pathParts := StrSplit(PathLocal, "\")
FileName := pathParts[pathParts.Length]
}
else {
FileName := PathLocal
PathLocal := A_ScriptDir "\" FileName
pathParts := StrSplit(PathLocal, "\")
}
if InStr(FileName, ".") {
FileNameParts := StrSplit(FileName, ".")
UserExtension := FileNameParts[FileNameParts.Length]
if (releaseExtension != userExtension) {
newName := ""
for key, val in FileNameParts {
if (A_Index == FileNameParts.Length) {
break
}
newName .= val
}
newPath := ""
for key, val in pathParts {
if (A_Index == pathParts.Length) {
break
}
newPath .= val
}
pathWithExtension := newPath newName "." releaseExtension
}
else {
pathWithExtension := PathLocal
}
}
else {
pathWithExtension := PathLocal "." releaseExtension
}
return pathWithExtension
}
}
;;;; AHK v2 - https://github.com/TheArkive/JXON_ahk2
;MIT License
;Copyright (c) 2021 TheArkive
;Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
;The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
;THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
;
; originally posted by user coco on AutoHotkey.com
; https://github.com/cocobelgica/AutoHotkey-JSON
; https://github.com/cocobelgica/AutoHotkey-JSON

132
lib/requests.ahk Normal file
View File

@ -0,0 +1,132 @@
class WinHttpRequest {
static AutoLogonPolicy := { Always: 0, OnlyIfBypassProxy: 1, Never: 2 }
static Option := { UserAgentString: 0, URL: 1, URLCodePage: 2, EscapePercentInURL: 3, SslErrorIgnoreFlags: 4, SelectCertificate: 5, EnableRedirects: 6, UrlEscapeDisable: 7, UrlEscapeDisableQuery: 8, SecureProtocols: 9, EnableTracing: 10, RevertImpersonationOverSsl: 11, EnableHttpsToHttpRedirects: 12, EnablePassportAuthentication: 13, MaxAutomaticRedirects: 14, MaxResponseHeaderSize: 15, MaxResponseDrainSize: 16, EnableHttp1_1: 17, EnableCertificateRevocationCheck: 18, RejectUserpwd: 19
}
static PROXYSETTING := { PRECONFIG: 0, DIRECT: 1, PROXY: 2
}
static SETCREDENTIALSFLAG := { SERVER: 0, PROXY: 1
}
static SecureProtocol := { SSL2: 0x08, SSL3: 0x20, TLS1: 0x80, TLS1_1: 0x200, TLS1_2: 0x800, All: 0xA8
}
static SslErrorFlag := { UnknownCA: 0x0100, CertWrongUsage: 0x0200, CertCNInvalid: 0x1000, CertDateInvalid: 0x2000, Ignore_All: 0x3300
}
__New(UserAgent := unset) {
this.whr := whr := ComObject('WinHttp.WinHttpRequest.5.1')
whr.Option[0] := IsSet(UserAgent) ? UserAgent : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36 Edg/89.0.774.68'
this.IEvents := WinHttpRequest.RequestEvents.Call(ComObjValue(whr), this.id := ObjPtr(this))
}
__Delete() => (this.whr := this.IEvents := this.OnError := this.OnResponseDataAvailable := this.OnResponseFinished := this.OnResponseStart := 0)
request(url, method := 'GET', data := '', headers := '') {
this.Open(method, url)
for k, v in (headers || {}).OwnProps()
this.SetRequestHeader(k, v)
this.Send(data)
return this.ResponseText
}
;#region IWinHttpRequest
SetProxy(ProxySetting, ProxyServer, BypassList) => this.whr.SetProxy(ProxySetting, ProxyServer, BypassList)
SetCredentials(UserName, Password, Flags) => this.whr.SetCredentials(UserName, Password, Flags)
SetRequestHeader(Header, Value) => this.whr.SetRequestHeader(Header, Value)
GetResponseHeader(Header) => this.whr.GetResponseHeader(Header)
GetAllResponseHeaders() => this.whr.GetAllResponseHeaders()
Send(Body := '') => this.whr.Send(Body)
Open(verb, url, async := false) {
this.readyState := 0
this.whr.Open(verb, url, this.async := !!async)
this.readyState := 1
}
WaitForResponse(Timeout := -1) => this.whr.WaitForResponse(Timeout)
Abort() => this.whr.Abort()
SetTimeouts(ResolveTimeout := 0, ConnectTimeout := 60000, SendTimeout := 30000, ReceiveTimeout := 30000) => this.whr.SetTimeouts(ResolveTimeout, ConnectTimeout, SendTimeout, ReceiveTimeout)
SetClientCertificate(ClientCertificate) => this.whr.SetClientCertificate(ClientCertificate)
SetAutoLogonPolicy(AutoLogonPolicy) => this.whr.SetAutoLogonPolicy(AutoLogonPolicy)
whr := 0, readyState := 0, IEvents := 0, id := 0, async := 0
OnResponseStart := 0, OnResponseFinished := 0
OnResponseDataAvailable := 0, OnError := 0
Status => this.whr.Status
StatusText => this.whr.StatusText
ResponseText => this.whr.ResponseText
ResponseBody {
get {
pSafeArray := ComObjValue(t := this.whr.ResponseBody)
pvData := NumGet(pSafeArray + 8 + A_PtrSize, 'ptr')
cbElements := NumGet(pSafeArray + 8 + A_PtrSize * 2, 'uint')
return ClipboardAll(pvData, cbElements)
}
}
ResponseStream => this.whr.responseStream
Option[Opt] {
get => this.whr.Option[Opt]
set => (this.whr.Option[Opt] := Value)
}
Headers {
get {
m := Map(), m.Default := ''
loop parse this.GetAllResponseHeaders(), '`r`n'
if (p := InStr(A_LoopField, ':'))
m[SubStr(A_LoopField, 1, p - 1)] .= LTrim(SubStr(A_LoopField, p + 1))
return m
}
}
;#endregion
;#region IWinHttpRequestEvents
class RequestEvents {
dwCookie := 0, pCPC := 0, UnkSink := 0
__New(pwhr, pparent) {
IConnectionPointContainer := ComObjQuery(pwhr, IID_IConnectionPointContainer := '{B196B284-BAB4-101A-B69C-00AA00341D07}')
DllCall("ole32\CLSIDFromString", "Str", IID_IWinHttpRequestEvents := '{F97F4E15-B787-4212-80D1-D380CBBF982E}', "Ptr", pCLSID := Buffer(16))
ComCall(4, IConnectionPointContainer, 'ptr', pCLSID, 'ptr*', &pCPC := 0) ; IConnectionPointContainer->FindConnectionPoint
IWinHttpRequestEvents := Buffer(11 * A_PtrSize), offset := IWinHttpRequestEvents.Ptr + 4 * A_PtrSize
NumPut('ptr', offset, 'ptr', pwhr, 'ptr', pCPC, IWinHttpRequestEvents)
for nParam in StrSplit('3113213')
offset := NumPut('ptr', CallbackCreate(EventHandler.Bind(A_Index), , Integer(nParam)), offset)
ComCall(5, pCPC, 'ptr', IWinHttpRequestEvents, 'uint*', &dwCookie := 0) ; IConnectionPoint->Advise
NumPut('ptr', dwCookie, IWinHttpRequestEvents, 3 * A_PtrSize)
this.dwCookie := dwCookie, this.pCPC := pCPC, this.UnkSink := IWinHttpRequestEvents
this.pwhr := pwhr
EventHandler(index, pEvent, arg1 := 0, arg2 := 0) {
req := ObjFromPtrAddRef(pparent)
if (!req.async && index > 3 && index < 7) {
req.readyState := index - 2
return 0
}
; critical('On')
switch index {
case 1: ; QueryInterface
NumPut('ptr', pEvent, arg2)
case 2, 3: ; AddRef, Release
case 4: ; OnResponseStart
req.readyState := 2
if (req.OnResponseStart)
req.OnResponseStart(arg1, StrGet(arg2, 'utf-16'))
case 5: ; OnResponseDataAvailable
req.readyState := 3
if (req.OnResponseDataAvailable) {
pSafeArray := NumGet(arg1, 'ptr')
pvData := NumGet(pSafeArray + 8 + A_PtrSize, 'ptr')
cbElements := NumGet(pSafeArray + 8 + A_PtrSize * 2, 'uint')
req.OnResponseDataAvailable(pvData, cbElements)
}
case 6: ; OnResponseFinished
req.readyState := 4
if (req.OnResponseFinished)
req.OnResponseFinished()
case 7: ; OnError
if (req.OnError)
req.OnError(arg1, StrGet(arg2, 'utf-16'))
}
}
}
__Delete() {
try ComCall(6, this.pCPC, 'uint', this.dwCookie)
loop 7
CallbackFree(NumGet(this.UnkSink, (A_Index + 3) * A_PtrSize, 'ptr'))
ObjRelease(this.pCPC), this.UnkSink := 0
}
}
;#endregion
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB