feat: optimize screenshot rendering quality

- Use networkidle instead of load — waits for Discourse JS rendering
- Wait for .cooked selector — smart content detection with fallback
- Hide fixed/sticky elements via JS injection:
  - .d-header (top navigation bar)
  - .sidebar-wrapper (left sidebar)
  - .topic-navigation-wrapper, .footer-nav
- Scroll to first post content for clean framing
- Default to viewport screenshot (not full_page) — practical preview
- Add screenshot_full_page config option for users who want full thread
- Adjust viewport to 1280×900 (16:9-ish)
This commit is contained in:
RainySY
2026-06-15 22:22:57 +08:00
parent a13be98c26
commit fa5c4e78b5
3 changed files with 39 additions and 6 deletions

View File

@@ -7,7 +7,7 @@
- 🔗 **自动检测** — 聊天中出现 `linux.do` 链接立即触发
- 🛡️ **绕过 Cloudflare** — 使用 [Scrapling](https://github.com/D4Vinci/Scrapling) 的 StealthySession 自动解 Turnstile
- 📸 **截图预览**全页面截图1280×1024
- 📸 **智能截图**视口截图显示主帖,自动隐藏导航栏/侧边栏,可选全页模式
- 📝 **内容摘要** — 提取标题 + 正文前 400 字
-**异步非阻塞** — Scrapling 在独立线程池运行,不阻塞 AstrBot 主循环
- 💾 **缓存机制** — 30 分钟内相同链接直接返回缓存截图
@@ -98,6 +98,7 @@ https://linux.do/t/topic/1378383
| `cache_ttl` | 缓存有效期(秒),设为 0 关闭缓存 | 1800 |
| `max_content_length` | 内容摘要最大长度(字符) | 400 |
| `screenshot_timeout` | 截图超时(秒) | 15 |
| `screenshot_full_page` | 全页截图模式false=仅视口,更实用) | false |
## ⚠️ 注意事项

View File

@@ -16,5 +16,11 @@
"type": "int",
"default": 15,
"hint": "Max seconds to wait for page screenshot."
},
"screenshot_full_page": {
"description": "Full page screenshot mode",
"type": "bool",
"default": false,
"hint": "When false (default), captures viewport only — shows the first post cleanly. Set to true for full thread capture (larger file size)."
}
}

36
main.py
View File

@@ -169,17 +169,43 @@ class LinuxDoPreviewPlugin(Star):
return None
page = ctx.new_page()
page.set_viewport_size({"width": 1280, "height": 1024})
page.set_viewport_size({"width": 1280, "height": 900})
# 导航(已有 cf_clearance cookie不应再触发 Cloudflare
page.goto(url, wait_until="load", timeout=timeout_ms)
page.wait_for_timeout(3000)
# ── 导航:等 networkidle 确保 JS 动态内容加载完成 ──
page.goto(url, wait_until="networkidle", timeout=timeout_ms)
# ── 等待 Discourse 帖子内容渲染 ──
try:
page.wait_for_selector(".cooked", timeout=min(timeout_ms, 10000))
except Exception:
page.wait_for_timeout(3000) # 回退:固定等待
# ── 隐藏固定元素,避免截图杂乱/重复 ──
page.evaluate("""() => {
const hide = (sel) => {
const el = document.querySelector(sel);
if (el) el.style.display = 'none';
};
hide('.d-header'); // 顶部导航栏
hide('.sidebar-wrapper'); // 左侧边栏
hide('.topic-navigation-wrapper'); // 帖子导航条
hide('.footer-nav.visible'); // 底部导航
// 滚动到第一篇帖子正文
const firstPost = document.querySelector('.cooked');
if (firstPost) firstPost.scrollIntoView({block: 'start'});
}""")
page.wait_for_timeout(1000) # 等待滚动稳定 + 懒加载图片
# ── 截图:默认视口模式,更实用的预览尺寸 ──
full_page = self.config.get("screenshot_full_page", False)
page.screenshot(
path=str(save_path),
full_page=True,
full_page=full_page,
timeout=timeout_ms,
)
sz = save_path.stat().st_size
logger.info(
f"[LinuxDoPreview] 截图保存: {save_path.name} ({sz / 1024:.1f} KB)"