# 简介 `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 字符串 Cookie Editor使用教程 请确保选择 "Header String" 格式,这样可以获取到完整的 Cookie 字符串形式。 ## 方式三:浏览器开发者工具获取 [#方式三浏览器开发者工具获取] 1. 打开浏览器,访问对应平台并登录 2. 按 F12 打开开发者工具(不同浏览器打开方式不同,如 Chrome 和 Edge 按 F12 或右键点击页面选择"检查") 3. 切换到 Network(网络)标签 4. 刷新页面,找到任意请求 5. 在请求头中复制 Cookie 值 获取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站评论示例 小红书评论示例 快手评论示例 ## 功能特性 [#功能特性] ### 内容还原 [#内容还原] * **表情包解析**:支持各平台自带表情(抖音表情、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**~ ## ☕ 请我喝杯咖啡 [#-请我喝杯咖啡] 开发不易,如果你觉得这个项目还不错,可以请我喝杯咖啡,你的支持是我持续更新的动力 💪 wechat alipay QQ afdian ## 赞助榜 [#赞助榜] # 贡献指南 # 贡献指南 [#贡献指南] 感谢你对 **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 图标库,支持任意缩放不失真。