# 简介
`karin-plugin-kkk` 是基于 Karin 开发的多平台内容解析插件。
## 核心定位 [#核心定位]
它的重点不是“再发一遍链接”,而是在拿到平台数据后,直接渲染成适合群聊阅读和浏览的图片内容。
* 自动识别抖音、B站、快手、小红书分享链接
* 提取视频、图文、热评、动态内容并渲染成图片
* 为抖音、B站提供动态推送、强制推送和统计能力
* 支持弹幕烧录、Live Photo 兼容导出等增强能力
## 当前能力概览 [#当前能力概览]
| 平台 | 自动解析 | 评论渲染 | 动态推送 | 扫码登录 | 弹幕烧录 |
| ------- | :--: | :--: | :--: | :--: | :--: |
| **抖音** | ✓ | ✓ | ✓ | ✓ | ✓ |
| **B站** | ✓ | ✓ | ✓ | ✓ | ✓ |
| **快手** | ✓ | ✓ | — | — | — |
| **小红书** | ✓ | ✓ | — | — | — |
## 推荐阅读 [#推荐阅读]
如果你是第一次接入,先看快速开始;如果你已经装好了插件,后面几页更适合按需查阅:
## 额外能力 [#额外能力]
* `#kkk帮助` 查看当前命令菜单
* `#kkk解析统计` / `#kkk全局解析统计` 查看解析数据
* `#kkk版本` / `#kkk更新日志` 查看本地更新日志
* `#kkk更新` 执行插件更新
## 开源协议 [#开源协议]
[GPL-3.0](https://github.com/ikenxuan/karin-plugin-kkk/blob/master/LICENSE)
# 获取 Cookies
Cookies 仅用于请求平台官方 API,不会上传到任何第三方。
## 方式一:扫码登录(推荐) [#方式一扫码登录推荐]
扫码登录暂时只支持抖音与B站。
在群聊中发送:
```
#抖音登录
#B站登录
```
使用对应 APP 扫码即可自动保存 Cookies。
## 方式二:浏览器插件获取(推荐) [#方式二浏览器插件获取推荐]
使用 Cookie Editor 浏览器插件快速获取 Cookies:
### 安装插件 [#安装插件]
* **Chrome 浏览器**:[Cookie Editor](https://chromewebstore.google.com/detail/cookie-editor/hlkenndednhfkekhgcdicdfddnkalmdm?hl=zh-CN\&utm_source=ext_sidebar)
* **Edge 浏览器**:在 Edge 扩展商店搜索 "Cookie Editor" 并安装
### 使用步骤 [#使用步骤]
1. 打开浏览器,访问对应平台并登录
2. 点击浏览器工具栏中的 Cookie Editor 插件图标打开扩展
3. 点击右下角的 "Export" 按钮(如图中标记 2)
4. 选择 "Header String" 格式(如图中标记 3)
5. 复制生成的完整 Cookie 字符串
请确保选择 "Header String" 格式,这样可以获取到完整的 Cookie 字符串形式。
## 方式三:浏览器开发者工具获取 [#方式三浏览器开发者工具获取]
1. 打开浏览器,访问对应平台并登录
2. 按 F12 打开开发者工具(不同浏览器打开方式不同,如 Chrome 和 Edge 按 F12 或右键点击页面选择"检查")
3. 切换到 Network(网络)标签
4. 刷新页面,找到任意请求
5. 在请求头中复制 Cookie 值
## 方式四:移动端获取 [#方式四移动端获取]
使用 Via 浏览器 访问平台网页版并登录:
* 抖音:[www.douyin.com](http://www.douyin.com)
* B站:[www.bilibili.com](http://www.bilibili.com)
* 快手:[www.kuaishou.com](http://www.kuaishou.com)
登录后点击 **左上角菜单** → **查看 Cookies** → **复制文本**
## 配置方式 [#配置方式]
通过 Karin WebUI 配置,或编辑配置文件:
```yaml title="cookies.yaml"
douyin: 你的抖音Cookie
bilibili: 你的B站Cookie
kuaishou: 你的快手Cookie
xiaohongshu: 你的小红书Cookie
```
# 评论区渲染
将各平台的评论区内容渲染为图片发送,方便在群聊中快速预览热评和用户讨论。
## 支持平台 [#支持平台]
| 平台 | 楼中楼深度 | 特色功能 |
| --- | ------ | ----------- |
| 抖音 | 最多 6 层 | 完整对话嵌套、自动缩进 |
| B站 | 1 层 | 粉丝勋章、用户等级 |
| 小红书 | 1 层 | 图片评论 |
| 快手 | 仅主评论 | - |
## 楼中楼说明 [#楼中楼说明]
不同平台对评论嵌套的支持程度不同:
* **抖音**:支持完整的楼中楼结构,最多可嵌套 6 层。能够完整还原用户在评论区的对话场景,根据"谁回复了谁"自动进行缩进嵌套,清晰展示讨论脉络。
* **B站 / 小红书**:支持 1 层嵌套,即主评论下可显示子评论,但子评论之间不再嵌套。
* **快手**:仅显示主评论,不显示回复。
## 效果预览 [#效果预览]
## 功能特性 [#功能特性]
### 内容还原 [#内容还原]
* **表情包解析**:支持各平台自带表情(抖音表情、B站小电视等)
* **图片评论**:显示评论中的图片,HEIC 格式自动转 JPG
* **特殊文本**:高亮显示 @用户、#话题
* **粉丝勋章**:B站评论显示用户粉丝勋章和等级
### 智能排版 [#智能排版]
* **置顶评论**:自动识别并置顶作者置顶的评论
* **长文优化**:长评论自动优化排版,保证阅读体验
* **对话嵌套**:抖音支持完整对话树,直观展示讨论结构
## 配置 [#配置]
在 WebUI 中可针对每个平台单独配置:
* **解析数量**:渲染的评论条数(建议 10-20 条)
* **子评论限制**:控制楼中楼显示数量,避免图片过长
* **显示真实数量**:显示实际解析数量或平台标注的总数
# 弹幕烧录
**性能警告**:弹幕烧录需要对视频进行完整的重新编码,这是一个非常消耗资源的操作。
* **硬件编码**:如果你的运行环境支持硬件加速(如 NVIDIA 显卡 + 正确安装的驱动),处理速度会很快,一般几秒到几十秒即可完成。
* **软件编码**:如果没有可用的硬件编码器,将回退到 CPU 软编码。此时处理一个几分钟的视频可能需要数分钟甚至更久,期间会占用大量 CPU 资源,**在服务器/云主机上使用可能导致资源耗尽或被限流**。
建议在开启此功能前,先确认你的运行环境是否支持硬件加速。
当前版本已经支持将弹幕**硬编码**到视频画面中,生成可直接分享的带弹幕视频。目前只支持 **B站** 和 **抖音**。
## 支持平台 [#支持平台]
| 平台 | 弹幕类型 | 说明 |
| -- | -------- | ----------- |
| B站 | 滚动、顶部、底部 | 支持彩色弹幕、多种字号 |
| 抖音 | 滚动 | 仅支持纯文字弹幕 |
## 效果预览 [#效果预览]
## 使用方式 [#使用方式]
你可以用两种方式触发烧录:
1. 在平台配置中开启 `burnDanmaku`,之后命中链接就默认烧录
2. 引用一条抖音 / B站消息,手动发送 `#弹幕解析`
其中 `#弹幕解析` 适合“平时默认关闭,偶尔按需烧录”的场景。
处理流程:
1. 解析视频链接,获取视频和弹幕数据
2. 生成 ASS 字幕文件(自动计算轨道、防碰撞)
3. 使用 FFmpeg 将弹幕烧录到视频
4. 发送带弹幕的视频文件
## 竖屏适配 [#竖屏适配]
针对手机竖屏观看场景,提供三种画面处理模式:
* **关闭**:保持原始比例
* **标准模式**:仅对宽屏视频(16:9 及以上)进行竖屏适配
* **强制模式**:所有视频强制转为 9:16 竖屏
## 硬件加速 [#硬件加速]
弹幕烧录需要对视频进行重新编码,这是一个计算密集型任务。使用硬件加速可以大幅提升处理速度。
插件会自动检测可用的硬件编码器,优先使用硬件加速,无可用硬件时自动回退到软件编码(CPU)。
### 支持的硬件编码器 [#支持的硬件编码器]
| 显卡 | 编码器 | 要求 |
| ------ | ----- | --------------------- |
| NVIDIA | NVENC | GTX 600 系列及以上,需安装显卡驱动 |
| Intel | QSV | 6 代酷睿及以上核显,需安装核显驱动 |
| AMD | AMF | RX 400 系列及以上,需安装显卡驱动 |
### 驱动安装 [#驱动安装]
作者开发只测试了开发环境下的 Nvidia 显卡,Intel 与 AMD 平台下未进行测试。
大多数情况下,只要你的电脑能正常显示画面,驱动就已经装好了。如果硬件加速不生效,可以尝试更新驱动。
前往 NVIDIA 官网下载并安装最新驱动:
[www.nvidia.cn/drivers/lookup](http://www.nvidia.cn/drivers/lookup)
安装完成后重启电脑即可。
前往 Intel 官网下载并安装核显驱动:
Intel 下载中心
或使用 Intel 驱动程序和支持助理自动检测安装:
Intel 驱动程序和支持助理
前往 AMD 官网下载并安装最新驱动:
AMD 驱动下载
安装完成后重启电脑即可。
### 软件编码 [#软件编码]
如果没有独立显卡或核显不支持,插件会自动使用 CPU 进行软件编码。软件编码速度较慢,但兼容性最好。
* H.264 → libx264
* H.265 → libx265
* AV1 → libsvtav1
## 配置 [#配置]
在 Karin WebUI 中分别进入抖音或 B站配置页,重点关注:
* 弹幕烧录(`burnDanmaku`)
* 弹幕显示区域 / 弹幕区域(`danmakuArea`)
* 弹幕字号(`danmakuFontSize`)
* 弹幕透明度(`danmakuOpacity`)
* 竖屏适配(`verticalMode`)
* 视频编码格式(`videoCodec`)
抖音和 B站的字段名称基本一致,但默认画质、竖屏适配说明和视频来源处理逻辑并不完全相同,建议分别调试。
# 全局错误处理机制
你在使用 其他的一些视频解析工具时,可能会遇到命令偶尔报错,想第一时间知道是哪里炸了,可是你**没有时间**去排查,即使你有时间,也要**进入服务器**查看对应的上下文日志、调用栈等信息,才能定位问题,并把问题通过 Github Issue 或者 聊天群聊报告给开发者。
本页解决了以下生产环境中的痛点:
凡是由本插件的命令执行出错时,会**自动捕获**异常信息并渲染错误图片反馈给用户或者主人(可通过插件配置控制),并且附带上详细的下文和调用栈所打印的 `Debug` 等级日志。
## 架构概览 [#架构概览]
## 机制特性 [#机制特性]
### 错误处理包装器 [#错误处理包装器]
用 `wrapWithErrorHandler` 包装命令处理函数,出错时自动渲染错误图片:
```ts twoslash
// @noErrors
import karin, { type Message } from 'node-karin'
// ---cut-start---
interface ErrorHandlerOptions {
businessName: string
}
declare function wrapWithErrorHandler(
fn: (e: Message, next: () => unknown) => Promise,
options: ErrorHandlerOptions
): (e: Message, next: () => unknown) => Promise
// ---cut-end---
const handler = wrapWithErrorHandler(
async (e) => {
// 业务逻辑,异常会被自动捕获
return true
},
{ businessName: '功能名称' }
)
karin.command(/^#命令$/, handler)
```
### 上下文日志追踪 [#上下文日志追踪]
基于 [@karinjs/log4js](https://github.com/KarinJS/esmify/tree/main/packages/log4js) 的 `runContext` API,自动收集执行期间的所有日志,方便排查问题。
```ts twoslash
// @noErrors
import { logger } from 'node-karin'
const ctx = logger.runContext(async () => {
/* 业务逻辑 */
})
await ctx.run()
const logs = ctx.logs() // 获取执行期间的日志
```
## 错误图片示例 [#错误图片示例]
图片包含:错误类型、调用栈、业务名称、触发命令、执行日志、版本信息。
# 动态照片解析
插件在解析作品、动态或推送内容时,遇到 Live Photo / Motion Photo 资源,会按当前配置生成兼容的实况图文件,并可额外生成“仿 iPhone Live Photo”效果视频。
## 平台兼容性 [#平台兼容性]
| 平台 | 存储方式 | 插件支持 | 说明 |
| ------------------ | --------------- | :--: | ---------------------- |
| **Google / Pixel** | 单文件(JPEG + MP4) | ✓ | 标准 Motion Photo 格式 |
| **小米 HyperOS** | 单文件(JPEG + MP4) | ✓ | 兼容 Google 标准 + 小米扩展 |
| **OPPO ColorOS** | 单文件(JPEG + MP4) | ✓ | 兼容 Google 标准 + OPPO 扩展 |
| **华为/荣耀** | 单文件(JPEG + 标记) | ⚠️ | 理论支持,未经实测验证 |
| **iPhone** | 双文件(HEIC + MOV) | ✗ | 独立存储,无法合成单文件 |
| **vivo OriginOS** | 双文件(JPG + MP4) | ✗ | 独立存储,无法合成单文件 |
当前默认组合是:
* `livePhotoMode: video_and_livephoto`
* `livePhotoSystem: oppo`
## 使用方式 [#使用方式]
动态照片解析是自动触发的,无需额外命令:
1. 当解析到包含动态照片的作品/动态时
2. 插件会自动提取封面图片和视频片段
3. 根据 `livePhotoMode` 决定发送实况图、效果视频,或两者都发
4. 根据 `livePhotoSystem` 生成兼容不同相册系统的单文件图片
5. 最终通过合并转发消息发送
动态照片会以独立文件的形式出现在合并转发消息中,保存到相册后即可在支持的设备上播放。
**重要提示**
:必须保存原图才能被设备正确识别为动态照片。如果保存压缩图,会丢失视频数据,只能看到静态图片。
## 配置选项 [#配置选项]
核心配置有两个:
* Live Photo 处理和发送方式(`livePhotoMode`)
* Live Photo 静态图兼容系统(`livePhotoSystem`)
### 配置方式 [#配置方式]
在配置文件 `config/app.yaml` 中修改:
```yaml
# video_and_livephoto: 实况图 + 效果视频
# video_only: 仅效果视频
# livephoto_only: 仅实况图
livePhotoMode: video_and_livephoto
# 可选值:'google'、'xiaomi'、'oppo'、'huawei_honor'
livePhotoSystem: oppo
```
### 可选值说明 [#可选值说明]
| 项目 | 可选值 | 说明 |
| ----------------- | --------------------- | ----------------------------------- |
| `livePhotoMode` | `video_and_livephoto` | 同时发送实况图和效果视频 |
| `livePhotoMode` | `video_only` | 仅发送效果视频,适合只关心播放效果的场景 |
| `livePhotoMode` | `livephoto_only` | 仅发送单文件实况图,性能开销更小 |
| `livePhotoSystem` | `google` | Google 标准格式 |
| `livePhotoSystem` | `xiaomi` | 小米兼容格式 |
| `livePhotoSystem` | `oppo` | OPPO / OnePlus / realme 兼容格式,当前默认推荐 |
| `livePhotoSystem` | `huawei_honor` | 华为 / 荣耀兼容格式,仍建议自行实机验证 |
如果你不确定选哪个系统,先用默认的
`oppo`
;如果你更在意“尽量标准”,可以改回
`google`
。
***
## 实现原理 [#实现原理]
### 文件结构 [#文件结构]
动态照片本质上是将视频数据附加到 JPEG 图片文件末尾,并在 JPEG 的 XMP 元数据中记录视频的位置和长度信息。
```
┌─────────────────────────────┐
│ JPEG 图片数据 │
│ (SOI 0xFFD8 开始) │
├─────────────────────────────┤
│ XMP 元数据 (APP1 段) │
│ - MotionPhoto 标记 │
│ - 视频长度 │
│ - 时间戳 │
├─────────────────────────────┤
│ MP4 视频数据 │
│ (完整的 MP4 文件) │
└─────────────────────────────┘
```
### 关键技术 [#关键技术]
#### 1. XMP 元数据注入 [#1-xmp-元数据注入]
插件使用 XMP(Extensible Metadata Platform)标准在 JPEG 的 APP1 段中写入 Motion Photo 元数据:
```xml
```
#### 2. EXIF 信息补全 [#2-exif-信息补全]
部分厂商(如小米、OPPO)要求 JPEG 必须包含特定的 EXIF 信息才能正确识别。插件会自动检测并补全必要的 EXIF 段:
* 图片宽度和高度
* 厂商特定标记(如 OPPO 的 `OpCamera:MotionPhotoOwner`)
#### 3. 厂商适配 [#3-厂商适配]
不同厂商对 Motion Photo 的实现略有差异,插件提供了四种兼容模式:
最通用的格式,兼容性最广。使用 Google Photos 定义的标准 XMP 命名空间。 **适用设备**: - Google Pixel 系列 -
部分三星设备 - 支持 Google Photos 的第三方应用
在 Google 标准基础上添加小米特有的 XMP 扩展字段: - `MiCamera:XMPMeta`:小米相册识别标记 - `GCamera:MicroVideo`:兼容旧版小米设备
**适用设备**: - 小米 / Redmi / POCO 系列(HyperOS)
在 Google 标准基础上添加 OPPO 特有的 XMP 扩展字段: - `OpCamera:MotionPhotoOwner="oplus"`:OPPO 相册识别标记 -
`OpCamera:OLivePhotoVersion`:动态照片版本号 - `OpCamera:VideoLength`:视频长度(字节) **适用设备**: - OPPO / OnePlus / Realme
系列(ColorOS)
使用不同的实现方式,在文件末尾添加特殊标记而非 XMP 元数据:
```
v2_f35 409:1000 LIVE_{timestamp}
```
**适用设备**:
* 华为 / 荣耀系列(HarmonyOS / MagicOS)
此模式未经实测验证,可能存在兼容性问题。
#### 4. 图片格式转换 [#4-图片格式转换]
如果原始封面不是 JPEG 格式(如 PNG、WebP),插件会自动使用 FFmpeg 转换为 JPEG:
```bash
ffmpeg -i input.png -frames:v 1 -q:v 2 output.jpg
```
### 技术参考 [#技术参考]
插件的动态照片实现参考了以下开源项目和技术文档:
* [Motion Live Photo WebUI](https://blog.zzbd.org/motion-live-photo-webui) - 实现原理详解
* [flashlab/motion-live-photo](https://github.com/flashlab/motion-live-photo) - 开源实现参考
* [Google Photos XMP Specification](https://developers.google.com/photos/library/guides/motion-photos) - Google 官方规范
***
## 常见问题 [#常见问题]
可能的原因:
1. **未保存原图**:必须保存原图才能保留视频数据
2. **设备不支持**:确认你的设备支持 Motion Photo 功能
3. **相册应用不支持**:尝试使用 Google Photos 或系统原生相册
4. **兼容模式不匹配**:尝试切换 `livePhotoSystem` 配置
5. **文件损坏**:检查插件日志,确认生成过程无错误
iPhone 的 Live Photo 使用独立的 HEIC 图片和 MOV 视频文件存储,而非单文件格式。
这种存储方式无法通过简单的文件合并实现,需要特殊的文件系统支持。插件目前无法生成 iPhone 兼容的 Live Photo。
动态照片文件大小 = 封面图片大小 + 视频大小,这是正常现象。
先检查 `livePhotoMode` 是否被设成了 `video_only`。如果是,这就是预期行为。
# 推送逻辑机制
本页按当前 `core` 实现说明抖音与 B站推送的检测、去重和分发方式。
## 抖音推送 (Douyin) [#抖音推送-douyin]
抖音推送当前支持多种类型的监听:
* `post`:作品更新
* `favorite`:喜欢列表更新
* `recommend`:推荐列表更新
* `live`:直播状态
当监控的博主点赞了某个视频时触发,是否能抓到数据取决于对方是否公开了喜欢列表。
当博主将某个视频标记为“推荐”时触发,同样依赖对方的公开设置。
**隐私设置警告**:这两个功能依赖于博主的隐私设置。如果博主将喜欢/推荐列表设置为“仅自己可见”,插件将无法获取数据并会输出警告日志。
### 核心机制 [#核心机制]
### 定时轮询 [#定时轮询]
插件会根据 `douyin.push.cron` 定时轮询。订阅源本身保存在 `pushlist` 中,通常由 `#设置抖音推送 抖音号` 维护。
### 类型分发 [#类型分发]
针对每个订阅用户,系统会并行检查以下配置开启的推送类型:
* **作品 (Post)**: 用户的发布视频或图文。
* **喜欢 (Favorite)**: 用户点赞的内容(需用户公开喜欢列表)。
* **推荐 (Recommend)**: 用户推荐的内容(需用户公开推荐列表)。
* **直播 (Live)**: 用户的实时直播状态。
### 数据比对与去重 [#数据比对与去重]
系统会把已推送记录写入数据库,按作品 ID 去重。这样即使你手动强制推送,也不会反复刷同一条内容。
### 渲染与分发 [#渲染与分发]
不同类型的推送会使用专属的 UI 模板进行渲染:
* **作品**: 展示视频封面、标题、数据统计。
* **喜欢/推荐**: 额外展示“谁喜欢了谁”或“谁推荐了谁”的关联信息,增强社交属性。
* **直播**: 展示直播封面、标题、在线人数及直播间链接。
最后,渲染生成的图片会分发至所有订阅了该用户的群组和机器人。
***
## Bilibili 推送 [#bilibili-推送]
B站推送主要关注动态更新和直播状态。
### 核心流程 [#核心流程]
### 动态获取 [#动态获取]
通过 Bilibili API 获取订阅 UP 主的最近动态历史。
### 智能筛选 [#智能筛选]
为了保证推送的时效性和质量,系统会执行以下筛选:
* **排除置顶**:置顶动态通常是旧内容的长期展示,默认忽略。
* **时效限制**:自动过滤发布时间超过 24 小时的旧动态(防止首次运行时刷屏)。
### 类型处理 [#类型处理]
支持多种动态类型的解析与渲染:
* **视频投稿 (`DYNAMIC_TYPE_AV`)**: 提取封面、标题、简介,生成视频卡片。
* **图文动态 (`DYNAMIC_TYPE_DRAW`)**: 展示图片预览。
* **直播推荐 (`DYNAMIC_TYPE_LIVE_RCMD`)**: 当 UP 主通过动态发布开播通知时触发。
* **转发动态 (`DYNAMIC_TYPE_FORWARD`)**: 嵌套展示原动态内容。
### 直播监控 [#直播监控]
除了依赖动态流中的开播通知,插件还会主动轮询直播状态,尽量避免漏掉未发动态的突袭直播。
### 去重机制 [#去重机制]
B站推送同样基于数据库进行严格去重。已推送的 `dynamic_id` 会被持久化存储,确保同一条动态不会重复打扰。
## 你最需要关心的配置 [#你最需要关心的配置]
* 推送开关(`push.switch`)
* 谁可以设置推送(`push.permission`)
* 定时任务表达式(`push.cron`)
* 作品解析(`push.parsedynamic`)
* 画质偏好 / 解析视频动态时的画质偏好(`push.pushVideoQuality`)
推送是否“能配置成功”,除了平台配置外,还取决于
`pushlist`
里是否存在正确的
`群号:机器人账号`
绑定。
# 配置说明
## 推荐方式 [#推荐方式]
插件当前配置面已经覆盖了解析、评论、推送、弹幕烧录、Live Photo、上传下载、代理等内容。日常使用时,**优先推荐在 Karin WebUI 中修改**。
手动 YAML 仍然可用,但它现在更适合作为排障或批量迁移时的兜底方案,不建议当作日常主要入口。
## 配置分区一览 [#配置分区一览]
| 分区 | 主要内容 | 典型配置 |
| ---------- | ------- | ---------------------------------------------------------------------------- |
| Cookies 相关 | 平台登录态 | 抖音、B站、快手、小红书 Cookie |
| 插件应用相关 | 全局行为 | 默认解析(`videoTool`)、渲染主题(`Theme`)、Live Photo、错误日志、API 服务 |
| 抖音相关 | 抖音解析与推送 | 解析时发送的内容(`sendContent`)、评论解析、画质偏好(`videoQuality`)、扫码登录、弹幕烧录 |
| B站相关 | B站解析与推送 | 解析时发送的内容(`sendContent`)、图文布局(`imageLayout`)、画质偏好(`videoQuality`)、扫码登录、弹幕烧录 |
| 视频上传和下载相关 | 文件发送链路 | 本地文件(`videoSendMode`)、Base64、群文件上传、压缩视频(`compress`)、下载限速(`downloadThrottle`) |
| 解析库请求配置相关 | 网络请求 | 超时时间(`timeout`)、User-Agent、代理 |
| 推送列表相关 | 订阅目标 | 绑定群聊、机器人账号、推送类型与过滤条件 |
## 哪些改动通常需要重启 [#哪些改动通常需要重启]
* 默认解析 / 自定义优先级(`videoTool` / `priority`)
* 挂载到 Karin(`APIServerMount`)
* 谁可以触发扫码登录(`loginPerm`)
* 推送开关(`push.switch`)
* 谁可以设置推送(`push.permission`)
如果你在 WebUI 里改完后感觉“不生效”,先确认是不是改到了这类选项。
## 最常用的几组配置 [#最常用的几组配置]
### 1. 通用行为 [#1-通用行为]
* 默认解析(`videoTool`):是否让插件直接以最高优先级识别链接
* 渲染图片的主题色(`Theme`):自动 / 浅色 / 深色
* 分页渲染(`multiPageRender`):长图内容很多时建议保持开启
* Live Photo 处理和发送方式(`livePhotoMode`):只发视频、只发实况图,或两者都发
* Live Photo 静态图兼容系统(`livePhotoSystem`):当前默认推荐 OPPO 兼容模式
### 2. 抖音 / B站解析 [#2-抖音--b站解析]
* 解析时发送的内容(`sendContent`):决定返回视频信息、评论列表还是视频文件
* 评论解析数量(`numcomment`):控制评论图长度
* 画质偏好(`videoQuality`):高画质更清晰,但更依赖登录态和发送能力
* 视频信息返回形式(`videoInfoMode`):图片模式更直观,文本模式更轻量
* 弹幕烧录(`burnDanmaku`):会显著增加耗时,建议按需开启
抖音额外还有:
* 次级评论解析数量(`subCommentLimit`)
* 合辑 Live 图 BGM 合并方式(`liveImageMergeMode`)
* 推送图二维码的类型(`push.shareType`)
B站额外还有:
* 解析图文动态时的页面布局方式(`imageLayout`)
* 视频信息前返回的内容(`displayContent`)
* 解析视频动态时的画质偏好(`push.pushVideoQuality`)
* 视频动态的视频体积上限(`push.pushMaxAutoVideoSize`)
### 3. 上传与下载 [#3-上传与下载]
* 本地视频发送方式(`videoSendMode`):
`File 协议(本地文件)` 适合 Karin 和协议端在同一机器
`Base64(编码传输)` 适合跨机器,但会增加流量
* 群文件上传(`usegroupfile`):适合超大视频
* 压缩视频(`compress`):适合发送受限环境,但会明显吃 CPU
* 下载限速(`downloadThrottle`):适合经常遇到 `ECONNRESET` 的网络环境
### 4. 推送 [#4-推送]
推送真正由两部分组成:
1. 平台页里的推送设置
2. 推送列表里的具体订阅目标
平时推荐直接在群里用命令维护订阅:
```bash
#设置抖音推送 抖音号
#设置B站推送 UID
```
只有在批量迁移、修复群号或机器人 ID 时,才建议回头手动看 YAML。
## 手动配置只作为兜底 [#手动配置只作为兜底]
如果你只是日常使用,基本不需要碰配置文件。除非你正在做迁移、备份恢复或批量修订,否则直接使用 WebUI 就够了。
就算是手动维护推送列表,也只要记住一点:绑定推送群时必须使用 `群号:机器人账号` 这种格式。这个地方填错,是推送不生效最常见的原因之一。
# 常见问题
1. 检查 Cookies 是否有效(可尝试重新扫码登录)
2. 检查网络是否正常
3. 检查对应平台 `switch` 是否开启
4. 检查 `sendContent` 是否把你期望的返回内容关掉了
5. 部分内容确实需要登录态或平台放行
当日志出现 `Error: ENOENT: no such file or directory, copyfile`,说明**协议端在容器里找不到文件**。这不只会出现在合并转发,**只要有文件上传**(图片、语音、视频)都有可能出现。
**先理解“宿主机路径”和“容器路径”**
* **宿主机路径**:你的服务器真实路径,比如 `/root/karin/@karinjs/...`
* **容器路径**:Docker 里的路径,比如 `/app/.config/QQ/NapCat/temp/...`
日志里一般会同时出现两段路径:
1. **源文件路径**(宿主机路径):`/home/xxx/karin/@karinjs/...`
2. **目标路径**(容器路径):`/app/.config/QQ/NapCat/temp/...`
**只要“源文件路径”在容器里不存在,就会报这个错。**
**小白操作步骤(以 Linux 宿主机为例)**
1. 在服务器上找到 Karin 的目录,比如:`/root/karin`
2. 找到karin的数据目录:`/root/karin/@karinjs`
3. 把这个目录挂载进 Docker,并且**容器内路径必须和日志里源文件路径一致**
示例:如果日志里的源文件路径是 `/root/karin/@karinjs/...`,就这样挂载:
```
-v /root/karin/@karinjs:/root/karin/@karinjs
```
**如果你用 docker-compose**
```
volumes:
- /root/karin/@karinjs:/root/karin/@karinjs
```
**路径关系说明(一定要一致)**
* 服务器路径:`/root/karin/@karinjs`
* Docker 内路径:`/root/karin/@karinjs`
* 两边必须一模一样,**不能只挂到别的路径**
**重要检查点**
1. 服务器上这个目录真实存在
2. 容器内路径和日志里的源文件路径完全一致
3. 改完挂载后重启协议端容器
完成后再触发一次上传/解析,通常就不会再出现该错误。
这是 B站的风控机制,需要手动完成极验验证。
使用{' '}
极验验证器
{' '}
工具手动完成验证,验证成功后结果会自动复制。
**使用步骤:**
1. 打开 极验验证器
2. 输入错误信息中的 `gt` 和 `challenge` 值
3. 点击「生成验证码」完成验证
4. 验证结果会自动复制,重新触发解析即可
先检查以下几项:
1. 平台配置里的 `sendContent` 是否勾选了 `video`
2. 视频体积是否超过了上传阈值或群文件阈值
3. 是否开启了 `usefilelimit` 直接拦截大视频
4. 协议端与 Karin 是否不在同一机器,如果是,优先尝试 `videoSendMode: base64`
* 使用自动画质模式:`videoQuality: adapt`(抖音/小红书)或 `videoQuality: 0`(B站)
* 调低 `maxAutoVideoSize` 值
* 必要时开启 `compress`
* 也可以启用 `usegroupfile`
* 或直接设置较低画质如 `720p`
1. 确认 `push.switch` 已开启
2. 检查 `pushlist.yaml` 中 `group_id` 格式:`群号:机器人账号`
3. 确保机器人在目标群中
4. 确认当前账号满足“谁可以设置推送(`push.permission`)”
5. 修改“推送开关(`push.switch`)”或权限后记得重启
6. 查看日志是否有报错
```
#抖音强制推送 → 当前群
#B站强制推送 → 当前群
#抖音全部强制推送 → 所有群
#B站全部强制推送 → 所有群
```
| 平台 | 解析 | 评论 | 推送 | 扫码登录 |
| --- | :-: | :-: | :-: | :--: |
| 抖音 | ✓ | ✓ | ✓ | ✓ |
| B站 | ✓ | ✓ | ✓ | ✓ |
| 快手 | ✓ | ✓ | — | — |
| 小红书 | ✓ | ✓ | — | — |
开启弹幕烧录后,视频需要进行**重新编码 (Re-encode)** 以将字幕“印”在画面上。
* **有损过程**:重新编码本质上是一个有损过程,必然会导致一定程度的画质损失。
* **码率控制**:插件默认会尝试匹配原视频的码率,但为了平衡处理速度和文件大小,可能会有一定的压缩。
* **改善方法**:
* 尝试在配置中将 `videoCodec` 设置为 `h265` 或 `av1`(如果硬件支持)。
* 确保没有开启过低的比特率限制。
* `burnDanmaku: true` 是平台默认行为,命中链接就会烧录
* `#弹幕解析` 是一次性的强制烧录入口,适合平时不开、偶尔想手动烧录的场景
* 当前只对抖音和 B站有效
# 快速开始
## 安装流程 [#安装流程]
### 环境要求 [#环境要求]
* Karin >= 1.14.0
* Node.js >= 18
* FFmpeg 或 [FFmpeg 插件](https://github.com/KarinJS/karin-plugin-ffmpeg)
### 安装插件 [#安装插件]
推荐直接在 Karin WebUI 插件市场搜索 `karin-plugin-kkk` 安装。
如果你是手动管理依赖,也可以执行:
```bash
pnpm add karin-plugin-kkk@latest -w
```
### 完成基础配置 [#完成基础配置]
打开 Karin WebUI → 插件配置 → `karin-plugin-kkk`,先把 Cookie 配好就够了。
* 抖音 Cookie
* B站 Cookie
* 如果你确实要用快手 / 小红书深度功能,也可以顺手补上对应 Cookie
其他配置都有默认值兜底,先不动也能直接用。真正影响首次使用体验的,主要就是 Cookie。
## 获取登录态 [#获取登录态]
群聊或私聊中可直接使用:
```bash
#抖音登录
#B站登录
```
详细方法见 [获取 Cookies](/docs/advanced/ck)。
## 第一次试跑 [#第一次试跑]
插件启动后会监听消息,命中以下内容时自动解析:
* 抖音:支持 `douyin.com` 与 `iesdouyin.com` 及其子域名 (`www`, `v`, `jx`, `m`, `jingxuan`)
* B站:支持 `bilibili.com`, `b23.tv`, `t.bilibili.com`, `bili2233.cn`,以及纯 **BV号** (`BV...`) 和 **av号** (`av...`)
* 快手:支持 `kuaishou.com`, `v.kuaishou.com`,以及APP分享的文本格式(如 `快手...快手`)
* 小红书:支持 `xiaohongshu.com`, `xhslink.com`, `xhslink.cn`
手动解析命令:
```bash
#解析
#kkk解析
#弹幕解析
```
其中 `#弹幕解析` 需要引用一条抖音或 B 站消息使用,会强制走弹幕烧录流程。
抖音和 B站的高画质、扫码登录、推送等能力都依赖登录态。没配 Cookie 也能做基础解析,但完整体验会受限。
## 反馈渠道 [#反馈渠道]
# 使用指南
## 解析功能 [#解析功能]
插件当前支持两类入口:自动命中分享链接,以及引用消息手动解析。
### 自动解析 [#自动解析]
默认情况下,插件会监听消息内容。只要平台开关开启,命中支持的链接、短链、BV 号、AV 号或 App 分享文本时,就会自动触发解析。
* 支持平台:抖音、B站、快手、小红书
* 抖音支持 `douyin.com` / `iesdouyin.com`
* B站支持站内链接、`b23.tv`、`BV...`、`av...`
* 快手支持链接和分享口令文本
* 小红书支持 `xiaohongshu.com` / `xhslink.com` / `xhslink.cn`
如果你在 WebUI 里关闭了“默认解析(
`videoTool`
)”,插件就会按你设置的“自定义优先级(
`priority`
)”工作。
### 手动解析 [#手动解析]
如果自动解析关闭了,或者你想处理历史消息,引用目标消息后发送:
```bash
#解析
#kkk解析
```
`#弹幕解析`
也属于引用解析命令,但它只对抖音 / B站生效,并会强制进入弹幕烧录流程。
***
## 常用命令 [#常用命令]
| 命令 | 作用 |
| --------------------- | -------------- |
| `#kkk帮助` | 查看帮助菜单 |
| `#kkk版本` / `#kkk更新日志` | 查看当前版本的更新日志 |
| `#kkk更新` | 执行插件更新 |
| `#kkk解析统计` | 查看当前群解析统计 |
| `#kkk全局解析统计` | 查看全局解析统计,仅主人可用 |
| `#抖音登录` | 获取抖音 Cookie |
| `#B站登录` | 获取 B站 Cookie |
## 动态推送 [#动态推送]
### 订阅与取消 [#订阅与取消]
```bash
#设置抖音推送 抖音号
#设置B站推送 UID
```
* 抖音使用抖音号,不是昵称
* B站使用数字 UID
* 两条命令都是切换式:已订阅则取消,未订阅则新增
* 实际权限由“谁可以设置推送(`push.permission`)”控制
### 推送列表 [#推送列表]
```bash
#抖音推送列表
#B站推送列表
```
### 强制推送与维护 [#强制推送与维护]
```bash
#抖音强制推送
#B站强制推送
#抖音全部强制推送
#B站全部强制推送
#kkk设置推送机器人 BotID
#测试抖音推送 https://...
```
* `强制推送` 只处理当前群
* `全部强制推送` 会模拟一次全局定时任务
* `#kkk设置推送机器人` 用于批量改绑定的机器人账号
* `#测试抖音推送` 适合调试推送图样式和链接二维码
***
## 扫码登录与权限 [#扫码登录与权限]
为了拿到更高画质、推送能力和更稳定的接口权限,建议尽早配置 Cookie。
```bash
#抖音登录
#B站登录
```
这两个命令谁能用,取决于各平台配置页里的“谁可以触发扫码登录(
`loginPerm`
)”,修改后通常需要重启。
扫码登录拿到的 Cookie 会自动写入配置。它们只用于请求平台官方接口,不会被插件上传到第三方。
## 统计与排障 [#统计与排障]
```bash
#kkk解析统计
#kkk全局解析统计
```
统计功能会按群、按平台记录解析次数,也会统计活跃用户和全局趋势。
如果你遇到异常,建议再结合下面几个页面一起看:
* [弹幕烧录](/docs/features/danmaku-burning)
* [动态照片解析](/docs/features/live-photo)
* [推送逻辑机制](/docs/features/push-logic)
* [常见问题](/docs/guide/faq)
# 支持项目
{/* 流星效果 - 覆盖整个页面前景 */}
如果本项目对你有帮助,欢迎前往 [GitHub](https://github.com/ikenxuan/karin-plugin-kkk) 给个 ⭐ **Star**~
## ☕ 请我喝杯咖啡 [#-请我喝杯咖啡]
开发不易,如果你觉得这个项目还不错,可以请我喝杯咖啡,你的支持是我持续更新的动力 💪
## 赞助榜 [#赞助榜]
# 贡献指南
# 贡献指南 [#贡献指南]
感谢你对 **karin-plugin-kkk** 感兴趣!我们需要你的帮助来让这个项目变得更好。
无论是修复 Bug、添加新功能,还是改进文档,我们都非常欢迎。
## 准备工作 [#准备工作]
在开始之前,请确保你的开发环境满足以下要求:
* **[Node.js](https://nodejs.org/)**: >= 22
* **[pnpm](https://pnpm.io/)**: >= 9
* **[Git](https://git-scm.com/)**: 版本控制工具
## 项目结构 [#项目结构]
本项目采用 **[Monorepo](https://monorepo.tools/)** 结构,主要包含以下部分:
* `packages/core`: 核心插件代码 (`karin-plugin-kkk`),包含主要业务逻辑。
* `packages/template`: [React](https://react.dev/) 截图模板源码已并入 `packages/core/template/`(基于 [`@karinjs/template-react`](https://github.com/KarinJS/template-react) 约定布局),SSR 生成 HTML 文件。
* `packages/amagi`: 接口库 (**[Git Submodule](https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E5%AD%90%E6%A8%A1%E5%9D%97)**),处理各平台的 API 请求与签名。
* `packages/docs`: 文档站点,基于 [Next.js](https://nextjs.org/) 和 [Fumadocs](https://fumadocs.vercel.app/)。
`packages/amagi` 是一个 **Git 子模块**。如果你需要修改 API 相关的逻辑(如签名算法),请**不要直接修改该目录**。你需要前往 [amagi
仓库](https://github.com/ikenxuan/amagi) 提交 Pull Request。
## 架构说明 [#架构说明]
### 插件在 Karin 中的位置 [#插件在-karin-中的位置]
`karin-plugin-kkk` 是 Karin 框架的一个功能插件,遵循 Karin 的插件规范开发。
### 消息处理流程 [#消息处理流程]
当用户在群聊中发送包含平台链接的消息时,插件的处理流程如下:
### 核心模块说明 [#核心模块说明]
**Apps 命令层** - 负责注册 Karin 命令,监听消息并分发到对应的平台处理器。
```
src/apps/
├── tools.ts # 视频解析命令(抖音/B站/快手/小红书)
├── push.ts # 动态推送任务
├── qrlogin.ts # 扫码登录功能
├── admin.ts # 管理员命令
├── help.ts # 帮助信息
└── update.ts # 插件更新
```
**Platform 平台层** - 每个平台独立封装,包含链接解析、数据获取、评论处理等。
```
src/platform/
├── douyin/ # 抖音
├── bilibili/ # B站
├── kuaishou/ # 快手
└── xiaohongshu/ # 小红书
```
**Module 工具层** - 提供配置管理、数据库操作、API 服务、网络请求等通用功能。
```
src/module/
├── config/ # 配置管理
├── db/ # 数据库操作
├── server/ # API 服务
└── utils/ # 工具函数
```
### 数据流向 [#数据流向]
## 开发流程 [#开发流程]
### Fork 本仓库 [#fork-本仓库]
点击项目主页右上角的 [**Fork**](https://github.com/ikenxuan/karin-plugin-kkk/fork) 按钮,将仓库 Fork 到你的 GitHub 账户下。
### 克隆仓库 [#克隆仓库]
将你 Fork 后的仓库克隆到本地。由于项目包含子模块,克隆时需要初始化子模块:
```bash
# 替换为你的 GitHub 用户名
git clone --recursive https://github.com/你的用户名/karin-plugin-kkk.git
# 或者如果你已经克隆了仓库但没有子模块
git submodule update --init --recursive
```
### 安装依赖 [#安装依赖]
使用 pnpm 安装所有依赖:
```bash
pnpm install
```
### 启动开发环境 [#启动开发环境]
根据你要修改的内容,启动相应的开发环境:
* **开发插件核心 (`packages/core`)**:
```bash
pnpm watch
```
* **开发模板 (`packages/core/template`)**:
```bash
pnpm template
```
启动 ktr 模板开发面板(`http://localhost:5174/__ktr/panel/`),模板在 `packages/core/template/<板块>/<模板>/`,新增/移动模板后重新运行会自动刷新注册表。
* **预览文档 (`packages/docs`)**:
```bash
pnpm docs
```
### 提交代码 [#提交代码]
我们遵循 [Conventional Commits](https://www.conventionalcommits.org/zh-hans/v1.0.0/) 规范。
提交信息的格式如下:
```
():
```
例如:
* `feat(core): 支持解析新的分享链接`
* `fix(template): 修复动态卡片样式错乱`
* `docs: 更新贡献指南`
### 提交 Pull Request [#提交-pull-request]
1. 推送到你的 Fork 仓库:
```bash
git push origin feature/amazing-feature
```
2. 在 GitHub 上向原仓库提交 Pull Request。
## 常见问题 [#常见问题]
### 如何更新子模块? [#如何更新子模块]
如果你发现 `packages/amagi` 落后于上游,可以使用以下命令更新:
```bash
git submodule update --remote
```
### 遇到 TypeScript 类型错误? [#遇到-typescript-类型错误]
尝试重新构建整个项目或重新安装依赖:
```bash
pnpm install
pnpm build
```
# 现代化模板渲染
本插件采用 **React + TailwindCSS** 技术栈进行图片渲染,将现代前端的工程化能力引入模板开发。
相比传统模板引擎在维护上的痛点——逻辑与视图耦合、全局 CSS 冲突、缺乏类型检查——本方案通过**组件化构建**、**原子化样式**和**类型安全**三条路径彻底解决了这些问题。
基于 `art-template` 的模板在项目迭代中往往会陷入维护泥潭: - **逻辑黑洞**:业务逻辑混杂在 HTML 模板中,难以阅读和剥离。 -
**样式冲突**:全局 CSS 类名随时间推移不断堆积,修改一处可能导致多处崩坏。 -
**重构风险**:缺乏类型检查,修改字段名就像在"排雷",只能祈祷运行时不出错。
## 架构概览 [#架构概览]
整个渲染链路分为四层:
1. **数据层(`@kkk/richtext`)**:定义平台无关的富文本文档协议,作为 core 与 template 之间的数据边界。
2. **Core 解析层**:将抖音、B 站等平台的原始 API 响应解析为标准的 `RichTextDocument` JSON。
3. **Template 渲染层**:React 组件消费 JSON 数据,TailwindCSS 处理样式,最终通过 SSR 输出静态 HTML。
4. **输出层**:Karin 框架调用 Puppeteer 截图,生成图片消息发送到群聊。
## 富文本文档(RichTextDocument) [#富文本文档richtextdocument]
`@kkk/richtext` 是 core 包与 template 包之间的共享子包,负责定义**平台无关的富文本中间表示(IR)**。
不同平台的文本描述格式差异很大:抖音的富文本是一段带特殊标记的字符串,B 站则提供了结构化的内容节点。如果在 template 侧分别解析,会导致平台逻辑泄漏到渲染层,维护成本极高。
富文本文档将这一问题收拢到 core 层:core 负责把各平台的异构数据转换成统一的 JSON 节点树,template 只负责渲染。
### 节点类型 [#节点类型]
富文本文档支持两类节点:**行内节点**与**块级节点**。
**行内节点**用于描述段落内的文本片段:
| 节点类型 | 用途 | 示例 |
| :--------------- | :------------------ | :----------- |
| `text` | 普通文本,支持粗体/斜体/颜色/超链接 | 评论正文 |
| `emoji` | 平台表情包图片 | \[doge] |
| `mention` / `at` | @用户 | @某某 |
| `searchKeyword` | 搜索词高亮 | 带搜索图标的蓝色高亮文本 |
| `topic` | 话题标签 | #某某话题# |
| `lottery` | 抽奖信息 | 带抽奖图标的文本 |
| `webLink` | 网页链接 | 带链接图标的标题 |
| `vote` | 投票 | 带投票图标的标题 |
| `viewPicture` | 查看图片提示 | 带相册图标的提示文本 |
| `lineBreak` | 换行 | `
` |
**块级节点**用于描述文档结构:
| 节点类型 | 用途 |
| :------------------ | :------------ |
| `heading` | 标题(1-6 级) |
| `paragraph` | 段落 |
| `image` | 图片 |
| `blockquote` | 引用块 |
| `list` / `listItem` | 有序/无序列表 |
| `codeBlock` | 代码块(带语法高亮和行号) |
| `linkCard` | 链接卡片 |
### 在 core 中使用 [#在-core-中使用]
`@kkk/richtext` 的 `parse` 模块提供了一系列工厂函数,用于从平台原始数据中构建节点:
```ts twoslash
import { createTextNode, createEmojiNode, createParagraphNode, createRichTextDocument } from '@kkk/richtext'
const doc = createRichTextDocument(
[
createParagraphNode([
createTextNode('这条视频太棒了', { bold: true }),
createEmojiNode('doge', 'https://example.com/doge.png'),
createTextNode('!推荐大家看看。')
])
],
{ platform: 'douyin' }
)
```
core 侧只需要导入**类型**和**节点创建方法**,不依赖 React 运行时,输出的是可序列化的纯 JSON。
### 在 template 中使用 [#在-template-中使用]
`@kkk/richtext` 的 `react` 模块提供了渲染器,将 `RichTextDocument` 转成 React 节点:
```tsx
import { renderRichTextToReact } from '@kkk/richtext/react'
// 在平台模板组件中
const content = renderRichTextToReact(document, {
mention: { className: 'text-blue-500' },
topic: { className: 'text-pink-500' },
searchKeyword: { className: 'text-blue-600 bg-blue-100', iconClassName: 'text-blue-400' }
})
return {content}
```
渲染器会自动处理以下细节:
* **文本转义**:React 自动转义文本内容,防止 XSS。
* **图片安全**:对 `emoji` 和 `image` 节点的 `src` 做协议白名单校验(仅允许 `http://`、`https://` 和 `data:image/*;base64`)。
* **URL 自动识别**:`text` 节点中的链接会被自动包裹为可点击的超链接。
* **行内样式**:支持 `bold`、`italic`、`strike`、`color`、`fontSize`、`link` 等行内样式。
平台返回的富文本描述往往包含未经校验的 HTML。使用 `renderRichTextToReact` 将结构化 JSON 映射为 React 节点,可以避免直接注入 HTML
带来的安全风险,同时让样式完全由 Tailwind 接管。
### 节点归一化 [#节点归一化]
`createRichTextDocument` 内部会自动调用 `normalizeRichTextNodes`,合并相邻的文本节点并丢弃空文本节点。这样 core 在解析时可以按匹配过程简单 `push` 节点,无需担心碎片过多的问题。
## 开发工作流 [#开发工作流]
内置的**可视化开发面板** (`pnpm dev`) 大幅提升模板开发效率:
* **实时预览**:修改组件代码,浏览器即时刷新渲染结果(HMR 热更新)。
* **数据 Mock**:可配置多套 JSON 数据,轻松测试文本超长、头像缺失等边缘情况。
* **快速调试**:无需启动整个 Bot,仅需浏览器即可完成模板开发。
## SSR 渲染引擎 [#ssr-渲染引擎]
core 包通过 `Render` 函数调用 template 子包的 `reactServerRender`,实现了插件逻辑与模板渲染的解耦。
**入口与初始化**:`reactServerRender` 接收渲染请求、输出目录和插件数组,首先确保输出目录存在,然后通过 `ComponentAutoRegistry` 扫描配置文件,按平台分组懒加载组件模块并绑定数据验证函数,最终存入 Map 注册表。
**SSRRender 实例化**:创建 `ResourcePathManager` 检测运行环境(开发/生产),解析包目录路径并处理 pnpm 符号链接;创建 `HtmlWrapper` 负责 HTML 包装;创建 `PluginContainer` 并按 `enforce` 字段(pre → normal → post)对插件排序。
**渲染流程**:构建 `PluginContext` 上下文和 `RenderState` 状态对象 → 执行 `runBefore` 前置插件(如二维码生成)注入额外 props → `ComponentRendererFactory` 从注册表查找组件、验证数据、合并 props、处理嵌套路径、调用 `React.createElement` → 执行 `runDuring` 渲染插件(可包装组件)→ 调用 `renderToString` 将 React 组件转为 HTML 字符串 → 执行 `runAfter` 后置插件(可修改 HTML)。
**输出阶段**:生成带时间戳的安全文件名 → `HtmlWrapper.wrapContent` 计算 CSS 和图片的相对路径、替换图片 src、注入 DOCTYPE/meta/CSS link/主题类名 → 写入文件系统 → 返回 HTML 文件路径供 Karin 框架截图。
SSR 直接输出包含完整样式与内容的 HTML,Puppeteer 打开页面后**无需等待 JavaScript 加载与执行**即可立即截图,显著降低了渲染耗时与内存占用。
## 生态复用 [#生态复用]
得益于 React 标准,可以直接引入成熟的库来丰富**静态画面**的表现力:
* **排版布局**:引入现代化的 UI 组件库,快速构建精美的卡片、列表。
* **数据可视化**:使用专业图表库将复杂数据渲染为统计图表。
* **矢量图标**:引入海量 SVG 图标库,支持任意缩放不失真。