Homepage 集成 Atsumeru Widget:为自托管漫画服务器添加统计信息展示
【免费下载链接】homepageA highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.项目地址: https://gitcode.com/GitHub_Trending/ho/homepage
Atsumeru 是一款自托管的漫画/轻小说阅读服务器,而 Homepage 是一个高度可定制的应用仪表盘。通过本文你将掌握:如何在 Homepage 的services.yaml中为 Atsumeru 配置 widget,使其在仪表盘上实时显示系列(series)、归档(archives)、章节(chapters)与分类(categories)四项核心统计数据,并理解该 widget 从配置到数据渲染的完整链路。本文以官方文档 docs/widgets/services/atsumeru.md 为主线,结合仓库源码深入讲解其认证机制与实现原理。
Atsumeru Widget 能做什么
Atsumeru(原 Comic Library)是一个以"一次导入、多端阅读"为理念的自托管漫画服务器,支持通过 Web 界面和多种移动端应用访问。当你在 Homepage 中为 Atsumeru 服务挂载 widget 后,仪表盘上会直接呈现该服务器媒体库的四项统计数字,无需再打开 Atsumeru 管理后台即可掌握库容状态:
- Series:系列总数(按作品聚合)
- Archives:归档/文件总数(导入的压缩包等原始媒体文件)
- Chapters:章节总数(按阅读单位聚合)
- Categories:分类总数(标签/分类体系的条目数量)
这些标签文案定义在 public/locales/en/common.json 中,并随 Homepage 的多语言体系自动翻译,你的仪表盘使用什么语言,统计块的标题就显示什么语言。
前置条件
在开始配置之前,请确认:
- 你已经有一个可访问的 Atsumeru 实例,且其版本提供的 API 兼容
/api/server/info端点(本文以当前仓库实现所调用的端点为依据)。 - 你拥有与 Web 或受支持 App 登录完全相同的用户名和密码。这一点非常关键——官方文档明确指出:"Define same username and password that is used for login from web or supported apps",也就是说该 widget 复用的是 Atsumeru 的正常账号体系,不需要额外创建 API Key。
- 你的 Homepage 已经能访问到 Atsumeru 所在的主机(容器网络、反向代理或直连 IP 均可,只要 URL 可解析)。
- 若你的 Homepage 与 Atsumeru 分别部署在不同主机,请确认目标端口在防火墙/安全组中放行。
配置 Atsumeru Widget
完整 YAML 配置
在 Homepage 的配置目录中找到services.yaml(参考骨架文件 src/skeleton/services.yaml,初始内容包含分组与服务示例),在服务条目中加入widget段。原文档给出的最小可用配置如下:
widget: type: atsumeru url: http://atsumeru.host.or.ip:port username: username password: password将其放置到服务定义中,完整的服务条目示例:
- 媒体中心: - Atsumeru 漫画库: icon: sh-atsumeru.png href: http://atsumeru.host.or.ip:port description: 自托管漫画阅读服务器 widget: type: atsumeru url: http://atsumeru.host.or.ip:port username: myaccount password: mypassword字段说明
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
type | string | 是 | 固定为atsumeru,用于匹配 Homepage 内置的 Atsumeru widget 实现 |
url | string | 是 | Atsumeru 实例的访问地址,格式为http://host:port或https://domain,不含尾部/api路径 |
username | string | 是 | Atsumeru Web/App 登录用户名 |
password | string | 是 | 对应的登录密码 |
关于url的取值,需要特别说明:从源码看,src/widgets/atsumeru/widget.js 中 API 模板定义为{url}/api/server/{endpoint},因此url只需填写 Atsumeru 的根地址(含协议与端口),Homepage 会自动拼接/api/server/info来拉取数据。
支持展示的字段
官方文档明确:Allowed fields:["series", "archives", "chapters", "categories"]。这四个字段即 widget 上展示的四个统计块,对应组件实现中的四个<Block>(详见下文"前端渲染层")。配置中不需要也不能额外指定其他展示字段。
配置完成后的效果与验证
保存配置并刷新 Homepage 页面后,Atsumeru 服务卡片上会出现四个统计块。数据未返回前,四个块以占位符(仅显示标签、无数值)的形式呈现;数据成功返回后,依次填充对应的数值。
若配置正确,你看到的卡片大致为:
┌────────────────────────────┐ │ Atsumeru 漫画库 │ │ Series Archives Chapters │ │ 128 3,452 24,109 │ │ Categories │ │ 56 │ └────────────────────────────┘深入源码:数据是怎么被取回来的
理解了"怎么配",再看"为什么这样配",有助于排查问题。Atsumeru widget 的数据链路由三部分构成:widget 定义(声明式配置)、通用代理处理器(服务端转发)、前端数据 Hook(客户端拉取)。
1. Widget 定义层:声明 API 模板与映射
src/widgets/atsumeru/widget.js 是整个 widget 的"身份证",全文仅有十余行:
import genericProxyHandler from "utils/proxy/handlers/generic"; const widget = { api: "{url}/api/server/{endpoint}", proxyHandler: genericProxyHandler, mappings: { info: { endpoint: "info", }, }, }; export default widget;要点解读:
api模板:{url}会被替换成配置中的url,{endpoint}会被替换为请求的端点名,本 widget 唯一的端点是info,最终请求地址为http://atsumeru.host.or.ip:port/api/server/info。mappings:定义了端点与校验/处理规则的映射。info映射用于将 API 响应与前端请求端点关联起来。proxyHandler:复用genericProxyHandler,这是 Homepage 绝大多数基于简单 REST API 的 widget 使用的通用转发器。- 该 widget 通过 src/widgets/widgets.js 被注册进全局 widget 注册表,Homepage 才能按
type: atsumeru找到对应实现。
2. 服务端转发层:Basic Auth 与数据校验
浏览器端无法直接请求 Atsumeru(存在跨域与凭据安全问题),因此所有 widget 数据请求都先打到 Homepage 自身的代理接口,由 src/utils/proxy/handlers/generic.js 统一处理。与 Atsumeru 相关的过程如下:
第一步:凭据注入。第 34–36 行:
if (widget.username && widget.password) { headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`; }这正是文档要求"填写与 Web 登录相同的用户名密码"的原因——Homepage 会将其编码为 HTTP Basic 认证头附加到对 Atsumeru 的请求上。只要 Atsumeru 能接受该账号密码,代理即可通过认证。
第二步:URL 组装。第 22 行通过formatApiCall将api模板中的{url}、{endpoint}占位符替换为实际值。
第三步:响应校验。状态码为 200 时,调用 src/utils/proxy/validate-widget-data.js 对返回数据做解析与校验(JSON 解析失败或响应为空等异常会被标记为无效数据,并以Invalid data形式返回前端展示错误)。
3. 前端渲染层:四个统计块
src/widgets/atsumeru/component.jsx 负责把数据渲染成卡片:
- 通过
useWidgetAPI(widget, "info")发起请求。该 Hook(src/utils/proxy/use-widget-api.js)基于 SWR 封装,支持自动刷新与错误透传。 - 数据未就绪时渲染四个无值
<Block>(series/archives/chapters/categories),见组件第 17–26 行; - 数据就绪后,从响应中读取
infoData.stats.total_series、total_archives、total_chapters、total_categories四个字段并格式化渲染,见第 28–35 行:
<Block label="atsumeru.series" value={t("common.number", { value: infoData.stats.total_series })} /> <Block label="atsumeru.archives" value={t("common.number", { value: infoData.stats.total_archives })} /> <Block label="atsumeru.chapters" value={t("common.number", { value: infoData.stats.total_chapters })} /> <Block label="atsumeru.categories" value={t("common.number", { value: infoData.stats.total_categories })} />由此可见,Atsumeru 的/api/server/info响应中必须包含stats.total_series等四个字段,否则统计块将无法正常取值。
4. 测试印证
仓库为该 widget 提供了完整的单元测试,可作为实现行为的权威佐证:
- src/widgets/atsumeru/widget.test.js:校验 widget 配置对象的形状(
api、mappings、proxyHandler等字段合法); - src/widgets/atsumeru/component.test.jsx:分别断言加载态渲染 4 个占位块、成功态渲染
stats中1/2/3/4四个数值,与上文所述渲染逻辑一一对应。
常见问题排查
1. 卡片一直显示占位符(无数字)说明useWidgetAPI尚未拿到数据。可能原因:
url填写错误或 Atsumeru 端口未开放,Homepage 代理请求失败;- 用户名/密码与 Atsumeru 登录凭据不一致,返回 401/403,genericProxyHandler 会将其作为
HTTP Error透出。
2. 卡片显示Invalid data说明请求成功(200)但响应体不是合法的 JSON,或缺少stats.total_series等字段,未能通过 src/utils/proxy/validate-widget-data.js 的校验。请确认 Atsumeru 版本提供的/api/server/info响应结构与本文描述一致。
3. 如何确认代理请求本身是否成功可以直接在浏览器访问 Atsumeru 的http://atsumeru.host.or.ip:port/api/server/info(带 Basic 认证),观察返回的 JSON 结构是否包含stats对象与上述四个total_*字段,即可快速定位是服务端问题还是 Homepage 侧问题。
小结
Atsumeru widget 是 Homepage 中典型的"声明式配置 + 通用代理"型集成:配置侧只需提供url与登录凭据,服务端由genericProxyHandler统一完成 Basic 认证与数据校验,前端由组件读取/api/server/info的stats字段渲染四个统计块。掌握这一链路后,你不仅能顺利接入 Atsumeru,也能举一反三地理解 Homepage 其他基于 REST API 的 widget(如 Komga、DiskStation 等)的接入方式。
【免费下载链接】homepageA highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.项目地址: https://gitcode.com/GitHub_Trending/ho/homepage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考