discord-voice-tracker 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 ADDED
@@ -0,0 +1,662 @@
1
+ # Discord Voice Tracker
2
+
3
+ > 🎙️ A modern, production-ready voice activity tracking system for Discord bots with XP, leveling, and comprehensive statistics.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/discord-voice-tracker?style=flat-square)](https://www.npmjs.com/package/discord-voice-tracker)
6
+ [![npm downloads](https://img.shields.io/npm/dt/discord-voice-tracker?style=flat-square)](https://www.npmjs.com/package/discord-voice-tracker)
7
+ [![License](https://img.shields.io/npm/l/discord-voice-tracker?style=flat-square)](LICENSE)
8
+ [![Node Version](https://img.shields.io/node/v/discord-voice-tracker?style=flat-square)](https://nodejs.org)
9
+
10
+ ---
11
+
12
+ ## ✨ Features
13
+
14
+ - 🎯 **Voice Time Tracking** - Track total and per-channel voice activity
15
+ - 💫 **XP & Leveling System** - Automatic XP gain and level progression
16
+ - 📊 **Statistics & Analytics** - Detailed user stats and session history
17
+ - 🏆 **Leaderboards** - Rank users by voice time, XP, or level
18
+ - ⚙️ **Highly Configurable** - Customize tracking behavior per guild
19
+ - 💾 **Multiple Storage Options** - JSON (built-in) and MongoDB support
20
+ - 🔒 **TypeScript Support** - Full type definitions included
21
+ - 🚀 **Production Ready** - Optimized performance with caching
22
+ - 📦 **Easy Integration** - Simple setup with sensible defaults
23
+
24
+ ---
25
+
26
+ ## 📋 Table of Contents
27
+
28
+ - [Installation](#-installation)
29
+ - [Quick Start](#-quick-start)
30
+ - [Slash Commands](#-slash-commands)
31
+ - [Configuration](#-configuration)
32
+ - [Events](#-events)
33
+ - [API Reference](#-api-reference)
34
+ - [Storage Options](#-storage-options)
35
+ - [Examples](#-examples)
36
+ - [Troubleshooting](#-troubleshooting)
37
+
38
+ ---
39
+
40
+ ## 📦 Installation
41
+
42
+ ### Prerequisites
43
+
44
+ Before installing, make sure you have:
45
+ - **Node.js 18.0.0 or higher** - [Download here](https://nodejs.org/)
46
+ - **A Discord Bot** - [Create one here](https://discord.com/developers/applications)
47
+
48
+ ### Step 1: Install the Package
49
+
50
+ ```bash
51
+ npm install discord-voice-tracker discord.js
52
+ ```
53
+
54
+ **What this does:**
55
+ - Installs `discord-voice-tracker` (this package)
56
+ - Installs `discord.js` (required peer dependency)
57
+
58
+ ### Step 2: (Optional) Install MongoDB
59
+
60
+ If you want to use MongoDB instead of JSON storage:
61
+
62
+ ```bash
63
+ npm install mongodb
64
+ ```
65
+
66
+ **When to use MongoDB:**
67
+ - ✅ Large servers (1000+ members)
68
+ - ✅ Multiple guilds
69
+ - ✅ Production environments
70
+ - ❌ Small bots or testing (use JSON instead)
71
+
72
+ ---
73
+
74
+ ## 🚀 Quick Start
75
+
76
+ ### Basic Setup (5 minutes)
77
+
78
+ Create a file called `bot.js`:
79
+
80
+ ```javascript
81
+ // Import required modules
82
+ const { Client, GatewayIntentBits } = require('discord.js');
83
+ const { VoiceManager, JSONStorage } = require('discord-voice-tracker');
84
+
85
+ // Create Discord client with required intents
86
+ const client = new Client({
87
+ intents: [
88
+ GatewayIntentBits.Guilds, // Required: Access to guilds
89
+ GatewayIntentBits.GuildVoiceStates, // Required: Voice state updates
90
+ ],
91
+ });
92
+
93
+ // Create storage (saves data to ./data folder)
94
+ const storage = new JSONStorage('./data');
95
+
96
+ // Create voice manager
97
+ const voiceManager = new VoiceManager(client, {
98
+ storage, // Where to save data
99
+ checkInterval: 5000, // Check voice activity every 5 seconds
100
+ debug: true, // Enable debug logs (disable in production)
101
+ defaultConfig: {
102
+ trackBots: false, // Don't track bot users
103
+ trackAllChannels: true, // Track all voice channels
104
+ xpPerCheck: 5, // Give 5 XP every 5 seconds in voice
105
+ },
106
+ });
107
+
108
+ // Listen for level ups
109
+ voiceManager.on('levelUp', (userData, oldLevel, newLevel) => {
110
+ console.log(`🎉 User ${userData.userId} leveled up to ${newLevel}!`);
111
+ });
112
+
113
+ // Initialize when bot is ready
114
+ client.once('ready', async () => {
115
+ console.log(`✅ Logged in as ${client.user.tag}`);
116
+
117
+ // Initialize voice manager
118
+ await voiceManager.init();
119
+ console.log('✅ Voice tracking active!');
120
+ });
121
+
122
+ // Login with your bot token
123
+ client.login('YOUR_BOT_TOKEN_HERE');
124
+ ```
125
+
126
+ ### Run Your Bot
127
+
128
+ ```bash
129
+ node bot.js
130
+ ```
131
+
132
+ **You should see:**
133
+ ```
134
+ ✅ Logged in as YourBot#1234
135
+ [VoiceTracker DEBUG] Initializing VoiceManager...
136
+ [VoiceTracker DEBUG] Storage initialized
137
+ [VoiceTracker DEBUG] Tracking started with 5000ms interval
138
+ ✅ Voice tracking active!
139
+ ```
140
+
141
+ ### Test It
142
+
143
+ 1. **Join a voice channel** in your Discord server
144
+ 2. **Wait 5-10 seconds**
145
+ 3. **Check the console** - you should see tracking activity
146
+ 4. **Leave the voice channel**
147
+ 5. **Check `data/guilds.json`** - you'll see your data saved!
148
+
149
+ ---
150
+
151
+ ## 💬 Slash Commands
152
+
153
+ Want users to check their stats? Add these commands to your bot!
154
+
155
+ ### Example: `/stats` Command
156
+
157
+ ```javascript
158
+ const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
159
+ const { XPCalculator } = require('discord-voice-tracker');
160
+
161
+ const calculator = new XPCalculator();
162
+
163
+ // Register the command
164
+ const statsCommand = new SlashCommandBuilder()
165
+ .setName('stats')
166
+ .setDescription('View your voice activity statistics')
167
+ .addUserOption(option =>
168
+ option
169
+ .setName('user')
170
+ .setDescription('User to check (optional)')
171
+ .setRequired(false)
172
+ );
173
+
174
+ // Handle the command
175
+ client.on('interactionCreate', async (interaction) => {
176
+ if (!interaction.isChatInputCommand()) return;
177
+ if (interaction.commandName !== 'stats') return;
178
+
179
+ const targetUser = interaction.options.getUser('user') || interaction.user;
180
+ const userData = await voiceManager.getUser(interaction.guildId, targetUser.id);
181
+
182
+ if (!userData) {
183
+ return interaction.reply({
184
+ content: `${targetUser.username} has no voice activity yet!`,
185
+ ephemeral: true,
186
+ });
187
+ }
188
+
189
+ const embed = new EmbedBuilder()
190
+ .setColor('#5865F2')
191
+ .setTitle(`📊 Voice Stats for ${targetUser.username}`)
192
+ .addFields(
193
+ { name: '⏱️ Total Voice Time', value: calculator.formatVoiceTime(userData.totalVoiceTime), inline: true },
194
+ { name: '⭐ Level', value: `${userData.level}`, inline: true },
195
+ { name: '💫 XP', value: `${userData.xp}`, inline: true }
196
+ );
197
+
198
+ await interaction.reply({ embeds: [embed] });
199
+ });
200
+
201
+ // Register commands when bot is ready
202
+ client.once('ready', async () => {
203
+ await client.application.commands.create(statsCommand);
204
+ console.log('✅ Slash commands registered!');
205
+ });
206
+ ```
207
+
208
+ ### Available Commands
209
+
210
+ | Command | Description | Example |
211
+ |---------|-------------|---------|
212
+ | `/stats [@user]` | View voice statistics | `/stats @John` |
213
+ | `/leaderboard [type]` | View server leaderboard | `/leaderboard xp` |
214
+ | `/rank [@user]` | Check server rank | `/rank` |
215
+ | `/sessions [@user]` | View recent sessions | `/sessions @John` |
216
+
217
+ **📖 See [examples/bot.js](examples/bot.js) for complete command implementations!**
218
+
219
+ ---
220
+
221
+ ## ⚙️ Configuration
222
+
223
+ ### Manager Options
224
+
225
+ ```javascript
226
+ const voiceManager = new VoiceManager(client, {
227
+ // Required
228
+ storage: storage, // Storage adapter (JSONStorage or MongoStorage)
229
+
230
+ // Optional
231
+ checkInterval: 5000, // How often to check (milliseconds)
232
+ debug: false, // Enable debug logging
233
+
234
+ defaultConfig: {
235
+ // Tracking options
236
+ trackBots: false, // Track bot users
237
+ trackAllChannels: true, // Track all voice channels
238
+ trackMuted: true, // Track muted users
239
+ trackDeafened: true, // Track deafened users
240
+
241
+ // Channel filters
242
+ channelIds: [], // Specific channels to track (if trackAllChannels: false)
243
+ minUsersToTrack: 0, // Minimum users in channel to track (0 = no limit)
244
+ maxUsersToTrack: 0, // Maximum users in channel to track (0 = no limit)
245
+
246
+ // Permission filters
247
+ exemptPermissions: [], // Users with these permissions won't be tracked
248
+
249
+ // XP & Leveling
250
+ xpPerCheck: 5, // XP to award per check interval
251
+ voiceTimePerCheck: 5000, // Voice time to add per check (milliseconds)
252
+ levelMultiplier: 0.1, // Level calculation multiplier
253
+ enableLeveling: true, // Enable XP/leveling system
254
+ enableVoiceTime: true, // Enable voice time tracking
255
+ },
256
+ });
257
+ ```
258
+
259
+ ### Per-Guild Configuration
260
+
261
+ Change settings for specific servers:
262
+
263
+ ```javascript
264
+ // Get current config
265
+ const config = await voiceManager.getGuildConfig(guildId);
266
+
267
+ // Modify settings
268
+ config.trackBots = true; // Now track bots
269
+ config.xpPerCheck = 10; // Give more XP
270
+ config.channelIds = ['123456789']; // Only track specific channel
271
+
272
+ // Save changes
273
+ await voiceManager.saveGuildConfig(guildId, config);
274
+ ```
275
+
276
+ ### Advanced Filtering
277
+
278
+ ```javascript
279
+ const config = await voiceManager.getGuildConfig(guildId);
280
+
281
+ // Only track channels with "voice" in the name
282
+ config.channelFilter = (channel) => {
283
+ return channel.name.toLowerCase().includes('voice');
284
+ };
285
+
286
+ // Don't track users with "Muted" role
287
+ config.memberFilter = (member) => {
288
+ return !member.roles.cache.some(role => role.name === 'Muted');
289
+ };
290
+
291
+ await voiceManager.saveGuildConfig(guildId, config);
292
+ ```
293
+
294
+ ---
295
+
296
+ ## 🎯 Events
297
+
298
+ Listen to these events to add custom features:
299
+
300
+ ```javascript
301
+ // User gained voice time
302
+ voiceManager.on('voiceTimeGained', (userData, gained) => {
303
+ console.log(`User gained ${gained}ms of voice time`);
304
+ });
305
+
306
+ // User gained XP
307
+ voiceManager.on('xpGained', (userData, gained) => {
308
+ console.log(`User gained ${gained} XP`);
309
+ });
310
+
311
+ // User leveled up
312
+ voiceManager.on('levelUp', (userData, oldLevel, newLevel) => {
313
+ console.log(`User leveled up from ${oldLevel} to ${newLevel}!`);
314
+
315
+ // Example: Give a role when reaching level 10
316
+ if (newLevel === 10) {
317
+ const guild = client.guilds.cache.get(userData.guildId);
318
+ const member = guild.members.cache.get(userData.userId);
319
+ const role = guild.roles.cache.find(r => r.name === 'Active Chatter');
320
+ if (member && role) {
321
+ member.roles.add(role);
322
+ }
323
+ }
324
+ });
325
+
326
+ // Voice session started
327
+ voiceManager.on('sessionStart', (session) => {
328
+ console.log(`Session started for ${session.userId}`);
329
+ });
330
+
331
+ // Voice session ended
332
+ voiceManager.on('sessionEnd', (session) => {
333
+ console.log(`Session ended, duration: ${session.duration}ms`);
334
+ });
335
+
336
+ // Configuration updated
337
+ voiceManager.on('configUpdated', (guildId, config) => {
338
+ console.log(`Config updated for guild ${guildId}`);
339
+ });
340
+
341
+ // Error occurred
342
+ voiceManager.on('error', (error) => {
343
+ console.error('Voice Manager Error:', error);
344
+ });
345
+
346
+ // Debug messages (only if debug: true)
347
+ voiceManager.on('debug', (message) => {
348
+ console.log(`[DEBUG] ${message}`);
349
+ });
350
+ ```
351
+
352
+ ---
353
+
354
+ ## 📚 API Reference
355
+
356
+ ### VoiceManager
357
+
358
+ #### Methods
359
+
360
+ ```javascript
361
+ // Initialize the manager
362
+ await voiceManager.init();
363
+
364
+ // Get user data
365
+ const userData = await voiceManager.getUser(guildId, userId);
366
+ // Returns: { userId, guildId, totalVoiceTime, xp, level, channels, ... }
367
+
368
+ // Update user data
369
+ await voiceManager.updateUser(guildId, userId, {
370
+ addVoiceTime: 60000, // Add 1 minute
371
+ addXp: 100, // Add 100 XP
372
+ setLevel: 5, // Set to level 5
373
+ metadata: { ... } // Custom data
374
+ });
375
+
376
+ // Get leaderboard
377
+ const leaderboard = await voiceManager.getLeaderboard(guildId, {
378
+ sortBy: 'xp', // 'voiceTime', 'xp', or 'level'
379
+ limit: 10, // Number of users
380
+ offset: 0, // Pagination offset
381
+ });
382
+
383
+ // Get/save guild config
384
+ const config = await voiceManager.getGuildConfig(guildId);
385
+ await voiceManager.saveGuildConfig(guildId, config);
386
+
387
+ // Delete data
388
+ await voiceManager.deleteGuild(guildId);
389
+ await voiceManager.deleteUser(guildId, userId);
390
+
391
+ // Cleanup
392
+ await voiceManager.destroy();
393
+ ```
394
+
395
+ ### XPCalculator
396
+
397
+ ```javascript
398
+ const { XPCalculator } = require('discord-voice-tracker');
399
+ const calculator = new XPCalculator();
400
+
401
+ // Calculate level from XP
402
+ const level = calculator.calculateLevel(1000, 0.1);
403
+ // Returns: 10
404
+
405
+ // Calculate XP needed for level
406
+ const xpNeeded = calculator.calculateXPForLevel(10, 0.1);
407
+ // Returns: 1000
408
+
409
+ // Calculate XP to next level
410
+ const xpToNext = calculator.calculateXPToNextLevel(1500, 0.1);
411
+ // Returns: 610
412
+
413
+ // Calculate progress percentage
414
+ const progress = calculator.calculateLevelProgress(1500, 0.1);
415
+ // Returns: 22 (22%)
416
+
417
+ // Format voice time to readable string
418
+ const formatted = calculator.formatVoiceTime(3661000);
419
+ // Returns: "1h 1m 1s"
420
+
421
+ // Calculate average session duration
422
+ const avgDuration = calculator.calculateAverageSessionDuration(
423
+ totalVoiceTime,
424
+ totalSessions
425
+ );
426
+ ```
427
+
428
+ ---
429
+
430
+ ## 💾 Storage Options
431
+
432
+ ### JSON Storage (Default)
433
+
434
+ **Best for:** Small to medium bots, testing, single server
435
+
436
+ ```javascript
437
+ const { JSONStorage } = require('discord-voice-tracker');
438
+
439
+ const storage = new JSONStorage('./data');
440
+ // Creates: ./data/guilds.json and ./data/sessions.json
441
+ ```
442
+
443
+ **Pros:**
444
+ - ✅ No external dependencies
445
+ - ✅ Easy to inspect/edit files
446
+ - ✅ Simple backup (just copy the folder)
447
+
448
+ **Cons:**
449
+ - ❌ Not suitable for large scale (1000+ users)
450
+ - ❌ No concurrent write protection
451
+
452
+ ### MongoDB Storage
453
+
454
+ **Best for:** Production, large servers, multiple bots
455
+
456
+ ```javascript
457
+ const { MongoStorage } = require('discord-voice-tracker');
458
+
459
+ // Make sure to: npm install mongodb
460
+
461
+ const storage = new MongoStorage(
462
+ 'mongodb://localhost:27017', // Connection string
463
+ 'voicetracker' // Database name
464
+ );
465
+
466
+ // Or with MongoDB Atlas:
467
+ const storage = new MongoStorage(
468
+ 'mongodb+srv://user:pass@cluster.mongodb.net/',
469
+ 'voicetracker'
470
+ );
471
+ ```
472
+
473
+ **Pros:**
474
+ - ✅ Handles large datasets efficiently
475
+ - ✅ Built-in indexing for fast queries
476
+ - ✅ Concurrent write support
477
+ - ✅ Easy to scale
478
+
479
+ **Cons:**
480
+ - ❌ Requires MongoDB server
481
+ - ❌ More complex setup
482
+
483
+ ---
484
+
485
+ ## 📝 Examples
486
+
487
+ ### Example 1: Basic Bot
488
+
489
+ ```javascript
490
+ const { Client, GatewayIntentBits } = require('discord.js');
491
+ const { VoiceManager, JSONStorage } = require('discord-voice-tracker');
492
+
493
+ const client = new Client({
494
+ intents: [
495
+ GatewayIntentBits.Guilds,
496
+ GatewayIntentBits.GuildVoiceStates,
497
+ ],
498
+ });
499
+
500
+ const storage = new JSONStorage('./data');
501
+ const voiceManager = new VoiceManager(client, { storage });
502
+
503
+ client.once('ready', async () => {
504
+ await voiceManager.init();
505
+ console.log('Bot ready!');
506
+ });
507
+
508
+ client.login('YOUR_TOKEN');
509
+ ```
510
+
511
+ ### Example 2: With Level-Up Rewards
512
+
513
+ ```javascript
514
+ voiceManager.on('levelUp', async (userData, oldLevel, newLevel) => {
515
+ const guild = client.guilds.cache.get(userData.guildId);
516
+ const member = await guild.members.fetch(userData.userId);
517
+
518
+ // Level 5: Bronze role
519
+ if (newLevel === 5) {
520
+ const role = guild.roles.cache.find(r => r.name === 'Bronze Chatter');
521
+ await member.roles.add(role);
522
+ }
523
+
524
+ // Level 10: Silver role
525
+ if (newLevel === 10) {
526
+ const role = guild.roles.cache.find(r => r.name === 'Silver Chatter');
527
+ await member.roles.add(role);
528
+ }
529
+
530
+ // Level 25: Gold role
531
+ if (newLevel === 25) {
532
+ const role = guild.roles.cache.find(r => r.name === 'Gold Chatter');
533
+ await member.roles.add(role);
534
+ }
535
+ });
536
+ ```
537
+
538
+ ### Example 3: Custom XP Based on Channel
539
+
540
+ ```javascript
541
+ const config = await voiceManager.getGuildConfig(guildId);
542
+
543
+ // Give more XP in certain channels
544
+ config.channelFilter = (channel) => {
545
+ if (channel.name === 'study-room') {
546
+ config.xpPerCheck = 10; // Double XP in study room
547
+ } else {
548
+ config.xpPerCheck = 5; // Normal XP elsewhere
549
+ }
550
+ return true; // Track all channels
551
+ };
552
+
553
+ await voiceManager.saveGuildConfig(guildId, config);
554
+ ```
555
+
556
+ **📖 More examples in [examples/](examples/) folder!**
557
+
558
+ ---
559
+
560
+ ## 🐛 Troubleshooting
561
+
562
+ ### "Module not found: discord-voice-tracker"
563
+
564
+ **Solution:** Make sure you installed it:
565
+ ```bash
566
+ npm install discord-voice-tracker discord.js
567
+ ```
568
+
569
+ ### "Cannot find module 'mongodb'"
570
+
571
+ **Solution:** MongoDB is optional. Install it if you want to use MongoStorage:
572
+ ```bash
573
+ npm install mongodb
574
+ ```
575
+
576
+ Or use JSONStorage instead:
577
+ ```javascript
578
+ const { JSONStorage } = require('discord-voice-tracker');
579
+ const storage = new JSONStorage('./data');
580
+ ```
581
+
582
+ ### Voice tracking not working
583
+
584
+ **Checklist:**
585
+ 1. ✅ Bot has correct intents:
586
+ - `GatewayIntentBits.Guilds`
587
+ - `GatewayIntentBits.GuildVoiceStates`
588
+ 2. ✅ Called `await voiceManager.init()`
589
+ 3. ✅ Bot is in the server
590
+ 4. ✅ User is in a voice channel
591
+ 5. ✅ Wait at least 5-10 seconds
592
+
593
+ **Check the logs:**
594
+ ```javascript
595
+ const voiceManager = new VoiceManager(client, {
596
+ storage,
597
+ debug: true, // Enable this!
598
+ });
599
+ ```
600
+
601
+ ### Stats command shows no data
602
+
603
+ **Possible causes:**
604
+ 1. User hasn't joined voice yet
605
+ 2. `trackBots` is false and checking a bot
606
+ 3. Config updated and wiped users (see bug fix in docs)
607
+
608
+ **Solution:**
609
+ ```javascript
610
+ const userData = await voiceManager.getUser(guildId, userId);
611
+ if (!userData) {
612
+ return interaction.reply('No data yet! Join a voice channel first.');
613
+ }
614
+ ```
615
+
616
+ ### TypeError: Cannot read property 'users' of null
617
+
618
+ **Solution:** Guild not initialized. The bot will create it automatically when someone joins voice, or you can create it manually:
619
+ ```javascript
620
+ const config = await voiceManager.getGuildConfig(guildId);
621
+ // This creates the guild if it doesn't exist
622
+ ```
623
+
624
+ ---
625
+
626
+ ## 🤝 Contributing
627
+
628
+ Contributions are welcome! Please feel free to submit a Pull Request.
629
+
630
+ 1. Fork the repository
631
+ 2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
632
+ 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
633
+ 4. Push to the branch (`git push origin feature/AmazingFeature`)
634
+ 5. Open a Pull Request
635
+
636
+ ---
637
+
638
+ ## 📄 License
639
+
640
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
641
+
642
+ ---
643
+
644
+ ## 🙏 Support
645
+
646
+ - 📖 **Documentation:** [GitHub](https://github.com/yourusername/discord-voice-tracker)
647
+ - 🐛 **Bug Reports:** [Issues](https://github.com/yourusername/discord-voice-tracker/issues)
648
+ - 💬 **Discord:** [Join our server](https://discord.gg/your-invite)
649
+ - ⭐ **Star on GitHub** if you find this useful!
650
+
651
+ ---
652
+
653
+ ## 📊 Stats
654
+
655
+ ![npm](https://img.shields.io/npm/v/discord-voice-tracker?style=flat-square)
656
+ ![downloads](https://img.shields.io/npm/dt/discord-voice-tracker?style=flat-square)
657
+ ![license](https://img.shields.io/npm/l/discord-voice-tracker?style=flat-square)
658
+ ![size](https://img.shields.io/bundlephobia/min/discord-voice-tracker?style=flat-square)
659
+
660
+ ---
661
+
662
+ **Made with ❤️ by [Async](https://github.com/yourusername)**