Repository navigation
refactor - #8
refactor#8
Conversation
ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (25)
📝 WalkthroughWalkthroughThe PR relocates configuration under ChangesConfiguration and runtime integration
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant ConfigUI
participant config.yml
participant weekly_timeouts.yml
ConfigUI->>config.yml: load and save script paths
ConfigUI->>weekly_timeouts.yml: load and save daily timeout values
sequenceDiagram
participant set_config
participant config.yml
participant GameConfig
set_config->>config.yml: resolve script configuration path
set_config->>GameConfig: load and update dungeon settings
set_config->>GameConfig: save changed configuration
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 11
🧹 Nitpick comments (3)
src/python_script/mute.py (1)
1-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
set_muteis duplicated verbatim inunmute.py.Both
mute.pyandunmute.pydefine an identicalset_mutefunction; the only difference is the argument passed in__main__. Extract the shared function into a common module (e.g.,audio_utils.py) and have both scripts import it.♻️ Suggested refactor
# src/python_script/audio_utils.py +from pycaw.pycaw import AudioUtilities + +def set_mute(mute_status): + devices = AudioUtilities.GetSpeakers() + interface = devices.EndpointVolume + interface.SetMute(mute_status, None) + print(f"系统已{'静音' if mute_status else '恢复声音'}") # src/python_script/mute.py -from pycaw.pycaw import AudioUtilities - -def set_mute(mute_status): - devices = AudioUtilities.GetSpeakers() - interface = devices.EndpointVolume - interface.SetMute(mute_status, None) - print(f"系统已{'静音' if mute_status else '恢复声音'}") - -if __name__ == "__main__": - set_mute(True) +from audio_utils import set_mute + +if __name__ == "__main__": + set_mute(True)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/python_script/mute.py` around lines 1 - 16, Extract the shared set_mute function from mute.py and unmute.py into a common audio_utils.py module, then import and reuse it from both scripts. Keep each script’s __main__ entry point responsible only for passing its appropriate mute status.src/python_script/shutdown.py (1)
64-70: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd error handling around the shutdown subprocess call.
If
subprocess.runfails (e.g., insufficient privileges,shutdownnot in PATH), the exception is unhandled and the user gets no feedback. The static-analysis CWE-78 flag is a false positive here since the command list is hardcoded with no untrusted input, but atry/exceptaround the call would improve the user experience.🛡️ Suggested fix
def do_shutdown(self): self.close() - subprocess.run( - ["shutdown", "/s", "/t", "0"], - shell=False, - creationflags=subprocess.CREATE_NO_WINDOW - ) + try: + subprocess.run( + ["shutdown", "/s", "/t", "0"], + shell=False, + creationflags=subprocess.CREATE_NO_WINDOW, + check=True, + ) + except subprocess.CalledProcessError: + print("关机命令执行失败,请手动关机。") + except FileNotFoundError: + print("未找到关机程序,请手动关机。")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/python_script/shutdown.py` around lines 64 - 70, Wrap the subprocess.run call in do_shutdown with focused exception handling for failures launching or executing the hardcoded shutdown command, and provide clear user feedback when it fails. Preserve the existing command arguments, close() call, and successful shutdown behavior.Source: Linters/SAST tools
src/utils.py (1)
36-39: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReplace fullwidth parentheses with halfwidth in docstring.
Ruff flags RUF002: the docstring at line 37 contains fullwidth
(and)instead of halfwidth(and). This is a minor style consistency issue.♻️ Proposed fix
def get_root_dir() -> str: """ 获取项目根目录 - :return: 项目根目录(src/ 的父目录) + :return: 项目根目录(src/ 的父目录) """ return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils.py` around lines 36 - 39, Update the docstring associated with the project-root directory function to replace the fullwidth parentheses in its return description with standard halfwidth parentheses, without changing the function behavior.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@config/config.yml`:
- Line 24: Remove all user-specific absolute values from the script_path entries
in config.yml, including the WinSa username and D:\game_helper paths. Replace
them with configurable placeholders or environment-variable references, provide
a config.yml.example template if needed, and add the real config.yml to
.gitignore so machine-specific paths and usernames are not committed.
In `@src/config/bgi.py`:
- Around line 12-18: Update get_BGI_user_dir to handle an empty YAML result by
treating it as an empty configuration, and validate that the matching script has
a non-empty script_path before deriving its directory. Skip entries with missing
or empty paths so the function never calls os.path.dirname(None) or returns a
relative User path.
In `@src/config/onedrag_ui.py`:
- Around line 149-153: Update the weekly timeout parsing in the save flow around
weekly_timeouts so empty or whitespace-only line-edit values do not call int()
and crash. Validate each le.text() value before conversion, and provide the
existing user feedback or appropriate fallback for invalid empty fields while
preserving normal integer parsing and weekly_timeouts_map assignment.
- Around line 52-66: Update load_data so yaml.safe_load for the main
configuration always produces a mapping, defaulting empty or null content to {}
before assigning self.config_data. Initialize self.weekly_timeouts_map to {}
before the missing-file early return, while preserving the existing
weekly_timeouts.yml loading behavior when the file exists.
In `@src/dungeon_adapter.py`:
- Around line 315-318: Remove the unnecessary f-string prefixes from the four
static print statements in the Star Rail configuration update paths, including
the branches around the existing “config 无需更新” and “config 已更新” messages and the
corresponding statements near the second referenced location; keep their text
and control flow unchanged.
- Around line 178-180: Update the Zenless dungeon handling in the adapter,
including the corresponding logic around the second referenced location, so
unsupported Zenless adaptation returns False rather than being treated as a
successful no-op. Preserve the existing True return for valid handlers that
return None to indicate no write is needed.
- Around line 111-120: Update the configuration-writing function containing the
ext check to validate supported extensions before opening or creating files.
Serialize the JSON/YAML data to a temporary file in the target’s directory, then
atomically replace the destination with os.replace; ensure temporary-file
cleanup on failure and preserve the existing unsupported-format return behavior.
- Line 249: Update the changed-state assignment around update_task() and
update_sequence() so both functions are evaluated before combining their boolean
results, ensuring the selected sequence is applied after a dungeon change. Apply
the same change to the corresponding occurrence near the other reported
location.
- Around line 38-41: Update the YAML and JSON loader functions used by
set_config to catch OSError, yaml.YAMLError, and json.JSONDecodeError, returning
None for unreadable or invalid configuration. In _load_config_yml and the
corresponding JSON loader, validate that parsed content is a mapping and treat
missing or empty content as invalid. Ensure set_config handles a None loader
result and returns False without allowing these errors to escape.
- Around line 379-384: Update the task-enabling logic near task_map so only the
user-selected dungeon is re-enabled after all tasks are disabled. Remove the
unconditional task_config[task_map["土"]] assignment, while preserving the
selected dungeon assignment and ensuring selecting “土” still enables that
dungeon.
In `@src/python_script/mute.py`:
- Line 1: Add pycaw as a runtime dependency in the project configuration and
regenerate the lockfile so it is recorded in uv.lock. Keep the existing
AudioUtilities import in src/python_script/mute.py unchanged.
---
Nitpick comments:
In `@src/python_script/mute.py`:
- Around line 1-16: Extract the shared set_mute function from mute.py and
unmute.py into a common audio_utils.py module, then import and reuse it from
both scripts. Keep each script’s __main__ entry point responsible only for
passing its appropriate mute status.
In `@src/python_script/shutdown.py`:
- Around line 64-70: Wrap the subprocess.run call in do_shutdown with focused
exception handling for failures launching or executing the hardcoded shutdown
command, and provide clear user feedback when it fails. Preserve the existing
command arguments, close() call, and successful shutdown behavior.
In `@src/utils.py`:
- Around line 36-39: Update the docstring associated with the project-root
directory function to replace the fullwidth parentheses in its return
description with standard halfwidth parentheses, without changing the function
behavior.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 64608388-8a3b-4a2f-96c6-c3fbbcce42d5
⛔ Files ignored due to path filters (1)
assets/demo.pngis excluded by!**/*.png
📒 Files selected for processing (25)
.github/workflows/ci.ymlREADME.mdconfig/BGI_User/KeyMouseScript/120s随机游走.jsonconfig/BGI_User/KeyMouseScript/木桩.jsonconfig/BGI_User/ScriptGroup/千星.jsonconfig/BGI_User/ScriptGroup/锄地.jsonconfig/config.ymlconfig/dungeon_list.ymlconfig/weekly_timeouts.ymlenv.batlauncher.batsrc/config/__init__.pysrc/config/bgi.pysrc/config/onedrag_ui.pysrc/config/onedragon.pysrc/dungeon_adapter.pysrc/gui_launcher.pysrc/python_script/mute.pysrc/python_script/shutdown.pysrc/python_script/unmute.pysrc/utils.pytests/test_bgi.pytests/test_onedrag_ui.pytests/test_onedragon.pytests/test_utils.py
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 11
🧹 Nitpick comments (3)
src/python_script/mute.py (1)
1-16: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
set_muteis duplicated verbatim inunmute.py.Both
mute.pyandunmute.pydefine an identicalset_mutefunction; the only difference is the argument passed in__main__. Extract the shared function into a common module (e.g.,audio_utils.py) and have both scripts import it.♻️ Suggested refactor
# src/python_script/audio_utils.py +from pycaw.pycaw import AudioUtilities + +def set_mute(mute_status): + devices = AudioUtilities.GetSpeakers() + interface = devices.EndpointVolume + interface.SetMute(mute_status, None) + print(f"系统已{'静音' if mute_status else '恢复声音'}") # src/python_script/mute.py -from pycaw.pycaw import AudioUtilities - -def set_mute(mute_status): - devices = AudioUtilities.GetSpeakers() - interface = devices.EndpointVolume - interface.SetMute(mute_status, None) - print(f"系统已{'静音' if mute_status else '恢复声音'}") - -if __name__ == "__main__": - set_mute(True) +from audio_utils import set_mute + +if __name__ == "__main__": + set_mute(True)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/python_script/mute.py` around lines 1 - 16, Extract the shared set_mute function from mute.py and unmute.py into a common audio_utils.py module, then import and reuse it from both scripts. Keep each script’s __main__ entry point responsible only for passing its appropriate mute status.src/python_script/shutdown.py (1)
64-70: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAdd error handling around the shutdown subprocess call.
If
subprocess.runfails (e.g., insufficient privileges,shutdownnot in PATH), the exception is unhandled and the user gets no feedback. The static-analysis CWE-78 flag is a false positive here since the command list is hardcoded with no untrusted input, but atry/exceptaround the call would improve the user experience.🛡️ Suggested fix
def do_shutdown(self): self.close() - subprocess.run( - ["shutdown", "/s", "/t", "0"], - shell=False, - creationflags=subprocess.CREATE_NO_WINDOW - ) + try: + subprocess.run( + ["shutdown", "/s", "/t", "0"], + shell=False, + creationflags=subprocess.CREATE_NO_WINDOW, + check=True, + ) + except subprocess.CalledProcessError: + print("关机命令执行失败,请手动关机。") + except FileNotFoundError: + print("未找到关机程序,请手动关机。")🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/python_script/shutdown.py` around lines 64 - 70, Wrap the subprocess.run call in do_shutdown with focused exception handling for failures launching or executing the hardcoded shutdown command, and provide clear user feedback when it fails. Preserve the existing command arguments, close() call, and successful shutdown behavior.Source: Linters/SAST tools
src/utils.py (1)
36-39: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReplace fullwidth parentheses with halfwidth in docstring.
Ruff flags RUF002: the docstring at line 37 contains fullwidth
(and)instead of halfwidth(and). This is a minor style consistency issue.♻️ Proposed fix
def get_root_dir() -> str: """ 获取项目根目录 - :return: 项目根目录(src/ 的父目录) + :return: 项目根目录(src/ 的父目录) """ return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/utils.py` around lines 36 - 39, Update the docstring associated with the project-root directory function to replace the fullwidth parentheses in its return description with standard halfwidth parentheses, without changing the function behavior.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@config/config.yml`:
- Line 24: Remove all user-specific absolute values from the script_path entries
in config.yml, including the WinSa username and D:\game_helper paths. Replace
them with configurable placeholders or environment-variable references, provide
a config.yml.example template if needed, and add the real config.yml to
.gitignore so machine-specific paths and usernames are not committed.
In `@src/config/bgi.py`:
- Around line 12-18: Update get_BGI_user_dir to handle an empty YAML result by
treating it as an empty configuration, and validate that the matching script has
a non-empty script_path before deriving its directory. Skip entries with missing
or empty paths so the function never calls os.path.dirname(None) or returns a
relative User path.
In `@src/config/onedrag_ui.py`:
- Around line 149-153: Update the weekly timeout parsing in the save flow around
weekly_timeouts so empty or whitespace-only line-edit values do not call int()
and crash. Validate each le.text() value before conversion, and provide the
existing user feedback or appropriate fallback for invalid empty fields while
preserving normal integer parsing and weekly_timeouts_map assignment.
- Around line 52-66: Update load_data so yaml.safe_load for the main
configuration always produces a mapping, defaulting empty or null content to {}
before assigning self.config_data. Initialize self.weekly_timeouts_map to {}
before the missing-file early return, while preserving the existing
weekly_timeouts.yml loading behavior when the file exists.
In `@src/dungeon_adapter.py`:
- Around line 315-318: Remove the unnecessary f-string prefixes from the four
static print statements in the Star Rail configuration update paths, including
the branches around the existing “config 无需更新” and “config 已更新” messages and the
corresponding statements near the second referenced location; keep their text
and control flow unchanged.
- Around line 178-180: Update the Zenless dungeon handling in the adapter,
including the corresponding logic around the second referenced location, so
unsupported Zenless adaptation returns False rather than being treated as a
successful no-op. Preserve the existing True return for valid handlers that
return None to indicate no write is needed.
- Around line 111-120: Update the configuration-writing function containing the
ext check to validate supported extensions before opening or creating files.
Serialize the JSON/YAML data to a temporary file in the target’s directory, then
atomically replace the destination with os.replace; ensure temporary-file
cleanup on failure and preserve the existing unsupported-format return behavior.
- Line 249: Update the changed-state assignment around update_task() and
update_sequence() so both functions are evaluated before combining their boolean
results, ensuring the selected sequence is applied after a dungeon change. Apply
the same change to the corresponding occurrence near the other reported
location.
- Around line 38-41: Update the YAML and JSON loader functions used by
set_config to catch OSError, yaml.YAMLError, and json.JSONDecodeError, returning
None for unreadable or invalid configuration. In _load_config_yml and the
corresponding JSON loader, validate that parsed content is a mapping and treat
missing or empty content as invalid. Ensure set_config handles a None loader
result and returns False without allowing these errors to escape.
- Around line 379-384: Update the task-enabling logic near task_map so only the
user-selected dungeon is re-enabled after all tasks are disabled. Remove the
unconditional task_config[task_map["土"]] assignment, while preserving the
selected dungeon assignment and ensuring selecting “土” still enables that
dungeon.
In `@src/python_script/mute.py`:
- Line 1: Add pycaw as a runtime dependency in the project configuration and
regenerate the lockfile so it is recorded in uv.lock. Keep the existing
AudioUtilities import in src/python_script/mute.py unchanged.
---
Nitpick comments:
In `@src/python_script/mute.py`:
- Around line 1-16: Extract the shared set_mute function from mute.py and
unmute.py into a common audio_utils.py module, then import and reuse it from
both scripts. Keep each script’s __main__ entry point responsible only for
passing its appropriate mute status.
In `@src/python_script/shutdown.py`:
- Around line 64-70: Wrap the subprocess.run call in do_shutdown with focused
exception handling for failures launching or executing the hardcoded shutdown
command, and provide clear user feedback when it fails. Preserve the existing
command arguments, close() call, and successful shutdown behavior.
In `@src/utils.py`:
- Around line 36-39: Update the docstring associated with the project-root
directory function to replace the fullwidth parentheses in its return
description with standard halfwidth parentheses, without changing the function
behavior.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 64608388-8a3b-4a2f-96c6-c3fbbcce42d5
⛔ Files ignored due to path filters (1)
assets/demo.pngis excluded by!**/*.png
📒 Files selected for processing (25)
.github/workflows/ci.ymlREADME.mdconfig/BGI_User/KeyMouseScript/120s随机游走.jsonconfig/BGI_User/KeyMouseScript/木桩.jsonconfig/BGI_User/ScriptGroup/千星.jsonconfig/BGI_User/ScriptGroup/锄地.jsonconfig/config.ymlconfig/dungeon_list.ymlconfig/weekly_timeouts.ymlenv.batlauncher.batsrc/config/__init__.pysrc/config/bgi.pysrc/config/onedrag_ui.pysrc/config/onedragon.pysrc/dungeon_adapter.pysrc/gui_launcher.pysrc/python_script/mute.pysrc/python_script/shutdown.pysrc/python_script/unmute.pysrc/utils.pytests/test_bgi.pytests/test_onedrag_ui.pytests/test_onedragon.pytests/test_utils.py
🛑 Comments failed to post (11)
config/config.yml (1)
24-24: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Hardcoded user-specific paths with username leakage committed to repository.
Multiple
script_pathentries contain absolute Windows paths specific to one user's machine, includingC:\Users\WinSa\...(lines 24, 64) andD:\game_helper\...(lines 44, 84, 105, 124, 144). The usernameWinSais exposed in the repository, and these paths won't work for any other user who clones the repo.Consider using a template file (e.g.,
config.yml.example) with placeholder paths, or environment variable substitution, and add the realconfig.ymlto.gitignore.Also applies to: 44-44, 64-64, 84-84, 105-105, 124-124, 144-144
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@config/config.yml` at line 24, Remove all user-specific absolute values from the script_path entries in config.yml, including the WinSa username and D:\game_helper paths. Replace them with configurable placeholders or environment-variable references, provide a config.yml.example template if needed, and add the real config.yml to .gitignore so machine-specific paths and usernames are not committed.src/config/bgi.py (1)
12-18: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
get_BGI_user_dircrashes on empty YAML or missingscript_path.Two issues:
- Line 13:
yaml.safe_load(f)returnsNonefor an emptyconfig.yml, causingAttributeErroron line 14 (config_data.get(...)).- Line 17:
script.get('script_path')returnsNonewhen the key is absent, causingTypeErrorinos.path.dirname(None). Ifscript_pathis an empty string,os.path.dirname('')returns'', andos.path.join('', 'User')resolves to a relative'User'path —shutil.copytreewould then write to./Userunder the current working directory.🛡️ Proposed fix
with open(get_config_yml_path_under_root(), 'r', encoding='utf-8') as f: - config_data = yaml.safe_load(f) + config_data = yaml.safe_load(f) or {} script_list = config_data.get('script_list', []) for script in script_list: if script.get('display_name') == '原神': - BGI_dir = os.path.dirname(script.get('script_path')) - return os.path.join(BGI_dir, 'User') + script_path = script.get('script_path') + if script_path: + BGI_dir = os.path.dirname(script_path) + return os.path.join(BGI_dir, 'User') return None📝 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.with open(get_config_yml_path_under_root(), 'r', encoding='utf-8') as f: config_data = yaml.safe_load(f) or {} script_list = config_data.get('script_list', []) for script in script_list: if script.get('display_name') == '原神': script_path = script.get('script_path') if script_path: BGI_dir = os.path.dirname(script_path) return os.path.join(BGI_dir, 'User') return None🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/config/bgi.py` around lines 12 - 18, Update get_BGI_user_dir to handle an empty YAML result by treating it as an empty configuration, and validate that the matching script has a non-empty script_path before deriving its directory. Skip entries with missing or empty paths so the function never calls os.path.dirname(None) or returns a relative User path.src/config/onedrag_ui.py (2)
52-66: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
load_datais fragile against empty/missing YAML and early returns.Two issues:
- Line 58:
yaml.safe_load(f)returnsNonefor an emptyconfig.yml, causingAttributeErroron line 68 (self.config_data.get(...)).- Lines 53-55: When the config file is missing,
load_datareturns early without settingself.weekly_timeouts_map. The save button is still active, so clicking Save hitsAttributeErrorat line 164 (yaml.dump(self.weekly_timeouts_map, ...)).🛡️ Proposed fix
def load_data(self): if not os.path.exists(self.yml_path): MessageBox("错误", f"找不到文件: {self.yml_path}", self).exec() + self.weekly_timeouts_map = {} return with open(self.yml_path, 'r', encoding='utf-8') as f: - self.config_data = yaml.safe_load(f) + self.config_data = yaml.safe_load(f) or {}📝 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.def load_data(self): if not os.path.exists(self.yml_path): MessageBox("错误", f"找不到文件: {self.yml_path}", self).exec() self.weekly_timeouts_map = {} return with open(self.yml_path, 'r', encoding='utf-8') as f: self.config_data = yaml.safe_load(f) or {} # 从 weekly_timeouts.yml 读取每周超时配置 weekly_timeouts_path = get_weekly_timeouts_yml_path_under_root() weekly_timeouts_map = {} if os.path.exists(weekly_timeouts_path): with open(weekly_timeouts_path, 'r', encoding='utf-8') as f: weekly_timeouts_map = yaml.safe_load(f) or {} self.weekly_timeouts_map = weekly_timeouts_map🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 56-56: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(self.yml_path, 'r', encoding='utf-8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').(open-filename-from-request)
[warning] 63-63: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(weekly_timeouts_path, 'r', encoding='utf-8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').(open-filename-from-request)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/config/onedrag_ui.py` around lines 52 - 66, Update load_data so yaml.safe_load for the main configuration always produces a mapping, defaulting empty or null content to {} before assigning self.config_data. Initialize self.weekly_timeouts_map to {} before the missing-file early return, while preserving the existing weekly_timeouts.yml loading behavior when the file exists.
149-153: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
int(le.text().strip())crashes on empty timeout fields.
QIntValidatorallows empty strings (returnsIntermediate), so a user can clear a field and click Save.int("")raisesValueError, crashing the save operation with no user feedback.🛡️ Proposed fix
for le in lineedits: - val = int(le.text().strip()) + text = le.text().strip() + val = int(text) if text else 0 weekly_timeouts.append(val)📝 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.weekly_timeouts = [] for le in lineedits: text = le.text().strip() val = int(text) if text else 0 weekly_timeouts.append(val) self.weekly_timeouts_map[display_name] = weekly_timeouts🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/config/onedrag_ui.py` around lines 149 - 153, Update the weekly timeout parsing in the save flow around weekly_timeouts so empty or whitespace-only line-edit values do not call int() and crash. Validate each le.text() value before conversion, and provide the existing user feedback or appropriate fallback for invalid empty fields while preserving normal integer parsing and weekly_timeouts_map assignment.src/dungeon_adapter.py (6)
38-41: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Keep unreadable configuration within
set_config’s failure contract.Missing, malformed, empty, or non-mapping YAML/JSON can raise here before
set_configreaches itstryblocks, despite its documentedboolresult. CatchOSError,yaml.YAMLError, andjson.JSONDecodeErrorin the loaders; validateconfig.ymlis a mapping; returnNonesoset_configreturnsFalsecleanly.Also applies to: 90-95, 165-169
🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 39-39: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(get_config_yml_path_under_root(), 'r', encoding='utf-8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').(open-filename-from-request)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/dungeon_adapter.py` around lines 38 - 41, Update the YAML and JSON loader functions used by set_config to catch OSError, yaml.YAMLError, and json.JSONDecodeError, returning None for unreadable or invalid configuration. In _load_config_yml and the corresponding JSON loader, validate that parsed content is a mapping and treat missing or empty content as invalid. Ensure set_config handles a None loader result and returns False without allowing these errors to escape.
111-120: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Write configuration atomically.
Opening the live file in write mode can leave it empty or partially written if serialization, disk I/O, or the process fails. Serialize to a temporary file in the same directory, then replace the target with
os.replace; validate the extension before creating any file.🧰 Tools
🪛 ast-grep (0.44.1)
[warning] 111-111: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(path, 'w', encoding='utf-8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').(open-filename-from-request)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/dungeon_adapter.py` around lines 111 - 120, Update the configuration-writing function containing the ext check to validate supported extensions before opening or creating files. Serialize the JSON/YAML data to a temporary file in the target’s directory, then atomically replace the destination with os.replace; ensure temporary-file cleanup on failure and preserve the existing unsupported-format return behavior.
178-180: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Do not report Zenless configuration as successful.
Selecting a Zenless dungeon currently performs no update but returns
True. ReserveNonefor valid no-op updates; signal unsupported adaptation so callers receiveFalse.Proposed fix
def _apply_zenless(config: dict, dungeon_name: str, sequence: str | None = None) -> dict | None: - # TODO: 适配绝区零的副本配置 - print(f"[dungeon_adapter][Zenless] 待适配: {dungeon_name}") - return None + raise NotImplementedError( + f"[dungeon_adapter][Zenless] 未适配副本配置: {dungeon_name}" + )Also applies to: 296-300
🧰 Tools
🪛 Ruff (0.15.20)
[warning] 179-179: Comment contains ambiguous
((FULLWIDTH LEFT PARENTHESIS). Did you mean((LEFT PARENTHESIS)?(RUF003)
[warning] 179-179: Comment contains ambiguous
)(FULLWIDTH RIGHT PARENTHESIS). Did you mean)(RIGHT PARENTHESIS)?(RUF003)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/dungeon_adapter.py` around lines 178 - 180, Update the Zenless dungeon handling in the adapter, including the corresponding logic around the second referenced location, so unsupported Zenless adaptation returns False rather than being treated as a successful no-op. Preserve the existing True return for valid handlers that return None to indicate no write is needed.
249-249: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Apply the selected sequence after changing the dungeon.
update_task() or update_sequence()short-circuits, so a newly selected dungeon is saved without its selected sequence. Evaluate both updates before combining their results.Proposed fix
- changed = update_task() or update_sequence() + task_changed = update_task() + sequence_changed = update_sequence() + changed = task_changed or sequence_changedAlso applies to: 354-354
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/dungeon_adapter.py` at line 249, Update the changed-state assignment around update_task() and update_sequence() so both functions are evaluated before combining their boolean results, ensuring the selected sequence is applied after a dungeon change. Apply the same change to the corresponding occurrence near the other reported location.
315-318: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Remove the empty f-string prefixes.
These four statements trigger Ruff F541 errors.
Proposed fix
- print(f"[dungeon_adapter][Star Rail] config 无需更新") + print("[dungeon_adapter][Star Rail] config 无需更新") ... - print(f"[dungeon_adapter][Star Rail] config 已更新") + print("[dungeon_adapter][Star Rail] config 已更新") ... - print(f"[dungeon_adapter][Arknights] config 无需更新") + print("[dungeon_adapter][Arknights] config 无需更新") ... - print(f"[dungeon_adapter][Arknights] config 已更新") + print("[dungeon_adapter][Arknights] config 已更新")Also applies to: 391-394
🧰 Tools
🪛 Ruff (0.15.20)
[error] 315-315: f-string without any placeholders
Remove extraneous
fprefix(F541)
[error] 318-318: f-string without any placeholders
Remove extraneous
fprefix(F541)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/dungeon_adapter.py` around lines 315 - 318, Remove the unnecessary f-string prefixes from the four static print statements in the Star Rail configuration update paths, including the branches around the existing “config 无需更新” and “config 已更新” messages and the corresponding statements near the second referenced location; keep their text and control flow unchanged.Source: Linters/SAST tools
379-384: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Enable only the dungeon selected by the user.
For any selection other than “土”, Line 384 re-enables a second task after the loop disables all alternatives. The automation will run both the chosen dungeon and “土”.
Proposed fix
task_config[task_map[dungeon_name]]["IsEnable"] = True - task_config[task_map["土"]]["IsEnable"] = True print(f"enable task: {dungeon_name}")📝 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.# disable other tasks for key in task_map: task_config[task_map[key]]["IsEnable"] = False task_config[task_map[dungeon_name]]["IsEnable"] = True🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/dungeon_adapter.py` around lines 379 - 384, Update the task-enabling logic near task_map so only the user-selected dungeon is re-enabled after all tasks are disabled. Remove the unconditional task_config[task_map["土"]] assignment, while preserving the selected dungeon assignment and ensuring selecting “土” still enables that dungeon.src/python_script/mute.py (1)
1-1: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Check if pycaw is declared in project dependencies rg -n 'pycaw' pyproject.toml requirements*.txt setup.cfg setup.py 2>/dev/null || echo "pycaw not found in dependency files"Repository: LevelDownRefine/OneDragon-Helper
Length of output: 206
🏁 Script executed:
#!/bin/bash set -euo pipefail printf 'Files in repo root that look like dependency manifests:\n' git ls-files | rg '(^|/)(pyproject\.toml|requirements[^/]*\.txt|setup\.cfg|setup\.py|Pipfile|poetry\.lock|uv\.lock|pdm\.toml|conda\.ya?ml|environment\.ya?ml)$' || true printf '\n--- src/python_script/mute.py ---\n' wc -l src/python_script/mute.py cat -n src/python_script/mute.py printf '\n--- dependency manifests mentioning pycaw (if any) ---\n' rg -n 'pycaw' . -g 'pyproject.toml' -g 'requirements*.txt' -g 'setup.cfg' -g 'setup.py' -g 'Pipfile' -g 'poetry.lock' -g 'uv.lock' -g 'pdm.toml' -g 'conda*.yml' -g 'environment*.yml' 2>/dev/null || trueRepository: LevelDownRefine/OneDragon-Helper
Length of output: 862
🏁 Script executed:
#!/bin/bash set -euo pipefail echo '--- pyproject.toml ---' wc -l pyproject.toml cat -n pyproject.toml echo echo '--- uv.lock pycaw mentions ---' rg -n -C 2 'pycaw|pycaw.pycaw|win32|platform' uv.lock pyproject.toml || trueRepository: LevelDownRefine/OneDragon-Helper
Length of output: 50389
Declare
pycawas a dependency.src/python_script/mute.py:1importspycaw.pycawat module import time, butpycawis not listed inpyproject.toml/uv.lock, so a clean install will fail before this script runs.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/python_script/mute.py` at line 1, Add pycaw as a runtime dependency in the project configuration and regenerate the lockfile so it is recorded in uv.lock. Keep the existing AudioUtilities import in src/python_script/mute.py unchanged.
Summary by CodeRabbit
New Features
Improvements
Bug Fixes