-
Notifications
You must be signed in to change notification settings - Fork 9
合并 #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
合并 #16
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -340,11 +340,22 @@ public void toggleAlbumFavorite(String albumId, String folderId) { | |
| HttpUrl url = newHttpUrlBuilder() | ||
| .addPathSegment("ajax") | ||
| .addPathSegment("favorite_album") | ||
| .addQueryParameter("album_id", albumId) | ||
| .addQueryParameter("fid", folderId == null ? "0" : folderId) | ||
| .build(); | ||
|
|
||
| JmHtmlResponse jmHtmlResponse = executeGetRequest(url); | ||
| HttpUrl urlDel = newHttpUrlBuilder() | ||
| .addPathSegment("ajax") | ||
| .addPathSegment("delete_favorite_album") | ||
| .build(); | ||
|
|
||
| FormBody.Builder formBuilder = new FormBody.Builder() | ||
| .add("album_id", albumId) | ||
| .add("fid", folderId == null ? "0" : folderId); | ||
|
|
||
| FormBody.Builder formBuilderDel = new FormBody.Builder() | ||
| .add("album_id", albumId); | ||
|
|
||
| JmHtmlResponse jmHtmlResponse = executePostRequest(url, formBuilder.build()); | ||
|
|
||
| try { | ||
| /* | ||
| * 网页端收藏接口返回 JSON,status=1 成功,=0 表示已收藏过。 | ||
|
|
@@ -356,6 +367,15 @@ public void toggleAlbumFavorite(String albumId, String folderId) { | |
| status = jsonObject.get("status").getAsInt(); | ||
| } | ||
|
|
||
| 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(); | ||
| } | ||
| } | ||
|
Comment on lines
+370
to
+377
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 仅在响应明确表示已收藏时执行删除。
先拒绝缺失或为 🤖 Prompt for AI Agents |
||
|
|
||
| if (status != 1) { | ||
| String message = ""; | ||
| if (jsonObject.has("msg") && !jsonObject.get("msg").isJsonNull()) { | ||
|
|
@@ -453,9 +473,48 @@ public JmAlbumDownloadInfo getAlbumDownloadInfo(String albumId) { | |
| throw new UnsupportedOperationException("Getting album download info via HTML client is not currently supported. Use JmApiClient instead."); | ||
| } | ||
|
|
||
| /** | ||
| * 未完成 | ||
| * 移动作品到文件夹只对已经收藏作品的有效 | ||
| * 删除文件夹只能删除空文件夹 | ||
| * @param type 操作类型 (add/edit/move/del) | ||
| * @param folderId 文件夹ID | ||
| * @param folderName 文件夹名称(添加/重命名时需要) | ||
| * @param albumId 本子ID(移动时需要) | ||
| * @return | ||
| */ | ||
| @Override | ||
| public JmFavoriteFolderResult manageFavoriteFolder(FavoriteFolderType type, String folderId, String folderName, String albumId) { | ||
| throw new UnsupportedOperationException("Managing favorite folders via HTML client is not currently supported. Use JmApiClient instead."); | ||
| HttpUrl.Builder urlBuilder = newHttpUrlBuilder() | ||
| .addPathSegment("user") | ||
| .addPathSegment(getLoggedInUserName()) | ||
| .addPathSegment("favorite") | ||
| .addPathSegment("albums"); | ||
|
|
||
| FormBody.Builder formBuilder = new FormBody.Builder(); | ||
|
|
||
| if (type == FavoriteFolderType.ADD) { | ||
| formBuilder.add("addfolder-name", folderName); | ||
| } | ||
|
|
||
| if (type == FavoriteFolderType.DELETE) { | ||
| formBuilder.add("deletefolder-name", folderId); | ||
| } | ||
|
|
||
| if (type == FavoriteFolderType.EDIT) { | ||
| urlBuilder.addQueryParameter("folder", folderId); | ||
| formBuilder.add("editfolder-fid", folderId); | ||
| formBuilder.add("editfolder-name", folderName); | ||
| } | ||
|
|
||
| if (type == FavoriteFolderType.MOVE) { | ||
| formBuilder.add("movefolder-fid", folderId); | ||
| formBuilder.add("movefolder-aid", albumId); | ||
| } | ||
|
|
||
| JmHtmlResponse jmHtmlResponse = executePostRequest(urlBuilder.build(), formBuilder.build()); | ||
|
|
||
| return new JmFavoriteFolderResult("ok", type.getDescription()+"成功"); | ||
| } | ||
|
|
||
| // == HTML 客户端暂不实现(使用 JmApiClient) == | ||
|
|
@@ -468,7 +527,11 @@ public Map register(String username, String password, String passwordConfirm, St | |
|
|
||
| @Override | ||
| public void logout() { | ||
| throw new UnsupportedOperationException("Logout via HTML client is not currently supported. Use JmApiClient instead."); | ||
| HttpUrl url = newHttpUrlBuilder() | ||
| .addPathSegment("logout") | ||
| .build(); | ||
|
|
||
| JmHtmlResponse jmHtmlResponse = executeGetRequest(url); | ||
|
Comment on lines
+530
to
+534
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 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 登出后清理本地会话状态。
在 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| @Override | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -79,10 +79,9 @@ public static JmAlbum parseAlbum(String html) { | |
| parseRelatedAlbums(doc), | ||
| // 章节列表 | ||
| parsePhotoMetas(doc, id), | ||
| // HTML 解析不支持以下字段 | ||
| "0", // seriesId | ||
| false, // isFavorite | ||
| false, // liked | ||
| parseFavorite(doc, id), // isFavorite | ||
| parseLiked(doc, id), // liked | ||
| false, // isAids | ||
| Collections.emptyList(), // images | ||
| "", // price | ||
|
|
@@ -105,6 +104,11 @@ private static String decodeBase64Html(String html) { | |
| } | ||
|
|
||
| private static String parseAlbumId(Document doc) { | ||
| Element albumIdElement = doc.getElementById("album_id"); | ||
| if (albumIdElement != null && StringUtils.isNotBlank(albumIdElement.attr("value"))) { | ||
| return albumIdElement.attr("value"); | ||
| } | ||
|
|
||
| // 优先从PC布局的 h2 标签提取 | ||
| Element h2Element = doc.selectFirst("div.col-lg-7 h2:contains(禁漫车:), div.col-lg-7 h2:contains(禁漫車:)"); | ||
| if (h2Element != null && h2Element.parent() != null) { | ||
|
|
@@ -123,6 +127,30 @@ private static String parseAlbumId(Document doc) { | |
| throw new ParseResponseException("Could not parse album id."); | ||
| } | ||
|
|
||
| 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"); | ||
| } | ||
|
Comment on lines
+130
to
+138
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 不要把“不是黑色”直接判定为已收藏。 Line 137 在以下情况下会返回
这些情况只能说明“没有匹配到未收藏样式”,不能证明“已收藏”。请使用已确认的收藏状态正向标记;至少应把缺少或无法识别的样式判定为 最低限度的防误判修复 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 |
||
|
|
||
| private static boolean parseLiked(Document doc, String albumId) { | ||
| return doc.select("[id=love_likes_" + albumId + "] i") | ||
| .stream() | ||
| .anyMatch(element -> hasInlineStyle(element, "color", "red")); | ||
| } | ||
|
|
||
| private static boolean hasInlineStyle(Element element, String property, String value) { | ||
| return Arrays.stream(element.attr("style").split(";")) | ||
| .map(declaration -> declaration.split(":", 2)) | ||
| .anyMatch(parts -> parts.length == 2 | ||
| && property.equalsIgnoreCase(parts[0].trim()) | ||
| && value.equalsIgnoreCase(parts[1].trim())); | ||
| } | ||
|
|
||
| private static String extractDate(Document doc, String key) { | ||
| // 优先尝试PC端结构 | ||
| Element pcDateSpan = doc.selectFirst(String.format("div.col-lg-7 span:contains(%s)", key)); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: JUKOMU/JMComic-Api-Java
Length of output: 29394
🏁 Script executed:
Repository: JUKOMU/JMComic-Api-Java
Length of output: 13306
🏁 Script executed:
Repository: JUKOMU/JMComic-Api-Java
Length of output: 12970
🏁 Script executed:
Repository: JUKOMU/JMComic-Api-Java
Length of output: 9577
🏁 Script executed:
Repository: 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