Feat/card synopsis - #19
Conversation
审阅者指南在 T2I 卡片中引入清洗后的漫画描述作为 synopsis 字段,通过订阅/更新/章节流程传递描述,并更新文档/测试以覆盖新行为和 HTML 清洗工具。 更新通知卡片 synopsis 线缆的序列图sequenceDiagram
participant Updater as SuwayomiUpdater
participant Manga as MangaObject
participant Cards as cards_py
participant T2I as T2IRenderer
Updater->>Manga: _check_one_manga
Manga-->>Updater: manga_obj(description, thumbnail_url, status)
Updater->>Updater: _run(build item dict with description)
Updater->>Cards: build_update_card(items, heading)
Cards->>Cards: clean_description(description)
Cards-->>Updater: tmpldata(items with synopsis)
Updater->>Cards: embed_covers(client, tmpldata_items)
Cards-->>Updater: tmpldata_with_covers
Updater->>T2I: render_card(html_render, tmpldata_with_covers, timeout)
T2I-->>Updater: jpeg_image_with_synopsis
文件级变更
提示与命令与 Sourcery 交互
自定义你的体验访问你的控制面板以:
获取帮助Original review guide in EnglishReviewer's GuideIntroduce cleaned manga descriptions into T2I cards as a synopsis field, wire descriptions through subscribe/update/chapter flows, and update docs/tests to cover the new behavior and HTML-cleaning utility. Sequence diagram for update notification card synopsis wiringsequenceDiagram
participant Updater as SuwayomiUpdater
participant Manga as MangaObject
participant Cards as cards_py
participant T2I as T2IRenderer
Updater->>Manga: _check_one_manga
Manga-->>Updater: manga_obj(description, thumbnail_url, status)
Updater->>Updater: _run(build item dict with description)
Updater->>Cards: build_update_card(items, heading)
Cards->>Cards: clean_description(description)
Cards-->>Updater: tmpldata(items with synopsis)
Updater->>Cards: embed_covers(client, tmpldata_items)
Cards-->>Updater: tmpldata_with_covers
Updater->>T2I: render_card(html_render, tmpldata_with_covers, timeout)
T2I-->>Updater: jpeg_image_with_synopsis
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - 我发现了 1 个问题,并给出了一些总体反馈:
- 新的
.synopsisCSS 类替代了.hint,但部分卡片变体(例如搜索、批量订阅、订阅)仍然渲染带有class="hint"的元素;建议要么保留一组最小化的.hint样式,要么更新这些模板使用.synopsis或其他类,以避免出现意料之外的视觉回归。 _SCRIPT_STYLE_RE在整个描述文本上使用了带 DOTALL 的贪婪.*?;对于非常大的 HTML 内容,这可能相对开销较大,并有可能意外跨越格式不正确或嵌套的标签——建议收紧该正则(例如限制匹配长度,或者对这些块使用 HTML 解析器),以提升clean_description的健壮性。
供 AI Agents 使用的提示
Please address the comments from this code review:
## Overall Comments
- 新的 `.synopsis` CSS 类替代了 `.hint`,但部分卡片变体(例如搜索、批量订阅、订阅)仍然渲染带有 `class="hint"` 的元素;建议要么保留一组最小化的 `.hint` 样式,要么更新这些模板使用 `.synopsis` 或其他类,以避免出现意料之外的视觉回归。
- `_SCRIPT_STYLE_RE` 在整个描述文本上使用了带 DOTALL 的贪婪 `.*?`;对于非常大的 HTML 内容,这可能相对开销较大,并有可能意外跨越格式不正确或嵌套的标签——建议收紧该正则(例如限制匹配长度,或者对这些块使用 HTML 解析器),以提升 `clean_description` 的健壮性。
## Individual Comments
### Comment 1
<location path="tests/test_cards.py" line_range="67-70" />
<code_context>
+ assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"
+
+
+def test_clean_description_truncates_with_ellipsis():
+ text = "字" * 500
+ cleaned = clean_description(text, max_chars=100)
+ assert cleaned == "字" * 100 + "…"
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test that exercises the default `SYNOPSIS_MAX_CHARS` truncation behavior
Currently truncation is only verified with an explicit `max_chars=100`. Please add a test that calls `clean_description` without `max_chars` so it uses the default `SYNOPSIS_MAX_CHARS`, and asserts the resulting length and ellipsis position. This helps catch regressions if `SYNOPSIS_MAX_CHARS` changes or if off‑by‑one errors are introduced in the truncation logic.
Suggested implementation:
```python
def test_clean_description_strips_html_and_whitespace():
raw = "<p> 少年<b>吞下了</b>诅咒的手指,\n踏上讨伐&之路。 </p>"
assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"
def test_clean_description_truncates_with_ellipsis():
text = "字" * 500
cleaned = clean_description(text, max_chars=100)
assert cleaned == "字" * 100 + "…"
def test_clean_description_uses_default_max_chars_truncation():
text = "字" * (SYNOPSIS_MAX_CHARS + 50)
cleaned = clean_description(text)
# Truncation should use SYNOPSIS_MAX_CHARS characters and then append an ellipsis.
assert len(cleaned) == SYNOPSIS_MAX_CHARS + 1
assert cleaned.endswith("…")
assert cleaned[:-1] == "字" * SYNOPSIS_MAX_CHARS
def test_build_subscribe_confirm_card():
```
To make this test pass, ensure `SYNOPSIS_MAX_CHARS` is imported into `tests/test_cards.py` from the module where it is defined, e.g.:
- At the top of `tests/test_cards.py`, add `from <module> import SYNOPSIS_MAX_CHARS` (adjust `<module>` to match your existing imports and where `clean_description` is defined).
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据这些反馈改进为你提供的评审质量。
Original comment in English
Hey - I've found 1 issue, and left some high level feedback:
- The new
.synopsisCSS class replaces.hint, but some card variants (e.g., search, batch subscription, subscriptions) still render elements withclass="hint"; consider either retaining minimal.hintstyles or updating those templates to use.synopsis/another class to avoid unexpected visual regressions. _SCRIPT_STYLE_REuses a greedy.*?with DOTALL over the whole description; for very large HTML blobs this could be relatively expensive and may accidentally span malformed or nested tags—consider constraining the pattern (e.g., limiting length, or using an HTML parser for those blocks) to makeclean_descriptionmore robust.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new `.synopsis` CSS class replaces `.hint`, but some card variants (e.g., search, batch subscription, subscriptions) still render elements with `class="hint"`; consider either retaining minimal `.hint` styles or updating those templates to use `.synopsis`/another class to avoid unexpected visual regressions.
- `_SCRIPT_STYLE_RE` uses a greedy `.*?` with DOTALL over the whole description; for very large HTML blobs this could be relatively expensive and may accidentally span malformed or nested tags—consider constraining the pattern (e.g., limiting length, or using an HTML parser for those blocks) to make `clean_description` more robust.
## Individual Comments
### Comment 1
<location path="tests/test_cards.py" line_range="67-70" />
<code_context>
+ assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"
+
+
+def test_clean_description_truncates_with_ellipsis():
+ text = "字" * 500
+ cleaned = clean_description(text, max_chars=100)
+ assert cleaned == "字" * 100 + "…"
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Add a test that exercises the default `SYNOPSIS_MAX_CHARS` truncation behavior
Currently truncation is only verified with an explicit `max_chars=100`. Please add a test that calls `clean_description` without `max_chars` so it uses the default `SYNOPSIS_MAX_CHARS`, and asserts the resulting length and ellipsis position. This helps catch regressions if `SYNOPSIS_MAX_CHARS` changes or if off‑by‑one errors are introduced in the truncation logic.
Suggested implementation:
```python
def test_clean_description_strips_html_and_whitespace():
raw = "<p> 少年<b>吞下了</b>诅咒的手指,\n踏上讨伐&之路。 </p>"
assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"
def test_clean_description_truncates_with_ellipsis():
text = "字" * 500
cleaned = clean_description(text, max_chars=100)
assert cleaned == "字" * 100 + "…"
def test_clean_description_uses_default_max_chars_truncation():
text = "字" * (SYNOPSIS_MAX_CHARS + 50)
cleaned = clean_description(text)
# Truncation should use SYNOPSIS_MAX_CHARS characters and then append an ellipsis.
assert len(cleaned) == SYNOPSIS_MAX_CHARS + 1
assert cleaned.endswith("…")
assert cleaned[:-1] == "字" * SYNOPSIS_MAX_CHARS
def test_build_subscribe_confirm_card():
```
To make this test pass, ensure `SYNOPSIS_MAX_CHARS` is imported into `tests/test_cards.py` from the module where it is defined, e.g.:
- At the top of `tests/test_cards.py`, add `from <module> import SYNOPSIS_MAX_CHARS` (adjust `<module>` to match your existing imports and where `clean_description` is defined).
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| def test_clean_description_truncates_with_ellipsis(): | ||
| text = "字" * 500 | ||
| cleaned = clean_description(text, max_chars=100) | ||
| assert cleaned == "字" * 100 + "…" |
There was a problem hiding this comment.
suggestion (testing): 添加一个测试,用于覆盖默认 SYNOPSIS_MAX_CHARS 的截断行为
目前截断逻辑只通过显式传入 max_chars=100 进行了验证。请添加一个调用 clean_description 且不传入 max_chars 的测试,使其使用默认的 SYNOPSIS_MAX_CHARS,并断言结果的长度和省略号的位置。这样可以在 SYNOPSIS_MAX_CHARS 修改或截断逻辑出现 off‑by‑one 错误时及时发现回归。
建议的实现:
def test_clean_description_strips_html_and_whitespace():
raw = "<p> 少年<b>吞下了</b>诅咒的手指,\n踏上讨伐&之路。 </p>"
assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"
def test_clean_description_truncates_with_ellipsis():
text = "字" * 500
cleaned = clean_description(text, max_chars=100)
assert cleaned == "字" * 100 + "…"
def test_clean_description_uses_default_max_chars_truncation():
text = "字" * (SYNOPSIS_MAX_CHARS + 50)
cleaned = clean_description(text)
# Truncation should use SYNOPSIS_MAX_CHARS characters and then append an ellipsis.
assert len(cleaned) == SYNOPSIS_MAX_CHARS + 1
assert cleaned.endswith("…")
assert cleaned[:-1] == "字" * SYNOPSIS_MAX_CHARS
def test_build_subscribe_confirm_card():为了让这个测试通过,请确保在定义 SYNOPSIS_MAX_CHARS 的模块中,将它导入到 tests/test_cards.py,例如:
- 在
tests/test_cards.py文件顶部添加from <module> import SYNOPSIS_MAX_CHARS(将<module>调整为与你现有的导入以及clean_description所在模块相匹配的值)。
Original comment in English
suggestion (testing): Add a test that exercises the default SYNOPSIS_MAX_CHARS truncation behavior
Currently truncation is only verified with an explicit max_chars=100. Please add a test that calls clean_description without max_chars so it uses the default SYNOPSIS_MAX_CHARS, and asserts the resulting length and ellipsis position. This helps catch regressions if SYNOPSIS_MAX_CHARS changes or if off‑by‑one errors are introduced in the truncation logic.
Suggested implementation:
def test_clean_description_strips_html_and_whitespace():
raw = "<p> 少年<b>吞下了</b>诅咒的手指,\n踏上讨伐&之路。 </p>"
assert clean_description(raw) == "少年吞下了诅咒的手指, 踏上讨伐&之路。"
def test_clean_description_truncates_with_ellipsis():
text = "字" * 500
cleaned = clean_description(text, max_chars=100)
assert cleaned == "字" * 100 + "…"
def test_clean_description_uses_default_max_chars_truncation():
text = "字" * (SYNOPSIS_MAX_CHARS + 50)
cleaned = clean_description(text)
# Truncation should use SYNOPSIS_MAX_CHARS characters and then append an ellipsis.
assert len(cleaned) == SYNOPSIS_MAX_CHARS + 1
assert cleaned.endswith("…")
assert cleaned[:-1] == "字" * SYNOPSIS_MAX_CHARS
def test_build_subscribe_confirm_card():To make this test pass, ensure SYNOPSIS_MAX_CHARS is imported into tests/test_cards.py from the module where it is defined, e.g.:
- At the top of
tests/test_cards.py, addfrom <module> import SYNOPSIS_MAX_CHARS(adjust<module>to match your existing imports and whereclean_descriptionis defined).
Summary by Sourcery
在已支持的渲染结果卡片中,安全地添加规范化的漫画简介。
新功能:
错误修复:
改进:
文档:
测试:
杂项:
Original summary in English
Summary by Sourcery
Add safely normalized manga synopses to supported rendered result cards.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests:
Chores:
新功能:
错误修复:
改进:
文档:
测试:
Original summary in English
Summary by Sourcery
在已支持的渲染结果卡片中,安全地添加规范化的漫画简介。
新功能:
错误修复:
改进:
文档:
测试:
杂项:
Original summary in English
Summary by Sourcery
Add safely normalized manga synopses to supported rendered result cards.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests:
Chores:
新功能:
缺陷修复:
改进优化:
文档:
测试:
杂项维护:
Original summary in English
Summary by Sourcery
在已支持的渲染结果卡片中,安全地添加规范化的漫画简介。
新功能:
错误修复:
改进:
文档:
测试:
杂项:
Original summary in English
Summary by Sourcery
Add safely normalized manga synopses to supported rendered result cards.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests:
Chores:
新功能:
错误修复:
改进:
文档:
测试:
Original summary in English
Summary by Sourcery
在已支持的渲染结果卡片中,安全地添加规范化的漫画简介。
新功能:
错误修复:
改进:
文档:
测试:
杂项:
Original summary in English
Summary by Sourcery
Add safely normalized manga synopses to supported rendered result cards.
New Features:
Bug Fixes:
Enhancements:
Documentation:
Tests:
Chores: