thelounge-plugin-ntfy 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/docker-compose.yml +4 -0
- package/index.js +66 -1
- package/package.json +1 -1
- package/src/config.js +36 -1
- package/src/handler.js +66 -23
package/README.md
CHANGED
|
@@ -18,6 +18,8 @@ This plugin introduces the `/ntfy` command, subcommands are:
|
|
|
18
18
|
|
|
19
19
|
- `/ntfy start`: Start the ntfy listener for the network
|
|
20
20
|
- `/ntfy stop`: Stop the ntfy listener for the network
|
|
21
|
+
- `/ntfy status`: Show the ntfy listener status for this network
|
|
22
|
+
- `/ntfy test`: Send a test notification
|
|
21
23
|
- `/ntfy config`: Config commands
|
|
22
24
|
- `/ntfy config set <setting_key> <setting_value>`: Set a configuration setting
|
|
23
25
|
- `/ntfy config remove <setting_key>`: Set a configuration setting to null
|
|
@@ -39,6 +41,14 @@ To start/stop sending push notifications in the desired network, enter:
|
|
|
39
41
|
/ntfy start/stop
|
|
40
42
|
```
|
|
41
43
|
|
|
44
|
+
## Private Messages
|
|
45
|
+
|
|
46
|
+
By default, you will only be notified when you are mentioned, **this includes messages sent privately to you**. If you want to be notified of all private messages, enter this command and start the notifier like usual:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
/ntfy config set config.notify_on_private_messages true
|
|
50
|
+
```
|
|
51
|
+
|
|
42
52
|
## License
|
|
43
53
|
|
|
44
54
|
This plugin is licensed under [MIT](https://opensource.org/license/mit)
|
package/docker-compose.yml
CHANGED
|
@@ -8,3 +8,7 @@ services:
|
|
|
8
8
|
restart: unless-stopped
|
|
9
9
|
volumes:
|
|
10
10
|
- $PWD/tl:/var/opt/thelounge
|
|
11
|
+
- $PWD/src:/var/opt/thelounge/packages/thelounge-plugin-ntfy/src
|
|
12
|
+
- $PWD/index.js:/var/opt/thelounge/packages/thelounge-plugin-ntfy/index.js
|
|
13
|
+
- $PWD/package.json:/var/opt/thelounge/packages/thelounge-plugin-ntfy/package.json
|
|
14
|
+
- $PWD/package-lock.json:/var/opt/thelounge/packages/thelounge-plugin-ntfy/package-lock.json
|
package/index.js
CHANGED
|
@@ -12,7 +12,7 @@ const {
|
|
|
12
12
|
const globalActiveListeners = new Map();
|
|
13
13
|
|
|
14
14
|
const ntfyCommand = {
|
|
15
|
-
input: (client, target, command, args) => {
|
|
15
|
+
input: async (client, target, command, args) => {
|
|
16
16
|
const say = (message) => {
|
|
17
17
|
client.sendMessage(message, target.chan);
|
|
18
18
|
};
|
|
@@ -21,6 +21,10 @@ const ntfyCommand = {
|
|
|
21
21
|
say(`${command} command help:`);
|
|
22
22
|
say(`/${command} start - Start the ntfy listener for this network`);
|
|
23
23
|
say(`/${command} stop - Stop the ntfy listener for this network`);
|
|
24
|
+
say(
|
|
25
|
+
`/${command} status - Show the ntfy listener status for this network`
|
|
26
|
+
);
|
|
27
|
+
say(`/${command} test - Send a test notification`);
|
|
24
28
|
say(
|
|
25
29
|
`/${command} config set <setting_key> <setting_value> - Set a configuration setting`
|
|
26
30
|
);
|
|
@@ -105,6 +109,67 @@ const ntfyCommand = {
|
|
|
105
109
|
break;
|
|
106
110
|
}
|
|
107
111
|
|
|
112
|
+
case "status": {
|
|
113
|
+
const userListeners = globalActiveListeners.get(client.client.name);
|
|
114
|
+
|
|
115
|
+
if (
|
|
116
|
+
userListeners &&
|
|
117
|
+
typeof userListeners.has === "function" &&
|
|
118
|
+
userListeners.has(network.uuid)
|
|
119
|
+
) {
|
|
120
|
+
say("ntfy listener is running for this network");
|
|
121
|
+
} else {
|
|
122
|
+
say("ntfy listener is not running for this network");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
case "test": {
|
|
129
|
+
const { NtfyClient, MessagePriority } = await import("ntfy");
|
|
130
|
+
|
|
131
|
+
const [userConfig, errors] = loadUserConfig(client.client.name);
|
|
132
|
+
|
|
133
|
+
if (errors.length > 0) {
|
|
134
|
+
say("Cannot test ntfy due to invalid configuration:");
|
|
135
|
+
for (const error of errors) {
|
|
136
|
+
say(`- ${error.instancePath} ${error.message}`);
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let ntfyAuth;
|
|
142
|
+
|
|
143
|
+
if (userConfig.ntfy.token) {
|
|
144
|
+
ntfyAuth = userConfig.ntfy.token;
|
|
145
|
+
} else if (userConfig.ntfy.username && userConfig.ntfy.password) {
|
|
146
|
+
ntfyAuth = {
|
|
147
|
+
username: userConfig.ntfy.username,
|
|
148
|
+
password: userConfig.ntfy.password,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const ntfyClient = new NtfyClient({
|
|
153
|
+
server: userConfig.ntfy.server,
|
|
154
|
+
topic: userConfig.ntfy.topic,
|
|
155
|
+
priority: MessagePriority.HIGH,
|
|
156
|
+
tags: ["speech_balloon"],
|
|
157
|
+
authorization: ntfyAuth,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
ntfyClient.publish({
|
|
162
|
+
title: `${network.name} #afakechannel: ntfy`,
|
|
163
|
+
message: `Hello, ${client.client.name}!`,
|
|
164
|
+
});
|
|
165
|
+
say(`Sent to ${userConfig.ntfy.server}/${userConfig.ntfy.topic}`);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
say(`Failed to send test notification: ${error.message}`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
|
|
108
173
|
case "config": {
|
|
109
174
|
const subsubcommand = subcommand.slice(1);
|
|
110
175
|
|
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -14,6 +14,9 @@ const DEFAULT_CONFIG = {
|
|
|
14
14
|
password: null,
|
|
15
15
|
token: null,
|
|
16
16
|
},
|
|
17
|
+
config: {
|
|
18
|
+
notify_on_private_messages: false,
|
|
19
|
+
},
|
|
17
20
|
};
|
|
18
21
|
|
|
19
22
|
const ALLOWED_KEYS = new Set([
|
|
@@ -22,12 +25,15 @@ const ALLOWED_KEYS = new Set([
|
|
|
22
25
|
"ntfy.username",
|
|
23
26
|
"ntfy.password",
|
|
24
27
|
"ntfy.token",
|
|
28
|
+
"config.notify_on_private_messages",
|
|
25
29
|
]);
|
|
26
30
|
|
|
31
|
+
const BOOLEAN_KEYS = new Set(["config.notify_on_private_messages"]);
|
|
32
|
+
|
|
27
33
|
const userConfigSchema = {
|
|
28
34
|
type: "object",
|
|
29
35
|
additionalProperties: false,
|
|
30
|
-
required: ["ntfy"],
|
|
36
|
+
required: ["ntfy", "config"],
|
|
31
37
|
properties: {
|
|
32
38
|
ntfy: {
|
|
33
39
|
type: "object",
|
|
@@ -90,6 +96,17 @@ const userConfigSchema = {
|
|
|
90
96
|
password: ["username"],
|
|
91
97
|
},
|
|
92
98
|
},
|
|
99
|
+
config: {
|
|
100
|
+
type: "object",
|
|
101
|
+
additionalProperties: false,
|
|
102
|
+
required: ["notify_on_private_messages"],
|
|
103
|
+
properties: {
|
|
104
|
+
notify_on_private_messages: {
|
|
105
|
+
type: "boolean",
|
|
106
|
+
default: false,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
},
|
|
93
110
|
},
|
|
94
111
|
};
|
|
95
112
|
|
|
@@ -155,6 +172,24 @@ function saveUserSetting(username, settingKey, settingValue) {
|
|
|
155
172
|
}
|
|
156
173
|
}
|
|
157
174
|
|
|
175
|
+
if (settingValue && typeof settingValue !== "string") {
|
|
176
|
+
return `Error: expected value to be a string`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (BOOLEAN_KEYS.has(settingKey)) {
|
|
180
|
+
try {
|
|
181
|
+
settingValue = settingValue
|
|
182
|
+
? JSON.parse(settingValue.toLowerCase())
|
|
183
|
+
: false;
|
|
184
|
+
|
|
185
|
+
if (typeof settingValue !== "boolean") {
|
|
186
|
+
return `Invalid value for ${settingKey}, expected a boolean`;
|
|
187
|
+
}
|
|
188
|
+
} catch {
|
|
189
|
+
return `Invalid value for ${settingKey}, expected a boolean`;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
158
193
|
curr[keys[keys.length - 1]] = settingValue;
|
|
159
194
|
|
|
160
195
|
const userConfigPath = path.join(rootDir, "config", `${username}.json`);
|
package/src/handler.js
CHANGED
|
@@ -1,45 +1,88 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const { loadUserConfig } = require("./config.js");
|
|
4
|
+
const { PluginLogger } = require("./logger.js");
|
|
4
5
|
|
|
5
6
|
function createHandler(client, network) {
|
|
6
7
|
return async (data) => {
|
|
8
|
+
// Ignore own messages
|
|
9
|
+
if (network.nick === data.nick) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
7
13
|
const highlightRegex = new RegExp(network.highlightRegex, "i");
|
|
8
14
|
const message = data.message || "";
|
|
9
15
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
16
|
+
const mentioned = highlightRegex.test(message);
|
|
17
|
+
const isPM = data.target === network.nick;
|
|
18
|
+
|
|
19
|
+
let notify = false;
|
|
20
|
+
let userConfig;
|
|
21
|
+
|
|
22
|
+
if (mentioned) {
|
|
23
|
+
// Mentions always notify
|
|
24
|
+
notify = true;
|
|
25
|
+
} else if (isPM) {
|
|
26
|
+
// PMs notify only if enabled in config
|
|
27
|
+
const [uc, errors] = loadUserConfig(client.client.name);
|
|
13
28
|
|
|
14
29
|
if (errors.length > 0) {
|
|
15
30
|
return;
|
|
16
31
|
}
|
|
17
32
|
|
|
18
|
-
|
|
33
|
+
userConfig = uc;
|
|
19
34
|
|
|
20
|
-
if (userConfig.
|
|
21
|
-
|
|
22
|
-
} else if (userConfig.ntfy.username && userConfig.ntfy.password) {
|
|
23
|
-
ntfyAuth = {
|
|
24
|
-
username: userConfig.ntfy.username,
|
|
25
|
-
password: userConfig.ntfy.password,
|
|
26
|
-
};
|
|
35
|
+
if (userConfig.config.notify_on_private_messages) {
|
|
36
|
+
notify = true;
|
|
27
37
|
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (notify) {
|
|
41
|
+
try {
|
|
42
|
+
// Avoid needlessly loading user config multiple times
|
|
43
|
+
if (!userConfig) {
|
|
44
|
+
const [uc, errors] = loadUserConfig(client.client.name);
|
|
28
45
|
|
|
29
|
-
|
|
46
|
+
if (errors.length > 0) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
30
49
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
topic: userConfig.ntfy.topic,
|
|
34
|
-
priority: MessagePriority.HIGH,
|
|
35
|
-
tags: ["speech_balloon"],
|
|
36
|
-
authorization: ntfyAuth,
|
|
37
|
-
});
|
|
50
|
+
userConfig = uc;
|
|
51
|
+
}
|
|
38
52
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
let ntfyAuth;
|
|
54
|
+
|
|
55
|
+
if (userConfig.ntfy.token) {
|
|
56
|
+
ntfyAuth = {
|
|
57
|
+
username: "",
|
|
58
|
+
password: userConfig.ntfy.token,
|
|
59
|
+
};
|
|
60
|
+
} else if (userConfig.ntfy.username && userConfig.ntfy.password) {
|
|
61
|
+
ntfyAuth = {
|
|
62
|
+
username: userConfig.ntfy.username,
|
|
63
|
+
password: userConfig.ntfy.password,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const { NtfyClient, MessagePriority } = await import("ntfy");
|
|
68
|
+
|
|
69
|
+
const ntfyClient = new NtfyClient({
|
|
70
|
+
server: userConfig.ntfy.server,
|
|
71
|
+
topic: userConfig.ntfy.topic,
|
|
72
|
+
priority: MessagePriority.HIGH,
|
|
73
|
+
tags: ["speech_balloon"],
|
|
74
|
+
authorization: ntfyAuth,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
ntfyClient.publish({
|
|
78
|
+
title: isPM
|
|
79
|
+
? `${network.name}: ${data.nick}`
|
|
80
|
+
: `${network.name} ${data.target}: ${data.nick}`,
|
|
81
|
+
message: message,
|
|
82
|
+
});
|
|
83
|
+
} catch (e) {
|
|
84
|
+
PluginLogger.error("Failed to send ntfy notification", e);
|
|
85
|
+
}
|
|
43
86
|
}
|
|
44
87
|
};
|
|
45
88
|
}
|