Skip to content

Commit e18f231

Browse files
authored
feat: add NTFY.SH agent (#3195)
1 parent f59d3fc commit e18f231

File tree

5 files changed

+82
-0
lines changed

5 files changed

+82
-0
lines changed

docs/reference/notification.md

+13
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,16 @@ Copy the API key generated with the service activation.
262262
| `FREEMOBILE_API_KEY` | API key generated with your notification option activation |
263263

264264
Note: here you do not need to give neither your password nor phone number.
265+
266+
## NTFY.sh
267+
268+
You can send notifications using NTFY.sh, which supports various features like priority, tags, and action buttons.
269+
Use the free service at [ntfy.sh](https://ntfy.sh) or host your own instance.
270+
271+
| Environment variable | Description |
272+
|:---:|---|
273+
| `NTFY_URL` | ntfy server URL, e.g. `https://ntfy.sh` |
274+
| `NTFY_TOPIC` | Topic to publish alerts to |
275+
| `NTFY_PRIORITY` | Message priority, e.g. max/high/default/low/min, I recommend to use the numbers instead of the string values for the priority. https://docs.ntfy.sh/publish/?h=priority#message-priority |
276+
| `NTFY_TITLE` | Title of the message |
277+
| `NTFY_ACCESS_TOKEN` | Access token for authentication. https://docs.ntfy.sh/config/#access-tokens |

dotenv-example

+5
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,9 @@ STREAMLABS_SOUND=
163163
STREAMLABS_DURATION=
164164
FREEMOBILE_ID=
165165
FREEMOBILE_API_KEY=
166+
NTFY_TOPIC=
167+
NTFY_PRIORITY=
168+
NTFY_TITLE=
169+
NTFY_ACCESS_TOKEN=
170+
NTFY_URL=
166171
WEB_PORT=

src/config.ts

+7
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,13 @@ const notifications = {
379379
id: envOrString(process.env.FREEMOBILE_ID),
380380
apiKey: envOrString(process.env.FREEMOBILE_API_KEY),
381381
},
382+
ntfy: {
383+
url: envOrString(process.env.NTFY_URL, 'https://ntfy.sh'),
384+
topic: envOrString(process.env.NTFY_TOPIC),
385+
priority: envOrString(process.env.NTFY_PRIORITY),
386+
title: envOrString(process.env.NTFY_TITLE),
387+
accessToken: envOrString(process.env.NTFY_ACCESS_TOKEN),
388+
},
382389
};
383390

384391
const nvidia = {

src/messaging/notification.ts

+2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ import {updateRedis} from './redis';
2020
import {sendStreamLabsAlert} from './streamlabs';
2121
import {sendFreeMobileAlert} from './freemobile';
2222
import {DMPayload} from '.';
23+
import {sendNtfyAlert} from './ntfy';
2324

2425
export function sendNotification(link: Link, store: Store) {
2526
// Priority
2627
playSound();
28+
sendNtfyAlert(link, store);
2729
sendDiscordMessage(link, store);
2830
sendDesktopNotification(link, store);
2931
sendEmail(link, store);

src/messaging/ntfy.ts

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import {Link, Store} from '../store/model';
2+
import {Print, logger} from '../logger';
3+
import {config} from '../config';
4+
import fetch from 'node-fetch';
5+
6+
const {ntfy} = config.notifications;
7+
8+
export function sendNtfyAlert(link: Link, store: Store) {
9+
if (ntfy.topic) {
10+
logger.debug('↗ sending ntfy alert');
11+
12+
(async () => {
13+
const message = `${Print.inStock(link, store)}`;
14+
const headers: Record<string, string> = {};
15+
16+
if (ntfy.priority) headers['Priority'] = ntfy.priority;
17+
headers[
18+
'Tags'
19+
] = `${store.name},${link.model},${link.series},${link.brand}`;
20+
if (ntfy.title) headers['Title'] = ntfy.title;
21+
if (ntfy.accessToken)
22+
headers['Authorization'] = `Bearer ${ntfy.accessToken}`;
23+
24+
const body = {
25+
topic: ntfy.topic,
26+
message,
27+
actions: [
28+
{
29+
action: 'view',
30+
label: 'Add to cart',
31+
url: link.cartUrl ?? link.url,
32+
},
33+
],
34+
};
35+
36+
try {
37+
const response = await fetch(ntfy.url, {
38+
method: 'POST',
39+
body: JSON.stringify(body),
40+
headers: {
41+
...headers,
42+
'Content-Type': 'application/json',
43+
},
44+
});
45+
46+
if (!response.ok)
47+
throw new Error(`Failed to send ntfy alert: ${response.statusText}`);
48+
49+
logger.info('✔ ntfy alert sent');
50+
} catch (error: unknown) {
51+
logger.error("✖ couldn't send ntfy alert", error);
52+
}
53+
})();
54+
}
55+
}

0 commit comments

Comments
 (0)