mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-03-16 03:33:25 +08:00
[活动期限/周本通知器] 迭代 0.0.2 版本 (#2552)
* feat(ActivitySwitchNotice): 添加异步通知发送功能
- 新增异步发送通知函数 send,支持标题和内容拼接
- 添加通知发送前的日志记录和条件判断
- 导出新的 send 函数供外部调用
- 保留原有 sendNotice 函数兼容性
* feat(activity): 新增征讨领域次数识别与通知功能
- 实现征讨领域 OCR 识别逻辑,用于获取每周剩余次数
- 添加秘境与征讨领域的点击坐标配置
- 集成通知工具,发送剩余次数提醒
- 支持自动按键进入活动界面并执行点击操作
- 增加星期判断逻辑,跳过周日执行
- 提供字符串与整数解析工具函数,增强配置容错性
* fix(campaignArea): 修复周日不执行秘境征讨提醒的问题
- 将判断条件从等于0修改为不等于0,确保周日可以执行提醒逻辑
- 添加日志记录,便于追踪执行情况和调试
- 保留原有的延迟和按键操作逻辑
* feat(activity): 添加活动切换通知功能
- 引入 campaignArea.js 工具模块
- 在主流程中调用 toMainUi 函数
- 执行活动区域主逻辑处理
- 整合活动切换与通知机制
- 增强主界面判断逻辑
- 优化异步流程控制
* feat(activity): 实现秘境征讨剩余次数提醒功能
- 添加了每周日自动检查秘境征讨剩余次数的功能
- 实现了通过OCR识别剩余次数的逻辑
- 集成了日志记录和通知发送机制
- 添加了完整的操作延迟和点击坐标配置
- 实现了热键触发和界面点击的自动化流程
- 增加了详细的函数注释和执行日志
* feat(campaignArea): 更新征讨领域坐标并优化OCR识别逻辑
- 调整征讨领域点击坐标为{x: 493, y: 537}
- 新增ocrWeeklyCount函数用于OCR识别周计数信息
- 增强OCR识别后的文本处理与日志记录
- 修复周日判断逻辑,确保仅在周日执行特定操作
- 调整主流程顺序,先执行征讨领域再返回主界面
* refactor(campaignArea): 优化星期名称获取逻辑
- 提取星期名称到独立变量以提高可读性
- 更新日志记录以使用新的变量名
- 确保返回对象中的星期名称正确引用新变量
* feat(ActivitySwitchNotice): 新增征讨领域每周提醒功能
- 在 README 中新增“每周日自动提醒征讨领域剩余次数”特性说明
- 更新 settings.json 配置项表格,增加 toTopCount、scrollPageCount 和 campaignAreaKey 参数
- 新增 campaignArea.js 模块,实现 OCR 识别与周日提醒逻辑
- 调整目录结构说明,加入 campaignArea.js 文件介绍
- 修改工作原理部分,补充征讨领域提醒的执行流程
- 统一 README 中代码引用格式为反引号包裹
* docs(ActivitySwitchNotice): 更新 README 版本历史记录
- 新增 0.0.2 版本的征讨领域周次数提醒功能
- 新增 campaignArea.js 模块及相关配置选项
- 改进 滚动到顶部功能的稳定性并新增相关配置
- 新增 0.1 版本的活动检测、OCR识别及通知功能
- 新增 多种智能解析与防重复检测机制
- 新增 异常处理和错误恢复机制
* fix(ActivitySwitchNotice): 调整日志级别与周日判断逻辑
- 将 info 级别日志调整为 debug 级别
- 修正周日判断条件,确保仅周日执行提醒
- 增强周日判断日志描述
- 更新剩余次数提示文案,明确显示“本周剩余消耗减半次数”
- 在通知消息前添加 Markdown 格式符号 `>` 以突出显示
* refactor(campaignArea): 将日志级别从 info 调整为 debug
- 修改日志记录方式,将 info 级别调整为 debug
- 减少生产环境中的日志噪音
- 提高调试信息的可读性与准确性
* feat(ActivitySwitchNotice): 新增征讨领域模块和配置选项
- 新增 campaignArea.js 模块,包含征讨领域相关功能
- 新增 campaignAreaKey 配置选项,用于自定义征讨领域页面快捷键
- 改进增强滚动到顶部功能的稳定性
- 新增 toTopCount 和 scrollPageCount 配置选项,提供更多滚动控制参数
- 新增活动期限检测与通知功能
- 新增 OCR 识别活动列表和剩余时间功能
* docs: 更新活动通知器功能说明
* feat(ActivitySwitchNotice): 支持征讨领域周次数提醒功能
- 更新插件名称以明确支持活动期限与周本提醒
- 提升版本号至 0.0.2
- 新增 campaignAreaKey 配置项用于自定义征讨领域页面快捷键
- 在 README 中更新 campaignAreaKey 的使用状态为启用
- 更新版本历史记录日期及新增功能说明
- 新增 campaignArea.js 模块实现相关功能逻辑
* feat(ActivitySwitchNotice): 支持自定义征讨领域提醒日
- 新增配置项 campaignAreaReminderDay,用于设置提醒日期
- 修改判断逻辑,使用配置的提醒日替代固定周日判断
- 添加相关注释说明配置用途
* feat(settings): 添加周本提醒日设置选项
- 在设置中新增周本提醒日选择器
- 支持设置提醒日为周日至周六任意一天
- 默认值设为周日
- 保留原有冒险之证按键设置功能
* docs: 更新文档,新增征讨领域提醒日配置选项说明
* fix: 修改周本提醒日配置值为字符串格式
* feat(activity): 添加活动描述字段支持
- 在活动映射中新增 desc 字段,默认值为 null
- 更新通知文本生成逻辑,支持显示活动描述信息
- 优化剩余时间文本格式,增强可读性
- 保持现有功能兼容性,不影响无描述场景显示
* feat(activity): 增加活动时间转换和OCR功能
- 添加日期枚举类型DATE_ENUM及反向映射方法
- 新增活动周期转换映射表activityTermConversionMap
- 新增特定活动OCR内容映射表needOcrOtherMap
- 实现根据活动名称获取日期枚举值的函数getDATE_ENUM
- 添加将总小时数转换为周/天/小时格式的函数convertHoursToWeeksDaysHours
- 在活动时间处理中增加对不同时间单位的支持
- 增加对特定活动额外OCR识别内容的支持
- 修复数组遍历时的缩进问题
* feat(activity): 更新活动时间显示逻辑
- 修改"砺行修远"活动的时间枚举为周
- 调整剩余时间文本的显示格式
- 优化通知文本的排版和分隔符
- 增强日期枚举获取函数的返回值结构
- 添加调试日志用于追踪活动时间和枚举值
- 改进OCR识别时间的显示方式
* feat(ActivitySwitchNotice): 添加黑名单活动名称过滤功能
- 在配置中新增 blackActivityNameList 字段,支持通过 | 分割多个活动名称
- 实现活动黑名单过滤逻辑,排除黑名单中的活动名称
- 更新设置界面,增加黑名单活动名称输入框
- 完善活动筛选流程,优先过滤黑名单活动再判断剩余时间阈值
* feat(ActivitySwitchNotice): 新增活动黑名单过滤功能
- 在 settings.json 中新增 blackActivityNameList 配置项
- 支持通过黑名单排除不关心的活动提醒
- 更新文档说明,添加黑名单使用示例
- 增强活动过滤逻辑,提高匹配准确性
- 在核心扫描流程中集成黑名单过滤机制
- 优化通知显示格式,增加活动描述信息
- 修复若干已知问题,提升脚本稳定性
* fix(activity): 修复活动过滤逻辑
- 修改黑名单活动名称过滤方式,从完全匹配改为包含匹配
- 确保活动名称中包含黑名单关键词时能被正确过滤
- 保持小时数阈值过滤逻辑不变
- 维持扫描完成后统一发送通知的机制
* fix(activity): 修复活动黑名单过滤逻辑及通知文本
- 修正黑名单关键词过滤条件判断
- 优化通知消息文本格式,增加黑名单提示信息
* feat(activity): 支持多个OCR识别键值
- 修改needOcrOtherMap结构以支持数组形式的键值
- 更新OCR识别逻辑以遍历多个键值并拼接结果
- 为"砺行修远"活动添加"完成进度"作为新的OCR识别目标
* fix(activity): 修复OCR时间和活动过滤逻辑
- 修复OCR剩余时间函数调用参数错误,从keys改为key
- 优化活动黑名单过滤逻辑,提高过滤准确性
- 增强活动名称关键字匹配的判断条件
- 修复过滤器提前返回导致的逻辑中断问题
* fix(ActivitySwitchNotice): 优化活动黑名单过滤和日期枚举匹配逻辑
- 黑名单活动名称过滤时增加去除空字符串逻辑
- 日期枚举匹配改为模糊包含匹配,提升识别准确率
- 修复黑名单提示条件判断错误导致的消息格式问题
* docs: 更新活动模块文档,添加配置项说明
* feat(activity): 添加黑名单活动名称过滤功能
- 在活动点击前增加黑名单关键词匹配逻辑
- 跳过匹配黑名单的活动,避免无效点击
- 移除原有冗余的活动过滤逻辑
- 优化活动重复点击判断流程
* style(docs): 格式化 README.md 中的表格样式
- 调整表格列对齐方式,使用冒号对齐格式
- 统一表格分隔符的格式和间距
- 修复表格列宽和对齐问题
- 优化表格的视觉呈现效果
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
# 活动期限通知器
|
||||
# 活动期限/周本通知器
|
||||
|
||||
## 项目概述
|
||||
|
||||
这是一个用于《原神》游戏的自动化脚本工具,主要功能是自动检测游戏内活动的剩余时间,并在活动即将结束时发送通知提醒玩家。
|
||||
这是一个用于《原神》游戏的自动化脚本工具,主要功能是自动检测游戏内活动的剩余时间,并在活动即将结束时/每周指定日期自动提醒征讨领域减半剩余次数发送通知提醒玩家。
|
||||
|
||||
## 功能特性
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
- ✅ 智能解析剩余时间(支持"22天14小时"等格式)
|
||||
- ✅ 可配置的通知阈值(默认8760小时内结束的活动)
|
||||
- ✅ 支持指定特定活动进行监控
|
||||
- ✅ 支持活动黑名单过滤功能
|
||||
- ✅ 防重复检测机制
|
||||
- ✅ 异常处理和错误恢复
|
||||
- ✅ 自动提醒征讨领域减半剩余次数(默认`周日`提醒可配置)
|
||||
|
||||
---
|
||||
|
||||
@@ -22,23 +24,31 @@
|
||||
### 快速开始
|
||||
|
||||
#### 1. 安装与配置
|
||||
|
||||
- 确保游戏分辨率为 **1920×1080**(推荐分辨率)
|
||||
- 将脚本导入到 BetterGI 脚本管理器中
|
||||
- 在脚本设置界面进行个性化配置
|
||||
|
||||
#### 2. 基础设置
|
||||
在 [settings.json]() 中可以配置以下参数:
|
||||
|
||||
| 设置项 | 说明 | 默认值 |
|
||||
|--------|------|--------|
|
||||
| `toMainUi` | 执行前是否自动返回游戏主界面 | true |
|
||||
| `activityNameList` | 监控的特定活动名称(用\|分隔) | 空(监控所有活动) |
|
||||
| `notifyHoursThreshold` | 通知时间阈值(小时) | 8760(365天) |
|
||||
| `activityKey` | 打开活动页面的快捷键 | F5 |
|
||||
在 `settings.json` 中可以配置以下参数:
|
||||
|
||||
| 设置项 | 说明 | 默认值 | 开放 |
|
||||
|:---------------------------|:-----------------------------------------------|:------------|:--:|
|
||||
| `toMainUi` | 执行前是否自动返回游戏主界面 | true | v |
|
||||
| `activityNameList` | 监控的特定活动名称(用\|分隔) | 空(监控所有活动) | v |
|
||||
| `blackActivityNameList` | 黑名单活动名称(用\|分隔) | 空(无黑名单活动) | v |
|
||||
| `notifyHoursThreshold` | 通知时间阈值(小时) | 8760(365天) | v |
|
||||
| `activityKey` | 打开活动页面的快捷键 | F5 | v |
|
||||
| `toTopCount` | 滑动到顶最大尝试次数 | 10 | x |
|
||||
| `scrollPageCount` | 滑动次数/页 | 4 | x |
|
||||
| `campaignAreaKey` | 打开征讨领域页面的快捷键 | F1 | v |
|
||||
| `campaignAreaReminderDay` | 周本提醒日(0-6,0=周日,1=周一,2=周二,3=周三,4=周四,5=周五,6=周六) | 0 | v |
|
||||
|
||||
### 使用流程
|
||||
|
||||
#### 自动模式(推荐)
|
||||
|
||||
1. 启动脚本后,程序会自动:
|
||||
- 检测当前是否在游戏主界面
|
||||
- 如未在主界面,自动返回主界面
|
||||
@@ -46,6 +56,7 @@
|
||||
- 开始扫描所有活动
|
||||
|
||||
#### 手动模式
|
||||
|
||||
1. 关闭 `toMainUi` 选项
|
||||
2. 确保游戏处于主界面状态
|
||||
3. 启动脚本开始扫描
|
||||
@@ -53,15 +64,19 @@
|
||||
### 功能详解
|
||||
|
||||
#### 活动筛选
|
||||
|
||||
- **全部活动监控**:`activityNameList` 保持空值,监控所有有剩余时间的活动
|
||||
- **指定活动监控**:填写活动关键词,如 `海灯节\|盛典`,只监控包含这些关键词的活动
|
||||
- **黑名单过滤**:`blackActivityNameList` 可以设置不想接收提醒的活动名称,多个活动用`|`分隔
|
||||
|
||||
#### 时间通知机制
|
||||
|
||||
- 默认监控所有活动(`notifyHoursThreshold`=8760小时)
|
||||
- 可设置阈值,如设置为24,则只通知剩余时间≤24小时的活动
|
||||
- 即将结束的活动会在通知中标记 `<即将结束>`
|
||||
- 即将结束(24小时内)的活动会在通知中标记 `<即将结束>`
|
||||
|
||||
#### 智能防重复
|
||||
|
||||
- 自动识别已扫描过的活动页面
|
||||
- 防止因页面滚动不准确造成的重复识别
|
||||
- 自动判断是否已滚动到页面底部
|
||||
@@ -69,11 +84,13 @@
|
||||
### 注意事项
|
||||
|
||||
#### 使用环境要求
|
||||
|
||||
- ✅ 游戏分辨率为 1920×1080(最佳兼容性)
|
||||
- ✅ 游戏处于前台运行状态
|
||||
- ✅ 活动页面可通过设置的快捷键正常打开
|
||||
|
||||
#### 运行期间注意事项
|
||||
|
||||
- 🚫 运行期间请勿手动操作鼠标
|
||||
- 🚫 避免切换窗口或最小化游戏
|
||||
- ⚠️ 如遇异常可重新启动脚本
|
||||
@@ -81,10 +98,14 @@
|
||||
### 高级配置
|
||||
|
||||
#### 自定义快捷键
|
||||
|
||||
如活动页面不是F5打开,可在 `activityKey` 中修改为对应按键。
|
||||
如冒险之书页面不是F1打开,可在 `campaignAreaKey` 中修改为对应按键。
|
||||
|
||||
#### 时间阈值设置
|
||||
|
||||
根据个人需求设置 `notifyHoursThreshold`:
|
||||
|
||||
- 24:只关注24小时内结束的活动
|
||||
- 168:关注一周内结束的活动
|
||||
- 720:关注一个月内结束的活动
|
||||
@@ -92,22 +113,25 @@
|
||||
### 输出示例
|
||||
|
||||
通知消息格式如下:
|
||||
|
||||
```
|
||||
原神活动剩余时间提醒:
|
||||
> 海灯节庆典 剩余时间:3天14小时<还剩 86 小时>
|
||||
> 风花节活动 剩余时间:1天5小时<还剩 29 小时><即将结束>
|
||||
```
|
||||
|
||||
|
||||
|
||||
**`以上为用户使用指南全部内容`**
|
||||
---
|
||||
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
ActivitySwitchNotice/
|
||||
├── utils/
|
||||
│ ├── activity.js # 核心活动处理逻辑
|
||||
│ ├── campaignArea.js # 征讨领域提醒功能
|
||||
│ └── notice.js # 通知发送功能
|
||||
├── main.js # 主入口文件
|
||||
├── manifest.json # 插件配置文件
|
||||
@@ -116,9 +140,10 @@ ActivitySwitchNotice/
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 核心模块
|
||||
|
||||
### [activity.js]() - 活动处理核心
|
||||
### `activity.js` - 活动处理核心
|
||||
|
||||
主要包含以下功能函数:
|
||||
|
||||
@@ -132,33 +157,40 @@ ActivitySwitchNotice/
|
||||
### `notice.js` - 通知模块
|
||||
|
||||
- `sendNotice()` - 发送活动提醒通知,按剩余时间排序
|
||||
- `send()` - 发送普通通知
|
||||
|
||||
### [main.js]() - 主程序入口
|
||||
### `campaignArea.js` - 征讨领域模块
|
||||
|
||||
- 检测是否在主界面
|
||||
- 返回主界面功能
|
||||
- 执行主流程
|
||||
- `ocrWeeklyCount()` - OCR识别征讨领域周次数
|
||||
- `getDayOfWeek()` - 获取当前星期信息
|
||||
- `campaignAreaMain()` - 征讨领域提醒主函数
|
||||
|
||||
## 配置选项
|
||||
|
||||
在 [settings.json]() 中可配置以下参数:
|
||||
在 `settings.json` 中可配置以下参数:
|
||||
|
||||
| 配置项 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| `toMainUi` | Boolean | 是否先返回主界面再执行 |
|
||||
| `activityNameList` | String | 指定活动名称(用\|分隔) |
|
||||
| `notifyHoursThreshold` | Number | 通知阈值(小时) |
|
||||
| `activityKey` | String | 打开活动页面的快捷键 |
|
||||
| 配置项 | 类型 | 说明 |
|
||||
|:---------------------------|:-------:|:--|
|
||||
| `toMainUi` | Boolean | 是否先返回主界面再执行 |
|
||||
| `activityNameList` | String | 指定活动名称(用\|分隔) |
|
||||
| `blackActivityNameList` | String | 黑名单活动名称(用\|分隔) |
|
||||
| `notifyHoursThreshold` | Number | 通知阈值(小时) |
|
||||
| `activityKey` | String | 打开活动页面的快捷键 |
|
||||
| `toTopCount` | Number | 滑动到顶最大尝试次数 |
|
||||
| `scrollPageCount` | Number | 滑动次数/页 |
|
||||
| `campaignAreaKey` | String | 打开冒险之书页面的快捷键 |
|
||||
| `campaignAreaReminderDay` | Number | 周本提醒日(0-6,0=周日,1=周一,2=周二,3=周三,4=周四,5=周五,6=周六) |
|
||||
|
||||
## 工作原理
|
||||
|
||||
1. 自动返回游戏主界面
|
||||
2. 按配置快捷键打开活动页面
|
||||
3. 滚动到活动列表顶部
|
||||
4. 逐页扫描所有活动
|
||||
5. OCR识别每个活动的剩余时间
|
||||
6. 解析时间为小时数并过滤
|
||||
7. 发送符合条件的活动提醒
|
||||
2. 检查是否为设置的提醒日(默认周日),如果是则执行征讨领域提醒功能
|
||||
3. 按配置快捷键打开活动页面
|
||||
4. 滚动到活动列表顶部
|
||||
5. 逐页扫描所有活动
|
||||
6. OCR识别每个活动的剩余时间
|
||||
7. 解析时间为小时数并过滤(包括黑名单过滤)
|
||||
8. 发送符合条件的活动提醒
|
||||
|
||||
## 注意事项
|
||||
|
||||
@@ -169,6 +201,35 @@ ActivitySwitchNotice/
|
||||
|
||||
---
|
||||
|
||||
## 版本历史
|
||||
|
||||
### 0.0.2 (2025-12-22)
|
||||
|
||||
- 新增 征讨领域周次数提醒功能
|
||||
- 新增 `campaignArea.js` 模块,包含征讨领域相关功能
|
||||
- 新增 `campaignAreaKey` 配置选项,用于自定义冒险之书页面快捷键
|
||||
- 新增 `campaignAreaReminderDay` 配置选项,用于配置提醒日
|
||||
- 改进 增强滚动到顶部功能的稳定性
|
||||
- 新增 活动黑名单过滤功能,支持通过 `blackActivityNameList` 配置项排除不关心的活动
|
||||
- 新增 特殊活动时间格式支持,针对"砺行修远"等活动提供周数显示
|
||||
- 新增 额外OCR识别支持,可识别特定活动的附加信息(如"本周进度")
|
||||
- 改进 活动过滤逻辑,增强黑名单匹配准确性
|
||||
- 改进 通知显示格式,增加活动描述信息展示
|
||||
- 修复 若干已知问题,提升脚本稳定性
|
||||
|
||||
### 0.0.1 (2025-12-21)
|
||||
|
||||
- 新增 活动期限检测与通知功能
|
||||
- 新增 OCR识别活动列表和剩余时间
|
||||
- 新增 自动滚动浏览所有活动页面
|
||||
- 新增 智能解析剩余时间(支持"22天14小时"等格式)
|
||||
- 新增 可配置的通知阈值功能
|
||||
- 新增 指定特定活动监控功能
|
||||
- 新增 防重复检测机制
|
||||
- 新增 异常处理和错误恢复机制
|
||||
|
||||
---
|
||||
|
||||
## 其它
|
||||
|
||||
作者:云端客
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
eval(file.readTextSync(`utils/activity.js`));
|
||||
eval(file.readTextSync(`utils/notice.js`));
|
||||
eval(file.readTextSync(`utils/campaignArea.js`));
|
||||
|
||||
// 判断是否在主界面的函数
|
||||
const isInMainUI = () => {
|
||||
@@ -42,5 +43,7 @@ async function toMainUi() {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function main() {
|
||||
await campaignAreaUtil.campaignAreaMain()
|
||||
await toMainUi()
|
||||
await activityUtil.activityMain()
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "活动期限通知器",
|
||||
"version": "0.0.1",
|
||||
"name": "活动期限/周本通知器",
|
||||
"version": "0.0.2",
|
||||
"description": "",
|
||||
"settings_ui": "settings.json",
|
||||
"main": "main.js",
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
"type": "input-text",
|
||||
"label": "活动名称(使用|分割)<可不填 默认推送所有有剩余时间的活动>"
|
||||
},
|
||||
{
|
||||
"name": "blackActivityNameList",
|
||||
"type": "input-text",
|
||||
"label": "黑名单活动名称(使用|分割)<可不填,默认没有不推送的活动>"
|
||||
},
|
||||
{
|
||||
"name": "notifyHoursThreshold",
|
||||
"type": "input-text",
|
||||
@@ -21,5 +26,21 @@
|
||||
"type": "input-text",
|
||||
"label": "打开活动页面按键(不填,默认:F5)",
|
||||
"default": "F5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "campaignAreaReminderDay",
|
||||
"type": "select",
|
||||
"label": "周本提醒日(0-6,0=周日,1=周一,2=周二,3=周三,4=周四,5=周五,6=周六)",
|
||||
"options": [
|
||||
"0","1","2","3","4","5","6"
|
||||
],
|
||||
"default": "0"
|
||||
},
|
||||
{
|
||||
"name": "campaignAreaKey",
|
||||
"type": "input-text",
|
||||
"label": "打开冒险之证按键(不填,默认:F1)",
|
||||
"default": "F1"
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
@@ -10,9 +10,10 @@ function settingsParseInt(str, defaultValue) {
|
||||
const config = {
|
||||
activityNameList: (settings.activityNameList ? settings.activityNameList.split('|') : []),
|
||||
activityKey: (settings.activityKey ? settings.activityKey : 'F5'),
|
||||
toTopCount: settingsParseInt(settings.toTopCount,10),//滑动到顶最大尝试次数
|
||||
scrollPageCount: settingsParseInt(settings.scrollPageCount,4),//滑动次数/页
|
||||
toTopCount: settingsParseInt(settings.toTopCount, 10),//滑动到顶最大尝试次数
|
||||
scrollPageCount: settingsParseInt(settings.scrollPageCount, 4),//滑动次数/页
|
||||
notifyHoursThreshold: settingsParseInt(settings.notifyHoursThreshold, 8760),//剩余时间阈值(默认 8760小时=365天)
|
||||
blackActivityNameList: (settings.blackActivityNameList ? settings.blackActivityNameList.split('|').filter(s => s.trim()) : []),//黑名单活动名称
|
||||
}
|
||||
const ocrRegionConfig = {
|
||||
activity: {x: 267, y: 197, width: 226, height: 616},//活动识别区域坐标和尺寸
|
||||
@@ -22,12 +23,37 @@ const xyConfig = {
|
||||
top: {x: 344, y: 273},
|
||||
bottom: {x: 342, y: 791},
|
||||
}
|
||||
|
||||
const DATE_ENUM = Object.freeze({
|
||||
YEAR: '年',
|
||||
MON: '月',
|
||||
WEEK: '周',
|
||||
DAY: '天',
|
||||
HOUR: '小时',
|
||||
// 添加反向映射(可选)
|
||||
fromValue(value) {
|
||||
return Object.keys(this).find(key => this[key] === value);
|
||||
}
|
||||
});
|
||||
const activityTermConversionMap = new Map([
|
||||
["砺行修远", {dateEnum: DATE_ENUM.WEEK}],
|
||||
]);
|
||||
const needOcrOtherMap = new Map([
|
||||
["砺行修远", ["本周进度", "完成进度"]],
|
||||
]);
|
||||
const genshinJson = {
|
||||
width: 1920,//genshin.width,
|
||||
height: 1080,//genshin.height,
|
||||
}
|
||||
|
||||
|
||||
function getDATE_ENUM(activityName) {
|
||||
for (let key of activityTermConversionMap.keys()) {
|
||||
if (activityName.includes(key))
|
||||
return activityTermConversionMap.get(key)
|
||||
}
|
||||
return {dateEnum: DATE_ENUM.HOUR}
|
||||
}
|
||||
|
||||
/**
|
||||
* 滚动页面的异步函数
|
||||
* @param {number} totalDistance - 总滚动距离
|
||||
@@ -263,6 +289,32 @@ function formatRemainingTime(timeText) {
|
||||
return `${totalHours}小时(${days > 0 ? days + '天' : ''}${hours > 0 ? hours + '小时' : ''})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将总小时数转换为周、天和小时的组合表示
|
||||
* @param {number} totalHours - 需要转换的总小时数
|
||||
* @returns {string} 返回格式为"X周 Y天 Z小时"的字符串
|
||||
*/
|
||||
function convertHoursToWeeksDaysHours(totalHours) {
|
||||
// 1周 = 168小时 (7 * 24)
|
||||
const hoursPerWeek = 168;
|
||||
const hoursPerDay = 24;
|
||||
|
||||
// 计算整周数 - 使用Math.floor获取完整的周数
|
||||
const weeks = Math.floor(totalHours / hoursPerWeek);
|
||||
|
||||
// 剩余小时 - 总小时数减去完整周数对应的小时数
|
||||
let remainingHours = totalHours % hoursPerWeek;
|
||||
|
||||
// 从剩余小时中计算天数 - 使用Math.floor获取完整的天数
|
||||
const days = Math.floor(remainingHours / hoursPerDay);
|
||||
|
||||
// 剩余的小时 - 剩余小时数减去完整天数对应的小时数
|
||||
const hours = remainingHours % hoursPerDay;
|
||||
|
||||
// 返回格式化后的字符串,包含周、天和小时
|
||||
return `${weeks}周 ${days}天 ${hours}小时`;
|
||||
}
|
||||
|
||||
/**
|
||||
* OCR识别活动剩余时间的函数
|
||||
* @param {Object} ocrRegion - OCR识别的区域坐标和尺寸
|
||||
@@ -378,6 +430,13 @@ async function activityMain() {
|
||||
}
|
||||
}
|
||||
|
||||
if (config.blackActivityNameList.length > 0) {
|
||||
const matched = config.blackActivityNameList.some(keyword => activityName.includes(keyword));
|
||||
if (matched) {
|
||||
continue; // 不关心的活动,跳过不点击
|
||||
}
|
||||
}
|
||||
|
||||
// 避免重复点击同一个活动(防止 OCR 误识别或页面抖动)
|
||||
if (activityMap.has(activityName)) {
|
||||
log.info(`活动已记录,跳过重复点击: ${activityName}`);
|
||||
@@ -391,9 +450,32 @@ async function activityMain() {
|
||||
if (totalHours <= 24 && totalHours > 0) {
|
||||
remainingTimeText += '<即将结束>'
|
||||
}
|
||||
let desc = ""
|
||||
|
||||
let dateEnum = getDATE_ENUM(activityName);
|
||||
log.debug(`activityName:{activityName},dateEnum:{dateenum.dateEnum}`, activityName, dateEnum.dateEnum)
|
||||
switch (dateEnum.dateEnum) {
|
||||
case DATE_ENUM.WEEK:
|
||||
desc += "|==>" + convertHoursToWeeksDaysHours(totalHours) + "<==|";
|
||||
break;
|
||||
case DATE_ENUM.HOUR:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (needOcrOtherMap.has(activityName)) {
|
||||
const keys = needOcrOtherMap.get(activityName);
|
||||
for (const key of keys) {
|
||||
let text = await OcrRemainingTime(activityName, key);
|
||||
if (text) {
|
||||
remainingTimeText += " [" + text + "] "
|
||||
}
|
||||
}
|
||||
}
|
||||
activityMap.set(activityName, {
|
||||
text: remainingTimeText,
|
||||
hours: totalHours
|
||||
hours: totalHours,
|
||||
desc: desc
|
||||
});
|
||||
log.info(`成功记录 → {activityName} {remainingTime} 共计: {hours} 小时`, activityName, remainingTimeText, totalHours);
|
||||
newActivityCountThisPage++;
|
||||
@@ -427,13 +509,13 @@ async function activityMain() {
|
||||
await sleep(ms);
|
||||
}
|
||||
let activityMapFilter = new Map();
|
||||
Array.from(activityMap.entries())
|
||||
Array.from(activityMap.entries())
|
||||
.filter(([name, info]) => info.hours <= config.notifyHoursThreshold)
|
||||
.forEach(([name, info]) => activityMapFilter.set(name, info));
|
||||
// 7. 全部扫描完毕,统一发送通知(只发一次!)
|
||||
if (activityMapFilter.size > 0) {
|
||||
log.info(`扫描完成,共记录 {activityMap.size} 个活动,即将发送通知`, activityMapFilter.size);
|
||||
await noticeUtil.sendNotice(activityMapFilter, `原神活动剩余时间提醒(仅显示剩余 ≤ ${config.notifyHoursThreshold} 小时的活动):`);
|
||||
await noticeUtil.sendNotice(activityMapFilter, `原神活动剩余时间提醒(仅显示剩余 ≤ ${config.notifyHoursThreshold} 小时的活动)${config.blackActivityNameList.length <= 0 ? "" : "|==>已开启黑名单:" + config.blackActivityNameList.join(",") + "<==|"}`);
|
||||
} else {
|
||||
log.warn("未识别到任何活动,未发送通知");
|
||||
}
|
||||
|
||||
121
repo/js/ActivitySwitchNotice/utils/campaignArea.js
Normal file
121
repo/js/ActivitySwitchNotice/utils/campaignArea.js
Normal file
@@ -0,0 +1,121 @@
|
||||
function settingsParseInt(str, defaultValue) {
|
||||
try {
|
||||
return str ? parseInt('' + str) : defaultValue;
|
||||
} catch (e) {
|
||||
log.warn(`settingsParseInt error:${e}`)
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
function settingsParseStr(str, defaultValue) {
|
||||
return '' + (str ? str : defaultValue);
|
||||
}
|
||||
|
||||
const config = {
|
||||
campaignAreaKey: settingsParseStr(settings.campaignAreaKey, 'F1'),
|
||||
campaignAreaReminderDay: settingsParseInt(settings.campaignAreaReminderDay, 0),//征讨领域提醒日
|
||||
}
|
||||
const ocrRegionConfig = {
|
||||
weeklyCount: {x: 809, y: 258, width: 277, height: 37},//征讨领域减半次数识别区域坐标和尺寸
|
||||
}
|
||||
const xyConfig = {
|
||||
campaignArea: {x: 493, y: 537},//征讨领域坐标
|
||||
secretRealm: {x: 304, y: 448},//秘境坐标
|
||||
}
|
||||
|
||||
/**
|
||||
* OCR识别周计数函数
|
||||
* @param {Object} ocrRegion - OCR识别区域配置,默认为ocrRegionConfig.weeklyCount
|
||||
* @returns {Object} 返回包含周计数信息的JSON对象,包含text、total和count属性
|
||||
* @throws {Error} 当OCR识别失败时抛出错误
|
||||
*/
|
||||
async function ocrWeeklyCount(ocrRegion = ocrRegionConfig.weeklyCount) {
|
||||
let captureRegion = captureGameRegion(); // 获取游戏区域截图
|
||||
const ocrObject = RecognitionObject.Ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height); // 创建OCR识别对象
|
||||
// ocrObject.threshold = 1.0;
|
||||
let res = captureRegion.find(ocrObject); // 在指定区域进行OCR识别
|
||||
captureRegion.dispose(); // 释放截图资源
|
||||
if (!res.isExist()) {
|
||||
log.error(`ocrWeeklyCount not found`) // 记录错误日志
|
||||
throw new Error(`ocrWeeklyCount not found`) // 抛出错误异常
|
||||
}
|
||||
let weekJson = { // 初始化周计数JSON对象
|
||||
text: res.text,
|
||||
total: 3,
|
||||
count: 3,
|
||||
}
|
||||
let weekCountText = res.text // 获取OCR识别的文本结果
|
||||
let result = weekCountText.match(/[0-9/]+/g)?.join('') || ''; // 使用正则表达式提取数字和斜杠
|
||||
|
||||
log.debug(`识别结果:{weekCountText}`, weekCountText) // 记录原始识别结果
|
||||
log.debug(`处理结果:{result}`, result) // 记录处理后的结果
|
||||
const numbers = result.split('/').map((item) => parseInt(item)); // 分割字符串并转换为数字数组
|
||||
weekJson.total = numbers[1] // 设置总数
|
||||
weekJson.count = numbers[0] // 设置当前计数
|
||||
log.debug(`Json:{weekJson}`, weekJson) // 记录最终JSON结果
|
||||
return weekJson // 返回处理后的周计数JSON对象
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期的星期信息
|
||||
* @returns {Object} 返回包含星期数字和星期名称的对象
|
||||
*/
|
||||
async function getDayOfWeek() {
|
||||
// 获取当前日期对象
|
||||
const today = new Date();
|
||||
// 获取当前日期是星期几(0代表星期日,1代表星期一,以此类推)
|
||||
const day = today.getDay();
|
||||
// 创建包含星期名称的数组
|
||||
const weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
||||
let weekDay = `${weekDays[day]}`;
|
||||
|
||||
log.debug(`今天是[{day}]`, day)
|
||||
log.debug(`今天是[{weekDays}]`, weekDay)
|
||||
// 返回包含星期数字和对应星期名称的对象
|
||||
return {
|
||||
day: day,
|
||||
dayOfWeek: weekDay
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行秘境征讨剩余次数提醒的主函数
|
||||
* 该函数会在每周日执行,检查秘境征讨的剩余次数并发送提醒
|
||||
*/
|
||||
async function campaignAreaMain() {
|
||||
// 获取当前星期信息
|
||||
let dayOfWeek = await getDayOfWeek();
|
||||
// 如果不是周日(0代表周日),则直接返回
|
||||
if (dayOfWeek.day != config.campaignAreaReminderDay) {
|
||||
log.info(`[{dayOfWeek.dayOfWeek}],跳过执行秘境征讨剩余次数提醒`, dayOfWeek.dayOfWeek)
|
||||
return
|
||||
}
|
||||
// 记录开始执行秘境征讨提醒的日志
|
||||
log.info(`[{dayOfWeek.dayOfWeek}],开始执行秘境征讨剩余次数提醒`, dayOfWeek.dayOfWeek)
|
||||
// 设置操作间隔时间(毫秒)
|
||||
let ms = 600
|
||||
// 等待一段时间
|
||||
await sleep(ms)
|
||||
// 按下配置的热键
|
||||
await keyPress(config.campaignAreaKey)
|
||||
await sleep(ms * 2)
|
||||
// 点击秘境入口坐标
|
||||
await click(xyConfig.secretRealm.x, xyConfig.secretRealm.y)
|
||||
await sleep(ms * 2)
|
||||
// 点击秘境征讨坐标
|
||||
await click(xyConfig.campaignArea.x, xyConfig.campaignArea.y)
|
||||
await sleep(ms * 2)
|
||||
// 使用OCR识别本周秘境征讨剩余次数
|
||||
let weekJson = await ocrWeeklyCount();
|
||||
|
||||
// 如果有剩余次数,则记录日志并发送通知
|
||||
if (weekJson.count > 0) {
|
||||
log.info(`本周剩余消耗减半次数:${weekJson.count}`)
|
||||
await noticeUtil.send(`>|本周剩余消耗减半次数:${weekJson.count}`, '秘境征讨')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.campaignAreaUtil = {
|
||||
campaignAreaMain,
|
||||
}
|
||||
@@ -14,14 +14,36 @@ async function sendNotice(map, title, noNotice) {
|
||||
const sortedEntries = Array.from(map.entries())
|
||||
.sort((a, b) => a[1].hours - b[1].hours);
|
||||
|
||||
let noticeText = title ? title + "\n" : "\n"
|
||||
let noticeText = title ? title + "\n======\n" : "\n"
|
||||
for (const [name, info] of sortedEntries) {
|
||||
noticeText += `> ${name} ${info.text}<还剩 ${info.hours} 小时>\n`;
|
||||
noticeText += `> ${name} ${info.text} (还剩 ${info.hours} 小时) ${info.desc}\n----\n`;
|
||||
}
|
||||
// 发送通知
|
||||
notification.send(noticeText)
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步发送通知的函数
|
||||
* @param {string} noticeText - 通知内容文本
|
||||
* @param {string} title - 通知标题
|
||||
* @param {boolean} noNotice - 是否不发送通知的标志
|
||||
*/
|
||||
async function send(noticeText, title, noNotice) {
|
||||
// 检查是否有通知内容且设置了不发送通知的标志
|
||||
if (noticeText&&noNotice) {
|
||||
log.info(`无通知内容`) // 记录日志信息
|
||||
return // 直接返回,不执行后续操作
|
||||
}
|
||||
// 构建通知文本,如果有标题则先添加标题
|
||||
let text = title ? title + "\n======\n" : "\n"
|
||||
// 添加通知内容
|
||||
text += noticeText
|
||||
// 发送通知
|
||||
notification.send(text)
|
||||
|
||||
}
|
||||
|
||||
this.noticeUtil = {
|
||||
sendNotice,
|
||||
send,
|
||||
}
|
||||
Reference in New Issue
Block a user