@bettergi/utils 0.1.20 → 0.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -8
- package/dist/game.js +3 -3
- package/dist/http.d.ts +6 -6
- package/dist/http.js +10 -6
- package/dist/ocr.d.ts +10 -5
- package/dist/ocr.js +35 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -126,22 +126,32 @@ await assertRegionDisappearing(findButton, "点击购买按钮超时", () => fin
|
|
|
126
126
|
> 对常见鼠标操作的封装,如鼠标的平滑移动、鼠标滚轮滚动、鼠标拖拽等。
|
|
127
127
|
|
|
128
128
|
```ts
|
|
129
|
-
//
|
|
130
|
-
await
|
|
129
|
+
// 鼠标沿路径点移动并拖拽
|
|
130
|
+
await mouseMoveAlongWaypoints(
|
|
131
|
+
[
|
|
132
|
+
{ x: 100, y: 100 },
|
|
133
|
+
{ x: 200, y: 200 },
|
|
134
|
+
{ x: 300, y: 300 }
|
|
135
|
+
],
|
|
136
|
+
{ shouldDrag: true }
|
|
137
|
+
);
|
|
131
138
|
|
|
132
139
|
// 鼠标从 (745, 610) 拖拽到 (1280, 610)
|
|
133
140
|
await mouseDrag(745, 610, 1280, 610);
|
|
134
141
|
|
|
142
|
+
// 鼠标从 (745, 610) 平滑自然地移动 (1920, 1080)
|
|
143
|
+
await naturalMouseMove(745, 610, 1920, 1080);
|
|
144
|
+
|
|
135
145
|
// 鼠标滚轮向上滚动 175 像素
|
|
136
146
|
await mouseScrollUp(175);
|
|
137
147
|
|
|
138
148
|
// 鼠标滚轮向下滚动 175 像素
|
|
139
149
|
await mouseScrollDown(175);
|
|
140
150
|
|
|
141
|
-
// 鼠标滚轮向上滚动 99
|
|
151
|
+
// 鼠标滚轮向上滚动 99 行(默认: 175为背包物品行高)
|
|
142
152
|
await mouseScrollUpLines(99);
|
|
143
153
|
|
|
144
|
-
// 鼠标滚轮向下滚动 1
|
|
154
|
+
// 鼠标滚轮向下滚动 1 行(自定义: 115为商店物品行高)
|
|
145
155
|
await mouseScrollDownLines(1, 115);
|
|
146
156
|
```
|
|
147
157
|
|
|
@@ -201,12 +211,14 @@ tracker.complete(`任务完成`);
|
|
|
201
211
|
|
|
202
212
|
```ts
|
|
203
213
|
// 发送 GET 请求获取响应体内容
|
|
204
|
-
const body1 = await getForBody("https://
|
|
205
|
-
log.info(`GET 请求响应体内容${body1}`);
|
|
214
|
+
const body1 = await getForBody("https://jsonplaceholder.typicode.com/todos/1");
|
|
206
215
|
|
|
207
216
|
// 发送 POST 请求获取响应体内容
|
|
208
|
-
const body2 = await postForBody("https://
|
|
209
|
-
|
|
217
|
+
const body2 = await postForBody("https://jsonplaceholder.typicode.com/posts", {
|
|
218
|
+
title: "foo",
|
|
219
|
+
body: "bar",
|
|
220
|
+
userId: 1
|
|
221
|
+
});
|
|
210
222
|
```
|
|
211
223
|
|
|
212
224
|
### 文件操作
|
package/dist/game.js
CHANGED
|
@@ -71,14 +71,14 @@ export const openMenuPage = async (name, listView) => {
|
|
|
71
71
|
// 1.打开派蒙菜单
|
|
72
72
|
await openPaimonMenu();
|
|
73
73
|
// 2.搜索菜单页面按钮
|
|
74
|
+
const { x = 95, y = 330, w = 670, h = 730, lineHeight = 142 } = listView || {};
|
|
74
75
|
const button = await withGameMetrics(1920, 1080, 1.5, async () => {
|
|
75
|
-
|
|
76
|
-
return await findTextWithinListView(name, { x, y, w, h, lineHeight, scrollLines: 2 });
|
|
76
|
+
return await findTextWithinListView(name, { x, y, w, h, lineHeight, scrollLines: 5 });
|
|
77
77
|
});
|
|
78
78
|
if (!button)
|
|
79
79
|
throw new Error(`搜索菜单页面 ${name} 失败`);
|
|
80
80
|
// 3.点击打开菜单页面
|
|
81
|
-
await assertRegionDisappearing(() => findTextWithinBounds(name,
|
|
81
|
+
await assertRegionDisappearing(() => findTextWithinBounds(name, x, y, w, h), `打开菜单页面 ${name} 超时`, () => {
|
|
82
82
|
button.click();
|
|
83
83
|
});
|
|
84
84
|
};
|
package/dist/http.d.ts
CHANGED
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
* 发送 HTTP 请求,获取响应体内容
|
|
3
3
|
* @param method 请求方法
|
|
4
4
|
* @param url 请求 URL
|
|
5
|
-
* @param body
|
|
5
|
+
* @param body 请求体(UTF-8 编码)
|
|
6
6
|
* @param headers 请求头
|
|
7
7
|
* @returns 响应体内容
|
|
8
8
|
*/
|
|
9
|
-
export declare const requestForBody: (method: Parameters<typeof http.request>[0], url: string, body?: string, headers?: Record<string, any>) => Promise<string>;
|
|
9
|
+
export declare const requestForBody: (method: Parameters<typeof http.request>[0], url: string, body?: string | object, headers?: Record<string, any>) => Promise<string>;
|
|
10
10
|
/**
|
|
11
11
|
* 发送 HTTP GET 请求,获取响应体内容
|
|
12
12
|
* @param url 请求 URL
|
|
13
|
-
* @param body
|
|
13
|
+
* @param body 请求体(UTF-8 编码)
|
|
14
14
|
* @param headers 请求头
|
|
15
15
|
* @returns 响应体内容
|
|
16
16
|
*/
|
|
17
|
-
export declare const getForBody: (url: string, body?: string, headers?: Record<string, any>) => Promise<string>;
|
|
17
|
+
export declare const getForBody: (url: string, body?: string | object, headers?: Record<string, any>) => Promise<string>;
|
|
18
18
|
/**
|
|
19
19
|
* 发送 HTTP POST 请求,获取响应体内容
|
|
20
20
|
* @param url 请求 URL
|
|
21
|
-
* @param body
|
|
21
|
+
* @param body 请求体(UTF-8 编码)
|
|
22
22
|
* @param headers 请求头
|
|
23
23
|
* @returns 响应体内容
|
|
24
24
|
*/
|
|
25
|
-
export declare const postForBody: (url: string, body?: string, headers?: Record<string, any>) => Promise<string>;
|
|
25
|
+
export declare const postForBody: (url: string, body?: string | object, headers?: Record<string, any>) => Promise<string>;
|
package/dist/http.js
CHANGED
|
@@ -2,33 +2,37 @@
|
|
|
2
2
|
* 发送 HTTP 请求,获取响应体内容
|
|
3
3
|
* @param method 请求方法
|
|
4
4
|
* @param url 请求 URL
|
|
5
|
-
* @param body
|
|
5
|
+
* @param body 请求体(UTF-8 编码)
|
|
6
6
|
* @param headers 请求头
|
|
7
7
|
* @returns 响应体内容
|
|
8
8
|
*/
|
|
9
9
|
export const requestForBody = async (method, url, body, headers) => {
|
|
10
|
-
|
|
10
|
+
if (body && typeof body === "object") {
|
|
11
|
+
body = JSON.stringify(body);
|
|
12
|
+
headers = { ...headers, "Content-Type": "application/json" };
|
|
13
|
+
}
|
|
14
|
+
const resp = await http.request(method, url, body ?? null, headers ? JSON.stringify(headers) : null);
|
|
11
15
|
if (resp.status_code >= 200 && resp.status_code < 400) {
|
|
12
16
|
return resp.body;
|
|
13
17
|
}
|
|
14
18
|
else {
|
|
15
|
-
throw new Error(`HTTP request failed with status ${resp.status_code}`);
|
|
19
|
+
throw new Error(`HTTP request failed with status ${resp.status_code}: ${resp.body}`);
|
|
16
20
|
}
|
|
17
21
|
};
|
|
18
22
|
/**
|
|
19
23
|
* 发送 HTTP GET 请求,获取响应体内容
|
|
20
24
|
* @param url 请求 URL
|
|
21
|
-
* @param body
|
|
25
|
+
* @param body 请求体(UTF-8 编码)
|
|
22
26
|
* @param headers 请求头
|
|
23
27
|
* @returns 响应体内容
|
|
24
28
|
*/
|
|
25
|
-
export const getForBody =
|
|
29
|
+
export const getForBody = (url, body, headers) => {
|
|
26
30
|
return requestForBody("GET", url, body, headers);
|
|
27
31
|
};
|
|
28
32
|
/**
|
|
29
33
|
* 发送 HTTP POST 请求,获取响应体内容
|
|
30
34
|
* @param url 请求 URL
|
|
31
|
-
* @param body
|
|
35
|
+
* @param body 请求体(UTF-8 编码)
|
|
32
36
|
* @param headers 请求头
|
|
33
37
|
* @returns 响应体内容
|
|
34
38
|
*/
|
package/dist/ocr.d.ts
CHANGED
|
@@ -112,10 +112,11 @@ export type ListView = {
|
|
|
112
112
|
* @param condition 查找条件
|
|
113
113
|
* @param listView 列表视图参数
|
|
114
114
|
* @param retryOptions 重试选项
|
|
115
|
-
* @param sampling
|
|
115
|
+
* @param sampling 区域采样函数,通过采样区域画面变化判断列表是否触底(默认:底半区)
|
|
116
|
+
* @param threshold 采样区域匹配阈值(默认:0.9)
|
|
116
117
|
* @returns 如果找到匹配的区域,则返回该区域,否则返回 undefined
|
|
117
118
|
*/
|
|
118
|
-
export declare const findWithinListView: (condition: (listViewRegion: ImageRegion) => Region | undefined, listView: ListView, retryOptions?: RetryOptions, sampling?: (listViewRegion: ImageRegion) => ImageRegion) => Promise<Region | undefined>;
|
|
119
|
+
export declare const findWithinListView: (condition: (listViewRegion: ImageRegion) => Region | undefined, listView: ListView, retryOptions?: RetryOptions, sampling?: (listViewRegion: ImageRegion) => ImageRegion, threshold?: number) => Promise<Region | undefined>;
|
|
119
120
|
/**
|
|
120
121
|
* 在列表视图中滚动搜索文本
|
|
121
122
|
* @param text 待搜索文本
|
|
@@ -123,15 +124,19 @@ export declare const findWithinListView: (condition: (listViewRegion: ImageRegio
|
|
|
123
124
|
* @param matchOptions 搜索选项
|
|
124
125
|
* @param retryOptions 重试选项
|
|
125
126
|
* @param config 识别对象配置
|
|
127
|
+
* @param sampling 区域采样函数,通过采样区域画面变化判断列表是否触底(默认:底半区)
|
|
128
|
+
* @param threshold 采样区域匹配阈值(默认:0.9)
|
|
126
129
|
* @returns 如果找到匹配的文本区域,则返回该区域,否则返回 undefined
|
|
127
130
|
*/
|
|
128
|
-
export declare const findTextWithinListView: (text: string, listView: ListView, matchOptions?: TextMatchOptions, retryOptions?: RetryOptions, config?: ROConfig, sampling?: (listViewRegion: ImageRegion) => ImageRegion) => Promise<Region | undefined>;
|
|
131
|
+
export declare const findTextWithinListView: (text: string, listView: ListView, matchOptions?: TextMatchOptions, retryOptions?: RetryOptions, config?: ROConfig, sampling?: (listViewRegion: ImageRegion) => ImageRegion, threshold?: number) => Promise<Region | undefined>;
|
|
129
132
|
/**
|
|
130
133
|
* 在列表视图中查找图像
|
|
131
134
|
* @param image 图片路径 或 图片Mat
|
|
132
135
|
* @param listView 列表视图参数
|
|
133
|
-
* @param config 识别对象配置
|
|
134
136
|
* @param retryOptions 重试选项
|
|
137
|
+
* @param config 识别对象配置
|
|
138
|
+
* @param sampling 区域采样函数,通过采样区域画面变化判断列表是否触底(默认:底半区)
|
|
139
|
+
* @param threshold 采样区域匹配阈值(默认:0.9)
|
|
135
140
|
* @returns 如果找到匹配的区域,则返回该区域,否则返回 undefined
|
|
136
141
|
*/
|
|
137
|
-
export declare const findImageWithinListView: (image: string | ImageMat, listView: ListView,
|
|
142
|
+
export declare const findImageWithinListView: (image: string | ImageMat, listView: ListView, retryOptions?: RetryOptions, config?: ROConfig, sampling?: (listViewRegion: ImageRegion) => ImageRegion, threshold?: number) => Promise<Region | undefined>;
|
package/dist/ocr.js
CHANGED
|
@@ -202,28 +202,39 @@ export const findTextInDirection = (text, direction, options, config = {}) => {
|
|
|
202
202
|
* @param condition 查找条件
|
|
203
203
|
* @param listView 列表视图参数
|
|
204
204
|
* @param retryOptions 重试选项
|
|
205
|
-
* @param sampling
|
|
205
|
+
* @param sampling 区域采样函数,通过采样区域画面变化判断列表是否触底(默认:底半区)
|
|
206
|
+
* @param threshold 采样区域匹配阈值(默认:0.9)
|
|
206
207
|
* @returns 如果找到匹配的区域,则返回该区域,否则返回 undefined
|
|
207
208
|
*/
|
|
208
|
-
export const findWithinListView = async (condition, listView, retryOptions, sampling) => {
|
|
209
|
+
export const findWithinListView = async (condition, listView, retryOptions, sampling, threshold = 0.9) => {
|
|
209
210
|
const { x, y, w, h, lineHeight, scrollLines = 1, paddingX = 10, paddingY = 10 } = listView;
|
|
210
|
-
const { maxAttempts = 99, retryInterval =
|
|
211
|
-
sampling
|
|
211
|
+
const { maxAttempts = 99, retryInterval = 1200 } = retryOptions || {};
|
|
212
|
+
sampling ??= r => r.deriveCrop(1, r.height * 0.5, r.width - 1, r.height * 0.5);
|
|
212
213
|
const captureListViewRegion = () => captureGameRegion().deriveCrop(x, y, w, h);
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (
|
|
214
|
+
const isReachedBottom = (() => {
|
|
215
|
+
let lastCaptured;
|
|
216
|
+
return () => {
|
|
217
|
+
const newRegion = captureListViewRegion();
|
|
218
|
+
if (!newRegion?.isExist())
|
|
218
219
|
return true;
|
|
220
|
+
try {
|
|
221
|
+
if (!lastCaptured)
|
|
222
|
+
return false;
|
|
223
|
+
const oldRegion = sampling(lastCaptured);
|
|
224
|
+
if (!oldRegion?.isExist())
|
|
225
|
+
return true;
|
|
226
|
+
// 根据采样区域画面是否变化,判断列表是否触底
|
|
227
|
+
const ro = RecognitionObject.templateMatch(oldRegion.srcMat);
|
|
228
|
+
ro.threshold = threshold;
|
|
229
|
+
ro.use3Channels = true;
|
|
230
|
+
ro.initTemplate();
|
|
231
|
+
return newRegion.find(ro)?.isExist();
|
|
219
232
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
return false;
|
|
233
|
+
finally {
|
|
234
|
+
lastCaptured = newRegion;
|
|
223
235
|
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
};
|
|
236
|
+
};
|
|
237
|
+
})();
|
|
227
238
|
const isFoundOrReachedBottom = await waitForAction(() => condition(captureListViewRegion())?.isExist() || isReachedBottom(), async () => {
|
|
228
239
|
moveMouseTo(x + w - paddingX, y + paddingY); // 移动到滚动条附近
|
|
229
240
|
await sleep(50);
|
|
@@ -238,9 +249,11 @@ export const findWithinListView = async (condition, listView, retryOptions, samp
|
|
|
238
249
|
* @param matchOptions 搜索选项
|
|
239
250
|
* @param retryOptions 重试选项
|
|
240
251
|
* @param config 识别对象配置
|
|
252
|
+
* @param sampling 区域采样函数,通过采样区域画面变化判断列表是否触底(默认:底半区)
|
|
253
|
+
* @param threshold 采样区域匹配阈值(默认:0.9)
|
|
241
254
|
* @returns 如果找到匹配的文本区域,则返回该区域,否则返回 undefined
|
|
242
255
|
*/
|
|
243
|
-
export const findTextWithinListView = async (text, listView, matchOptions, retryOptions, config = {}, sampling) => {
|
|
256
|
+
export const findTextWithinListView = async (text, listView, matchOptions, retryOptions, config = {}, sampling, threshold = 0.9) => {
|
|
244
257
|
const ro = RecognitionObject.ocrThis;
|
|
245
258
|
if (Object.keys(config).length > 0) {
|
|
246
259
|
Object.assign(ro, config) && ro.initTemplate();
|
|
@@ -249,17 +262,19 @@ export const findTextWithinListView = async (text, listView, matchOptions, retry
|
|
|
249
262
|
return findFirstRegion(lvr, ro, region => {
|
|
250
263
|
return region.isExist() && textMatch(region.text, text, matchOptions);
|
|
251
264
|
});
|
|
252
|
-
}, listView, retryOptions, sampling);
|
|
265
|
+
}, listView, retryOptions, sampling, threshold);
|
|
253
266
|
};
|
|
254
267
|
/**
|
|
255
268
|
* 在列表视图中查找图像
|
|
256
269
|
* @param image 图片路径 或 图片Mat
|
|
257
270
|
* @param listView 列表视图参数
|
|
258
|
-
* @param config 识别对象配置
|
|
259
271
|
* @param retryOptions 重试选项
|
|
272
|
+
* @param config 识别对象配置
|
|
273
|
+
* @param sampling 区域采样函数,通过采样区域画面变化判断列表是否触底(默认:底半区)
|
|
274
|
+
* @param threshold 采样区域匹配阈值(默认:0.9)
|
|
260
275
|
* @returns 如果找到匹配的区域,则返回该区域,否则返回 undefined
|
|
261
276
|
*/
|
|
262
|
-
export const findImageWithinListView = async (image, listView, config = {},
|
|
277
|
+
export const findImageWithinListView = async (image, listView, retryOptions, config = {}, sampling, threshold = 0.9) => {
|
|
263
278
|
const mat = typeof image === "string" ? file.readImageMatSync(image) : image;
|
|
264
279
|
const ro = RecognitionObject.templateMatch(mat);
|
|
265
280
|
if (Object.keys(config).length > 0) {
|
|
@@ -268,5 +283,5 @@ export const findImageWithinListView = async (image, listView, config = {}, retr
|
|
|
268
283
|
return findWithinListView(ir => {
|
|
269
284
|
const region = ir.find(ro);
|
|
270
285
|
return region.isExist() ? region : undefined;
|
|
271
|
-
}, listView, retryOptions, sampling);
|
|
286
|
+
}, listView, retryOptions, sampling, threshold);
|
|
272
287
|
};
|