Skip to content

v2.6.17: 修复 download_cover 插件不兼容 download_photo 的问题 (fix #523)#524

Merged
hect0x7 merged 5 commits intomasterfrom
dev
Mar 28, 2026
Merged

v2.6.17: 修复 download_cover 插件不兼容 download_photo 的问题 (fix #523)#524
hect0x7 merged 5 commits intomasterfrom
dev

Conversation

@hect0x7
Copy link
Copy Markdown
Owner

@hect0x7 hect0x7 commented Mar 28, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Prevented folder-path errors when album info is missing; added early exits when no images are found and improved plugin failure handling to avoid crashes.
  • Refactor

    • Streamlined boolean/truthiness checks and adjusted plugin exception-safety behavior and logging toggle semantics for more consistent control flow.
  • Chores

    • Bumped module and app versions; added a development dependency for image-to-PDF processing.
  • Tests

    • Added a test for missing-album plugin behavior and fixed test cleanup to restore config state.

@hect0x7 hect0x7 changed the title v2.6.17: 修复 download_cover 插件不兼容 download_photo 的问题 v2.6.17: 修复 download_cover 插件不兼容 download_photo 的问题 (fix #523) Mar 28, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

Bumped package and app versions; replaced strict boolean comparisons with truthiness; added album fallback when album is None; made image-write plugins return early on empty inputs and updated related invoke flows; changed JmOption.call_all_plugin default safe to None; adjusted jm_log msg typing; added/updated tests for plugin album-less behavior and config cleanup.

Changes

Cohort / File(s) Summary
Version & Constants
src/jmcomic/__init__.py, src/jmcomic/jm_config.py
Incremented __version__ to 2.6.17 and JmMagicConstants.APP_VERSION to 2.0.19.
Plugin logic & control flow
src/jmcomic/jm_plugin.py
Use photo.from_album when album is None; replace is True/is not True checks with truthiness; early-return when image lists are empty; LongImgPlugin.write_img_2_long_img now returns Optional[List[str]]; Img2pdf/LongImg invoke flows handle falsy returns; tightened server running/update checks.
Configuration / Logging
src/jmcomic/jm_config.py
Removed type annotation on jm_log's msg parameter (now untyped) and replaced strict boolean checks with truthiness.
Option handling
src/jmcomic/jm_option.py
Changed JmOption.call_all_plugin(self, group: str, safe=None, **extra) and modified exception-swallowing logic to consider plugin pinfo.get('safe', True) when method-level safe is not explicitly True.
Tests
tests/test_jmcomic/test_jm_plugin.py, tests/test_jmcomic/test_jm_custom.py
Added test_plugin_missing_album_context to exercise folder-rule generation without album context; restored JmModuleConfig.CLASS_ALBUM/CLASS_PHOTO at end of test_custom_entity.
Dev dependencies
requirements-dev.txt
Added img2pdf to development requirements.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through code with tiny paws tonight,
Bumped versions, fixed paths when albums hide from sight.
I nibbled booleans till truthiness shone,
Skipped empty writes, so no error was sown.
A carrot, a test — now plugins sleep tight. 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly references version 2.6.17 and specifically addresses a compatibility issue between the download_cover plugin and download_photo function, directly reflecting the main changes in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/jmcomic/jm_plugin.py (1)

38-45: ⚠️ Potential issue | 🟠 Major

Plugin logging is inverted here.

self.log_enable defaults to True, but this branch returns before emitting anything. Combined with JmOption.invoke_plugin() setting log_enable = False for pinfo['log']=False, plugin logs are now suppressed by default and only show up when logging is disabled in config.

Suggested fix
     def log(self, msg, topic=None):
-        if self.log_enable:
+        if not self.log_enable:
             return
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/jmcomic/jm_plugin.py` around lines 38 - 45, The log method is inverted:
it returns early when self.log_enable is truthy, causing logs to be suppressed
by default; change the conditional in log (method name: log, attribute:
self.log_enable) so that it only returns when logging is disabled (i.e., if not
self.log_enable return), then call jm_log with the same topic construction
(using self.plugin_key and optional topic) and msg; also ensure any places that
set pinfo['log'] (e.g., JmOption.invoke_plugin) keep the intended semantics
(True = enable, False = disable).
src/jmcomic/jm_option.py (1)

525-546: ⚠️ Potential issue | 🟠 Major

safe=False no longer forces fail-fast plugin execution.

With the current condition, passing safe=False still swallows exceptions whenever pinfo['safe'] is omitted or True. If None is the new "defer to plugin config" sentinel, the method-level override should win whenever safe is explicitly set.

Suggested fix
-    def call_all_plugin(self, group: str, safe=None, **extra):
+    def call_all_plugin(self, group: str, safe: Optional[bool] = None, **extra):
         plugin_list: List[dict] = self.plugins.get(group, [])
         if plugin_list is None or len(plugin_list) == 0:
             return
@@
             try:
                 self.invoke_plugin(pclass, kwargs, extra, pinfo)
             except BaseException as e:
-                if safe is True or pinfo.get('safe', True):
+                swallow = pinfo.get('safe', True) if safe is None else safe
+                if swallow:
                     jm_log('plugin.exception', e)
                 else:
                     raise e
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/jmcomic/jm_option.py` around lines 525 - 546, In call_all_plugin, the
exception-swallowing logic ignores an explicit safe=False because it falls back
to pinfo.get('safe', True); change the decision to honor an explicit
method-level safe when provided: compute an effective_safe = safe if safe is not
None else pinfo.get('safe', True) (or equivalent conditional: if safe is True or
(safe is None and pinfo.get('safe', True'))) and use effective_safe when
deciding whether to log and continue or re-raise after invoking invoke_plugin;
reference pinfo, safe, pinfo.get('safe', True), and invoke_plugin to locate the
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/jmcomic/jm_option.py`:
- Around line 300-302: The code treats any falsy `log` value as "off" which
turns off logging when `log` is None (the sentinel for "inherit default");
change the pop to preserve the None sentinel and only disable logging on an
explicit False: use dic.pop('log', None) and call disable_jm_log() only when the
popped `log` is exactly False (e.g., if log is False: disable_jm_log()). This
keeps the JmModuleConfig.DEFAULT_OPTION_DICT['log'] = None behavior and allows
FLAG_ENABLE_JM_LOG to control inheritance.

In `@src/jmcomic/jm_plugin.py`:
- Around line 71-72: The guard in execute_deletion is inverted: currently it
returns when self.delete_original_file is True which means deletion runs by
default; change the condition to "if not self.delete_original_file: return" so
deletion is skipped unless the user opted in; update the check in the helper
method (execute_deletion) referenced by Img2pdfPlugin, LongImgPlugin, and
ZipPlugin to use the corrected boolean logic and ensure the default False for
delete_original_file prevents removal.

In `@tests/test_jmcomic/test_jm_plugin.py`:
- Around line 23-36: The test currently calls download_photo(...) which turns a
local path-resolution regression into a live API test and can false-pass when
img2pdf or Pillow aren’t installed; change the test to be self-contained by
constructing local JmAlbumDetail and JmPhotoDetail fixtures (or monkeypatch the
plugins' imports/I/O) and invoke the plugins' path-generation logic directly
(e.g., call Img2pdfPlugin.invoke and LongImgPlugin.invoke or their internal
path-generation helpers) instead of calling download_photo; ensure
option.plugins['before_photo'] still contains the same entries and assert the
generated path(s) and dir_rule handling, keeping DoNotDownloadImage out of the
execution path so no real network or optional dependency is required.

---

Outside diff comments:
In `@src/jmcomic/jm_option.py`:
- Around line 525-546: In call_all_plugin, the exception-swallowing logic
ignores an explicit safe=False because it falls back to pinfo.get('safe', True);
change the decision to honor an explicit method-level safe when provided:
compute an effective_safe = safe if safe is not None else pinfo.get('safe',
True) (or equivalent conditional: if safe is True or (safe is None and
pinfo.get('safe', True'))) and use effective_safe when deciding whether to log
and continue or re-raise after invoking invoke_plugin; reference pinfo, safe,
pinfo.get('safe', True), and invoke_plugin to locate the change.

In `@src/jmcomic/jm_plugin.py`:
- Around line 38-45: The log method is inverted: it returns early when
self.log_enable is truthy, causing logs to be suppressed by default; change the
conditional in log (method name: log, attribute: self.log_enable) so that it
only returns when logging is disabled (i.e., if not self.log_enable return),
then call jm_log with the same topic construction (using self.plugin_key and
optional topic) and msg; also ensure any places that set pinfo['log'] (e.g.,
JmOption.invoke_plugin) keep the intended semantics (True = enable, False =
disable).
🪄 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: 1c690c1d-c066-4b22-81ec-57b586301990

📥 Commits

Reviewing files that changed from the base of the PR and between 1786c15 and fcd99c0.

📒 Files selected for processing (5)
  • src/jmcomic/__init__.py
  • src/jmcomic/jm_config.py
  • src/jmcomic/jm_option.py
  • src/jmcomic/jm_plugin.py
  • tests/test_jmcomic/test_jm_plugin.py
✅ Files skipped from review due to trivial changes (1)
  • src/jmcomic/init.py

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/test_jmcomic/test_jm_custom.py (1)

24-40: ⚠️ Potential issue | 🟠 Major

Restore global config overrides in finally and reset to true default state.

Cleanup at Line 39-40 won’t run if the assertion fails, so JmModuleConfig can leak mutated global state into later tests. Also, resetting to JmAlbumDetail/JmPhotoDetail does not restore the class-level default state (None).

🔧 Proposed fix
@@
-        JmModuleConfig.CLASS_ALBUM = MyAlbum
-        JmModuleConfig.CLASS_PHOTO = MyPhoto
-
-        base_dir: str = workspace()
-        dir_rule = DirRule('Bd_Aaname_Ppname', base_dir)
-        # noinspection PyTypeChecker
-        save_dir = dir_rule.decide_image_save_dir(
-            MyAlbum('1', '0', '0', [], *['0'] * 10),
-            MyPhoto('2', *['0'] * 7)
-        )
-
-        self.assertEqual(
-            os.path.abspath(save_dir),
-            os.path.abspath(base_dir + dic[1] + '/' + dic[2]),
-        )
-        JmModuleConfig.CLASS_ALBUM = JmAlbumDetail
-        JmModuleConfig.CLASS_PHOTO = JmPhotoDetail
+        prev_album_cls = JmModuleConfig.CLASS_ALBUM
+        prev_photo_cls = JmModuleConfig.CLASS_PHOTO
+        JmModuleConfig.CLASS_ALBUM = MyAlbum
+        JmModuleConfig.CLASS_PHOTO = MyPhoto
+        try:
+            base_dir: str = workspace()
+            dir_rule = DirRule('Bd_Aaname_Ppname', base_dir)
+            # noinspection PyTypeChecker
+            save_dir = dir_rule.decide_image_save_dir(
+                MyAlbum('1', '0', '0', [], *['0'] * 10),
+                MyPhoto('2', *['0'] * 7)
+            )
+
+            self.assertEqual(
+                os.path.abspath(save_dir),
+                os.path.abspath(base_dir + dic[1] + '/' + dic[2]),
+            )
+        finally:
+            JmModuleConfig.CLASS_ALBUM = prev_album_cls
+            JmModuleConfig.CLASS_PHOTO = prev_photo_cls
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_jmcomic/test_jm_custom.py` around lines 24 - 40, Capture the
original JmModuleConfig.CLASS_ALBUM and CLASS_PHOTO before you override them,
wrap the test mutation and assertions in a try block, and in a finally block
restore those captured originals (or set them back to None) so the global config
is always reset even if the assertion fails; update the mutation lines that set
JmModuleConfig.CLASS_ALBUM = MyAlbum and JmModuleConfig.CLASS_PHOTO = MyPhoto to
follow this pattern so cleanup is guaranteed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@tests/test_jmcomic/test_jm_custom.py`:
- Around line 24-40: Capture the original JmModuleConfig.CLASS_ALBUM and
CLASS_PHOTO before you override them, wrap the test mutation and assertions in a
try block, and in a finally block restore those captured originals (or set them
back to None) so the global config is always reset even if the assertion fails;
update the mutation lines that set JmModuleConfig.CLASS_ALBUM = MyAlbum and
JmModuleConfig.CLASS_PHOTO = MyPhoto to follow this pattern so cleanup is
guaranteed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7f78d8a6-5593-44f5-b256-afbbddd478a7

📥 Commits

Reviewing files that changed from the base of the PR and between fcd99c0 and 89a7e38.

📒 Files selected for processing (1)
  • tests/test_jmcomic/test_jm_custom.py

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a 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

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)

38-45: ⚠️ Potential issue | 🔴 Critical

Logic is inverted: logging is disabled when log_enable is True.

The condition if self.log_enable: return causes the method to skip logging when log_enable is truthy. Since log_enable defaults to True (line 20), logging will never occur. The condition should be inverted.

🐛 Proposed fix
     def log(self, msg, topic=None):
-        if self.log_enable:
+        if not self.log_enable:
             return
 
         jm_log(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/jmcomic/jm_plugin.py` around lines 38 - 45, The log method's guard is
inverted: it returns when self.log_enable is True so logging never happens;
update the condition in jm_plugin.py inside def log(self, msg, topic=None) to
return early when logging is disabled (e.g., use if not self.log_enable: return)
and leave the jm_log call using self.plugin_key and optional topic unchanged so
messages are emitted when log_enable is True.
🧹 Nitpick comments (1)
src/jmcomic/jm_plugin.py (1)

869-884: Minor: Log message references empty list instead of searched directories.

At line 882, img_paths is logged but it's already an empty list at this point. The message would be more helpful if it logged img_dir_items (the directories that were searched) instead of the empty result.

📝 Suggested improvement
         if not img_paths:
-            self.log(f'所有文件夹都不存在图片,无法生成long_img:{img_paths}', 'error')
+            self.log(f'所有文件夹都不存在图片,无法生成long_img:{img_dir_items}', 'error')
             return
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/jmcomic/jm_plugin.py` around lines 869 - 884, In write_img_2_long_img,
the error log prints img_paths (already empty) instead of the directories
searched; update the process to log img_dir_items (the list of directories
generated by option.decide_image_save_dir / album mapping) in the self.log call
so the message shows which folders were searched when no images were found (keep
the same message text but replace the referenced variable from img_paths to
img_dir_items and leave the subsequent return as-is).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/jmcomic/jm_plugin.py`:
- Around line 123-127: The fallback that sets album = photo.from_album can still
leave album as None if photo.from_album is unset (JmPhotoDetail), so update the
album handling in the method containing the lines setting album to
photo.from_album to defensively handle that case: after the current fallback
check, if album is still None log a warning (or raise a clear error) and
short-circuit before calling DirRule/placeholder parsing (mirroring the
defensive pattern used in apply_rule_to_filename in jm_option.py), ensuring any
downstream calls that expect a non-None album do not receive None.

---

Outside diff comments:
In `@src/jmcomic/jm_plugin.py`:
- Around line 38-45: The log method's guard is inverted: it returns when
self.log_enable is True so logging never happens; update the condition in
jm_plugin.py inside def log(self, msg, topic=None) to return early when logging
is disabled (e.g., use if not self.log_enable: return) and leave the jm_log call
using self.plugin_key and optional topic unchanged so messages are emitted when
log_enable is True.

---

Nitpick comments:
In `@src/jmcomic/jm_plugin.py`:
- Around line 869-884: In write_img_2_long_img, the error log prints img_paths
(already empty) instead of the directories searched; update the process to log
img_dir_items (the list of directories generated by option.decide_image_save_dir
/ album mapping) in the self.log call so the message shows which folders were
searched when no images were found (keep the same message text but replace the
referenced variable from img_paths to img_dir_items and leave the subsequent
return as-is).
🪄 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: 0faefae8-a715-4b8d-916f-34309e154496

📥 Commits

Reviewing files that changed from the base of the PR and between 89a7e38 and 4d36f70.

📒 Files selected for processing (3)
  • requirements-dev.txt
  • src/jmcomic/jm_option.py
  • src/jmcomic/jm_plugin.py
✅ Files skipped from review due to trivial changes (1)
  • requirements-dev.txt
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/jmcomic/jm_option.py

@hect0x7 hect0x7 merged commit 2225136 into master Mar 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant