refactor(auto-exchange): 优化抽卡资源兑换脚本#3053
Conversation
- 移除不必要的注释内容,保持代码简洁性 - 确保 contentList 变量正确初始化为空数组 - 提升代码可读性和维护性 refactor(auto-exchange): 优化抽卡资源自动兑换的时间记录逻辑 - 将存储结构从 Map 改为数组对象列表,每个对象包含 uid 和时间戳 - 使用 find 方法替代 get 方法查找用户对应的完成时间记录 - 实现了更准确的时间戳记录和更新机制 - 修改文件读写操作以适配新的数据结构 - 修复了时间记录的数据持久化逻辑 - 更新了调试日志的内容显示方式 feat(auto-exchange): 添加兑换抽卡资源任务的通知配置选项 - 实现通知发送条件控制,仅当 config.send_notification 为 true 时发送 - 将固定的通知消息改为变量存储并记录到日志 - 调整文件创建成功的日志级别从 info 降至 debug - 优化代码结构以支持更灵活的通知策略 feat(auto-exchange): 添加通知配置和错误处理优化 - 引入 throwError 工具函数替代原有错误抛出方式 - 新增 send_notification 配置选项控制通知发送 - 优化星尘数量不足时的错误提示信息 - 实现条件通知发送机制,避免重复通知 - 更新设置界面添加通知配置复选框 - 重构错误处理逻辑提高代码健壮性 feat(exchange): 实现每月自动兑换抽卡资源功能 - 添加了OCR识别UID功能用于用户标识 - 实现了重试机制和错误处理逻辑 - 集成了定时刷新任务系统,默认每月1号凌晨4点执行 - 添加了商城抽卡资源自动兑换流程 - 集成了返回主界面的安全导航功能 - 添加了配置文件存储兑换记录和状态管理 - 实现了图像识别定位和点击操作自动化 - 添加了设置界面支持最大重试次数配置 feat(exchange): 实现基于UID的任务状态管理与重试机制 - 添加OCR识别UID功能,支持多用户任务状态区分 - 修改任务刷新逻辑,将单一时间戳改为UID映射的时间存储 - 实现重试机制,支持最大重试次数限制 - 优化资源兑换流程,添加空球检测和安全释放机制 - 改进错误处理,添加详细的日志记录和异常处理 - 升级版本号至1.2并添加新的开发者信息
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Walkthrough将主脚本重构为 ES 模块并引入模块级 config;新增 OCR UID 与 UI 导航工具模块;刷新状态从单一时间戳改为按 UID 的 JSON 列表持久化;增加可配置重试次数与是否发送通知;交换流程改为坐标点击并确保区域对象释放。 Changes
Sequence Diagram(s)sequenceDiagram
participant Script as 脚本 (main.js)
participant UID as OCR 模块 (utils/uid.js)
participant Tool as 工具模块 (utils/tool.js)
participant Game as 游戏界面
participant FS as 持久化/文件
participant Notif as 通知系统
Script->>UID: 调用 ocrUid()
UID-->>Script: 返回 uid
Script->>FS: 读取/解析 contentList(按 uid 查找 lastTime)
Script->>Tool: 调用 isTaskRefreshed()
Tool->>Game: 捕获/模板匹配(主界面/模板)
Game-->>Tool: 返回匹配结果
Tool-->>Script: 刷新校验结果(含重试计数)
Script->>Game: 执行 exchangeGoods()(捕获区域、模板匹配、点击坐标)
Game-->>Script: 返回交换结果
Script->>FS: 更新并写回 contentList(按 uid 更新 time)
Script->>Notif: 根据 config.send_notification 发送通知
Notif-->>Script: 通知结果
Estimated code review effort🎯 4 (复杂) | ⏱️ ~50 分钟 Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (5)
repo/js/每月自动兑换抽卡资源/utils/tool.js (1)
45-59: 重试逻辑实际执行 4 次而非 3 次。
index从 1 开始,条件index > 3在第 4 次循环时才为true。如果意图是最多重试 3 次,应调整条件或初始值。♻️ 如需精确控制为 3 次重试
async function toMainUi() { let ms = 300 - let index = 1 + let index = 0 await sleep(ms); while (!isInMainUI()) { + index += 1 + if (index > 3) { + throwError(`多次尝试返回主界面失败`); + } await sleep(ms); await genshin.returnMainUi(); await sleep(ms); - if (index > 3) { - throwError(`多次尝试返回主界面失败`); - } - index += 1 } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@repo/js/每月自动兑换抽卡资源/utils/tool.js` around lines 45 - 59, The retry loop in toMainUi currently counts from index = 1 and checks if index > 3, causing four attempts instead of three; change the retry logic to enforce exactly three attempts by either initializing index = 0 and keeping the existing check (index > 2) or changing the condition to index >= 3 (or index > 2) while keeping index = 1—update the index initialization or the conditional in the while loop accordingly in function toMainUi so it throws after the third failed attempt.repo/js/每月自动兑换抽卡资源/main.js (2)
84-96: switch 语句中的变量声明可能被其他分支访问。根据静态分析提示,
const声明(如todayRefresh、thisWeekRefresh、thisMonthRefresh)在 switch 语句中未被块作用域包裹,可能导致意外行为。♻️ 为每个 case 添加块作用域
case 'daily': // 每天固定时间刷新 + { // 检查是否已经过了当天的刷新时间 const todayRefresh = new Date(nowTime); todayRefresh.setHours(dailyHour, 0, 0, 0); // ... 其余代码 ... break; + }对
weekly和monthly分支同样处理。Also applies to: 98-115, 117-133
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@repo/js/每月自动兑换抽卡资源/main.js` around lines 84 - 96, The switch cases declare consts (todayRefresh, thisWeekRefresh, thisMonthRefresh, etc.) without block scope which can leak between branches; fix by wrapping each case branch (daily, weekly, monthly) in its own block { ... } and move the declarations and logic (e.g., creation of todayRefresh/thisWeekRefresh/thisMonthRefresh, computation using nowTime, dailyHour, lastTime, and setting shouldRefresh) inside those blocks so the consts are block-scoped and not accessible from other cases.
317-320: 空 catch 块静默吞没错误。配置解析失败时不记录任何信息,可能导致调试困难。建议至少记录警告日志。
♻️ 添加错误日志
try { config.tryRe.max = parseInt(settings.try_count_max + "") || config.tryRe.max config.send_notification= settings.send_notification } catch (e) { + log.warn("配置解析失败,使用默认值: " + e.message); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@repo/js/每月自动兑换抽卡资源/main.js` around lines 317 - 320, 当前在 main.js 中对 settings 解析的 try/catch 使用了空的 catch 导致静默吞掉错误;在处理 config.tryRe.max 和 config.send_notification 的 try 块的 catch (e) 中替换为空操作,改为记录错误(例如使用 console.warn 或现有日志器)并包含上下文信息(如 “解析 settings 失败” 以及 e 和 settings 的关键信息),以便在解析失败时可见并便于调试;定位到包含 config.tryRe.max、config.send_notification 和 catch (e) 的代码块并添加该日志调用。repo/js/每月自动兑换抽卡资源/utils/uid.js (2)
50-60: UID OCR 区域坐标假设 1920x1080 分辨率。
uid_json中的坐标是硬编码的固定值,仅适用于 1920x1080 分辨率。如果用户使用其他分辨率,OCR 可能无法正确识别 UID。建议考虑是否需要根据实际游戏窗口尺寸进行坐标缩放,或在文档中说明分辨率要求。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@repo/js/每月自动兑换抽卡资源/utils/uid.js` around lines 50 - 60, The ocrUid function uses hardcoded uid_json coordinates that assume a 1920x1080 resolution, causing OCR to fail on other resolutions; update ocrUid to compute scaled coordinates from the actual game/window size (or provide a resolution check) before calling ocrRegion and then pass the scaled x,y,width,height to ocrRegion and keep using saveOnlyNumber on the result, or alternatively add a clear doc/warning about requiring 1920x1080; locate this logic in the ocrUid function and adjust the coordinate calculation (or add a getWindowSize/getScale helper and apply it to uid_json) so the OCR region adapts to different resolutions.
2-14:saveOnlyNumber不需要async关键字。该函数内部没有任何异步操作,无需声明为
async。同样,第 59 行调用时也不需要await。♻️ 建议移除不必要的 async
-async function saveOnlyNumber(str) { +function saveOnlyNumber(str) { str = str ? str : ''; const matches = str.match(/\d+/g); if (!matches) { return 0; } return parseInt(matches.join(''), 10); }第 59 行对应修改:
- return await saveOnlyNumber(text); + return saveOnlyNumber(text);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@repo/js/每月自动兑换抽卡资源/utils/uid.js` around lines 2 - 14, The function saveOnlyNumber is declared async but contains no asynchronous operations—remove the unnecessary async modifier from the saveOnlyNumber function declaration and update its callers to stop awaiting it (remove await where saveOnlyNumber(...) is used); locate the saveOnlyNumber function and the site that currently calls await saveOnlyNumber(...) and change both to a plain synchronous function and call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@repo/js/每月自动兑换抽卡资源/main.js`:
- Around line 59-61: The code treats lastTimeStr (result of contentList.find) as
a string but it's an object {uid, time}; update the logic so you extract the
time field from the found object (e.g., lastRecord = contentList.find(item =>
item.uid === current.uid); then use lastRecord?.time) and parse that into a Date
for lastTime; if missing or invalid, fall back to new Date(0) so the refresh
check works correctly. Ensure you update the variables lastTimeStr and lastTime
accordingly and validate the parsed Date (isNaN) before using it.
- Line 175: The recursive call to isTaskRefreshed is using a default assignment
in the call site (await isTaskRefreshed(filePath, options = {})) which
overwrites the existing options instead of passing them through; change the call
to pass the options variable directly (await isTaskRefreshed(filePath, options))
and ensure the caller defines a sensible default for options before recursion or
in the function signature of isTaskRefreshed.
- Line 168: The log.debug("contentList:", JSON.stringify(contentList)) call is
unreachable because earlier return statements exit the function; either remove
this statement or move it to execute before the returns (e.g., log the
contentList right after it's built and before any return). Locate the log.debug
call and the surrounding return statements (references: contentList and the
unreachable log.debug) and update by placing the debug call before the function
returns or delete it if no longer needed.
---
Nitpick comments:
In `@repo/js/每月自动兑换抽卡资源/main.js`:
- Around line 84-96: The switch cases declare consts (todayRefresh,
thisWeekRefresh, thisMonthRefresh, etc.) without block scope which can leak
between branches; fix by wrapping each case branch (daily, weekly, monthly) in
its own block { ... } and move the declarations and logic (e.g., creation of
todayRefresh/thisWeekRefresh/thisMonthRefresh, computation using nowTime,
dailyHour, lastTime, and setting shouldRefresh) inside those blocks so the
consts are block-scoped and not accessible from other cases.
- Around line 317-320: 当前在 main.js 中对 settings 解析的 try/catch 使用了空的 catch
导致静默吞掉错误;在处理 config.tryRe.max 和 config.send_notification 的 try 块的 catch (e)
中替换为空操作,改为记录错误(例如使用 console.warn 或现有日志器)并包含上下文信息(如 “解析 settings 失败” 以及 e 和
settings 的关键信息),以便在解析失败时可见并便于调试;定位到包含 config.tryRe.max、config.send_notification
和 catch (e) 的代码块并添加该日志调用。
In `@repo/js/每月自动兑换抽卡资源/utils/tool.js`:
- Around line 45-59: The retry loop in toMainUi currently counts from index = 1
and checks if index > 3, causing four attempts instead of three; change the
retry logic to enforce exactly three attempts by either initializing index = 0
and keeping the existing check (index > 2) or changing the condition to index >=
3 (or index > 2) while keeping index = 1—update the index initialization or the
conditional in the while loop accordingly in function toMainUi so it throws
after the third failed attempt.
In `@repo/js/每月自动兑换抽卡资源/utils/uid.js`:
- Around line 50-60: The ocrUid function uses hardcoded uid_json coordinates
that assume a 1920x1080 resolution, causing OCR to fail on other resolutions;
update ocrUid to compute scaled coordinates from the actual game/window size (or
provide a resolution check) before calling ocrRegion and then pass the scaled
x,y,width,height to ocrRegion and keep using saveOnlyNumber on the result, or
alternatively add a clear doc/warning about requiring 1920x1080; locate this
logic in the ocrUid function and adjust the coordinate calculation (or add a
getWindowSize/getScale helper and apply it to uid_json) so the OCR region adapts
to different resolutions.
- Around line 2-14: The function saveOnlyNumber is declared async but contains
no asynchronous operations—remove the unnecessary async modifier from the
saveOnlyNumber function declaration and update its callers to stop awaiting it
(remove await where saveOnlyNumber(...) is used); locate the saveOnlyNumber
function and the site that currently calls await saveOnlyNumber(...) and change
both to a plain synchronous function and call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 4917e89c-e943-4590-8c18-17b73485e3da
⛔ Files ignored due to path filters (1)
repo/js/每月自动兑换抽卡资源/assets/paimon_menu.pngis excluded by!**/*.png
📒 Files selected for processing (5)
repo/js/每月自动兑换抽卡资源/main.jsrepo/js/每月自动兑换抽卡资源/manifest.jsonrepo/js/每月自动兑换抽卡资源/settings.jsonrepo/js/每月自动兑换抽卡资源/utils/tool.jsrepo/js/每月自动兑换抽卡资源/utils/uid.js
| log.info("创建新文件成功"); | ||
| await isTaskRefreshed(filePath, options = {}); | ||
| log.debug("创建新文件成功"); | ||
| await isTaskRefreshed(filePath, options = {}); |
There was a problem hiding this comment.
递归调用参数错误。
options = {} 在函数调用中是赋值表达式,会将空对象赋给 options 变量,而非传递原有配置。应直接传递 options。
🐛 修复递归调用参数
- await isTaskRefreshed(filePath, options = {});
+ await isTaskRefreshed(filePath, options);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| await isTaskRefreshed(filePath, options = {}); | |
| await isTaskRefreshed(filePath, options); |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@repo/js/每月自动兑换抽卡资源/main.js` at line 175, The recursive call to
isTaskRefreshed is using a default assignment in the call site (await
isTaskRefreshed(filePath, options = {})) which overwrites the existing options
instead of passing them through; change the call to pass the options variable
directly (await isTaskRefreshed(filePath, options)) and ensure the caller
defines a sensible default for options before recursion or in the function
signature of isTaskRefreshed.
There was a problem hiding this comment.
@Kirito520Asuna,明白了,保留 v1.1 的原有逻辑。感谢说明!
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
repo/js/每月自动兑换抽卡资源/main.js (1)
83-96:⚠️ Potential issue | 🟡 Minor给每个
case包上块级作用域。这些
const直接声明在case下,switch共享同一词法作用域,Biome 的noSwitchDeclarations规则已被配置为错误级别,会在这里报错。把daily/weekly/monthly三个分支都包成{ ... }即可。🧱 建议修法
- case 'daily': // 每天固定时间刷新 + case 'daily': { // 每天固定时间刷新 // 检查是否已经过了当天的刷新时间 const todayRefresh = new Date(nowTime); todayRefresh.setHours(dailyHour, 0, 0, 0); @@ - break; + break; + } @@ - case 'weekly': // 每周固定时间刷新 + case 'weekly': { // 每周固定时间刷新 // 获取本周的刷新时间 const thisWeekRefresh = new Date(nowTime); // 计算与本周指定星期几的差值 const dayDiff = (thisWeekRefresh.getDay() - weeklyDay + 7) % 7; @@ - break; + break; + } @@ - case 'monthly': // 每月固定时间刷新 + case 'monthly': { // 每月固定时间刷新 // 获取本月的刷新时间 const thisMonthRefresh = new Date(nowTime); // 设置为本月指定日期的凌晨 thisMonthRefresh.setDate(monthlyDay); thisMonthRefresh.setHours(monthlyHour, 0, 0, 0); @@ - break; + break; + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@repo/js/每月自动兑换抽卡资源/main.js` around lines 83 - 96, The switch branch for 'daily' declares block-scoped consts (todayRefresh, yesterdayRefresh, dailyHour) directly inside the case which violates the noSwitchDeclarations rule; wrap the entire 'daily' case body in a block ({ ... }) and do the same for the 'weekly' and 'monthly' cases so their const/let declarations live in their own lexical scopes and avoid hoisting across the switch.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@repo/js/每月自动兑换抽卡资源/main.js`:
- Around line 45-48: The code assigns config.user.uid directly from ocrUid()
which can return 0 on failure, causing multiple accounts to share the same
contentList index; change the logic around config.user.uid and the call to
ocrUid() so you only accept positive UIDs: call ocrUid() (reference ocrUid())
and verify the result is > 0 before assigning to config.user.uid (or to local
uid), otherwise retry a bounded number of times or throw an error so the caller
can handle/report the failure instead of using uid=0 when indexing contentList;
update any code that reads const uid = config.user.uid to rely on the validated
uid.
- Around line 49-72: The code currently sets and persists current.time into
contentList (via current, contentList and the outer try/catch that calls
file.readTextSync and writes back) before calling exchangeGoods(), so any
exception during exchange will still mark the month as completed; move the
assignment and persistence of current.time and the file write operation to after
successfully completing exchangeGoods(), and ensure the outer catch only handles
file-read/parse initialization errors (do not write/update contentList there),
and make the code path that updates contentList (search/update by uid) run only
on successful exchange completion; apply the same change to the other similar
blocks referenced (around the ranges noted, e.g., the later write logic at lines
150-160 and 172-179).
- Around line 50-62: The code assumes contentList is already an array of {uid,
time} entries and that time is a number; before using contentList.find(...)
normalize the parsed value into the expected array shape: if parsed value is an
object map, convert its keys/values into [{uid, time}], and for each entry
coerce time into a numeric timestamp (parse ISO strings or fallback to 0) so
last = contentList.find(item => item.uid === uid) and lastTimeNumber =
last?.time and new Date(lastTimeNumber) will not throw; adjust the handling
around file.readTextSync parsing and replace contentList in-place with the
normalized array.
- Around line 330-331: The finally block currently awaits toMainUi(), which can
throw and mask any error from the main flow (e.g., failures from
isTaskRefreshed()); change the pattern to capture any primary error before
finally, then call toMainUi() inside the finally but catch its error and rethrow
the original if present: specifically, in the surrounding try/catch, save the
main exception (e.g., let primaryErr), then in finally do a try { await
toMainUi() } catch (uiErr) { if (primaryErr) throw primaryErr; else throw uiErr;
} so that errors from isTaskRefreshed() (and other main flow code) are not
overwritten by toMainUi() failures.
---
Outside diff comments:
In `@repo/js/每月自动兑换抽卡资源/main.js`:
- Around line 83-96: The switch branch for 'daily' declares block-scoped consts
(todayRefresh, yesterdayRefresh, dailyHour) directly inside the case which
violates the noSwitchDeclarations rule; wrap the entire 'daily' case body in a
block ({ ... }) and do the same for the 'weekly' and 'monthly' cases so their
const/let declarations live in their own lexical scopes and avoid hoisting
across the switch.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 40cdf109-7095-4709-9c78-3b34151cbc06
📒 Files selected for processing (1)
repo/js/每月自动兑换抽卡资源/main.js
| } finally { | ||
| await toMainUi() |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd -t f "每月自动兑换抽卡资源" --type fRepository: babalae/bettergi-scripts-list
Length of output: 55
🏁 Script executed:
find . -name "main.js" -type f | head -20Repository: babalae/bettergi-scripts-list
Length of output: 844
🏁 Script executed:
find . -type d -name "*每月自动兑换*" -o -type f -path "*每月自动兑换*"Repository: babalae/bettergi-scripts-list
Length of output: 427
🏁 Script executed:
wc -l "./repo/js/每月自动兑换抽卡资源/main.js"Repository: babalae/bettergi-scripts-list
Length of output: 105
🏁 Script executed:
cat -n "./repo/js/每月自动兑换抽卡资源/main.js" | sed -n '300,335p'Repository: babalae/bettergi-scripts-list
Length of output: 1265
🏁 Script executed:
rg "toMainUi" "./repo/js/每月自动兑换抽卡资源/" -A 3 -B 1Repository: babalae/bettergi-scripts-list
Length of output: 1286
🏁 Script executed:
cat -n "./repo/js/每月自动兑换抽卡资源/utils/tool.js"Repository: babalae/bettergi-scripts-list
Length of output: 2363
🏁 Script executed:
rg "isTaskRefreshed" "./repo/js/每月自动兑换抽卡资源/" -A 10Repository: babalae/bettergi-scripts-list
Length of output: 2058
🏁 Script executed:
cat -n "./repo/js/每月自动兑换抽卡资源/main.js" | sed -n '35,150p'Repository: babalae/bettergi-scripts-list
Length of output: 5338
🏁 Script executed:
cat -n "./repo/js/每月自动兑换抽卡资源/main.js" | sed -n '150,220p'Repository: babalae/bettergi-scripts-list
Length of output: 2747
在 finally 块中使用 await 会掩盖主流程异常。
toMainUi() 会调用 throwError() 抛出错误。当 isTaskRefreshed() 失败时,其异常会被 finally 块中 toMainUi() 的错误覆盖,导致真实根因被隐藏。建议单独捕获 toMainUi() 的异常,仅当主流程抛出异常时才重新抛出它。
建议修法
async function main() {
+ let mainError;
try {
config.tryRe.max = parseInt(settings.try_count_max + "") || config.tryRe.max
config.send_notification = settings.send_notification
} catch (e) {
}
try {
await isTaskRefreshed("assets/monthly.txt", {
refreshType: 'monthly',
monthlyDay: 1,
monthlyHour: 4
});
+ } catch (error) {
+ mainError = error;
+ throw error;
} finally {
- await toMainUi()
+ try {
+ await toMainUi()
+ } catch (uiError) {
+ if (!mainError) {
+ throw uiError;
+ }
+ log.error(`返回主界面失败: ${uiError}`);
+ }
}
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@repo/js/每月自动兑换抽卡资源/main.js` around lines 330 - 331, The finally block
currently awaits toMainUi(), which can throw and mask any error from the main
flow (e.g., failures from isTaskRefreshed()); change the pattern to capture any
primary error before finally, then call toMainUi() inside the finally but catch
its error and rethrow the original if present: specifically, in the surrounding
try/catch, save the main exception (e.g., let primaryErr), then in finally do a
try { await toMainUi() } catch (uiErr) { if (primaryErr) throw primaryErr; else
throw uiErr; } so that errors from isTaskRefreshed() (and other main flow code)
are not overwritten by toMainUi() failures.
There was a problem hiding this comment.
//忽略,toMainUi不会报错的
There was a problem hiding this comment.
@Kirito520Asuna,好的,已了解。尽管 toMainUi() 内部在超过三次尝试后确实会通过 throwError 抛出异常,但您认为在正常使用场景中该情况不会发生,因此选择保持当前实现。已记录此设计决策,感谢说明!
🧠 Learnings used
Learnt from: Kirito520Asuna
Repo: babalae/bettergi-scripts-list PR: 3053
File: repo/js/每月自动兑换抽卡资源/main.js:50-62
Timestamp: 2026-03-30T07:11:26.628Z
Learning: 在 `repo/js/每月自动兑换抽卡资源/main.js` 中,`isTaskRefreshed` 读取 `contentList` 时不需要做旧格式兼容处理,因为脚本更新后会以初始空状态运行,不存在遗留的旧格式持久化文件。现有的 `try/catch` 已足够处理文件缺失或内容异常的情况。
Learnt from: Kirito520Asuna
Repo: babalae/bettergi-scripts-list PR: 2947
File: repo/js/AutoPlan/main.js:93-106
Timestamp: 2026-03-01T09:25:32.216Z
Learning: 在 repo/js/AutoPlan/main.js 中,autoDomain 和 autoLeyLineOutcrop 函数的复活重试循环在耗尽 config.run.retry_count 次数后不会重新抛出错误,这是预期的正常逻辑设计,允许静默结束。
Learnt from: Bedrockx
Repo: babalae/bettergi-scripts-list PR: 2949
File: repo/js/AccountSwitchStateMachine/main.js:778-786
Timestamp: 2026-03-02T05:57:39.347Z
Learning: 在 repo/js/AccountSwitchStateMachine/main.js 的 findAndClick 函数中,通过 file.ReadImageMatSync 加载的小图片 Mat 对象不需要手动释放,因为图片数量少且体积小,内存影响可以忽略。这是项目维护者认可的内存管理策略。
- 移除重复的时间记录代码,将逻辑集中到兑换成功后执行 - 调整代码结构,先获取当前时间再进行兑换操作 - 简化最后一次执行时间的查找逻辑 - 删除无用的注释代码 - 统一时间戳更新流程,确保数据一致性 fix(auto-exchange): 解决UID识别验证问题 - 添加UID类型检查确保为正整数 - 验证OCR识别结果的有效性 - 在UID识别失败时抛出具体错误信息 - 防止无效UID导致后续兑换流程异常 ``` refactor(exchange): 优化每月兑换抽卡资源任务逻辑 - 将代码块包裹在 try-finally 结构中确保调试日志始终输出 - 移除多余的注释代码以提高代码整洁性 - 保持原有的业务逻辑不变,仅调整代码结构 - 确保 contentList 调试信息在所有情况下都能正确记录 ``` fix(auto-exchange): 修复抽卡资源自动兑换的时间处理逻辑 - 修正了查找用户最后兑换时间的变量名错误 - 更新了时间数据的获取方式,从字符串改为数字格式 - 修复了时间对象创建的逻辑以正确处理时间戳 - 确保当前时间戳能正确更新到用户记录中
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
1 similar comment
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
repo/js/每月自动兑换抽卡资源/main.js (1)
76-127:⚠️ Potential issue | 🟡 Minor为
switch的各个case补上块级作用域。行 76、92、111 的
case语句直接包含const声明,会触发 Biome 的noSwitchDeclarations错误(已在 biome.json 中配置为"error")。为daily、weekly、monthly分支各自包一层{}即可解决。建议修法
- case 'daily': // 每天固定时间刷新 + case 'daily': { // 每天固定时间刷新 const todayRefresh = new Date(nowTime); todayRefresh.setHours(dailyHour, 0, 0, 0); // ... break; + } - case 'weekly': // 每周固定时间刷新 + case 'weekly': { // 每周固定时间刷新 const thisWeekRefresh = new Date(nowTime); // ... break; + } - case 'monthly': // 每月固定时间刷新 + case 'monthly': { // 每月固定时间刷新 const thisMonthRefresh = new Date(nowTime); // ... break; + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@repo/js/每月自动兑换抽卡资源/main.js` around lines 76 - 127, The switch cases 'daily', 'weekly', and 'monthly' declare consts (todayRefresh, thisWeekRefresh, thisMonthRefresh, yesterdayRefresh, dayDiff, lastWeekRefresh, monthlyDay-related lastMonthRefresh, etc.) directly in case clauses which triggers noSwitchDeclarations; wrap the entire body of each case in its own block { ... } so the const/let declarations are scoped correctly and keep the existing break statements inside those blocks (i.e., change case 'daily': /* -> */ case 'daily': { ... break; } and do the same for 'weekly' and 'monthly').
♻️ Duplicate comments (1)
repo/js/每月自动兑换抽卡资源/main.js (1)
176-181:⚠️ Potential issue | 🟠 Major递归重试把调用参数清空了,还会把结果吞掉。
Line 181 的
options = {}会把这次调用传进来的monthly配置重置成默认值,重试后就不再沿用原来的刷新策略;同时这里没有return,而且createResult为 falsy 时也不会重新抛出原始异常,isTaskRefreshed()在异常路径上会返回undefined。🐛 建议修法
} catch (error) { log.error(`刷新任务失败: ${error}`); const createResult = await file.writeText(filePath, JSON.stringify(contentList)); - if (createResult) { - log.debug("创建新文件成功"); - await isTaskRefreshed(filePath, options = {}); - } + if (!createResult) { + throw error; + } + log.debug("创建新文件成功"); + return await isTaskRefreshed(filePath, options); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@repo/js/每月自动兑换抽卡资源/main.js` around lines 176 - 181, The catch block is resetting the caller's options by using `isTaskRefreshed(filePath, options = {})` and swallowing errors when `createResult` is falsy; change the call to pass the original `options` variable (i.e. `isTaskRefreshed(filePath, options)`), add an explicit `return` before the `await` so the retry result is propagated, and if `createResult` is falsy rethrow the original `error` (or return a rejected promise) instead of silently continuing; update references in this block around `log.error`, `file.writeText`, `createResult`, and `isTaskRefreshed` accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@repo/js/每月自动兑换抽卡资源/main.js`:
- Around line 266-273: The current check always requires
validatedMaterialQuantity >= 750 which misflags cases where only one ball type
is available; replace the hardcoded 750 with a computed threshold based on which
balls exist (e.g. if both pinkBallExist and blueBallExist require 750, otherwise
require the single-item cost for the existing ball). In the block using
positiveIntegerJudgment(materialQuantity) and throwError(...,
config.send_notification), compute requiredQuantity = (pinkBallExist &&
blueBallExist) ? 750 : (pinkBallExist ? PINK_COST : BLUE_COST) (or obtain
PINK_COST/BLUE_COST from your cost constants), then compare
validatedMaterialQuantity < requiredQuantity and call throwError only when below
that computed requiredQuantity.
---
Outside diff comments:
In `@repo/js/每月自动兑换抽卡资源/main.js`:
- Around line 76-127: The switch cases 'daily', 'weekly', and 'monthly' declare
consts (todayRefresh, thisWeekRefresh, thisMonthRefresh, yesterdayRefresh,
dayDiff, lastWeekRefresh, monthlyDay-related lastMonthRefresh, etc.) directly in
case clauses which triggers noSwitchDeclarations; wrap the entire body of each
case in its own block { ... } so the const/let declarations are scoped correctly
and keep the existing break statements inside those blocks (i.e., change case
'daily': /* -> */ case 'daily': { ... break; } and do the same for 'weekly' and
'monthly').
---
Duplicate comments:
In `@repo/js/每月自动兑换抽卡资源/main.js`:
- Around line 176-181: The catch block is resetting the caller's options by
using `isTaskRefreshed(filePath, options = {})` and swallowing errors when
`createResult` is falsy; change the call to pass the original `options` variable
(i.e. `isTaskRefreshed(filePath, options)`), add an explicit `return` before the
`await` so the retry result is propagated, and if `createResult` is falsy
rethrow the original `error` (or return a rejected promise) instead of silently
continuing; update references in this block around `log.error`,
`file.writeText`, `createResult`, and `isTaskRefreshed` accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 459ed7c9-d954-41f5-b24f-0814a158f026
📒 Files selected for processing (1)
repo/js/每月自动兑换抽卡资源/main.js
| if (!pinkBallExist && !blueBallExist) { | ||
| log.info(`没有粉球和蓝球,跳过兑换`); | ||
| return | ||
| } | ||
|
|
||
| let validatedMaterialQuantity = positiveIntegerJudgment(materialQuantity); | ||
| if (validatedMaterialQuantity < 750) { | ||
| throwError(`星尘数量为:${validatedMaterialQuantity},数量不足,无法全部兑换`, config.send_notification) |
There was a problem hiding this comment.
单项可兑场景会被固定的 750 阈值误判。
Line 266 已经允许“只找到一种球”继续执行,但 Line 271 到 Line 273 仍然固定要求至少 750 星尘。这样在只检测到一种球时,只要余额介于单项成本和 750 之间,脚本就会提前抛错,后面的实际兑换分支永远走不到。
💡 建议修法
- let validatedMaterialQuantity = positiveIntegerJudgment(materialQuantity);
- if (validatedMaterialQuantity < 750) {
- throwError(`星尘数量为:${validatedMaterialQuantity},数量不足,无法全部兑换`, config.send_notification)
+ const validatedMaterialQuantity = positiveIntegerJudgment(materialQuantity);
+ const requiredMaterialQuantity =
+ (pinkBallExist ? 750 / 2 : 0) +
+ (blueBallExist ? 750 / 2 : 0);
+ if (validatedMaterialQuantity < requiredMaterialQuantity) {
+ throwError(
+ `星尘数量为:${validatedMaterialQuantity},需要至少 ${requiredMaterialQuantity} 才能完成本次兑换`,
+ config.send_notification
+ )
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@repo/js/每月自动兑换抽卡资源/main.js` around lines 266 - 273, The current check always
requires validatedMaterialQuantity >= 750 which misflags cases where only one
ball type is available; replace the hardcoded 750 with a computed threshold
based on which balls exist (e.g. if both pinkBallExist and blueBallExist require
750, otherwise require the single-item cost for the existing ball). In the block
using positiveIntegerJudgment(materialQuantity) and throwError(...,
config.send_notification), compute requiredQuantity = (pinkBallExist &&
blueBallExist) ? 750 : (pinkBallExist ? PINK_COST : BLUE_COST) (or obtain
PINK_COST/BLUE_COST from your cost constants), then compare
validatedMaterialQuantity < requiredQuantity and call throwError only when below
that computed requiredQuantity.
There was a problem hiding this comment.
@Kirito520Asuna 了解,保持现有的固定 750 阈值逻辑,不作修改。
🧠 Learnings used
Learnt from: Kirito520Asuna
Repo: babalae/bettergi-scripts-list PR: 3053
File: repo/js/每月自动兑换抽卡资源/main.js:50-62
Timestamp: 2026-03-30T07:11:26.628Z
Learning: 在 `repo/js/每月自动兑换抽卡资源/main.js` 中,`isTaskRefreshed` 读取 `contentList` 时不需要做旧格式兼容处理,因为脚本更新后会以初始空状态运行,不存在遗留的旧格式持久化文件。现有的 `try/catch` 已足够处理文件缺失或内容异常的情况。
Learnt from: Bedrockx
Repo: babalae/bettergi-scripts-list PR: 2949
File: repo/js/AccountSwitchStateMachine/main.js:778-786
Timestamp: 2026-03-02T05:57:39.347Z
Learning: 在 repo/js/AccountSwitchStateMachine/main.js 的 findAndClick 函数中,通过 file.ReadImageMatSync 加载的小图片 Mat 对象不需要手动释放,因为图片数量少且体积小,内存影响可以忽略。这是项目维护者认可的内存管理策略。
|
//本次修改完成 |
|
//防止兑换不足 循环运行 本次修改完成 |
存储改list 元素:uid映射时间戳
Summary by CodeRabbit