-
Notifications
You must be signed in to change notification settings - Fork 9.9k
Dev #481
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
Conversation
|
Caution Review failedThe pull request is closed. WalkthroughAdds album-cover download support (JmcomicText.get_album_cover_url + JmImageClient.download_album_cover), a DownloadCoverPlugin, tests and docs updates, a fallback rule parser change, domain_retry_strategy injection into AbstractJmClient, an advanced_retry plugin rename, and a version bump. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as Caller
participant IC as JmImageClient
participant JT as JmcomicText
participant Net as HTTP
participant FS as FileSystem
Dev->>IC: download_album_cover(album_id, save_path, size?)
IC->>JT: get_album_cover_url(album_id, image_domain?, size?)
JT-->>IC: cover_url
IC->>Net: GET cover_url (scramble_id=None, decode_image=False)
alt 200 OK
Net-->>IC: image bytes
IC->>FS: write save_path (e.g., cover.png)
FS-->>IC: OK
IC-->>Dev: success
else error
IC-->>Dev: error
end
sequenceDiagram
autonumber
participant C as AbstractJmClient
participant S as domain_retry_strategy (optional)
participant Net as HTTP
C->>Net: request(url)
alt success
Net-->>C: response
else failure
opt strategy provided
C->>S: strategy(url, attempt, error)
S-->>C: next_domain / None
alt next_domain provided
C->>Net: request(url@next_domain)
Net-->>C: response/error
else no suggestion
C->>Net: fallback retry logic
Net-->>C: response/error
end
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (7)
src/jmcomic/jm_toolkit.py (1)
384-387: Non-crypto randomness is fine here; hush the linter or switch API.Domain selection isn’t security‑sensitive. Either keep
random.choiceand add# noqa: S311(as in the diff above), or replace withsecrets.choiceif you prefer zero lint noise.tests/test_jmcomic/test_jm_client.py (1)
336-339: Assert the download and avoid polluting CWD.Use a temp directory and assert the file exists to make the test meaningful and hermetic.
- def test_download_cover(self): - album_id = 123 - self.client.download_album_cover(album_id, f'./{album_id}.jpg') + def test_download_cover(self): + import os, tempfile + album_id = 123 + with tempfile.TemporaryDirectory() as td: + path = os.path.join(td, f'{album_id}.jpg') + self.client.download_album_cover(album_id, path) + self.assertTrue(os.path.exists(path), f'cover not downloaded: {path}')src/jmcomic/jm_client_interface.py (1)
296-303: Expose size passthrough and make import explicit for linters.
- Optional: surface
sizeso callers can request variants like "_3x4".- Lint: star import obscures
JmcomicText; add an explicit import or alias.Apply this diff:
- def download_album_cover(self, album_id, save_path: str): + def download_album_cover(self, album_id, save_path: str, size: str = ''): self.download_image( - img_url=JmcomicText.get_album_cover_url(album_id), + img_url=JmcomicText.get_album_cover_url(album_id, size=size), img_save_path=save_path, scramble_id=None, decode_image=False, )And near the top of the file (outside this hunk), add:
from .jm_toolkit import JmcomicText # explicit symbol to satisfy linters (F405)If you prefer not to change the public signature, ignore the
sizepart and only add the explicit import. Please confirm which route you want.assets/docs/sources/tutorial/0_common_usage.md (2)
52-54: Docs: mention optional size for cover.Add an example that shows requesting a specific cover size to match the API surface.
-# 下载本子封面图,保存为 cover.png (图片后缀可指定为jpg、webp等) -client.download_album_cover('427413', './cover.png') +# 下载本子封面图,保存为 cover.png (图片后缀可指定为jpg、webp等) +client.download_album_cover('427413', './cover.png') +# 指定封面尺寸(例如列表页用的 3x4) +client.download_album_cover('427413', './cover_3x4.png', size='_3x4')
69-71: Prefer helper for cover URL in examples.Use
JmcomicText.get_album_cover_urlinstead of hardcoding the albums path.- random_image_domain = JmModuleConfig.DOMAIN_IMAGE_LIST[0] - client.download_image(f'https://{random_image_domain}/media/albums/416130.jpg', './a.jpg') + client.download_image(JmcomicText.get_album_cover_url('416130'), './a.jpg')src/jmcomic/jm_client_impl.py (2)
14-31: Constructor param added; update docstring and typing.Document
domain_retry_strategyand, if possible, type it as an Optional[Callable]. This improves discoverability and plugin authoring.def __init__(self, postman: Postman, domain_list: List[str], retry_times=0, - domain_retry_strategy=None, + domain_retry_strategy=None, ): @@ - :param retry_times: 重试次数 + :param retry_times: 重试次数 + :param domain_retry_strategy: 自定义域名/重试策略回调,签名: + (client, request, url, is_image, *, domain_index, retry_count, **kwargs) -> ResponseOptionally (outside this hunk), annotate the field:
from typing import Optional, Callable, Any self.domain_retry_strategy: Optional[Callable[..., Any]] = domain_retry_strategy
73-80: Pass retry context into custom strategy.Hand the
domain_indexandretry_countto the strategy; it’s often needed for proper backoff/switching.- if self.domain_retry_strategy: - return self.domain_retry_strategy(self, - request, - url, - is_image, - **kwargs, - ) + if self.domain_retry_strategy: + return self.domain_retry_strategy(self, + request, + url, + is_image, + domain_index=domain_index, + retry_count=retry_count, + **kwargs)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
assets/docs/sources/tutorial/0_common_usage.md(2 hunks)src/jmcomic/jm_client_impl.py(2 hunks)src/jmcomic/jm_client_interface.py(1 hunks)src/jmcomic/jm_toolkit.py(1 hunks)tests/test_jmcomic/test_jm_client.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
tests/test_jmcomic/test_jm_client.py (1)
src/jmcomic/jm_client_interface.py (1)
download_album_cover(296-302)
src/jmcomic/jm_client_interface.py (5)
src/jmcomic/jm_entity.py (1)
album_id(363-364)src/jmcomic/jm_toolkit.py (1)
get_album_cover_url(372-388)src/jmcomic/jm_option.py (1)
download_album(489-495)src/jmcomic/jm_downloader.py (3)
download_album(85-88)download_by_image_detail(121-146)download_by_image_detail(328-333)tests/test_jmcomic/test_jm_api.py (1)
test_download_album_by_id(13-18)
src/jmcomic/jm_toolkit.py (2)
src/jmcomic/jm_entity.py (1)
album_id(363-364)src/jmcomic/jm_config.py (1)
JmModuleConfig(84-503)
🪛 Ruff (0.13.1)
src/jmcomic/jm_client_interface.py
298-298: JmcomicText may be undefined, or defined from star imports
(F405)
src/jmcomic/jm_toolkit.py
374-374: PEP 484 prohibits implicit Optional
Convert to Optional[T]
(RUF013)
382-382: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
386-386: Standard pseudo-random generators are not suitable for cryptographic purposes
(S311)
386-386: JmModuleConfig may be undefined, or defined from star imports
(F405)
388-388: JmModuleConfig may be undefined, or defined from star imports
(F405)
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/jmcomic/jm_toolkit.py (2)
377-383: Docstring punctuation triggers Ruff (RUF002).Switch fullwidth punctuation to ASCII to appease the linter.
Apply this diff:
- 根据本子id生成封面url + 根据本子 id 生成封面 URL @@ - :param image_domain: 图片cdn域名(可传入裸域或含协议的域名) - :param size: 尺寸后缀,例如搜索列表页会使用 size="_3x4" 的封面图 + :param image_domain: 图片 CDN 域名 (可传入裸域或含协议的域名) + :param size: 尺寸后缀, 例如搜索列表页会使用 size="_3x4" 的封面图
388-389: Optional: guard against trailing slashes in domains.If callers pass image_domain with a trailing slash, format_url currently produces a double slash. Consider normalizing in format_url.
Example (outside this hunk):
@classmethod def format_url(cls, path, domain): ExceptionTool.require_true(isinstance(domain, str) and len(domain) != 0, '域名为空') path = path if path.startswith('/') else '/' + path if domain.startswith(JmModuleConfig.PROT): return f'{domain.rstrip("/")}{path}' return f'{JmModuleConfig.PROT}{domain.rstrip("/")}{path}'
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/jmcomic/jm_toolkit.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/jmcomic/jm_toolkit.py (1)
src/jmcomic/jm_config.py (1)
JmModuleConfig(84-503)
🪛 Ruff (0.13.1)
src/jmcomic/jm_toolkit.py
373-373: Union may be undefined, or defined from star imports
(F405)
374-374: Optional may be undefined, or defined from star imports
(F405)
381-381: Docstring contains ambiguous ( (FULLWIDTH LEFT PARENTHESIS). Did you mean ( (LEFT PARENTHESIS)?
(RUF002)
381-381: Docstring contains ambiguous ) (FULLWIDTH RIGHT PARENTHESIS). Did you mean ) (RIGHT PARENTHESIS)?
(RUF002)
382-382: Docstring contains ambiguous , (FULLWIDTH COMMA). Did you mean , (COMMA)?
(RUF002)
386-386: JmModuleConfig may be undefined, or defined from star imports
(F405)
🔇 Additional comments (2)
src/jmcomic/jm_toolkit.py (2)
371-389: Album-cover URL helper: logic LGTM.Broader typing + format_url usage resolve the scheme-duplication concern and handle int/str album IDs correctly.
373-386: Import Optional/Union and JmModuleConfig explicitly.Silences F405 and avoids annotation runtime issues in environments without postponed annotations.
Add these imports near the top of the file:
from typing import Optional, Union from .jm_config import JmModuleConfig#!/bin/bash # Verify explicit imports exist rg -nP 'from\s+typing\s+import\s+.*\b(Optional|Union)\b' src/jmcomic/jm_toolkit.py rg -nP 'from\s+\.jm_config\s+import\s+JmModuleConfig' src/jmcomic/jm_toolkit.py
|
@coderabbitai review new commit |
|
@hect0x7 I'll review the new commit for you. This appears to be a feature addition for downloading album cover images, along with some infrastructure improvements for domain retry strategies. ✅ Actions performedReview triggered.
|
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.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/jmcomic/jm_plugin.py (1)
1311-1328: Register plugin 'download-cover'Add a call to JmModuleConfig.register_plugin(DownloadCoverPlugin) (e.g., immediately after the class in src/jmcomic/jm_plugin.py) — current repo search shows no register_plugin invocations except the method definition and a docs example, so 'download-cover' is not being added to JmModuleConfig.REGISTRY_PLUGIN and will fail to resolve from config.
🧹 Nitpick comments (4)
src/jmcomic/jm_option.py (1)
161-163: Make the fallback observable; remove dead code.Silently treating unknown tokens as f-string text is fine, but log once per token to aid misconfig debugging, and drop the commented raise.
- return cls.parse_f_string_rule - # ExceptionTool.raises(f'不支持的rule配置: "{rule}"') + jm_log('dir_rule.fallback', f'未识别的rule片段"{rule}",按f-string文本处理。') + return cls.parse_f_string_rulesrc/jmcomic/jm_client_interface.py (1)
296-303: Return the delegate call; importJmcomicTextexplicitly to satisfy Ruff F405.
- Keep semantics aligned with
download_by_image_detailby returning the inner call.- Add an explicit import for
JmcomicTextto avoid F405 from star-imports.- def download_album_cover(self, album_id, save_path: str, size: str = ''): - self.download_image( + def download_album_cover(self, album_id, save_path: str, size: str = ''): + """Download album cover without decoding.""" + return self.download_image( img_url=JmcomicText.get_album_cover_url(album_id, size=size), img_save_path=save_path, scramble_id=None, decode_image=False, )Add near the top of the file (outside this hunk):
from .jm_toolkit import JmcomicText # explicit import to avoid F405assets/docs/sources/option_file_syntax.md (1)
197-205: Clarify overwrite behavior for download-cover.The plugin currently always re-downloads/overwrites the cover. Consider adding a note here (or a
skip_if_existsflag) so users know repeated runs won’t be skipped.src/jmcomic/jm_plugin.py (1)
1311-1328: Harden DownloadCoverPlugin: validate context, optional cache-skip, lint nits.
- Validate that either album or photo is provided and that
dir_ruleexists.- Honor global cache by skipping if the target file exists.
- Rename unused kwargs to
_kwargsto satisfy ARG002.class DownloadCoverPlugin(JmOptionPlugin): plugin_key = 'download-cover' - def invoke(self, - dir_rule: dict, - size='', - photo: JmPhotoDetail = None, - album: JmAlbumDetail = None, - downloader=None, - **kwargs) -> None: - album_id = album.id if album else photo.album_id - save_path = self.decide_filepath( - album, photo, - None, None, None, - dir_rule - ) - downloader.client.download_album_cover(album_id, save_path, size) + def invoke(self, + dir_rule: dict, + size='', + photo: JmPhotoDetail = None, + album: JmAlbumDetail = None, + downloader=None, + **_kwargs) -> None: + self.require_param(album is not None or photo is not None, 'download-cover需在before_album/after_photo上下文运行') + self.require_param(isinstance(dir_rule, dict), '必须提供dir_rule配置(包含base_dir与rule)') + + # 构造保存路径 + save_path = self.decide_filepath(album, photo, None, None, None, dir_rule) + + # 避免重复下载(遵循全局cache设置) + if getattr(self.option.download, 'cache', False) and os.path.exists(save_path): + self.log(f'封面已存在,跳过: {save_path}') + return + + album_id = album.id if album else photo.album_id + downloader.client.download_album_cover(album_id, save_path, size)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
assets/docs/sources/option_file_syntax.md(2 hunks)src/jmcomic/jm_client_interface.py(1 hunks)src/jmcomic/jm_option.py(1 hunks)src/jmcomic/jm_plugin.py(2 hunks)tests/test_jmcomic/test_jm_client.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/test_jmcomic/test_jm_client.py
🧰 Additional context used
🧬 Code graph analysis (2)
src/jmcomic/jm_plugin.py (2)
src/jmcomic/jm_entity.py (6)
JmPhotoDetail(292-451)JmAlbumDetail(454-568)album_id(363-364)id(67-68)id(433-434)id(514-515)src/jmcomic/jm_client_interface.py (1)
download_album_cover(296-302)
src/jmcomic/jm_client_interface.py (1)
src/jmcomic/jm_toolkit.py (1)
get_album_cover_url(372-389)
🪛 Ruff (0.13.1)
src/jmcomic/jm_plugin.py
114-114: Optional may be undefined, or defined from star imports
(F405)
114-114: Optional may be undefined, or defined from star imports
(F405)
114-114: Optional may be undefined, or defined from star imports
(F405)
1317-1317: JmPhotoDetail may be undefined, or defined from star imports
(F405)
1318-1318: JmAlbumDetail may be undefined, or defined from star imports
(F405)
1320-1320: Unused method argument: kwargs
(ARG002)
src/jmcomic/jm_client_interface.py
298-298: JmcomicText may be undefined, or defined from star imports
(F405)
🔇 Additional comments (2)
assets/docs/sources/option_file_syntax.md (1)
113-118: LGTM: default rule and “auto Bd” note match implementation.Doc reflects
split_rule_dslauto-insertingBd. Keep braces quoted in YAML as shown to avoid parser surprises.src/jmcomic/jm_plugin.py (1)
114-116: Good change: Optional filename/suffix/base_dir unlocks flexible callers. Also import typing names explicitly.The type loosening is helpful. To quiet Ruff F405 from star-imports, explicitly import typing names at module top.
Add at the top of this file:
from typing import Optional, Dict, Any, List, Callable
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests
Chores