grammy-broadcast 2.0.2
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/LICENSE +21 -0
- package/Readme.md +603 -0
- package/dist/index.d.mts +180 -0
- package/dist/index.d.ts +180 -0
- package/dist/index.js +884 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +884 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Smaznet
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Readme.md
ADDED
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
# 📢 Grammy Broadcast Plugin
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
**A powerful and professional plugin for broadcasting messages to all Telegram bot chats**
|
|
6
|
+
|
|
7
|
+
[](https://www.typescriptlang.org/)
|
|
8
|
+
[](https://grammy.dev/)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ✨ Key Features
|
|
16
|
+
|
|
17
|
+
### 🚀 Performance & Speed
|
|
18
|
+
- ⚡ **Smart Rate Limiting**: Automatic Telegram rate limit management with auto-throttling on errors
|
|
19
|
+
- 🔥 **Paid Broadcast Support**: Support for paid broadcasts at 1000 messages per second (requires Telegram Stars)
|
|
20
|
+
- 📊 **Concurrent Sending**: Send messages concurrently with queue management
|
|
21
|
+
- 🎯 **Queue Management**: Broadcast queue management with pause/resume/stop capabilities
|
|
22
|
+
|
|
23
|
+
### 💾 Flexible Storage
|
|
24
|
+
- 🔴 **Redis Storage**: For production environments and clusters
|
|
25
|
+
- 💻 **Memory Storage**: For development and testing
|
|
26
|
+
- 📁 **File Storage**: For local storage without Redis
|
|
27
|
+
|
|
28
|
+
### 🎮 Full Control
|
|
29
|
+
- ⏸️ **Pause/Resume**: Pause and resume sending at any time
|
|
30
|
+
- 🛑 **Stop**: Complete stop and removal of broadcast
|
|
31
|
+
- 📈 **Progress Tracking**: Track progress with percentage, sent count, and errors
|
|
32
|
+
- 🔍 **Preview**: Preview messages before sending
|
|
33
|
+
- 📌 **Pin Support**: Ability to pin messages after sending
|
|
34
|
+
|
|
35
|
+
### 🎨 Send Types
|
|
36
|
+
- 📋 **Copy Messages**: Copy messages while preserving content
|
|
37
|
+
- ➡️ **Forward Messages**: Forward messages
|
|
38
|
+
- ✍️ **Text Messages**: Send plain text
|
|
39
|
+
- 📦 **Multi-Message**: Support for sending multiple messages in one broadcast
|
|
40
|
+
|
|
41
|
+
### 🔐 Security & Access Control
|
|
42
|
+
- 👥 **Sudo Users**: Define authorized users
|
|
43
|
+
- 🔒 **Custom Permission**: Custom permission system
|
|
44
|
+
- 🚫 **Auto Block Management**: Automatic management of blocked users
|
|
45
|
+
|
|
46
|
+
### 🌐 Cluster Support
|
|
47
|
+
- 🔄 **Multi-Instance**: Support for multiple instances
|
|
48
|
+
- 🎯 **Main Instance**: Designate main instance for queue processing
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 📦 Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npm install grammy-broadcast
|
|
56
|
+
# or
|
|
57
|
+
yarn add grammy-broadcast
|
|
58
|
+
# or
|
|
59
|
+
pnpm add grammy-broadcast
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Requirements
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
npm install grammy ioredis
|
|
66
|
+
# or
|
|
67
|
+
yarn add grammy ioredis
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 🚀 Quick Start
|
|
73
|
+
|
|
74
|
+
### Basic Example with Redis
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { Bot } from "grammy";
|
|
78
|
+
import { createBroadcaster, RedisStorage } from "grammy-broadcast";
|
|
79
|
+
import Redis from "ioredis";
|
|
80
|
+
|
|
81
|
+
const bot = new Bot("YOUR_BOT_TOKEN");
|
|
82
|
+
const redis = new Redis();
|
|
83
|
+
|
|
84
|
+
const broadcaster = createBroadcaster({
|
|
85
|
+
storage: new RedisStorage(redis),
|
|
86
|
+
isMainInstance: true, // For clusters, set true only on the main instance
|
|
87
|
+
sudoUsers: [123456789], // Authorized user IDs
|
|
88
|
+
getApi: async (botId) => bot.api, // or bot.api for single bot
|
|
89
|
+
getBroadcastChats: async (botId, offset, limit, filter) => {
|
|
90
|
+
// You can use any database here
|
|
91
|
+
// Example with MongoDB:
|
|
92
|
+
const users = await UserModel.find({ blocked: { $ne: true } })
|
|
93
|
+
.skip(offset)
|
|
94
|
+
.limit(limit)
|
|
95
|
+
.select("uid")
|
|
96
|
+
.lean();
|
|
97
|
+
return users.map(u => u.uid);
|
|
98
|
+
},
|
|
99
|
+
setRestricted: async (botId, chatId, type) => {
|
|
100
|
+
// Manage blocked users
|
|
101
|
+
if (type === 'block' || type === 'deactivated') {
|
|
102
|
+
await UserModel.updateOne({ uid: chatId }, { blocked: true });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Add middleware to bot
|
|
108
|
+
bot.use(broadcaster.getMiddleware());
|
|
109
|
+
|
|
110
|
+
bot.start();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Example with Memory Storage (for testing)
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { Bot } from "grammy";
|
|
117
|
+
import { createBroadcaster, MemoryStorage } from "grammy-broadcast";
|
|
118
|
+
|
|
119
|
+
const bot = new Bot("YOUR_BOT_TOKEN");
|
|
120
|
+
|
|
121
|
+
const broadcaster = createBroadcaster({
|
|
122
|
+
storage: new MemoryStorage(),
|
|
123
|
+
isMainInstance: true,
|
|
124
|
+
sudoUsers: [123456789],
|
|
125
|
+
getApi: async () => bot.api,
|
|
126
|
+
getBroadcastChats: async (botId, offset, limit, filter) => {
|
|
127
|
+
// Test chat list
|
|
128
|
+
return [123456, 789012, 345678];
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
bot.use(broadcaster.getMiddleware());
|
|
133
|
+
bot.start();
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Example with File Storage
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { Bot } from "grammy";
|
|
140
|
+
import { createBroadcaster, FileStorage } from "grammy-broadcast";
|
|
141
|
+
|
|
142
|
+
const bot = new Bot("YOUR_BOT_TOKEN");
|
|
143
|
+
|
|
144
|
+
const broadcaster = createBroadcaster({
|
|
145
|
+
storage: new FileStorage("./broadcast-data"), // Storage path
|
|
146
|
+
isMainInstance: true,
|
|
147
|
+
sudoUsers: [123456789],
|
|
148
|
+
getApi: async () => bot.api,
|
|
149
|
+
getBroadcastChats: async (botId, offset, limit, filter) => {
|
|
150
|
+
// Chat retrieval logic
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
bot.use(broadcaster.getMiddleware());
|
|
156
|
+
bot.start();
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 📖 Usage Guide
|
|
162
|
+
|
|
163
|
+
### Available Commands
|
|
164
|
+
|
|
165
|
+
#### 1️⃣ `/broadcast <type> [filter]`
|
|
166
|
+
Send broadcast with specified type
|
|
167
|
+
|
|
168
|
+
**Parameters:**
|
|
169
|
+
- `type`: Send type (`copy` or `forward`)
|
|
170
|
+
- `filter`: Optional filter for selecting chats (passed to `getBroadcastChats`)
|
|
171
|
+
|
|
172
|
+
**Examples:**
|
|
173
|
+
```
|
|
174
|
+
/broadcast copy users
|
|
175
|
+
/broadcast forward groups
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
#### 2️⃣ `/copy [filter]`
|
|
179
|
+
Shortcut for `/broadcast copy`
|
|
180
|
+
|
|
181
|
+
**Examples:**
|
|
182
|
+
```
|
|
183
|
+
/copy users
|
|
184
|
+
/copy
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### 3️⃣ `/forward [filter]`
|
|
188
|
+
Shortcut for `/broadcast forward`
|
|
189
|
+
|
|
190
|
+
**Examples:**
|
|
191
|
+
```
|
|
192
|
+
/forward groups
|
|
193
|
+
/forward
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### 4️⃣ `/addmsg <broadcast_id>`
|
|
197
|
+
Add message to existing broadcast
|
|
198
|
+
|
|
199
|
+
**Example:**
|
|
200
|
+
```
|
|
201
|
+
/addmsg abc123
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Usage Steps
|
|
205
|
+
|
|
206
|
+
1. **Create Broadcast:**
|
|
207
|
+
- Reply to the message you want to broadcast
|
|
208
|
+
- Send `/copy` or `/forward` command
|
|
209
|
+
- You'll receive a broadcast ID
|
|
210
|
+
|
|
211
|
+
2. **Add More Messages (Optional):**
|
|
212
|
+
- Reply to another message
|
|
213
|
+
- Send `/addmsg <broadcast_id>` command
|
|
214
|
+
|
|
215
|
+
3. **Settings (Optional):**
|
|
216
|
+
- **Preview** button for preview
|
|
217
|
+
- **Pin** button to pin messages after sending
|
|
218
|
+
|
|
219
|
+
4. **Start Sending:**
|
|
220
|
+
- Click **Start** button
|
|
221
|
+
- Sending progress is displayed in real-time
|
|
222
|
+
|
|
223
|
+
5. **Control Sending:**
|
|
224
|
+
- **Pause**: Temporary pause
|
|
225
|
+
- **Resume**: Resume sending
|
|
226
|
+
- **Stop**: Complete stop
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## ⚙️ Advanced Configuration
|
|
231
|
+
|
|
232
|
+
### BroadcastOptions
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
interface BroadcastOptions {
|
|
236
|
+
// Storage instance (required)
|
|
237
|
+
storage: Storage;
|
|
238
|
+
|
|
239
|
+
// Function to get chats (required)
|
|
240
|
+
getBroadcastChats: (botId: number, offset: number, limit: number, filter?: string) => Promise<string[] | number[]>;
|
|
241
|
+
|
|
242
|
+
// API instance (required)
|
|
243
|
+
getApi: (botId: number) => Promise<Api> | Api;
|
|
244
|
+
|
|
245
|
+
// Designate main instance (required)
|
|
246
|
+
isMainInstance: boolean;
|
|
247
|
+
|
|
248
|
+
// List of authorized users
|
|
249
|
+
sudoUsers?: number[];
|
|
250
|
+
|
|
251
|
+
// Custom permission check function
|
|
252
|
+
hasPermission?: (ctx: Context) => boolean | Promise<boolean>;
|
|
253
|
+
|
|
254
|
+
// Manage blocked users
|
|
255
|
+
setRestricted?: (botId: number, chatId: string, type: 'block' | 'deactivated' | 'banned' | 'restricted') => Promise<void>;
|
|
256
|
+
|
|
257
|
+
// Number of chats processed per chunk (default: 100)
|
|
258
|
+
chunkSize?: number;
|
|
259
|
+
|
|
260
|
+
// Redis key prefix (default: 'brdc:')
|
|
261
|
+
keyPrefix?: string;
|
|
262
|
+
|
|
263
|
+
// Progress report frequency in milliseconds (default: 60000)
|
|
264
|
+
reportFrequency?: number;
|
|
265
|
+
|
|
266
|
+
// Queue check interval in milliseconds (default: 60000)
|
|
267
|
+
checkQueueInterval?: number;
|
|
268
|
+
|
|
269
|
+
// Progress callback function (optional)
|
|
270
|
+
progressCallback?: (id: string, sent: number, error: number, total: number) => void;
|
|
271
|
+
|
|
272
|
+
// Enable Paid Broadcast (default: false)
|
|
273
|
+
allowPaidBroadcast?: boolean;
|
|
274
|
+
|
|
275
|
+
// Customize command names
|
|
276
|
+
cmds?: {
|
|
277
|
+
broadcast?: string; // default: 'broadcast'
|
|
278
|
+
copy?: string; // default: 'copy'
|
|
279
|
+
forward?: string; // default: 'forward'
|
|
280
|
+
addmsg?: string; // default: 'addmsg'
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Complete Example with All Settings
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { Bot, Context } from "grammy";
|
|
289
|
+
import { createBroadcaster, RedisStorage } from "grammy-broadcast";
|
|
290
|
+
import Redis from "ioredis";
|
|
291
|
+
|
|
292
|
+
const bot = new Bot("YOUR_BOT_TOKEN");
|
|
293
|
+
const redis = new Redis();
|
|
294
|
+
|
|
295
|
+
const broadcaster = createBroadcaster({
|
|
296
|
+
// Storage
|
|
297
|
+
storage: new RedisStorage(redis),
|
|
298
|
+
|
|
299
|
+
// Get chats with filter
|
|
300
|
+
getBroadcastChats: async (botId, offset, limit, filter) => {
|
|
301
|
+
if (filter === 'users') {
|
|
302
|
+
const users = await UserModel.find({ blocked: { $ne: true } })
|
|
303
|
+
.skip(offset)
|
|
304
|
+
.limit(limit)
|
|
305
|
+
.select("uid")
|
|
306
|
+
.lean();
|
|
307
|
+
return users.map(u => u.uid);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (filter === 'groups') {
|
|
311
|
+
const groups = await GroupModel.find({ botRemoved: { $ne: true } })
|
|
312
|
+
.skip(offset)
|
|
313
|
+
.limit(limit)
|
|
314
|
+
.select("chatId")
|
|
315
|
+
.lean();
|
|
316
|
+
return groups.map(g => g.chatId);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (filter === 'premium') {
|
|
320
|
+
const premiumUsers = await UserModel.find({
|
|
321
|
+
premium: true,
|
|
322
|
+
blocked: { $ne: true }
|
|
323
|
+
})
|
|
324
|
+
.skip(offset)
|
|
325
|
+
.limit(limit)
|
|
326
|
+
.select("uid")
|
|
327
|
+
.lean();
|
|
328
|
+
return premiumUsers.map(u => u.uid);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// No filter - all chats
|
|
332
|
+
const allChats = await ChatModel.find({})
|
|
333
|
+
.skip(offset)
|
|
334
|
+
.limit(limit)
|
|
335
|
+
.select("chatId")
|
|
336
|
+
.lean();
|
|
337
|
+
return allChats.map(c => c.chatId);
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
// Manage blocked users
|
|
341
|
+
setRestricted: async (botId, chatId, type) => {
|
|
342
|
+
if (type === 'block' || type === 'deactivated') {
|
|
343
|
+
await UserModel.updateOne(
|
|
344
|
+
{ uid: chatId },
|
|
345
|
+
{ blocked: true, blockedAt: new Date() }
|
|
346
|
+
);
|
|
347
|
+
} else if (type === 'banned' || type === 'restricted') {
|
|
348
|
+
await GroupModel.updateOne(
|
|
349
|
+
{ chatId },
|
|
350
|
+
{ botRemoved: true, removedAt: new Date() }
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
// API instance
|
|
356
|
+
getApi: async (botId) => bot.api,
|
|
357
|
+
|
|
358
|
+
// Settings
|
|
359
|
+
isMainInstance: true,
|
|
360
|
+
sudoUsers: [123456789, 987654321],
|
|
361
|
+
|
|
362
|
+
// Or use custom function for permissions
|
|
363
|
+
// hasPermission: async (ctx: Context) => {
|
|
364
|
+
// const user = await UserModel.findOne({ uid: ctx.from?.id });
|
|
365
|
+
// return user?.isAdmin === true;
|
|
366
|
+
// },
|
|
367
|
+
|
|
368
|
+
// Advanced settings
|
|
369
|
+
chunkSize: 50, // Process 50 chats per batch
|
|
370
|
+
keyPrefix: 'mybot:brdc:', // Custom prefix
|
|
371
|
+
reportFrequency: 30000, // Report every 30 seconds
|
|
372
|
+
checkQueueInterval: 10000, // Check queue every 10 seconds
|
|
373
|
+
allowPaidBroadcast: true, // Enable paid broadcast
|
|
374
|
+
|
|
375
|
+
// Progress callback
|
|
376
|
+
progressCallback: (id, sent, error, total) => {
|
|
377
|
+
console.log(`Broadcast ${id}: ${sent}/${total} sent, ${error} errors`);
|
|
378
|
+
},
|
|
379
|
+
|
|
380
|
+
// Customize commands
|
|
381
|
+
cmds: {
|
|
382
|
+
broadcast: 'bbroadcast',
|
|
383
|
+
copy: 'bcopy',
|
|
384
|
+
forward: 'bforward',
|
|
385
|
+
addmsg: 'baddmsg'
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
bot.use(broadcaster.getMiddleware());
|
|
390
|
+
bot.start();
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## 🎯 Practical Examples
|
|
396
|
+
|
|
397
|
+
### Example 1: Broadcast to Specific Users
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
// Send to premium users
|
|
401
|
+
/broadcast copy premium
|
|
402
|
+
|
|
403
|
+
// Send to active groups
|
|
404
|
+
/broadcast forward active_groups
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Example 2: Using in Cluster
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
// Main instance
|
|
411
|
+
const broadcaster = createBroadcaster({
|
|
412
|
+
// ...
|
|
413
|
+
isMainInstance: true, // Only in this instance
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
// Other instances
|
|
417
|
+
const broadcaster = createBroadcaster({
|
|
418
|
+
// ...
|
|
419
|
+
isMainInstance: false, // In other instances
|
|
420
|
+
});
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Example 3: Error Management
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
const broadcaster = createBroadcaster({
|
|
427
|
+
// ...
|
|
428
|
+
setRestricted: async (botId, chatId, type) => {
|
|
429
|
+
console.log(`Chat ${chatId} restricted: ${type}`);
|
|
430
|
+
|
|
431
|
+
// Save to log
|
|
432
|
+
await LogModel.create({
|
|
433
|
+
chatId,
|
|
434
|
+
type,
|
|
435
|
+
timestamp: new Date()
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
// Update database
|
|
439
|
+
if (type === 'block') {
|
|
440
|
+
await UserModel.updateOne(
|
|
441
|
+
{ uid: chatId },
|
|
442
|
+
{ blocked: true, blockedReason: 'user_blocked_bot' }
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
### Example 4: Using Progress Callback
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
const broadcaster = createBroadcaster({
|
|
453
|
+
// ...
|
|
454
|
+
progressCallback: async (id, sent, error, total) => {
|
|
455
|
+
// Send report to admin
|
|
456
|
+
const progress = ((sent + error) / total * 100).toFixed(2);
|
|
457
|
+
await bot.api.sendMessage(
|
|
458
|
+
ADMIN_CHAT_ID,
|
|
459
|
+
`📊 Broadcast ${id}\n` +
|
|
460
|
+
`✅ Sent: ${sent}\n` +
|
|
461
|
+
`❌ Errors: ${error}\n` +
|
|
462
|
+
`📈 Progress: ${progress}%`
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
---
|
|
469
|
+
|
|
470
|
+
## 🔧 Storage Implementations
|
|
471
|
+
|
|
472
|
+
### RedisStorage
|
|
473
|
+
|
|
474
|
+
For use in production and cluster environments:
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
import { RedisStorage } from "grammy-broadcast";
|
|
478
|
+
import Redis from "ioredis";
|
|
479
|
+
|
|
480
|
+
const redis = new Redis({
|
|
481
|
+
host: 'localhost',
|
|
482
|
+
port: 6379,
|
|
483
|
+
// or connection string
|
|
484
|
+
// host: 'redis://localhost:6379'
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
const storage = new RedisStorage(redis);
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### MemoryStorage
|
|
491
|
+
|
|
492
|
+
For development and testing (data stored in memory):
|
|
493
|
+
|
|
494
|
+
```typescript
|
|
495
|
+
import { MemoryStorage } from "grammy-broadcast";
|
|
496
|
+
|
|
497
|
+
const storage = new MemoryStorage();
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### FileStorage
|
|
501
|
+
|
|
502
|
+
For local storage without Redis:
|
|
503
|
+
|
|
504
|
+
```typescript
|
|
505
|
+
import { FileStorage } from "grammy-broadcast";
|
|
506
|
+
|
|
507
|
+
const storage = new FileStorage("./broadcast-storage");
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
## 📊 Progress Display
|
|
513
|
+
|
|
514
|
+
The plugin automatically displays broadcast progress:
|
|
515
|
+
|
|
516
|
+
```
|
|
517
|
+
⌛ Broadcasting
|
|
518
|
+
████████░░ (80%)
|
|
519
|
+
⌛ Progress: 800/1000
|
|
520
|
+
✅ Sent: 750
|
|
521
|
+
❌ Error: 50 (5%)
|
|
522
|
+
⚡ Rate: 30 msg/sec
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
Control buttons:
|
|
526
|
+
- **Progress Bar**: Show progress details
|
|
527
|
+
- **Pause**: Temporary pause
|
|
528
|
+
- **Stop**: Complete stop
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## 🛡️ Error Management
|
|
533
|
+
|
|
534
|
+
The plugin automatically handles the following errors:
|
|
535
|
+
|
|
536
|
+
- ✅ **Blocked Users**: Blocked users
|
|
537
|
+
- ✅ **Deactivated Accounts**: Deactivated accounts
|
|
538
|
+
- ✅ **Kicked from Groups**: Kicked from groups
|
|
539
|
+
- ✅ **Restricted**: Access restrictions
|
|
540
|
+
- ✅ **Rate Limiting**: Automatic Telegram rate limit management
|
|
541
|
+
|
|
542
|
+
Errors are automatically handled in the `setRestricted` callback.
|
|
543
|
+
|
|
544
|
+
---
|
|
545
|
+
|
|
546
|
+
## 🚀 Paid Broadcast
|
|
547
|
+
|
|
548
|
+
To use Paid Broadcast feature (sending at 1000 messages/second):
|
|
549
|
+
|
|
550
|
+
```typescript
|
|
551
|
+
const broadcaster = createBroadcaster({
|
|
552
|
+
// ...
|
|
553
|
+
allowPaidBroadcast: true, // Requires Telegram Stars
|
|
554
|
+
});
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**Note:** This feature requires Telegram Stars and is paid.
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## 📝 Important Notes
|
|
562
|
+
|
|
563
|
+
1. **Main Instance**: In cluster environments, only one instance should have `isMainInstance: true`
|
|
564
|
+
2. **Storage**: Always use Redis for production
|
|
565
|
+
3. **Rate Limiting**: The plugin automatically manages rate limiting
|
|
566
|
+
4. **Error Handling**: Always implement `setRestricted`
|
|
567
|
+
5. **Database**: You can use any database for `getBroadcastChats`
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## 🤝 Contributing
|
|
572
|
+
|
|
573
|
+
Contributions are always welcome! Please make sure before submitting a PR that:
|
|
574
|
+
|
|
575
|
+
- ✅ Your code follows the project standards
|
|
576
|
+
- ✅ You've added necessary tests
|
|
577
|
+
- ✅ You've updated the documentation
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
## 📄 License
|
|
582
|
+
|
|
583
|
+
This project is licensed under the [MIT](LICENSE) License.
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
## 👤 Author
|
|
588
|
+
|
|
589
|
+
**Aria** - [smaznet98@gmail.com](mailto:smaznet98@gmail.com)
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
## ⭐ Stars
|
|
594
|
+
|
|
595
|
+
If this project was useful to you, please give it a star ⭐!
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
<div align="center">
|
|
600
|
+
|
|
601
|
+
**Made with ❤️ for the Grammy community**
|
|
602
|
+
|
|
603
|
+
</div>
|