update documentation and remove systemd support
This commit is contained in:
317
docs/PLUGINS (en).md
Normal file
317
docs/PLUGINS (en).md
Normal file
@@ -0,0 +1,317 @@
|
||||
# 🔌 Creating Plugins
|
||||
|
||||
Complete guide to creating plugins in ManyBot.
|
||||
|
||||
---
|
||||
|
||||
## 📑 Index
|
||||
|
||||
- [Basic Structure](#basic-structure)
|
||||
- [Plugin Manifest](#plugin-manifest-manyplug-json)
|
||||
- [Creating Your First Plugin](#creating-your-first-plugin)
|
||||
- [Object API](#object-api)
|
||||
- [Exposing API](#exposing-api-to-other-plugins)
|
||||
- [Translating Your Plugin](#translating-your-plugin)
|
||||
- [Error Handling](#error-handling)
|
||||
|
||||
---
|
||||
|
||||
## Basic Structure
|
||||
|
||||
```
|
||||
src/plugins/
|
||||
└── my-plugin/
|
||||
├── index.js
|
||||
├── manyplug.json
|
||||
└── locale/ (optional)
|
||||
├── en.json
|
||||
├── pt.json
|
||||
└── es.json
|
||||
```
|
||||
|
||||
`index.js` must export a `default` function that receives `{ msg, api }`:
|
||||
|
||||
```javascript
|
||||
export default async function ({ msg, api }) {
|
||||
// Your logic here
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Plugin Manifest (manyplug.json)
|
||||
|
||||
Every plugin should have a `manyplug.json` at its root. It describes the plugin and declares any extra npm dependencies it needs.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "my-plugin",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"service": false,
|
||||
"dependencies": {}
|
||||
}
|
||||
```
|
||||
|
||||
### Fields
|
||||
|
||||
| Field | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `name` | `string` | Plugin identifier, must match the folder name |
|
||||
| `version` | `string` | Semantic version (e.g., `"1.0.0"`) |
|
||||
| `category` | `string` | Plugin category: `utility`, `media`, `game`, `humor`, `info` |
|
||||
| `service` | `boolean` | `true` if the plugin runs in the background (scheduler, listener). `false` if triggered by a command or event |
|
||||
| `dependencies` | `object` | Extra npm packages required by the plugin, same format as `package.json` |
|
||||
|
||||
### Example with dependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "weather",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"service": false,
|
||||
"dependencies": {
|
||||
"axios": "^1.6.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After adding dependencies, run `npm install` at the project root to install them.
|
||||
|
||||
---
|
||||
|
||||
## Creating Your First Plugin
|
||||
|
||||
### Example 1: Simple command
|
||||
|
||||
```javascript
|
||||
// plugins/greeting/index.js
|
||||
import { CMD_PREFIX } from "../../config.js";
|
||||
|
||||
export default async function ({ msg, api }) {
|
||||
// Only responds if the message starts with "!hi"
|
||||
if (!msg.is(CMD_PREFIX + "hi")) return;
|
||||
|
||||
await msg.reply("Hello! 👋");
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Command with arguments
|
||||
|
||||
```javascript
|
||||
// plugins/calculate/index.js
|
||||
import { CMD_PREFIX } from "../../config.js";
|
||||
|
||||
export default async function ({ msg, api }) {
|
||||
if (!msg.is(CMD_PREFIX + "calculate")) return;
|
||||
|
||||
// msg.args = ["!calculate", "5", "+", "3"]
|
||||
const [, a, operator, b] = msg.args;
|
||||
|
||||
let result;
|
||||
switch (operator) {
|
||||
case "+": result = Number(a) + Number(b); break;
|
||||
case "-": result = Number(a) - Number(b); break;
|
||||
case "*": result = Number(a) * Number(b); break;
|
||||
case "/": result = Number(a) / Number(b); break;
|
||||
default: return msg.reply("Invalid operator!");
|
||||
}
|
||||
|
||||
await msg.reply(`Result: ${result}`);
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: Processing media
|
||||
|
||||
```javascript
|
||||
// plugins/echo-media/index.js
|
||||
import { CMD_PREFIX } from "../../config.js";
|
||||
|
||||
export default async function ({ msg, api }) {
|
||||
if (!msg.is(CMD_PREFIX + "echo")) return;
|
||||
|
||||
// Checks if the message has media
|
||||
if (!msg.hasMedia) {
|
||||
return msg.reply("Send a media file with the command!");
|
||||
}
|
||||
|
||||
// Downloads the media
|
||||
const media = await msg.downloadMedia();
|
||||
|
||||
// Resends in the chat
|
||||
await api.sendSticker(media.data);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Object API
|
||||
|
||||
### `msg` Object
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `msg.body` | `string` | Message text |
|
||||
| `msg.args` | `string[]` | Message tokens |
|
||||
| `msg.type` | `string` | Type: `chat`, `image`, `video`, `audio`, `sticker` |
|
||||
| `msg.sender` | `string` | Sender ID |
|
||||
| `msg.senderName` | `string` | Sender name |
|
||||
| `msg.fromMe` | `boolean` | Whether the bot sent it |
|
||||
| `msg.hasMedia` | `boolean` | Whether it has media |
|
||||
| `msg.hasReply` | `boolean` | Whether it is a reply |
|
||||
| `msg.isGif` | `boolean` | Whether it is a GIF |
|
||||
| `msg.is(cmd)` | `function` | Checks if starts with command |
|
||||
| `msg.reply(text)` | `function` | Replies with quote |
|
||||
| `msg.downloadMedia()` | `function` | Returns `{ mimetype, data }` |
|
||||
| `msg.getReply()` | `function` | Returns quoted message |
|
||||
|
||||
### `api` Object
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `api.send(text)` | Sends text |
|
||||
| `api.sendVideo(path)` | Sends video |
|
||||
| `api.sendAudio(path)` | Sends audio (voice) |
|
||||
| `api.sendImage(path, caption?)` | Sends image |
|
||||
| `api.sendSticker(bufferOrPath)` | Sends sticker |
|
||||
| `api.getPlugin(name)` | Accesses another plugin |
|
||||
| `api.chat.id` | Chat ID |
|
||||
| `api.chat.name` | Chat name |
|
||||
| `api.chat.isGroup` | Whether it is a group |
|
||||
| `api.log.info(...)` | Info log |
|
||||
| `api.log.warn(...)` | Warning log |
|
||||
| `api.log.error(...)` | Error log |
|
||||
|
||||
---
|
||||
|
||||
## Exposing API to Other Plugins
|
||||
|
||||
A plugin can export functions for others to use:
|
||||
|
||||
```javascript
|
||||
// plugins/utilities/index.js
|
||||
|
||||
// Public API
|
||||
export const api = {
|
||||
formatDate: (date) => date.toLocaleDateString("en-US"),
|
||||
formatCurrency: (value) => `$${value.toFixed(2)}`,
|
||||
wait: (ms) => new Promise(resolve => setTimeout(resolve, ms))
|
||||
};
|
||||
|
||||
// Normal plugin logic
|
||||
export default async function ({ msg }) {
|
||||
if (msg.is("!ping")) {
|
||||
await msg.reply("pong!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Another plugin using it:
|
||||
|
||||
```javascript
|
||||
// plugins/other/index.js
|
||||
export default async function ({ msg, api }) {
|
||||
const utils = api.getPlugin("utilities");
|
||||
|
||||
const date = utils.formatDate(new Date());
|
||||
await msg.reply(`Today is ${date}`);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Translating Your Plugin
|
||||
|
||||
Each plugin can have its own translations, completely independent from the bot core. The bot locale (set in `manybot.conf`) is used automatically.
|
||||
|
||||
### Structure
|
||||
|
||||
```
|
||||
src/plugins/
|
||||
└── my-plugin/
|
||||
├── index.js
|
||||
└── locale/
|
||||
├── en.json
|
||||
├── pt.json
|
||||
└── es.json
|
||||
```
|
||||
|
||||
### locale/en.json
|
||||
|
||||
```json
|
||||
{
|
||||
"hello": "Hello, {{name}}! 👋",
|
||||
"error": {
|
||||
"notFound": "Item not found."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### index.js
|
||||
|
||||
```javascript
|
||||
import { CMD_PREFIX } from "../../config.js";
|
||||
import { createPluginI18n } from "../../utils/pluginI18n.js";
|
||||
|
||||
const { t } = createPluginI18n(import.meta.url);
|
||||
|
||||
export default async function ({ msg }) {
|
||||
if (!msg.is(CMD_PREFIX + "hi")) return;
|
||||
|
||||
// Simple key
|
||||
await msg.reply(t("hello", { name: msg.senderName }));
|
||||
|
||||
// Nested key
|
||||
await msg.reply(t("error.notFound"));
|
||||
}
|
||||
```
|
||||
|
||||
### Notes
|
||||
|
||||
- If the configured locale has no translation file, falls back to `en.json`.
|
||||
- If the key doesn't exist in any file, the key itself is returned as-is.
|
||||
- Use `{{variable}}` syntax for interpolation.
|
||||
- Each plugin manages its own translations — never import `t` from the bot core.
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
If a plugin throws an error, the kernel automatically disables it:
|
||||
|
||||
```javascript
|
||||
export default async function ({ msg, api }) {
|
||||
try {
|
||||
// Code that might fail
|
||||
const result = await somethingRisky();
|
||||
await msg.reply(result);
|
||||
} catch (error) {
|
||||
// Logs the error and notifies
|
||||
api.log.error("Plugin error:", error);
|
||||
await msg.reply("Oops! Something went wrong.");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Enabling the Plugin
|
||||
|
||||
After creating it, add to `manybot.conf`:
|
||||
|
||||
```bash
|
||||
PLUGINS=[
|
||||
# ... other plugins
|
||||
my-plugin
|
||||
]
|
||||
```
|
||||
|
||||
Restart the bot to load it.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [API Reference](./API.md)
|
||||
- [Plugin examples](../src/plugins/)
|
||||
Reference in New Issue
Block a user