@manybot/manybot 5.0.0 → 5.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 +5 -7
- package/package.json +35 -24
- package/src/client/banner.js +0 -57
- package/src/client/whatsappClient.js +0 -178
- package/src/config.js +0 -190
- package/src/download/queue.js +0 -55
- package/src/i18n/index.js +0 -235
- package/src/kernel/messageHandler.js +0 -35
- package/src/kernel/pluginApi.js +0 -524
- package/src/kernel/pluginGuard.js +0 -37
- package/src/kernel/pluginLoader.js +0 -134
- package/src/kernel/pluginState.js +0 -99
- package/src/kernel/scheduler.js +0 -48
- package/src/locales/en.json +0 -67
- package/src/locales/es.json +0 -62
- package/src/locales/pt.json +0 -68
- package/src/logger/logger.js +0 -31
- package/src/main.js +0 -105
- package/src/utils/file.js +0 -9
- package/src/utils/getChatId.js +0 -3
- package/src/utils/get_id.js +0 -177
- package/src/utils/pluginI18n.js +0 -129
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|

|
|
7
7
|

|
|
8
8
|

|
|
9
|
-

|
|
10
10
|
|
|
11
11
|
</div>
|
|
12
12
|
|
|
@@ -27,9 +27,9 @@ npm install -g @manybot/manyplug
|
|
|
27
27
|
manybot
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
On first run, a configuration file is created at `~/.manybot/manybot.
|
|
30
|
+
On first run, a configuration file is created at `~/.manybot/manybot.toml`. Edit it to set up your preferences.
|
|
31
31
|
|
|
32
|
-
For detailed setup instructions, see the **[documentation](https://manybot.
|
|
32
|
+
For detailed setup instructions, see the **[documentation](https://manybot.org/docs/)**.
|
|
33
33
|
|
|
34
34
|
## Plugins
|
|
35
35
|
|
|
@@ -39,16 +39,14 @@ ManyBot's functionality comes from plugins. Install them with ManyPlug:
|
|
|
39
39
|
manyplug install <plugin-name>
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
Browse available plugins at **[manybot.
|
|
43
|
-
|
|
44
|
-
Want to build your own? The plugin API lets you add commands and features without touching the bot's core - *documentation coming soon*.
|
|
42
|
+
Browse available plugins at **[manybot.org/plugins](https://manybot.org/plugins/)**.
|
|
45
43
|
|
|
46
44
|
## Contributing
|
|
47
45
|
|
|
48
46
|
All kinds of contributions are welcome:
|
|
49
47
|
|
|
50
48
|
- **Bug reports and feature requests**: open an issue on GitHub or Codeberg
|
|
51
|
-
- **Code**: pull requests are welcome on [GitHub](https://github.com/many-bot/manybot) or [Codeberg](https://codeberg.org/many-bot/manybot); patches by email (`devel+manybot
|
|
49
|
+
- **Code**: pull requests are welcome on [GitHub](https://github.com/many-bot/manybot) or [Codeberg](https://codeberg.org/many-bot/manybot); patches by email (`devel+manybot.org`) are also accepted - subscribe to the mailing list [here](https://list.stxerr.dev).
|
|
52
50
|
- **Plugins**: submit your plugin to [manyplug-repo](https://github.com/many-bot/manyplug-repo), which has instructions on how to do it
|
|
53
51
|
- **Anything else**: suggestions, translations, documentation fixes - reach out by email or open an issue
|
|
54
52
|
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"name": "SyntaxError!",
|
|
6
6
|
"email": "me@stxerr.dev"
|
|
7
7
|
},
|
|
8
|
-
"version": "5.
|
|
8
|
+
"version": "5.2.0",
|
|
9
9
|
"license": "GPL-3.0-only",
|
|
10
10
|
"private": false,
|
|
11
11
|
"engines": {
|
|
@@ -17,38 +17,49 @@
|
|
|
17
17
|
},
|
|
18
18
|
"type": "module",
|
|
19
19
|
"bin": {
|
|
20
|
-
"manybot": "
|
|
20
|
+
"manybot": "dist/main.js"
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
|
-
"
|
|
24
|
-
"src/config.js",
|
|
25
|
-
"src/download",
|
|
26
|
-
"src/i18n",
|
|
27
|
-
"src/kernel",
|
|
28
|
-
"src/locales",
|
|
29
|
-
"src/logger",
|
|
30
|
-
"src/main.js",
|
|
31
|
-
"src/utils",
|
|
23
|
+
"dist/",
|
|
32
24
|
"README.md",
|
|
33
|
-
"README_EN.md",
|
|
34
|
-
"latest",
|
|
35
25
|
"LICENSE"
|
|
36
26
|
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc && node -e \"fs.mkdirSync('dist/locales', { recursive: true }); fs.cpSync('src/locales', 'dist/locales', { recursive: true });\"",
|
|
29
|
+
"start": "node dist/main.js",
|
|
30
|
+
"typecheck": "tsc --noEmit"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
34
|
+
"@types/node": "^22.0.0",
|
|
35
|
+
"tsx": "^4.19.2",
|
|
36
|
+
"typescript": "^5.7.3"
|
|
37
|
+
},
|
|
37
38
|
"dependencies": {
|
|
39
|
+
"@clack/prompts": "^0.10.0",
|
|
40
|
+
"@hapi/boom": "^10.0.1",
|
|
41
|
+
"@whiskeysockets/baileys": "^6.7.23",
|
|
42
|
+
"better-sqlite3": "^12.11.1",
|
|
43
|
+
"node-cron": "^4.6.0",
|
|
38
44
|
"node-webpmux": "^3.2.1",
|
|
45
|
+
"pino": "^10.3.1",
|
|
39
46
|
"qrcode-terminal": "^0.12.0",
|
|
40
|
-
"
|
|
41
|
-
"whatsapp-web.js": "^1.24.0"
|
|
47
|
+
"smol-toml": "^1.7.0"
|
|
42
48
|
},
|
|
43
49
|
"imports": {
|
|
44
|
-
"#
|
|
45
|
-
"#
|
|
46
|
-
"#
|
|
47
|
-
"#
|
|
48
|
-
"#
|
|
49
|
-
"#
|
|
50
|
-
"#
|
|
51
|
-
"#
|
|
52
|
-
"#
|
|
50
|
+
"#drivers/*": "./dist/drivers/*",
|
|
51
|
+
"#core/*": "./dist/core/*",
|
|
52
|
+
"#client/*": "./dist/client/*",
|
|
53
|
+
"#kernel/*": "./dist/kernel/*",
|
|
54
|
+
"#manyapi": "./dist/kernel/pluginApi.js",
|
|
55
|
+
"#settingsdb": "./dist/kernel/settingsDb.js",
|
|
56
|
+
"#sendguard": "./dist/kernel/sendGuard.js",
|
|
57
|
+
"#logger": "./dist/logger/logger.js",
|
|
58
|
+
"#utils/*": "./dist/utils/*",
|
|
59
|
+
"#i18n": "./dist/i18n/index.js",
|
|
60
|
+
"#download": "./dist/download/queue.js",
|
|
61
|
+
"#config": "./dist/config.js",
|
|
62
|
+
"#main": "./dist/main.js",
|
|
63
|
+
"#types": "./dist/types.js"
|
|
53
64
|
}
|
|
54
65
|
}
|
package/src/client/banner.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
const C = {
|
|
2
|
-
reset: "\x1b[0m",
|
|
3
|
-
bold: "\x1b[1m",
|
|
4
|
-
|
|
5
|
-
blue: "\x1b[94m",
|
|
6
|
-
magenta: "\x1b[95m",
|
|
7
|
-
cyan: "\x1b[96m",
|
|
8
|
-
gray: "\x1b[90m",
|
|
9
|
-
yellow: "\x1b[93m",
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
import { readFileSync } from "fs";
|
|
13
|
-
import { fileURLToPath } from "url";
|
|
14
|
-
import path from "path";
|
|
15
|
-
|
|
16
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
17
|
-
const __dirname = path.dirname(__filename);
|
|
18
|
-
|
|
19
|
-
const v = JSON.parse(
|
|
20
|
-
readFileSync(
|
|
21
|
-
path.join(__dirname, "../../package.json"),
|
|
22
|
-
"utf8"
|
|
23
|
-
)
|
|
24
|
-
).version;
|
|
25
|
-
|
|
26
|
-
export function printBanner() {
|
|
27
|
-
const banner = [
|
|
28
|
-
` _ _ `,
|
|
29
|
-
` | | | | `,
|
|
30
|
-
` _ __ ___ __ _ _ __ _ _| |__ ___ | |_`,
|
|
31
|
-
`| '_ \` _ \\ / _\` | '_ \\| | | | '_ \\ / _ \\| __`,
|
|
32
|
-
`| | | | | | (_| | | | | |_| | |_) | (_) | |_`,
|
|
33
|
-
`|_| |_| |_|\\__,_|_| |_|\\__, |_.__/ \\___/ \\__`,
|
|
34
|
-
` __/ | `,
|
|
35
|
-
` ${v} |___/ `
|
|
36
|
-
];
|
|
37
|
-
|
|
38
|
-
console.log(`${C.bold}${C.blue}`);
|
|
39
|
-
console.log(banner.join("\n"));
|
|
40
|
-
console.log(C.reset);
|
|
41
|
-
|
|
42
|
-
console.log(
|
|
43
|
-
` made with ${C.magenta}<3${C.reset} by ${C.bold}${C.cyan}SyntaxError!${C.reset} ${C.gray}<me@stxerr.dev>${C.reset}`
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
console.log();
|
|
47
|
-
|
|
48
|
-
console.log(
|
|
49
|
-
` ${C.gray}website${C.reset} : ${C.yellow}https://manybot.stxerr.dev${C.reset}`
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
console.log(
|
|
53
|
-
` ${C.gray}github ${C.reset} : ${C.yellow}https://github.com/many-bot${C.reset}`
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
console.log();
|
|
57
|
-
}
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
/* whatsappClient
|
|
2
|
-
*
|
|
3
|
-
* Initialize client and connect to WhatsApp
|
|
4
|
-
*
|
|
5
|
-
* if PHONE_NUMBER is set on config, it will request a verficiation code
|
|
6
|
-
* but if it is not, it will display a QR Code on the screen to scan using your phone
|
|
7
|
-
*
|
|
8
|
-
* */
|
|
9
|
-
|
|
10
|
-
import pkg from "whatsapp-web.js";
|
|
11
|
-
import fs from "fs";
|
|
12
|
-
import path from "path";
|
|
13
|
-
import { fileURLToPath } from "url";
|
|
14
|
-
import { PHONE_NUMBER, CLIENT_ID } from "#config";
|
|
15
|
-
import { logger } from "#logger";
|
|
16
|
-
import qrcode from "qrcode-terminal";
|
|
17
|
-
import { t } from "#i18n"
|
|
18
|
-
import { CONFIG_DIR } from "#config";
|
|
19
|
-
import { extract } from "tar";
|
|
20
|
-
import { pipeline } from "node:stream/promises";
|
|
21
|
-
import { Readable } from "node:stream";
|
|
22
|
-
import { Transform } from "node:stream";
|
|
23
|
-
|
|
24
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
25
|
-
const __dirname = path.dirname(__filename);
|
|
26
|
-
|
|
27
|
-
const DATA_PATH = path.join(CONFIG_DIR, "sessions");
|
|
28
|
-
|
|
29
|
-
const chrome = path.join(CONFIG_DIR, "chrome/chrome")
|
|
30
|
-
|
|
31
|
-
if (!fs.existsSync(chrome)) {
|
|
32
|
-
try {
|
|
33
|
-
logger.warn(t("errors.chromeNotFound"));
|
|
34
|
-
const tmpDir = "/tmp/manybot-chrome";
|
|
35
|
-
const tmpPath = path.join(tmpDir, "chrome.tar.gz");
|
|
36
|
-
const os = process.platform;
|
|
37
|
-
const urls = {
|
|
38
|
-
linux: "https://api.manybot.stxerr.dev/download-chrome-linux",
|
|
39
|
-
win32: "https://api.manybot.stxerr.dev/download-chrome-win"
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const url = urls[os];
|
|
43
|
-
if (!url) throw new Error(t("errors.OSNotSupported", { os }));
|
|
44
|
-
|
|
45
|
-
fs.mkdirSync(tmpDir, { recursive: true });
|
|
46
|
-
|
|
47
|
-
const res = await fetch(url);
|
|
48
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
49
|
-
|
|
50
|
-
const expected = Number(res.headers.get("content-length"));
|
|
51
|
-
let received = 0;
|
|
52
|
-
const frames = ["|","/","-","\\"];
|
|
53
|
-
let frame = 0;
|
|
54
|
-
let spinner;
|
|
55
|
-
|
|
56
|
-
const file = fs.createWriteStream(tmpPath);
|
|
57
|
-
|
|
58
|
-
spinner = setInterval(() => {
|
|
59
|
-
const pct = expected
|
|
60
|
-
? ` ${Math.floor((received / expected) * 100)}%`
|
|
61
|
-
: ` ${(received / 1024 / 1024).toFixed(1)}MB`;
|
|
62
|
-
process.stderr.write(`\r${frames[frame++ % frames.length]} Baixando Chrome...${pct}`);
|
|
63
|
-
}, 80);
|
|
64
|
-
|
|
65
|
-
const counter = new Transform({
|
|
66
|
-
transform(chunk, _enc, cb) {
|
|
67
|
-
received += chunk.length;
|
|
68
|
-
cb(null, chunk);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
try {
|
|
73
|
-
await pipeline(
|
|
74
|
-
Readable.fromWeb(res.body),
|
|
75
|
-
counter,
|
|
76
|
-
file
|
|
77
|
-
);
|
|
78
|
-
} finally {
|
|
79
|
-
clearInterval(spinner);
|
|
80
|
-
process.stderr.write("\r\x1b[2K"); // limpa a linha
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (expected && received !== expected) {
|
|
84
|
-
throw new Error("Download incompleto");
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
await extract({ file: tmpPath, cwd: CONFIG_DIR, gzip: true });
|
|
88
|
-
} catch (err) {
|
|
89
|
-
throw new Error(t("errors.couldNotDownloadChrome") + err.message);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
export const { Client, LocalAuth, MessageMedia } = pkg;
|
|
94
|
-
|
|
95
|
-
// -- Instance --------------------------------------------------
|
|
96
|
-
const clientOptions = {
|
|
97
|
-
authStrategy: new LocalAuth({
|
|
98
|
-
clientId: CLIENT_ID,
|
|
99
|
-
dataPath: DATA_PATH
|
|
100
|
-
}),
|
|
101
|
-
puppeteer: {
|
|
102
|
-
executablePath: chrome,
|
|
103
|
-
headless: true,
|
|
104
|
-
args: [
|
|
105
|
-
'--no-sandbox',
|
|
106
|
-
'--disable-setuid-sandbox'
|
|
107
|
-
],
|
|
108
|
-
},
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
// -- Qr Handle --------------------------------------------------
|
|
112
|
-
export function handleQR(qr) {
|
|
113
|
-
logger.info(t("system.qrScan"));
|
|
114
|
-
qrcode.generate(qr, { small: true });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// -- Handle pairing code ---------------------------------------
|
|
118
|
-
export function handlePairingCode(code) {
|
|
119
|
-
logger.info(t("system.pairingCodeTitle"));
|
|
120
|
-
logger.info(t("system.pairingCodeValue", { code: code }));
|
|
121
|
-
logger.info(t("system.pairingCodeInstructions"));
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// -- Phone Number Validation ------------------------------------
|
|
125
|
-
const AUTH_STATE_PATH = path.join(__dirname, `../../.auth_${CLIENT_ID}.json`);
|
|
126
|
-
|
|
127
|
-
// Validates if phone string has 10-15 characters
|
|
128
|
-
function isValidPhoneNumber(phone) {
|
|
129
|
-
if (!phone || typeof phone !== 'string') return false;
|
|
130
|
-
const phoneRegex = /^\d{10,15}$/;
|
|
131
|
-
return phoneRegex.test(phone);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Checks if phone number changed since last authentication
|
|
135
|
-
function hasPhoneNumberChanged(currentPhone) {
|
|
136
|
-
try {
|
|
137
|
-
if (!fs.existsSync(AUTH_STATE_PATH)) return false;
|
|
138
|
-
const state = JSON.parse(fs.readFileSync(AUTH_STATE_PATH, 'utf8'));
|
|
139
|
-
const storedPhone = state.phoneNumber || null;
|
|
140
|
-
return storedPhone !== currentPhone;
|
|
141
|
-
} catch {
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Saves phone number to auth state file
|
|
147
|
-
function savePhoneNumber(phone) {
|
|
148
|
-
try {
|
|
149
|
-
fs.writeFileSync(AUTH_STATE_PATH, JSON.stringify({ phoneNumber: phone, savedAt: new Date().toISOString() }));
|
|
150
|
-
} catch {
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Check if phone number changed and force re-authentication if needed
|
|
156
|
-
if (PHONE_NUMBER && hasPhoneNumberChanged(PHONE_NUMBER)) {
|
|
157
|
-
// Delete auth folder to force fresh authentication
|
|
158
|
-
const authPath = path.join(__dirname, `../../.wwebjs_auth/session-${CLIENT_ID}`);
|
|
159
|
-
if (fs.existsSync(authPath)) {
|
|
160
|
-
fs.rmSync(authPath, { recursive: true, force: true });
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Add phone number pairing if PHONE_NUMBER is configured and valid
|
|
165
|
-
if (PHONE_NUMBER) {
|
|
166
|
-
if (isValidPhoneNumber(PHONE_NUMBER)) {
|
|
167
|
-
clientOptions.pairWithPhoneNumber = {
|
|
168
|
-
phoneNumber: PHONE_NUMBER,
|
|
169
|
-
showNotification: true,
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
savePhoneNumber(PHONE_NUMBER);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export const client = new Client(clientOptions);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
export default client;
|
package/src/config.js
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* config.js
|
|
3
|
-
*
|
|
4
|
-
* Loads:
|
|
5
|
-
* ~/.manybot/manybot.conf
|
|
6
|
-
* ~/.manybot/manyplug.conf
|
|
7
|
-
*
|
|
8
|
-
* Merges both files into a single configuration object.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import fs from "fs/promises";
|
|
12
|
-
import os from "os";
|
|
13
|
-
import path from "path";
|
|
14
|
-
|
|
15
|
-
import { logger } from "#logger";
|
|
16
|
-
|
|
17
|
-
export const CONFIG_DIR = path.join(os.homedir(), ".manybot");
|
|
18
|
-
export const CONFIG_FILE = path.join(CONFIG_DIR, "manybot.conf");
|
|
19
|
-
export const PLUGIN_FILE = path.join(CONFIG_DIR, "manyplug.conf");
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Converts strings to native JS values.
|
|
23
|
-
*/
|
|
24
|
-
function parseValue(value) {
|
|
25
|
-
value = value.trim();
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
(value.startsWith('"') && value.endsWith('"')) ||
|
|
29
|
-
(value.startsWith("'") && value.endsWith("'"))
|
|
30
|
-
) {
|
|
31
|
-
value = value.slice(1, -1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (value === "true")
|
|
35
|
-
return true;
|
|
36
|
-
|
|
37
|
-
if (value === "false")
|
|
38
|
-
return false;
|
|
39
|
-
|
|
40
|
-
return value;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Reads comments safely.
|
|
45
|
-
* Ignores # inside quoted strings.
|
|
46
|
-
*/
|
|
47
|
-
function stripInlineComment(line) {
|
|
48
|
-
let result = "";
|
|
49
|
-
let quote = null;
|
|
50
|
-
|
|
51
|
-
for (let i = 0; i < line.length; i++) {
|
|
52
|
-
const ch = line[i];
|
|
53
|
-
|
|
54
|
-
if ((ch === '"' || ch === "'") && line[i - 1] !== "\\") {
|
|
55
|
-
if (quote === ch)
|
|
56
|
-
quote = null;
|
|
57
|
-
else if (!quote)
|
|
58
|
-
quote = ch;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
if (ch === "#" && !quote)
|
|
62
|
-
break;
|
|
63
|
-
|
|
64
|
-
result += ch;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return result.trim();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Parses manybot.conf syntax.
|
|
72
|
-
*/
|
|
73
|
-
function parseConf(raw) {
|
|
74
|
-
const lines = raw.split(/\r?\n/);
|
|
75
|
-
|
|
76
|
-
const mergedLines = [];
|
|
77
|
-
|
|
78
|
-
let insideList = false;
|
|
79
|
-
let buffer = "";
|
|
80
|
-
|
|
81
|
-
for (let line of lines) {
|
|
82
|
-
line = stripInlineComment(line);
|
|
83
|
-
|
|
84
|
-
if (!line)
|
|
85
|
-
continue;
|
|
86
|
-
|
|
87
|
-
if (!insideList) {
|
|
88
|
-
if (/=\s*\[$/.test(line)) {
|
|
89
|
-
insideList = true;
|
|
90
|
-
buffer = line;
|
|
91
|
-
} else {
|
|
92
|
-
mergedLines.push(line);
|
|
93
|
-
}
|
|
94
|
-
} else {
|
|
95
|
-
buffer += " " + line;
|
|
96
|
-
|
|
97
|
-
if (line.includes("]")) {
|
|
98
|
-
mergedLines.push(buffer);
|
|
99
|
-
buffer = "";
|
|
100
|
-
insideList = false;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const config = {};
|
|
106
|
-
|
|
107
|
-
for (const line of mergedLines) {
|
|
108
|
-
const idx = line.indexOf("=");
|
|
109
|
-
|
|
110
|
-
if (idx === -1)
|
|
111
|
-
continue;
|
|
112
|
-
|
|
113
|
-
const key = line.slice(0, idx).trim();
|
|
114
|
-
let value = line.slice(idx + 1).trim();
|
|
115
|
-
|
|
116
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
117
|
-
config[key] = value
|
|
118
|
-
.slice(1, -1)
|
|
119
|
-
.split(",")
|
|
120
|
-
.map(v => parseValue(v))
|
|
121
|
-
.filter(v => v !== "");
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
config[key] = parseValue(value);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return config;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async function readFileSafe(file) {
|
|
132
|
-
try {
|
|
133
|
-
return await fs.readFile(file, "utf-8");
|
|
134
|
-
} catch (err) {
|
|
135
|
-
if (err.code !== "ENOENT") {
|
|
136
|
-
logger.warn(`Error reading ${file}: ${err.message}`);
|
|
137
|
-
}
|
|
138
|
-
return "";
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const defaultConfig =
|
|
143
|
-
`
|
|
144
|
-
# Many bot configuration file
|
|
145
|
-
# See https://manybot.stxerr.dev/docs/config to learn more
|
|
146
|
-
|
|
147
|
-
CLIENT_ID="manybot"
|
|
148
|
-
CMD_PREFIX="!"
|
|
149
|
-
CHATS=[]
|
|
150
|
-
LANGUAGE=en
|
|
151
|
-
PHONE_NUMBER=
|
|
152
|
-
`;
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
await fs.stat(CONFIG_FILE);
|
|
156
|
-
} catch {
|
|
157
|
-
logger.warn("Configuration file not found: ", CONFIG_FILE, ". Creating a new one.");
|
|
158
|
-
|
|
159
|
-
await fs.mkdir(CONFIG_DIR, { recursive: true });
|
|
160
|
-
await fs.writeFile(CONFIG_FILE, defaultConfig);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const baseConfig = await readFileSafe(CONFIG_FILE);
|
|
164
|
-
const pluginConfig = await readFileSafe(PLUGIN_FILE);
|
|
165
|
-
|
|
166
|
-
export const CONFIG = {
|
|
167
|
-
CMD_PREFIX: "!",
|
|
168
|
-
CLIENT_ID: "manybot",
|
|
169
|
-
CHATS: [],
|
|
170
|
-
PLUGINS: [],
|
|
171
|
-
LANGUAGE: "en",
|
|
172
|
-
PHONE_NUMBER: null,
|
|
173
|
-
...parseConf(baseConfig + "\n" + pluginConfig),
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
export const CLIENT_ID = CONFIG.CLIENT_ID;
|
|
177
|
-
export const CMD_PREFIX = CONFIG.CMD_PREFIX;
|
|
178
|
-
export const CHATS = CONFIG.CHATS;
|
|
179
|
-
export const PLUGINS = CONFIG.PLUGINS;
|
|
180
|
-
export const LANGUAGE = CONFIG.LANGUAGE;
|
|
181
|
-
export const PHONE_NUMBER = CONFIG.PHONE_NUMBER;
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Useful paths for plugins/modules.
|
|
185
|
-
*/
|
|
186
|
-
export const PATHS = {
|
|
187
|
-
HOME: CONFIG_DIR,
|
|
188
|
-
CONFIG_FILE,
|
|
189
|
-
PLUGIN_FILE
|
|
190
|
-
};
|
package/src/download/queue.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* src/download/queue.js
|
|
3
|
-
*
|
|
4
|
-
* Sequential execution queue for heavy jobs (downloads, conversions).
|
|
5
|
-
* Ensures only one job runs at a time — without overloading yt-dlp or ffmpeg.
|
|
6
|
-
*
|
|
7
|
-
* Plugin passes a `workFn` that does everything: download, convert, send.
|
|
8
|
-
* Queue only handles sequence and error handling.
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* import { enqueue } from "../../src/download/queue.js";
|
|
12
|
-
* enqueue(async () => { ... all plugin logic ... }, onError);
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import { logger } from "#logger";
|
|
16
|
-
import { t } from "#i18n";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @typedef {{
|
|
20
|
-
* workFn: () => Promise<void>,
|
|
21
|
-
* errorFn: (err: Error) => Promise<void>,
|
|
22
|
-
* }} Job
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/** @type {Job[]} */
|
|
26
|
-
let queue = [];
|
|
27
|
-
let processing = false;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Add job to queue and start processing if idle.
|
|
31
|
-
*
|
|
32
|
-
* @param {Function} workFn — async () => void — all plugin logic
|
|
33
|
-
* @param {Function} errorFn — async (err) => void — called if workFn throws
|
|
34
|
-
*/
|
|
35
|
-
export function enqueue(workFn, errorFn) {
|
|
36
|
-
queue.push({ workFn, errorFn });
|
|
37
|
-
if (!processing) processQueue();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async function processQueue() {
|
|
41
|
-
processing = true;
|
|
42
|
-
while (queue.length) {
|
|
43
|
-
await processJob(queue.shift());
|
|
44
|
-
}
|
|
45
|
-
processing = false;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async function processJob({ workFn, errorFn }) {
|
|
49
|
-
try {
|
|
50
|
-
await workFn();
|
|
51
|
-
} catch (err) {
|
|
52
|
-
logger.error(t("system.downloadJobFailed", { message: err.message }));
|
|
53
|
-
try { await errorFn(err); } catch { }
|
|
54
|
-
}
|
|
55
|
-
}
|