Conversation
📝 WalkthroughWalkthrough客户端新增收藏切换、收藏夹管理和退出请求。解析器现在从 HTML 页面读取专辑 ID、收藏状态和点赞状态。 ChangesHTML 专辑状态与账户操作
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches 💡 1📝 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: 4
🧹 Nitpick comments (2)
jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/parser/HtmlParser.java (2)
82-84: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win为新增状态解析补充 HTML fixture 测试。
parseAlbum现在填充真实的isFavorite和liked状态。请覆盖以下样例:
- 收藏和点赞均为真。
- 收藏和点赞均为假。
- 缺少状态元素或图标。
- 缺少
style属性。album_id使用直接值和回退布局。测试应断言
JmAlbum的两个字段,避免远端 HTML 结构变化后静默返回错误状态。🤖 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 `@jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/parser/HtmlParser.java` around lines 82 - 84, 为 HtmlParser 的 parseAlbum 增加基于 HTML fixture 的测试,覆盖收藏和点赞均为真、均为假、缺少状态元素或图标、缺少 style 属性,以及 album_id 直接值和回退布局等场景。测试应调用 parseAlbum 并断言返回 JmAlbum 的 isFavorite 与 liked 字段,覆盖 parseFavorite 和 parseLiked 的状态解析结果。
107-111: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win规范化
album_id,避免将非数字值传入后端的 CSS 选择器。
album_id回退路径始终返回纯数字,但album_idinput 直接返回原始字符串,可能包含空格、非数字字符或JM前缀;这会使后续的#albim_likes_...、[id=love_likes_...]、#favorite_album_...等查询结果不一致,并可能生成非法 CSS 选择器导致状态匹配失败。先trim()并只允许纯数字 ID;否则继续走后续回退逻辑再抛异常。点赞状态选择器改用doc.getElementById("love_likes_" + albumId).select("i"),避免把非数字 ID 拼入 CSS 查询。🤖 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 `@jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/parser/HtmlParser.java` around lines 107 - 111, 在 HtmlParser 的 album_id 解析逻辑中,先对 input 的 value 执行 trim,仅当结果为纯数字时返回,否则继续后续回退逻辑并最终抛出异常。更新点赞状态查询,使用 doc.getElementById("love_likes_" + albumId).select("i"),避免将未经规范化的 ID 拼接进 CSS 选择器。Source: MCP 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
`@jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java`:
- Around line 370-377: Update the deletion flow in JmHtmlClient around the
status parsing and delete_favorite_album request so a missing or null response
status does not fall through to deletion. Only invoke the delete request when
the response status is successfully parsed and explicitly equals 0; otherwise
preserve the existing status without deleting.
- Around line 530-534: 更新 JmHtmlClient.logout():成功完成 /logout 请求后清理
cacheUsername(username) 保存的当前用户名状态及该用户相关的收藏夹、观看历史缓存,确保后续请求不会复用旧会话数据。若现有清理 API
不足,在基类或 HTML 客户端补充并复用统一的会话清理接口;保留登出请求本身的现有流程。
- Line 357: 在 JmHtmlClient.java 的 357-357 行对应的 toggleAlbumFavorite() 成功流程中,调用
cachePool.remove 清除受影响的 JmAlbum 和 JmFavoritePage 缓存;在 515-517 行对应的
manageFavoriteFolder() 成功流程中,清除受影响的 JmFavoritePage 缓存,确保后续 getAlbum 和
getFavorites 不返回旧数据。
In
`@jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/parser/HtmlParser.java`:
- Around line 130-138: Update parseFavorite to require a positively recognized
collected-state marker instead of treating any icon that is not exactly black as
favorited. Ensure missing, unrecognized, or differently formatted
styles—including absent style attributes, short hex, and rgb values—return
false, while preserving true only for the confirmed favorite marker.
---
Nitpick comments:
In
`@jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/parser/HtmlParser.java`:
- Around line 82-84: 为 HtmlParser 的 parseAlbum 增加基于 HTML fixture
的测试,覆盖收藏和点赞均为真、均为假、缺少状态元素或图标、缺少 style 属性,以及 album_id 直接值和回退布局等场景。测试应调用
parseAlbum 并断言返回 JmAlbum 的 isFavorite 与 liked 字段,覆盖 parseFavorite 和 parseLiked
的状态解析结果。
- Around line 107-111: 在 HtmlParser 的 album_id 解析逻辑中,先对 input 的 value 执行
trim,仅当结果为纯数字时返回,否则继续后续回退逻辑并最终抛出异常。更新点赞状态查询,使用 doc.getElementById("love_likes_"
+ albumId).select("i"),避免将未经规范化的 ID 拼接进 CSS 选择器。
🪄 Autofix
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 Plus
Run ID: fe140c57-c7be-44e8-8afb-de44eeba5ef2
📒 Files selected for processing (2)
jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.javajmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/parser/HtmlParser.java
| FormBody.Builder formBuilderDel = new FormBody.Builder() | ||
| .add("album_id", albumId); | ||
|
|
||
| JmHtmlResponse jmHtmlResponse = executePostRequest(url, formBuilder.build()); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 5 \
'getCachedJmFavoritePage|cacheJmFavoritePage|getCachedJmAlbum|cacheJmAlbum|invalidate|evict|clear.*Cache' \
jmcomic-core/src/main/javaRepository: JUKOMU/JMComic-Api-Java
Length of output: 29394
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 查看目标文件的关键方法概要,然后定位收藏切换和收藏夹相关实现。
ast-grep outline jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java --view expanded | sed -n '1,260p'
printf '\n== target lines 330-375 ==\n'
sed -n '330,375p' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java | cat -n -v
printf '\n== target lines 495-530 ==\n'
sed -n '495,530p' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java | cat -n -v
printf '\n== CachePool cache removal methods ==\n'
rg -n -C 4 'public|void|put|get|remove|keys|size|currentSize|freqMap|node' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/cache/CachePool.java | sed -n '1,260p'Repository: JUKOMU/JMComic-Api-Java
Length of output: 13306
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '== JmHtmlClient toggleAlbumFavorite full method =='
sed -n '333,500p' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java | cat -n -v
printf '%s\n' '== AbstractJmClient cache operations summary =='
sed -n '960,1030p' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/AbstractJmClient.java | cat -n -v
printf '%s\n' '== JmHtmlClient AbstractJmClient remove inheritance/use =="
rg -n 'class JmHtmlClient|extends AbstractJmClient|protected void cache|protected.*getCached' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/AbstractJmClient.java
printf '%s\n' '== inspect methods called around toggleAlbumFavorite =="
sed -n '295,315p' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java | cat -n -vRepository: JUKOMU/JMComic-Api-Java
Length of output: 12970
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '== JmHtmlClient inheritance =='
sed -n '1,55p;88,95p;183,210p' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java | cat -n -v
printf '%s\n' '== AbstractJmClient cache methods and removal helpers summary =='
python3 - <<'PY'
from pathlib import Path
p = Path('jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/AbstractJmClient.java')
lines = p.read_text(errors='replace').splitlines()
for i,l in enumerate(lines, 1):
if 'protected' in l or 'public' in l or 'remove' in l or 'cachePool' in l:
if any(s in l for s in ['getCachedJmAlbum', 'getCachedJmFavoritePage', 'cacheJmAlbum', 'cacheJmFavoritePage', 'CacheKey', 'remove']):
start=max(1,i-2); end=min(len(lines),i+6)
print(f'-- lines {start}-{end} --')
for n in range(start,end+1):
print(f'{n:5d}: {lines[n-1]}')
PY
printf '%s\n' '== CachePool keys =="
python3 - <<'PY'
from pathlib import Path
p = Path('jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/cache/CachePool.java')
print(p.read_text(errors='replace'))
PY
printf '%s\n' '== CacheKey of methods ='
rg -n -C 3 'class CacheKey|record CacheKey|public static .*of|static .*of|CacheKey\.of' .Repository: JUKOMU/JMComic-Api-Java
Length of output: 9577
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 使用 Python 读取文件,避免 shell 转义问题。
python3 - <<'PY'
from pathlib import Path
files = {
'JmHtmlClient': Path('jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java'),
'AbstractJmClient': Path('jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/AbstractJmClient.java'),
'CacheKey': Path('jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/cache/CacheKey.java'),
'CachePool': Path('jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/cache/CachePool.java'),
}
for name, p in files.items():
lines = p.read_text(errors='replace').splitlines()
print(f'== {name}: {p} ({len(lines)} lines) ==')
for i,l in enumerate(lines,1):
if name == 'CacheKey':
print(f'{i:5d}: {l}')
elif any(s in l for s in ['toggleAlbumFavorite', 'manageFavoriteFolder', 'getCachedJmAlbum', 'getCachedJmFavoritePage', 'cacheJmAlbum', 'cacheJmFavoritePage', 'CacheKey.of', 'cachePool.remove', 'remove(']):
start=max(1,i-3); end=min(len(lines),i+6)
print(f'-- {start}-{end} --')
for n in range(start,end+1):
print(f'{n:5d}: {lines[n-1]}')
print()
# 收集收藏相关操作成功后的缓存调用
for name, p in files.items():
lines = p.read_text(errors='replace').splitlines()
print(f'== cache calls after favorite album methods in {name} ==')
in_method=False
method_ends_at=0
cache_calls=[]
for i,l in enumerate(lines,1):
if 'public void toggleAlbumFavorite' in l or 'public JmFavoriteFolderResult manageFavoriteFolder' in l:
in_method=True
if in_method and l.strip().startswith('}'):
method_ends_at=i
if in_method and i>=method_ends_at-100 and i<=method_ends_at:
if 'cachePool.' in l or 'remove(' in l or 'cacheJm' in l or 'getCachedJm' in l:
cache_calls.append((i,l.strip()))
for call in cache_calls:
print(f'{call[0]}: {call[1]}')
PYRepository: JUKOMU/JMComic-Api-Java
Length of output: 12108
服务端收藏数据变更后必须失效本地缓存。 采集客户端在收藏切换或收藏夹变更后不会调用 cachePool.remove,后续 getAlbum / getFavorites 仍可能直接返回旧缓存。
JmHtmlClient: toggleAlbumFavorite()成功后应移除缓存的相关JmAlbum和JmFavoritePage。JmHtmlClient: manageFavoriteFolder()成功后应移除受影响的JmFavoritePage缓存。
📍 Affects 1 file
jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java#L357-L357(this comment)jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java#L515-L517
🤖 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
`@jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java`
at line 357, 在 JmHtmlClient.java 的 357-357 行对应的 toggleAlbumFavorite() 成功流程中,调用
cachePool.remove 清除受影响的 JmAlbum 和 JmFavoritePage 缓存;在 515-517 行对应的
manageFavoriteFolder() 成功流程中,清除受影响的 JmFavoritePage 缓存,确保后续 getAlbum 和
getFavorites 不返回旧数据。
| if (status == 0) { | ||
| // 删除收藏 | ||
| JmHtmlResponse jmHtmlResponseDel = executePostRequest(urlDel, formBuilderDel.build()); | ||
| jsonObject = JsonParser.parseString(jmHtmlResponseDel.getHtml()).getAsJsonObject(); | ||
| if (jsonObject.has("status") && !jsonObject.get("status").isJsonNull()) { | ||
| status = jsonObject.get("status").getAsInt(); | ||
| } | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
仅在响应明确表示已收藏时执行删除。
status 的默认值是 0。如果响应 JSON 缺少 status,当前代码也会调用 delete_favorite_album。这会把协议变更或不完整响应误判为“已收藏”,并删除现有收藏。
先拒绝缺失或为 null 的 status。仅在已成功解析且值确实为 0 时执行删除。
🤖 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
`@jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java`
around lines 370 - 377, Update the deletion flow in JmHtmlClient around the
status parsing and delete_favorite_album request so a missing or null response
status does not fall through to deletion. Only invoke the delete request when
the response status is successfully parsed and explicitly equals 0; otherwise
preserve the existing status without deleting.
| HttpUrl url = newHttpUrlBuilder() | ||
| .addPathSegment("logout") | ||
| .build(); | ||
|
|
||
| JmHtmlResponse jmHtmlResponse = executeGetRequest(url); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n -C 4 \
'cacheUsername|getLoggedInUserName|getCachedJmFavoritePage|cacheJmFavoritePage|clear.*(Cache|Username|User)' \
jmcomic-core/src/main/javaRepository: JUKOMU/JMComic-Api-Java
Length of output: 22912
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- AbstractJmClient session/cache fields and methods ---\n'
sed -n '1,130p;880,1025p' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/AbstractJmClient.java | cat -n
printf '\n--- JmHtmlClient logout and login/logout declarations ---\n'
sed -n '210,240p;520-545p' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java | cat -n
printf '\n--- logout implementation across core clients ---\n'
rg -n -C 5 'logout\(|clear.*Cache|username|FavoriteQuery|FolderId|Folder' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/implRepository: JUKOMU/JMComic-Api-Java
Length of output: 252
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- AbstractJmClient session/cache fields and methods ---'
sed -n '1,140p;880,1030p' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/AbstractJmClient.java | cat -n
printf '%s\n' ''
printf '%s\n' '--- JmHtmlClient login/logout snippets ---'
sed -n '210,240p;520,545p' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java | cat -n
printf '%s\n' ''
printf '%s\n' '--- logout/user/cache usages in core client files ---'
rg -n -C 5 'logout\(|clear.*Cache|username|clear.*username|FavoriteQuery|FolderId|Folder|isBlank\(.*username|loggedInUserName' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/implRepository: JUKOMU/JMComic-Api-Java
Length of output: 50379
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- watchHistory/cache references around getWatchHistory ---'
rg -n -C 6 'getWatchHistory|watchHistory|cache.*Favorite|Favorite.*cache|cache.*History|History.*cache' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/AbstractJmClient.java jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java
printf '%s\n' ''
printf '%s\n' '--- cachePool operations in AbstractJmClient/java impls ---'
rg -n -C 2 'cachePool\.(put|remove|clear|get)|new EmptyCookieJar|CookieManager|saveFromResponse|clearAll|evictAll|logout\(\{|\blog\(' jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client jmcomic-core/src/main/java/org/apache/http/clientRepository: JUKOMU/JMComic-Api-Java
Length of output: 19425
登出后清理本地会话状态。
login() 会调用 cacheUsername(username),但 logout() 只请求 /logout。登出后,同一客户端仍可使用旧用户名请求收藏夹或观看历史,并读取对应的收藏夹缓存。
在 logout() 中清理用户名状态及用户相关缓存;若现有 API 不支持,则在基类/HTML 客户端补充清理接口。
🤖 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
`@jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/client/impl/JmHtmlClient.java`
around lines 530 - 534, 更新 JmHtmlClient.logout():成功完成 /logout 请求后清理
cacheUsername(username) 保存的当前用户名状态及该用户相关的收藏夹、观看历史缓存,确保后续请求不会复用旧会话数据。若现有清理 API
不足,在基类或 HTML 客户端补充并复用统一的会话清理接口;保留登出请求本身的现有流程。
| private static boolean parseFavorite(Document doc, String albumId) { | ||
| Element favoriteElement = doc.getElementById("favorite_album_" + albumId); | ||
| if (favoriteElement == null) { | ||
| return false; | ||
| } | ||
|
|
||
| Element favoriteIcon = favoriteElement.selectFirst("i"); | ||
| return favoriteIcon != null && !hasInlineStyle(favoriteIcon, "color", "#000000"); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
不要把“不是黑色”直接判定为已收藏。
Line 137 在以下情况下会返回 true:
- 图标没有
style属性。 style存在,但颜色不是精确的#000000。- 颜色格式发生变化,例如短十六进制或
rgb(...)。
这些情况只能说明“没有匹配到未收藏样式”,不能证明“已收藏”。请使用已确认的收藏状态正向标记;至少应把缺少或无法识别的样式判定为 false。
最低限度的防误判修复
Element favoriteIcon = favoriteElement.selectFirst("i");
- return favoriteIcon != null && !hasInlineStyle(favoriteIcon, "color", "`#000000`");
+ return favoriteIcon != null
+ && StringUtils.isNotBlank(favoriteIcon.attr("style"))
+ && !hasInlineStyle(favoriteIcon, "color", "`#000000`");🤖 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
`@jmcomic-core/src/main/java/io/github/jukomu/jmcomic/core/parser/HtmlParser.java`
around lines 130 - 138, Update parseFavorite to require a positively recognized
collected-state marker instead of treating any icon that is not exactly black as
favorited. Ensure missing, unrecognized, or differently formatted
styles—including absent style attributes, short hex, and rgb values—return
false, while preserving true only for the confirmed favorite marker.
Summary by CodeRabbit