Seerr 集成 Pushover 推送通知完整指南:从应用注册、Token 配置到消息发送源码解析
【免费下载链接】seerrOpen-source media request and discovery manager for Jellyfin, Plex, and Emby.项目地址: https://gitcode.com/GitHub_Trending/je/seerr
Seerr 内置 Pushover 通知代理(Agent),可将媒体请求、审批、下载完成、问题反馈等系统事件实时推送到你的 Pushover 账户或群组。本文以官方文档 docs/using-seerr/notifications/pushover.md 为主线,完整讲解 Pushover 应用注册、API Token 与 User Key 的获取与填写、通知类型选择、测试验证,并结合仓库源码(代理实现、API 封装、设置接口、前端表单)深入剖析消息发送的底层原理,帮助你完成配置的同时理解其工作机制。
Pushover 通知在 Seerr 中的角色
Pushover 是一种面向个人与团队的消息推送服务,通过「应用(Application)+ 用户/群组(User/Group)」两级凭证模型实现定向推送:应用代表消息的发送方,用户密钥代表消息的接收方。在 Seerr 中,Pushover 通知被划分为两类场景(这一点在官方文档开头有明确说明):
- 系统通知(System Notifications):由管理员在「设置 → 通知」中全局配置,作用于整个实例;
- 个人通知(User Notifications):由用户在个人设置中自行配置,与系统通知相互独立,且可选的通知类型受用户权限约束——用户只能订阅自己权限允许看到的事件类型。
从源码结构看,Seerr 的通知体系由 server/lib/notifications/agents/pushover.ts 中的PushoverAgent承担,它同时处理系统通知、个人通知和面向管理员的通知三种投递路径,同一份配置结构贯穿前后端。
前置条件:理解两类凭证
配置 Pushover 前,先理清两个关键凭证的含义:
| 凭证 | 作用 | 在 Seerr 中的字段名 |
|---|---|---|
| Application/API Token | 标识「哪个应用在发送消息」(应用凭证) | Application API Token(accessToken) |
| User Key | 标识「消息发送给谁」(接收者凭证),可填用户密钥或群组密钥 | User or Group Key(userToken) |
前端表单(src/components/Settings/Notifications/NotificationsPushover/index.tsx)对两项字段做了严格格式校验:正则^[a-z\d]{30}$(大小写不敏感),即两者都必须是由 30 位字母数字组成的凭证串,否则表单会拒绝保存并提示 "You must provide a valid application token" / "You must provide a valid user or group key"。这一校验同样存在于个人通知设置页 UserNotificationsPushover.tsx,前后端保持了一致的约束。
第一步:注册应用并获取 API Token
按照官方文档说明,需要先在 Pushover 平台注册一个应用程序(Application),注册完成后即可获得该应用的 API Token。官方文档同时提示:注册应用时可以选用仓库public/目录下提供的官方图标(例如 public/images/os_icon.svg、public/logo_full.png 等),让推送在手机端展示为 Seerr 的专属图标,提升辨识度。
注册与 Token 相关细节以 Pushover 官方 API 文档的注册(registration)章节为准。在 Seerr 中,这一 Token 最终落位到设置对象settings.notifications.agents.pushover.options.accessToken。
第二步:填写 User Key(或群组密钥)
User Key 即你 Pushover 账户的 30 位用户密钥。官方文档特别强调一个实用技巧:
除了填自己的用户密钥外,也可以填写群组密钥(Group Key),从而把同一条通知同时投递给群组内的多个成员。
这对家庭媒体库、团队运维场景非常实用:管理员只需维护一个群组密钥,所有成员的设备都能收到请求审批、媒体可用等通知,无需逐一配置。
User Key 在设置对象中对应options.userToken。当启用代理且两项凭证均非空时,PushoverAgent.shouldSend()才返回true(见 pushover.ts),这也是发送测试通知的硬性前置条件。
在 Seerr 中完成系统级配置
进入「设置(Settings)→ 通知(Notifications)→ Pushover」,按以下步骤操作(对应表单组件 NotificationsPushover/index.tsx):
- Enable Agent:打开「启用代理」开关,该开关对应
enabled字段; - Embed Poster:勾选「嵌入海报」后,通知会附带媒体海报图片(对应
embedPoster字段,默认开启); - Application API Token:粘贴第一步获取的 30 位应用 Token;
- User or Group Key:粘贴你的用户密钥或群组密钥;
- Notification Sound:选择通知铃声。该下拉框默认显示「Device Default(设备默认)」,输入 Token 后 Seerr 会实时调用 Pushover 接口拉取可用铃声列表(详见下文"铃声拉取接口");
- Notification Types:通过 NotificationTypeSelector 勾选要接收的事件类型(媒体请求、审批、可用、问题反馈等)。注意:启用状态下至少需要勾选一种类型,否则保存按钮会被禁用;
- 点击Test(测试)按钮发送一条 "Check check, 1, 2, 3..." 的测试消息,确认手机端能收到后再点击Save保存。
配置的持久化
表单提交后,前端通过POST /api/v1/settings/notifications/pushover将完整配置写入后端,路由实现在 server/routes/settings/notifications.ts:
notificationRoutes.post('/pushover', async (req, res) => { const settings = getSettings(); settings.notifications.agents.pushover = req.body; await settings.save(); res.status(200).json(settings.notifications.agents.pushover); });同时提供GET /api/v1/settings/notifications/pushover读取当前配置。该路由挂载在isAuthenticated(Permission.ADMIN)权限之下(见 server/routes/index.ts),只有管理员可读写系统级推送配置。
默认配置一览
从 server/lib/settings/index.ts 可看到 Pushover 代理的默认值:
pushover: { enabled: false, embedPoster: true, types: 0, options: { accessToken: '', userToken: '', sound: '', }, }即:默认关闭、默认嵌入海报、默认不勾选任何通知类型、sound 为空字符串表示使用设备默认铃声。类型字段types是位掩码(bitmask)整数,0表示不订阅任何事件。
铃声拉取接口
通知设置页的铃声下拉框数据并非写死的,而是通过后端代理实时从 Pushover 获取:
- 路由
GET /settings/notifications/pushover/sounds?token=<appToken>(server/routes/index.ts)要求请求中携带应用 Token; - 底层由 server/api/pushover.ts 中的
PushoverAPI.getSounds(appToken)调用https://api.pushover.net/1/sounds.json实现,返回的sounds映射(铃声名 → 描述)经mapSounds转换为{ name, description }列表; - 前端拿到列表后渲染为下拉选项,空值代表「Device Default」。
测试通知的发送链路
点击「Test」按钮时,前端直接POST /api/v1/settings/notifications/pushover/test(携带当前表单的完整配置,无需先保存)。服务端处理位于 notifications.ts:
notificationRoutes.post('/pushover/test', async (req, res, next) => { const pushoverAgent = new PushoverAgent(req.body); if (await sendTestNotification(pushoverAgent, req.user)) { return res.status(204).send(); } else { return next({ status: 500, message: 'Failed to send Pushover notification.', }); } });sendTestNotification会构造一条Notification.TEST_NOTIFICATION事件(主题 "Test Notification"、正文 "Check check, 1, 2, 3. Are we coming in clear?"),并分别以系统通知与当前用户个人通知两种身份尝试投递。前端对应有三种 Toast 反馈:发送中、发送成功、发送失败(见表单组件中的toastPushoverTestSending/TestSuccess/TestFailed)。
消息发送的源码级原理
请求目标与负载结构
PushoverAgent.send()将消息 POST 到https://api.pushover.net/1/messages.json(pushover.ts),负载结构定义在PushoverPayload接口中:
| 字段 | 说明 |
|---|---|
token | 应用 API Token |
user | 用户/群组密钥 |
title | 通知标题(事件名或媒体标题) |
message | 通知正文(HTML 格式) |
url/url_title | 回链到 Seerr 对应页面(媒体详情页或问题页) |
priority | 优先级(普通 0 / 高优先级 1) |
html | 固定为1,启用 HTML 富文本渲染 |
sound | 铃声名称 |
attachment_base64/attachment_type | 海报图片的 Base64 数据与 MIME 类型 |
正文组装与本地化
正文由getNotificationPayload()动态拼接,并基于接收者的locale进行国际化(getIntl(locale)):
- 事件类消息先输出加粗的媒体标题
<b>...</b>,再追加<small>正文细节; - 请求类事件附带「请求人(requestedBy)」与「请求状态(pendingApproval / processing / available / declined / failed)」;
- 评论类事件附带「评论人与评论内容」;
- 问题类事件附带「报告人、问题类型、问题状态(open / resolved)」;
- 额外字段
extra以名称: 值的形式逐行追加。
优先级的自动提升
priority字段不是静态的,而是根据事件类型自动调整:
- 普通事件:
priority = 0; MEDIA_DECLINED(请求被拒绝)、MEDIA_FAILED(媒体获取失败)、ISSUE_CREATED(新问题上报):priority = 1,即 Pushover 的高优先级模式,确保关键事件得到即时提醒。
回链地址
若 Seerr 配置了applicationUrl(主设置中的应用地址),消息会附带url回链:问题事件跳转/issues/{issueId},媒体事件跳转/{mediaType}/{tmdbId},url_title则本地化为「查看媒体 / 查看问题」。
海报嵌入的实现
勾选 Embed Poster 后,代理会通过getImagePayload()以arraybuffer方式下载海报原图,转成 Base64 与 MIME 类型后作为attachment_base64/attachment_type一起提交(pushover.ts)。下载失败时仅记录错误日志并继续发送纯文本消息,不会导致整个通知中断。
三种投递路径
send()内部按优先级依次处理三类接收者:
- 系统通知:
payload.notifySystem为真、事件类型命中settings.types位掩码、且代理已启用并填全凭证时,使用系统配置的 Token/Key/Sound 发送; - 个人通知:
payload.notifyUser为真,且该用户在UserSettings中开启了 Pushover 订阅(hasNotificationType(NotificationAgentKey.PUSHOVER, type))并填有自己的pushoverApplicationToken/pushoverUserKey时,用用户自己的凭证发送。源码中还隐含一个去重逻辑:当用户凭证与系统凭证完全相同时跳过个人发送,避免同一用户收到重复消息; - 管理员通知:当
payload.notifyAdmin为真时,遍历所有用户,找出启用了 Pushover 订阅且满足管理员通知条件的用户,逐一按各自凭证发送。
个人通知的相关字段(pushoverApplicationToken、pushoverUserKey、pushoverSound)定义在 server/entity/UserSettings.ts,并由迁移脚本 AddPushbulletPushoverUserSettings.ts 与 AddUserPushoverSound.ts 逐版本补充,这也解释了为何用户级配置支持独立的铃声选择。
用户级个人通知配置
若用户希望使用自己的Pushover 账户接收通知,可在个人设置(或管理员编辑用户的「通知」页)中独立配置:
- 进入「用户设置 → 通知」;
- 找到 Pushover 区块,填入自己的Application API Token与User or Group Key;
- 选择铃声与订阅的通知类型,保存即可。
该表单对应组件 UserNotificationsPushover.tsx,与系统级配置同样使用^[a-z\d]{30}$校验,且只有在勾选了至少一种通知类型时才要求填写凭证。个人配置通过POST /api/v1/user/{userId}/settings/notifications持久化到UserSettings。
这种「系统一套、个人一套」的设计,让 Seerr 既能满足管理员全局广播的需求,也能让每个用户按自己的偏好与权限接收消息,二者互不干扰。
常见问题与排查建议
- 测试失败 / 收不到消息:优先检查
shouldSend()的三个条件——代理已启用(enabled)、accessToken与userToken均非空。任一项缺失都会导致发送被跳过,服务端日志(label 为Notifications)会打印 "Sending Pushover notification" 调试信息; - 提示 Token 格式错误:确认两项凭证均为 30 位字母数字串(大小写均可),可到 Pushover 账户页核对后重新粘贴;
- 铃声下拉框为空:铃声列表依赖输入的应用 Token 实时拉取,若 Token 无效或网络受限,下拉框仅显示「Device Default」(前端据此禁用选择器);
- 通知丢失或重复:注意源码中的去重逻辑——当用户凭证与系统凭证一致时,该用户只收到系统级投递,不会重复收到个人投递;反之,凭证不同的用户会按自己的凭证独立接收;
- 希望团队共享通知:将 User Key 换成 Pushover 群组密钥即可实现一对多广播,无需为每个成员单独配置。
小结
Pushover 通知的完整链路可概括为:管理员在设置页(NotificationsPushover/index.tsx)填写 30 位应用 Token 与用户/群组密钥 → 配置保存至settings.notifications.agents.pushover(server/lib/settings/index.ts)→ 事件触发时由PushoverAgent.send()(server/lib/notifications/agents/pushover.ts)组装含标题、HTML 正文、优先级、回链、海报附件的负载,POST 至 Pushover 消息接口;铃声列表则由 server/api/pushover.ts 通过sounds.json接口实时拉取。掌握这些配置项与源码细节后,你既能完成开箱即用的推送部署,也能在出现问题时快速定位是凭证、事件订阅还是负载组装环节出了偏差。
【免费下载链接】seerrOpen-source media request and discovery manager for Jellyfin, Plex, and Emby.项目地址: https://gitcode.com/GitHub_Trending/je/seerr
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考