thelounge-plugin-ntfy 1.0.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 +44 -0
- package/docker-compose.yml +10 -0
- package/index.js +230 -0
- package/misc/api.txt +53 -0
- package/package.json +35 -0
- package/src/config.js +181 -0
- package/src/handler.js +49 -0
- package/src/logger.js +26 -0
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# The Lounge ntfy Plugin
|
|
2
|
+
|
|
3
|
+
A plugin for [The Lounge](https://thelounge.chat/) that sends a message to an [ntfy](https://ntfy.sh/) server whenever you are mentioned in a chat.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Via the `thelounge` command line:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
thelounge install thelounge-plugin-ntfy
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Restart The Lounge after installation
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
This plugin introduces the `/ntfy` command, subcommands are:
|
|
18
|
+
|
|
19
|
+
- `/ntfy start`: Start the ntfy listener for the network
|
|
20
|
+
- `/ntfy stop`: Stop the ntfy listener for the network
|
|
21
|
+
- `/ntfy config`: Config commands
|
|
22
|
+
- `/ntfy config set <setting_key> <setting_value>`: Set a configuration setting
|
|
23
|
+
- `/ntfy config remove <setting_key>`: Set a configuration setting to null
|
|
24
|
+
- `/ntfy config print`: Print the current configuration with warnings if any
|
|
25
|
+
|
|
26
|
+
## Setup
|
|
27
|
+
|
|
28
|
+
This plugin will **not** work out of the box, by default the plugin sends notifications to the official `ntfy.sh` server but no topic is set. To set a topic, enter this command:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
/ntfy config set ntfy.topic <topic>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
You may also set your account credentials or token as well if needed, see the config print command for all the possible settings.
|
|
35
|
+
|
|
36
|
+
To start/stop sending push notifications in the desired network, enter:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
/ntfy start/stop
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## License
|
|
43
|
+
|
|
44
|
+
This plugin is licensed under [MIT](https://opensource.org/license/mit)
|
package/index.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { PluginLogger } = require("./src/logger.js");
|
|
4
|
+
const { createHandler } = require("./src/handler.js");
|
|
5
|
+
const {
|
|
6
|
+
setRootDir,
|
|
7
|
+
loadUserConfig,
|
|
8
|
+
saveUserSetting,
|
|
9
|
+
} = require("./src/config.js");
|
|
10
|
+
|
|
11
|
+
// user -> Map<network.uuid -> handler and client>
|
|
12
|
+
const globalActiveListeners = new Map();
|
|
13
|
+
|
|
14
|
+
const ntfyCommand = {
|
|
15
|
+
input: (client, target, command, args) => {
|
|
16
|
+
const say = (message) => {
|
|
17
|
+
client.sendMessage(message, target.chan);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const helpMessage = () => {
|
|
21
|
+
say(`${command} command help:`);
|
|
22
|
+
say(`/${command} start - Start the ntfy listener for this network`);
|
|
23
|
+
say(`/${command} stop - Stop the ntfy listener for this network`);
|
|
24
|
+
say(
|
|
25
|
+
`/${command} config set <setting_key> <setting_value> - Set a configuration setting`
|
|
26
|
+
);
|
|
27
|
+
say(
|
|
28
|
+
`/${command} config remove <setting_key> - Set configuration setting to null`
|
|
29
|
+
);
|
|
30
|
+
say(
|
|
31
|
+
`/${command} config print - Print the current configuration with warnings if any`
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const subcommand = args;
|
|
36
|
+
const network = target.network;
|
|
37
|
+
|
|
38
|
+
if (subcommand.length === 0) {
|
|
39
|
+
helpMessage();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (typeof subcommand[0] !== "string") {
|
|
44
|
+
helpMessage();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
switch (subcommand[0].toLowerCase()) {
|
|
49
|
+
case "start": {
|
|
50
|
+
const [_, errors] = loadUserConfig(client.client.name);
|
|
51
|
+
|
|
52
|
+
if (errors.length > 0) {
|
|
53
|
+
say("Cannot start ntfy listener due to invalid configuration:");
|
|
54
|
+
for (const error of errors) {
|
|
55
|
+
say(`- ${error.instancePath} ${error.message}`);
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const userListeners = globalActiveListeners.get(client.client.name);
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
userListeners &&
|
|
64
|
+
typeof userListeners.has === "function" &&
|
|
65
|
+
userListeners.has(network.uuid)
|
|
66
|
+
) {
|
|
67
|
+
say("ntfy listener is already running for this network");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const handler = createHandler(client, network);
|
|
72
|
+
network.irc.on("privmsg", handler);
|
|
73
|
+
|
|
74
|
+
if (!userListeners) {
|
|
75
|
+
const map = new Map();
|
|
76
|
+
map.set(network.uuid, { handler: handler, client: client });
|
|
77
|
+
globalActiveListeners.set(client.client.name, map);
|
|
78
|
+
} else {
|
|
79
|
+
userListeners.set(network.uuid, { handler: handler, client: client });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
say("ntfy listener started for this network");
|
|
83
|
+
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
case "stop": {
|
|
88
|
+
const userListeners = globalActiveListeners.get(client.client.name);
|
|
89
|
+
|
|
90
|
+
if (
|
|
91
|
+
!userListeners ||
|
|
92
|
+
typeof userListeners.has !== "function" ||
|
|
93
|
+
!userListeners.has(network.uuid)
|
|
94
|
+
) {
|
|
95
|
+
say("ntfy listener is not running for this network");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const { handler } = userListeners.get(network.uuid);
|
|
100
|
+
network.irc.removeListener("privmsg", handler);
|
|
101
|
+
userListeners.delete(network.uuid);
|
|
102
|
+
|
|
103
|
+
say("ntfy listener stopped for this network");
|
|
104
|
+
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
case "config": {
|
|
109
|
+
const subsubcommand = subcommand.slice(1);
|
|
110
|
+
|
|
111
|
+
if (subsubcommand.length === 0) {
|
|
112
|
+
helpMessage();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (typeof subsubcommand[0] !== "string") {
|
|
117
|
+
helpMessage();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
switch (subsubcommand[0].toLowerCase()) {
|
|
122
|
+
case "set": {
|
|
123
|
+
const subsubargs = subsubcommand.slice(1);
|
|
124
|
+
|
|
125
|
+
if (subsubargs.length < 2) {
|
|
126
|
+
helpMessage();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const settingKey = subsubargs[0];
|
|
131
|
+
const settingValue = subsubargs.slice(1).join(" ");
|
|
132
|
+
const response = saveUserSetting(
|
|
133
|
+
client.client.name,
|
|
134
|
+
settingKey,
|
|
135
|
+
settingValue
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
say(response);
|
|
139
|
+
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
case "remove": {
|
|
144
|
+
const subsubargs = subsubcommand.slice(1);
|
|
145
|
+
|
|
146
|
+
if (subsubargs.length < 1) {
|
|
147
|
+
helpMessage();
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const settingKey = subsubargs[0];
|
|
152
|
+
const response = saveUserSetting(
|
|
153
|
+
client.client.name,
|
|
154
|
+
settingKey,
|
|
155
|
+
null
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
say(response);
|
|
159
|
+
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
case "print": {
|
|
164
|
+
const [userConfig, errors] = loadUserConfig(client.client.name);
|
|
165
|
+
|
|
166
|
+
const printConfig = (obj, parentKey = "") => {
|
|
167
|
+
for (const key in obj) {
|
|
168
|
+
const value = obj[key];
|
|
169
|
+
const fullKey = parentKey ? `${parentKey}.${key}` : key;
|
|
170
|
+
|
|
171
|
+
if (typeof value === "object" && value !== null) {
|
|
172
|
+
printConfig(value, fullKey);
|
|
173
|
+
} else {
|
|
174
|
+
say(`${fullKey}=${value}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
printConfig(userConfig);
|
|
180
|
+
|
|
181
|
+
if (errors.length > 0) {
|
|
182
|
+
say("");
|
|
183
|
+
|
|
184
|
+
for (const error of errors) {
|
|
185
|
+
say(`Warning: ${error.instancePath} ${error.message}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (
|
|
190
|
+
userConfig.ntfy.token &&
|
|
191
|
+
userConfig.ntfy.username &&
|
|
192
|
+
userConfig.ntfy.password
|
|
193
|
+
) {
|
|
194
|
+
say(
|
|
195
|
+
"Warning: Both ntfy.token and ntfy.username/password are set, ntfy.token will be used for authentication"
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
default: {
|
|
203
|
+
helpMessage();
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
default: {
|
|
212
|
+
helpMessage();
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
allowDisconnected: true,
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
module.exports = {
|
|
221
|
+
onServerStart(tl) {
|
|
222
|
+
PluginLogger.init(tl.Logger);
|
|
223
|
+
|
|
224
|
+
const configDir = tl.Config.getPersistentStorageDir();
|
|
225
|
+
setRootDir(configDir);
|
|
226
|
+
PluginLogger.info(`[ntfy] Using config directory: ${configDir}`);
|
|
227
|
+
|
|
228
|
+
tl.Commands.add("ntfy", ntfyCommand);
|
|
229
|
+
},
|
|
230
|
+
};
|
package/misc/api.txt
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
https://thelounge.chat/docs/api
|
|
2
|
+
|
|
3
|
+
api
|
|
4
|
+
Commands
|
|
5
|
+
add(commandText: string, command: Command)
|
|
6
|
+
Config
|
|
7
|
+
getConfig()
|
|
8
|
+
getPersistentStorageDir()
|
|
9
|
+
Logger
|
|
10
|
+
error(...args)
|
|
11
|
+
warn(...args)
|
|
12
|
+
info(...args)
|
|
13
|
+
debug(...args)
|
|
14
|
+
Stylesheets
|
|
15
|
+
addFile(filename: String)
|
|
16
|
+
|
|
17
|
+
command
|
|
18
|
+
input(client: Client, target: Target, command: String, args: String[])
|
|
19
|
+
allowDisconnected: bool
|
|
20
|
+
|
|
21
|
+
target
|
|
22
|
+
network: String
|
|
23
|
+
chan: String
|
|
24
|
+
|
|
25
|
+
client
|
|
26
|
+
runAsUser(command: String, targetId: String)
|
|
27
|
+
createChannel(attributes: Attributes)
|
|
28
|
+
sendToBrowser(event: String, data: Object)
|
|
29
|
+
getChannel(channelId: Number)
|
|
30
|
+
sendMessage(text: String, chan: Chan)
|
|
31
|
+
|
|
32
|
+
attributes
|
|
33
|
+
id: Number
|
|
34
|
+
messages: Msg[]
|
|
35
|
+
name: string
|
|
36
|
+
key: String
|
|
37
|
+
topic: String
|
|
38
|
+
type: Chan.Type
|
|
39
|
+
state: Chan.State
|
|
40
|
+
firstUnread: Number
|
|
41
|
+
unread: Number
|
|
42
|
+
highlight: Number
|
|
43
|
+
users: String -> User Map
|
|
44
|
+
|
|
45
|
+
Chan.Type
|
|
46
|
+
CHANNEL
|
|
47
|
+
LOBBY
|
|
48
|
+
QUERY
|
|
49
|
+
SPECIAL
|
|
50
|
+
|
|
51
|
+
Chan.State
|
|
52
|
+
PARTED
|
|
53
|
+
JOINED
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "thelounge-plugin-ntfy",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A plugin for The Lounge that sends push notifications via ntfy when highlighted",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"thelounge",
|
|
7
|
+
"thelounge-plugin",
|
|
8
|
+
"ntfy",
|
|
9
|
+
"irc"
|
|
10
|
+
],
|
|
11
|
+
"thelounge": {
|
|
12
|
+
"name": "ntfy",
|
|
13
|
+
"type": "plugin",
|
|
14
|
+
"supports": ">=4.0.0"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/cy1der/thelounge-plugin-ntfy#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/cy1der/thelounge-plugin-ntfy/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/cy1der/thelounge-plugin-ntfy.git"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "cy1der",
|
|
26
|
+
"type": "commonjs",
|
|
27
|
+
"main": "index.js",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"ajv": "^8.17.1",
|
|
30
|
+
"ajv-errors": "^3.0.0",
|
|
31
|
+
"ajv-formats": "^3.0.1",
|
|
32
|
+
"ntfy": "^1.11.8",
|
|
33
|
+
"thelounge": "^4.4.3"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/config.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const Ajv2019 = require("ajv/dist/2019").default;
|
|
6
|
+
const addFormats = require("ajv-formats");
|
|
7
|
+
const addErrors = require("ajv-errors");
|
|
8
|
+
|
|
9
|
+
const DEFAULT_CONFIG = {
|
|
10
|
+
ntfy: {
|
|
11
|
+
server: "https://ntfy.sh",
|
|
12
|
+
topic: null, // Intentionally left null to force user configuration
|
|
13
|
+
username: null,
|
|
14
|
+
password: null,
|
|
15
|
+
token: null,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const ALLOWED_KEYS = new Set([
|
|
20
|
+
"ntfy.server",
|
|
21
|
+
"ntfy.topic",
|
|
22
|
+
"ntfy.username",
|
|
23
|
+
"ntfy.password",
|
|
24
|
+
"ntfy.token",
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
const userConfigSchema = {
|
|
28
|
+
type: "object",
|
|
29
|
+
additionalProperties: false,
|
|
30
|
+
required: ["ntfy"],
|
|
31
|
+
properties: {
|
|
32
|
+
ntfy: {
|
|
33
|
+
type: "object",
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
required: ["server", "topic"],
|
|
36
|
+
properties: {
|
|
37
|
+
server: {
|
|
38
|
+
type: "string",
|
|
39
|
+
format: "uri",
|
|
40
|
+
errorMessage: "Invalid server URL",
|
|
41
|
+
},
|
|
42
|
+
topic: {
|
|
43
|
+
type: "string",
|
|
44
|
+
minLength: 1,
|
|
45
|
+
errorMessage: "Topic cannot be empty",
|
|
46
|
+
},
|
|
47
|
+
username: { type: "string", nullable: true },
|
|
48
|
+
password: { type: "string", nullable: true },
|
|
49
|
+
token: {
|
|
50
|
+
type: "string",
|
|
51
|
+
format: "ntfy-token",
|
|
52
|
+
nullable: true,
|
|
53
|
+
errorMessage: "Invalid ntfy token, must start with 'tk_'",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
allOf: [
|
|
57
|
+
{
|
|
58
|
+
if: {
|
|
59
|
+
properties: { username: { type: "string" } },
|
|
60
|
+
required: ["username"],
|
|
61
|
+
},
|
|
62
|
+
then: {
|
|
63
|
+
properties: { password: { type: "string" } },
|
|
64
|
+
required: ["password"],
|
|
65
|
+
errorMessage: {
|
|
66
|
+
properties: {
|
|
67
|
+
password: "Password is required when username is set",
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
if: {
|
|
74
|
+
properties: { password: { type: "string" } },
|
|
75
|
+
required: ["password"],
|
|
76
|
+
},
|
|
77
|
+
then: {
|
|
78
|
+
properties: { username: { type: "string" } },
|
|
79
|
+
required: ["username"],
|
|
80
|
+
errorMessage: {
|
|
81
|
+
properties: {
|
|
82
|
+
username: "Username is required when password is set",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
dependentRequired: {
|
|
89
|
+
username: ["password"],
|
|
90
|
+
password: ["username"],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const ajv = new Ajv2019({ allErrors: true });
|
|
97
|
+
addFormats(ajv);
|
|
98
|
+
addErrors(ajv);
|
|
99
|
+
ajv.addFormat("ntfy-token", {
|
|
100
|
+
validate: (data) => typeof data === "string" && data.startsWith("tk_"),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
let rootDir = null;
|
|
104
|
+
|
|
105
|
+
function setRootDir(dir) {
|
|
106
|
+
rootDir = dir;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function loadUserConfig(username) {
|
|
110
|
+
if (!rootDir) {
|
|
111
|
+
throw new Error("Root directory is not set");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const userConfigPath = path.join(rootDir, "config", `${username}.json`);
|
|
115
|
+
|
|
116
|
+
if (!fs.existsSync(userConfigPath)) {
|
|
117
|
+
const validate = ajv.compile(userConfigSchema);
|
|
118
|
+
const valid = validate(DEFAULT_CONFIG);
|
|
119
|
+
|
|
120
|
+
return [DEFAULT_CONFIG, valid ? [] : validate.errors];
|
|
121
|
+
} else {
|
|
122
|
+
let userConfig;
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
userConfig = JSON.parse(fs.readFileSync(userConfigPath, "utf-8"));
|
|
126
|
+
} catch (e) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Invalid JSON in user config for ${username}: ${e.message}`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const validate = ajv.compile(userConfigSchema);
|
|
133
|
+
const valid = validate(userConfig);
|
|
134
|
+
|
|
135
|
+
return [userConfig, valid ? [] : validate.errors];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function saveUserSetting(username, settingKey, settingValue) {
|
|
140
|
+
if (!rootDir) {
|
|
141
|
+
throw new Error("Root directory is not set");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (ALLOWED_KEYS.has(settingKey)) {
|
|
145
|
+
let userConfig = loadUserConfig(username)[0];
|
|
146
|
+
|
|
147
|
+
const keys = settingKey.split(".");
|
|
148
|
+
|
|
149
|
+
let curr = userConfig;
|
|
150
|
+
|
|
151
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
152
|
+
const key = keys[i];
|
|
153
|
+
if (key in curr) {
|
|
154
|
+
curr = curr[key];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
curr[keys[keys.length - 1]] = settingValue;
|
|
159
|
+
|
|
160
|
+
const userConfigPath = path.join(rootDir, "config", `${username}.json`);
|
|
161
|
+
|
|
162
|
+
fs.mkdirSync(path.dirname(userConfigPath), { recursive: true });
|
|
163
|
+
fs.writeFileSync(
|
|
164
|
+
userConfigPath,
|
|
165
|
+
JSON.stringify(userConfig, null, 2),
|
|
166
|
+
"utf-8"
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
return "Success";
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return `Invalid setting ${settingKey}, allowed settings are: ${Array.from(
|
|
173
|
+
ALLOWED_KEYS
|
|
174
|
+
).join(", ")}`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
module.exports = {
|
|
178
|
+
setRootDir,
|
|
179
|
+
loadUserConfig,
|
|
180
|
+
saveUserSetting,
|
|
181
|
+
};
|
package/src/handler.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { loadUserConfig } = require("./config.js");
|
|
4
|
+
|
|
5
|
+
function createHandler(client, network) {
|
|
6
|
+
return async (data) => {
|
|
7
|
+
const highlightRegex = new RegExp(network.highlightRegex, "i");
|
|
8
|
+
const message = data.message || "";
|
|
9
|
+
|
|
10
|
+
if (highlightRegex.test(message)) {
|
|
11
|
+
// Load config after each message to get latest settings
|
|
12
|
+
const [userConfig, errors] = loadUserConfig(client.client.name);
|
|
13
|
+
|
|
14
|
+
if (errors.length > 0) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let ntfyAuth;
|
|
19
|
+
|
|
20
|
+
if (userConfig.ntfy.token) {
|
|
21
|
+
ntfyAuth = userConfig.ntfy.token;
|
|
22
|
+
} else if (userConfig.ntfy.username && userConfig.ntfy.password) {
|
|
23
|
+
ntfyAuth = {
|
|
24
|
+
username: userConfig.ntfy.username,
|
|
25
|
+
password: userConfig.ntfy.password,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const { NtfyClient, MessagePriority } = await import("ntfy");
|
|
30
|
+
|
|
31
|
+
const ntfyClient = new NtfyClient({
|
|
32
|
+
server: userConfig.ntfy.server,
|
|
33
|
+
topic: userConfig.ntfy.topic,
|
|
34
|
+
priority: MessagePriority.HIGH,
|
|
35
|
+
tags: ["speech_balloon"],
|
|
36
|
+
authorization: ntfyAuth,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
ntfyClient.publish({
|
|
40
|
+
title: `${network.name} ${data.target}: ${data.nick}`,
|
|
41
|
+
message: message,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
createHandler,
|
|
49
|
+
};
|
package/src/logger.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
let Logger;
|
|
4
|
+
|
|
5
|
+
// Inspired by https://github.com/juanjocerero/thelounge-plugin-am/blob/main/src/logger.js
|
|
6
|
+
const PluginLogger = {
|
|
7
|
+
init: (logger) => {
|
|
8
|
+
Logger = logger;
|
|
9
|
+
},
|
|
10
|
+
error: (...args) => {
|
|
11
|
+
if (Logger) Logger.error(...args);
|
|
12
|
+
},
|
|
13
|
+
warn: (...args) => {
|
|
14
|
+
if (Logger) Logger.warn(...args);
|
|
15
|
+
},
|
|
16
|
+
info: (...args) => {
|
|
17
|
+
if (Logger) Logger.info(...args);
|
|
18
|
+
},
|
|
19
|
+
debug: (...args) => {
|
|
20
|
+
if (Logger) Logger.debug(...args);
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
PluginLogger,
|
|
26
|
+
};
|