Skip to content
This repository was archived by the owner on Feb 15, 2026. It is now read-only.

Commit 8251c73

Browse files
authored
feat(pushover): attach image to pushover notification payload (#3701)
1 parent be04742 commit 8251c73

File tree

1 file changed

+50
-4
lines changed

1 file changed

+50
-4
lines changed

server/lib/notifications/agents/pushover.ts

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ import {
1414
import type { NotificationAgent, NotificationPayload } from './agent';
1515
import { BaseAgent } from './agent';
1616

17-
interface PushoverPayload {
17+
interface PushoverImagePayload {
18+
attachment_base64: string;
19+
attachment_type: string;
20+
}
21+
22+
interface PushoverPayload extends PushoverImagePayload {
1823
token: string;
1924
user: string;
2025
title: string;
@@ -43,10 +48,36 @@ class PushoverAgent
4348
return true;
4449
}
4550

46-
private getNotificationPayload(
51+
private async getImagePayload(
52+
imageUrl: string
53+
): Promise<Partial<PushoverImagePayload>> {
54+
try {
55+
const response = await axios.get(imageUrl, {
56+
responseType: 'arraybuffer',
57+
});
58+
const base64 = Buffer.from(response.data, 'binary').toString('base64');
59+
const contentType = (
60+
response.headers['Content-Type'] || response.headers['content-type']
61+
)?.toString();
62+
63+
return {
64+
attachment_base64: base64,
65+
attachment_type: contentType,
66+
};
67+
} catch (e) {
68+
logger.error('Error getting image payload', {
69+
label: 'Notifications',
70+
errorMessage: e.message,
71+
response: e.response?.data,
72+
});
73+
return {};
74+
}
75+
}
76+
77+
private async getNotificationPayload(
4778
type: Notification,
4879
payload: NotificationPayload
49-
): Partial<PushoverPayload> {
80+
): Promise<Partial<PushoverPayload>> {
5081
const { applicationUrl, applicationTitle } = getSettings().main;
5182

5283
const title = payload.event ?? payload.subject;
@@ -122,13 +153,25 @@ class PushoverAgent
122153
? `View ${payload.issue ? 'Issue' : 'Media'} in ${applicationTitle}`
123154
: undefined;
124155

156+
let attachment_base64;
157+
let attachment_type;
158+
if (payload.image) {
159+
const imagePayload = await this.getImagePayload(payload.image);
160+
if (imagePayload.attachment_base64 && imagePayload.attachment_type) {
161+
attachment_base64 = imagePayload.attachment_base64;
162+
attachment_type = imagePayload.attachment_type;
163+
}
164+
}
165+
125166
return {
126167
title,
127168
message,
128169
url,
129170
url_title,
130171
priority,
131172
html: 1,
173+
attachment_base64,
174+
attachment_type,
132175
};
133176
}
134177

@@ -138,7 +181,10 @@ class PushoverAgent
138181
): Promise<boolean> {
139182
const settings = this.getSettings();
140183
const endpoint = 'https://api.pushover.net/1/messages.json';
141-
const notificationPayload = this.getNotificationPayload(type, payload);
184+
const notificationPayload = await this.getNotificationPayload(
185+
type,
186+
payload
187+
);
142188

143189
// Send system notification
144190
if (

0 commit comments

Comments
 (0)