js: CD-Aware-AutoGather: 扫描待处理的材料时跳过空文件夹 (#1336)
This commit is contained in:
@@ -28,11 +28,11 @@
|
|||||||
|
|
||||||
| 选项 | 说明 |
|
| 选项 | 说明 |
|
||||||
| ---- | ---- |
|
| ---- | ---- |
|
||||||
|
| `地图追踪`中已订阅的任务目录的处理方式 | 有三种处理方式:<br>- `每次自动扫描,并采集扫描到的所有材料`<br>- `手动扫描,并采集扫描到的所有材料`<br>- `手动扫描,只采集已勾选的材料`<br>`自动扫描`会在每次执行采集前扫描当前已订阅的任务目录,`手动扫描`则是手动将运行模式切换到扫描模式执行脚本进行扫描。<br>`采集所有`会无视后面的每个材料⬇️是否选中,`采集已勾选`则是根据勾选的列表进行采集 |
|
||||||
| 设置首选队伍名称 | 执行采集任务前切换到指定的队伍,未设置则不切换。 |
|
| 设置首选队伍名称 | 执行采集任务前切换到指定的队伍,未设置则不切换。 |
|
||||||
| 设置备选队伍名称 | 首选队伍缺少对应的采集角色时使用。<br>两支队伍的名称不要存在包含关系,例如不能一支叫`特产`一支叫`特产备选` |
|
| 设置备选队伍名称 | 首选队伍缺少对应的采集角色时使用。<br>两支队伍的名称不要存在包含关系,例如不能一支叫`特产`一支叫`特产备选` |
|
||||||
| 停止运行时间 | 超过此时间后,停止后续的任务(会等待正在运行的那条json路线结束)。 |
|
| 停止运行时间 | 超过此时间后,停止后续的任务(会等待正在运行的那条json路线结束)。 |
|
||||||
| 我肝的账号不止一个 | 如果你有多个账号,可以选中此选项,选中后将分账号维护对应的材料刷新时间。 |
|
| 我肝的账号不止一个 | 如果你有多个账号,可以选中此选项,选中后将分账号维护对应的材料刷新时间。 |
|
||||||
| `地图追踪`中已订阅的任务目录的处理方式 | 有三种处理方式:<br>- `每次自动扫描,并采集扫描到的所有材料`<br>- `手动扫描,并采集扫描到的所有材料`<br>- `手动扫描,只采集已勾选的材料`<br>`自动扫描`会在每次执行采集前扫描当前已订阅的任务目录,`手动扫描`则是手动将运行模式切换到扫描模式执行脚本进行扫描。<br>`采集所有`会无视后面的每个材料⬇️是否选中,`采集已勾选`则是根据勾选的列表进行采集 |
|
|
||||||
| 即使同一种材料有多个版本的路线,也全都执行采集 | 如果某种材料选中了多个版本的路线(常见于不同作者),默认只会执行第一个。勾选此选项后会每个版本都执行,可能造成部分点位重复(空跑)。 |
|
| 即使同一种材料有多个版本的路线,也全都执行采集 | 如果某种材料选中了多个版本的路线(常见于不同作者),默认只会执行第一个。勾选此选项后会每个版本都执行,可能造成部分点位重复(空跑)。 |
|
||||||
| `↓` 地方特产\稻妻\绯樱绣球 | 根据你订阅的路径追踪任务数量,这里将会显示相应个数的选择框。<br>勾选后将执行你选中的条目的采集任务。<br>Tip: `↓`符号是在提示你应该勾选文本下面的选择框 |
|
| `↓` 地方特产\稻妻\绯樱绣球 | 根据你订阅的路径追踪任务数量,这里将会显示相应个数的选择框。<br>勾选后将执行你选中的条目的采集任务。<br>Tip: `↓`符号是在提示你应该勾选文本下面的选择框 |
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,16 @@
|
|||||||
|
|
||||||
let scriptContext = {
|
let scriptContext = {
|
||||||
scriptStartTime: new Date(),
|
scriptStartTime: new Date(),
|
||||||
version: "1.0"
|
version: "1.1",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 Date 对象格式化为 ISO 8601 字符串,包含本地时区(如:2020-09-28T20:20:20.999+08:00)
|
* 将 Date 对象格式化为 ISO 8601 字符串,包含本地时区(如:2020-09-28T20:20:20+08:00)
|
||||||
* @param {Date} date - 要格式化的日期对象
|
* @param {Date} date - 要格式化的日期对象
|
||||||
* @returns {string} 格式化后的字符串
|
* @returns {string} 格式化后的字符串
|
||||||
*/
|
*/
|
||||||
function formatDateTime(date) {
|
function formatDateTime(date) {
|
||||||
const pad = (n) => n.toString().padStart(2, "0");
|
const pad = (n) => n.toString().padStart(2, "0");
|
||||||
const padMs = (n) => n.toString().padStart(3, "0");
|
|
||||||
|
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
const month = pad(date.getMonth() + 1);
|
const month = pad(date.getMonth() + 1);
|
||||||
@@ -25,7 +24,6 @@ function formatDateTime(date) {
|
|||||||
const hour = pad(date.getHours());
|
const hour = pad(date.getHours());
|
||||||
const minute = pad(date.getMinutes());
|
const minute = pad(date.getMinutes());
|
||||||
const second = pad(date.getSeconds());
|
const second = pad(date.getSeconds());
|
||||||
const ms = padMs(date.getMilliseconds());
|
|
||||||
|
|
||||||
// 获取时区偏移(分钟),转换成±HH:MM
|
// 获取时区偏移(分钟),转换成±HH:MM
|
||||||
const offset = -date.getTimezoneOffset();
|
const offset = -date.getTimezoneOffset();
|
||||||
@@ -33,7 +31,7 @@ function formatDateTime(date) {
|
|||||||
const offsetHour = pad(Math.floor(Math.abs(offset) / 60));
|
const offsetHour = pad(Math.floor(Math.abs(offset) / 60));
|
||||||
const offsetMin = pad(Math.abs(offset) % 60);
|
const offsetMin = pad(Math.abs(offset) % 60);
|
||||||
|
|
||||||
return `${year}-${month}-${day}T${hour}:${minute}:${second}.${ms}${sign}${offsetHour}:${offsetMin}`;
|
return `${year}-${month}-${day}T${hour}:${minute}:${second}${sign}${offsetHour}:${offsetMin}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -329,9 +327,10 @@ async function switchPartySafely(partyName) {
|
|||||||
*
|
*
|
||||||
* @async
|
* @async
|
||||||
* @param {*} multiAccount 是否使用OCR区分多个账号(可以传入一个设置项)
|
* @param {*} multiAccount 是否使用OCR区分多个账号(可以传入一个设置项)
|
||||||
|
* @param {boolean} mask 对UID进行掩码,只保留开头和结尾
|
||||||
* @returns {Promise<string>} 当前账号的UID,如果不区分多账号或OCR失败则返回"默认账号"。
|
* @returns {Promise<string>} 当前账号的UID,如果不区分多账号或OCR失败则返回"默认账号"。
|
||||||
*/
|
*/
|
||||||
async function getGameAccount(multiAccount = false) {
|
async function getGameAccount(multiAccount = false, mask = true) {
|
||||||
let account = "默认账号";
|
let account = "默认账号";
|
||||||
if (!multiAccount) {
|
if (!multiAccount) {
|
||||||
return account;
|
return account;
|
||||||
@@ -352,6 +351,10 @@ async function getGameAccount(multiAccount = false) {
|
|||||||
const match = text.match(/\d+/);
|
const match = text.match(/\d+/);
|
||||||
if (match) {
|
if (match) {
|
||||||
account = match[0];
|
account = match[0];
|
||||||
|
if (mask) {
|
||||||
|
// 避免完整UID出现在log中造成意外暴露
|
||||||
|
account = account.replace(/\d*(\d{4})\d{4}/, (match, group1) => match.replace(group1, "xxxx"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -397,7 +400,7 @@ function getScriptName() {
|
|||||||
* @returns {string} - 文件名。
|
* @returns {string} - 文件名。
|
||||||
*/
|
*/
|
||||||
function basename(filePath) {
|
function basename(filePath) {
|
||||||
const lastSlashIndex = filePath.lastIndexOf('\\'); // 或者使用 '/'
|
const lastSlashIndex = filePath.lastIndexOf("\\"); // 或者使用 '/'
|
||||||
return filePath.substring(lastSlashIndex + 1);
|
return filePath.substring(lastSlashIndex + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -504,8 +507,9 @@ function _fakeLogCore(name, isJs = true, dateIn = null) {
|
|||||||
logTime = dateIn;
|
logTime = dateIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 时间部分从第11位开始,长度是12("20:20:20.999")
|
const ms = logTime.getMilliseconds().toString().padStart(3, "0");
|
||||||
const formattedTime = formatDateTime(logTime).slice(11, 23);
|
// 时间部分从第11位开始,长度是12("20:20:20")
|
||||||
|
const formattedTime = formatDateTime(logTime).slice(11, 19) + "." + ms;
|
||||||
|
|
||||||
if (isStart) {
|
if (isStart) {
|
||||||
logMessage =
|
logMessage =
|
||||||
@@ -594,3 +598,24 @@ function logFakeScriptEnd({ scriptName = null, startTime = new Date() } = {}) {
|
|||||||
}
|
}
|
||||||
return _fakeLogCore(scriptName, true, startTime);
|
return _fakeLogCore(scriptName, true, startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 等待传送结束
|
||||||
|
* @param {Int} timeout 单位为ms
|
||||||
|
* @note 参考了七圣召唤七日历练脚本
|
||||||
|
*/
|
||||||
|
async function waitTpFinish(timeout = 30000) {
|
||||||
|
const region = RecognitionObject.ocr(1690, 230, 75, 350); // 队伍名称区域
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
await sleep(500); //点击传送后等待一段时间避免误判
|
||||||
|
while (Date.now() - startTime < timeout) {
|
||||||
|
let res = captureGameRegion().find(region);
|
||||||
|
if (!res.isEmpty()) {
|
||||||
|
await sleep(600); //传送结束后有僵直
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await sleep(100);
|
||||||
|
}
|
||||||
|
throw new Error("传送时间超时");
|
||||||
|
}
|
||||||
|
|||||||
@@ -167,9 +167,8 @@ async function runClearMode() {
|
|||||||
const resetTimeStr = formatDateTime(getDefaultTime());
|
const resetTimeStr = formatDateTime(getDefaultTime());
|
||||||
let account = await getGameAccount(settings.iHaveMultipleAccounts);
|
let account = await getGameAccount(settings.iHaveMultipleAccounts);
|
||||||
for (const pathTask of selectedMaterials) {
|
for (const pathTask of selectedMaterials) {
|
||||||
const jsonFiles = filterFilesInTaskDir(pathTask.label);
|
|
||||||
const recordFile = getRecordFilePath(account, pathTask);
|
const recordFile = getRecordFilePath(account, pathTask);
|
||||||
const lines = jsonFiles.map((filePath) => {
|
const lines = pathTask.jsonFiles.map((filePath) => {
|
||||||
return `${basename(filePath)}\t${resetTimeStr}`;
|
return `${basename(filePath)}\t${resetTimeStr}`;
|
||||||
});
|
});
|
||||||
const content = lines.join("\n");
|
const content = lines.join("\n");
|
||||||
@@ -280,7 +279,7 @@ async function runPathScriptFile(jsonPath) {
|
|||||||
|
|
||||||
async function runPathTaskIfCooldownExpired(account, pathTask) {
|
async function runPathTaskIfCooldownExpired(account, pathTask) {
|
||||||
const recordFile = getRecordFilePath(account, pathTask);
|
const recordFile = getRecordFilePath(account, pathTask);
|
||||||
const jsonFiles = filterFilesInTaskDir(pathTask.label);
|
const jsonFiles = pathTask.jsonFiles;
|
||||||
|
|
||||||
log.info("{0}共有{1}条路线", pathTask.label, jsonFiles.length);
|
log.info("{0}共有{1}条路线", pathTask.label, jsonFiles.length);
|
||||||
|
|
||||||
@@ -397,7 +396,13 @@ function getSelectedMaterials() {
|
|||||||
if (selectAllMaterials || settings[entry.name] === true) {
|
if (selectAllMaterials || settings[entry.name] === true) {
|
||||||
let index = entry.label.indexOf(" ");
|
let index = entry.label.indexOf(" ");
|
||||||
entry.label = entry.label.slice(index + 1); // 去除⬇️指示
|
entry.label = entry.label.slice(index + 1); // 去除⬇️指示
|
||||||
selectedMaterials.push(entry);
|
const jsonFiles = filterFilesInTaskDir(entry.label);
|
||||||
|
if (jsonFiles.length > 0) {
|
||||||
|
entry.jsonFiles = jsonFiles;
|
||||||
|
selectedMaterials.push(entry);
|
||||||
|
} else {
|
||||||
|
log.debug("跳过空文件夹: {0}", entry.label);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 1,
|
"manifest_version": 1,
|
||||||
"name": "带CD管理的自动采集",
|
"name": "带CD管理的自动采集",
|
||||||
"version": "1.4",
|
"version": "1.5",
|
||||||
"bgi_version": "0.45.0",
|
"bgi_version": "0.45.0",
|
||||||
"description": "自动同步你通过BetterGI订阅的地图追踪任务,执行采集任务,并管理材料刷新时间(支持多账号)。\n首次使用前请先简单阅读说明(可在`全自动`——`JS脚本`页面,点击本脚本名称查看)",
|
"description": "自动同步你通过BetterGI订阅的地图追踪任务,执行采集任务,并管理材料刷新时间(支持多账号)。\n首次使用前请先简单阅读说明(可在`全自动`——`JS脚本`页面,点击本脚本名称查看)",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|||||||
@@ -9,6 +9,16 @@
|
|||||||
"清除运行记录(重置材料刷新时间)"
|
"清除运行记录(重置材料刷新时间)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "subscribeMode",
|
||||||
|
"type": "select",
|
||||||
|
"label": "'地图追踪'中已订阅的任务目录的处理方式:",
|
||||||
|
"options": [
|
||||||
|
"每次自动扫描,并采集扫描到的所有材料",
|
||||||
|
"手动扫描,并采集扫描到的所有材料",
|
||||||
|
"手动扫描,只采集已勾选的材料"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "partyName",
|
"name": "partyName",
|
||||||
"type": "input-text",
|
"type": "input-text",
|
||||||
@@ -29,16 +39,6 @@
|
|||||||
"type": "checkbox",
|
"type": "checkbox",
|
||||||
"label": "我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间)"
|
"label": "我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间)"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "subscribeMode",
|
|
||||||
"type": "select",
|
|
||||||
"label": "'地图追踪'中已订阅的任务目录的处理方式:",
|
|
||||||
"options": [
|
|
||||||
"每次自动扫描,并采集扫描到的所有材料",
|
|
||||||
"手动扫描,并采集扫描到的所有材料",
|
|
||||||
"手动扫描,只采集已勾选的材料"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "acceptMultiplePathOfSameMaterial",
|
"name": "acceptMultiplePathOfSameMaterial",
|
||||||
"type": "checkbox",
|
"type": "checkbox",
|
||||||
|
|||||||
@@ -9,6 +9,16 @@
|
|||||||
"清除运行记录(重置材料刷新时间)"
|
"清除运行记录(重置材料刷新时间)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "subscribeMode",
|
||||||
|
"type": "select",
|
||||||
|
"label": "'地图追踪'中已订阅的任务目录的处理方式:",
|
||||||
|
"options": [
|
||||||
|
"每次自动扫描,并采集扫描到的所有材料",
|
||||||
|
"手动扫描,并采集扫描到的所有材料",
|
||||||
|
"手动扫描,只采集已勾选的材料"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "partyName",
|
"name": "partyName",
|
||||||
"type": "input-text",
|
"type": "input-text",
|
||||||
@@ -29,16 +39,6 @@
|
|||||||
"type": "checkbox",
|
"type": "checkbox",
|
||||||
"label": "我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间)"
|
"label": "我肝的账号不止一个(选中后将分账号维护对应的材料刷新时间)"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "subscribeMode",
|
|
||||||
"type": "select",
|
|
||||||
"label": "'地图追踪'中已订阅的任务目录的处理方式:",
|
|
||||||
"options": [
|
|
||||||
"每次自动扫描,并采集扫描到的所有材料",
|
|
||||||
"手动扫描,并采集扫描到的所有材料",
|
|
||||||
"手动扫描,只采集已勾选的材料"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "acceptMultiplePathOfSameMaterial",
|
"name": "acceptMultiplePathOfSameMaterial",
|
||||||
"type": "checkbox",
|
"type": "checkbox",
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
|
|
||||||
这种情况只能手动操作小号投降(见前面的[使用说明](#使用说明))。由于发起邀请的角色(大号)操作会更复杂,建议用脚本来发起邀请。
|
这种情况只能手动操作小号投降(见前面的[使用说明](#使用说明))。由于发起邀请的角色(大号)操作会更复杂,建议用脚本来发起邀请。
|
||||||
|
|
||||||
|
或者你也可以在QQ群或者QQ频道找同样想刷熟练度的玩家,互相挂投降模式协助对方。[右击此链接——在新窗口中打开](https://bettergi.com/community.html)查看QQ群和QQ频道信息。
|
||||||
|
|
||||||
- **只有一台电脑,能不能运行一个原神,运行一个云原神?**
|
- **只有一台电脑,能不能运行一个原神,运行一个云原神?**
|
||||||
|
|
||||||
Better GI在检测到已经有运行中的实例时不会再启动第二份,但并不像原神那样针对同一台物理设备。我也尝试过通过创建多个Windows账号,以双开Better GI,但是后启动的截图器会报错,可能是无法同时运行多个截图器。
|
Better GI在检测到已经有运行中的实例时不会再启动第二份,但并不像原神那样针对同一台物理设备。我也尝试过通过创建多个Windows账号,以双开Better GI,但是后启动的截图器会报错,可能是无法同时运行多个截图器。
|
||||||
|
|||||||
Reference in New Issue
Block a user