djs-selfbot-v13 3.7.1 → 3.7.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/README.md CHANGED
@@ -14,6 +14,32 @@
14
14
 
15
15
  - discord.js-selfbot-v13 is a [Node.js](https://nodejs.org) module that allows user accounts to interact with the Discord API v9.
16
16
 
17
+ ## Nouveautés
18
+
19
+ > **Nouvelles fonctionnalités ajoutées :**
20
+ - `guild.mute()` - Supprime completement les pings
21
+ - `guild.unmute()` - Remet les pings sur le serveur
22
+
23
+ - `rpc.setDetailsURL(url)` - Met une URL pour les details du RPC
24
+ - `rpc.setStateURL(url)` - Met une URL pour le state du RPC
25
+
26
+ - `client.user.setNameStyle(fontName, effectName, color1, color2?)` - Définir le style du nom d'affichage avec police, effet et couleurs
27
+ - `client.user.setClan(GuildID)` - Changer votre TAG de serveur
28
+ - `client.user.deleteClan()` - Retire le TAG de serveur
29
+
30
+ - `client.user.addWidget(type, gameId, comment?, tags?)` - Ajouter un widget de jeu au profil
31
+ - `client.user.delWidget(type, gameId?)` - Supprimer un widget ou un jeu spécifique
32
+ - `client.user.widgetsList()` - Obtenir la liste de tous les widgets
33
+
34
+ - `client.quests.get()` - Récupérer toutes les quêtes disponibles
35
+ - `client.quests.orbs()` - Obtenir le solde de la monnaie virtuelle
36
+ - `client.quests.acceptQuest(questId, options?)` - S'inscrire à une quête
37
+ - `client.quests.doingQuest(quest)` - Compléter automatiquement une quête
38
+ - `client.quests.autoCompleteAll()` - Compléter automatiquement toutes les quêtes valides
39
+ - `client.quests.getCompleted()` - Obtenir les quêtes terminées
40
+ - `client.quests.getClaimable()` - Obtenir les quêtes réclamables
41
+ - `client.quests.filterQuestsValid()` - Filtrer les quêtes valides
42
+
17
43
 
18
44
  <div align="center">
19
45
  <p>
@@ -49,13 +75,13 @@
49
75
  > **Node.js 20.18.0 or newer is required**
50
76
 
51
77
  ```sh-session
52
- npm install discord.js-selfbot-v13-next@latest
78
+ npm install djs-selfbot-v13@latest
53
79
  ```
54
80
 
55
81
  ## Example
56
82
 
57
83
  ```js
58
- const { Client } = require('discord.js-selfbot-v13-next');
84
+ const { Client } = require('djs-selfbot-v13');
59
85
  const client = new Client();
60
86
 
61
87
  client.on('ready', async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "djs-selfbot-v13",
3
- "version": "3.7.1",
3
+ "version": "3.7.2",
4
4
  "description": "An unofficial discord.js fork for creating selfbots",
5
5
  "main": "./src/index.js",
6
6
  "types": "./typings/index.d.ts",
@@ -17,6 +17,7 @@ const ChannelManager = require('../managers/ChannelManager');
17
17
  const ClientUserSettingManager = require('../managers/ClientUserSettingManager');
18
18
  const GuildManager = require('../managers/GuildManager');
19
19
  const PresenceManager = require('../managers/PresenceManager');
20
+ const QuestManager = require('../managers/QuestManager');
20
21
  const RelationshipManager = require('../managers/RelationshipManager');
21
22
  const SessionManager = require('../managers/SessionManager');
22
23
  const UserManager = require('../managers/UserManager');
@@ -158,6 +159,12 @@ class Client extends BaseClient {
158
159
  */
159
160
  this.billing = new BillingManager(this);
160
161
 
162
+ /**
163
+ * Manages quest-related API methods
164
+ * @type {QuestManager}
165
+ */
166
+ this.quests = new QuestManager(this);
167
+
161
168
  /**
162
169
  * All of the sessions of the client
163
170
  * @type {SessionManager}
@@ -0,0 +1,376 @@
1
+ 'use strict';
2
+
3
+ const { Collection } = require('@discordjs/collection');
4
+ const BaseManager = require('./BaseManager');
5
+
6
+ /**
7
+ * Represents a single quest
8
+ */
9
+ class Quest {
10
+ constructor(data) {
11
+ this.id = data.id;
12
+ this.config = data.config;
13
+ this.userStatus = data.user_status;
14
+ }
15
+
16
+ /**
17
+ * Check if quest is expired
18
+ * @param {Date} [date=new Date()] Date to check against
19
+ * @returns {boolean}
20
+ */
21
+ isExpired(date = new Date()) {
22
+ if (!this.config.expires_at) return false;
23
+ return new Date(this.config.expires_at) < date;
24
+ }
25
+
26
+ /**
27
+ * Check if quest is completed
28
+ * @returns {boolean}
29
+ */
30
+ isCompleted() {
31
+ return this.userStatus?.completed_at != null;
32
+ }
33
+
34
+ /**
35
+ * Check if quest rewards have been claimed
36
+ * @returns {boolean}
37
+ */
38
+ hasClaimedRewards() {
39
+ return this.userStatus?.claimed_at != null;
40
+ }
41
+
42
+ /**
43
+ * Check if user is enrolled in quest
44
+ * @returns {boolean}
45
+ */
46
+ isEnrolledQuest() {
47
+ return this.userStatus?.enrolled_at != null;
48
+ }
49
+
50
+ /**
51
+ * Update user status for this quest
52
+ * @param {Object} status New status data
53
+ */
54
+ updateUserStatus(status) {
55
+ this.userStatus = { ...this.userStatus, ...status };
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Manages API methods for Discord quests
61
+ * @extends {BaseManager}
62
+ */
63
+ class QuestManager extends BaseManager {
64
+ constructor(client) {
65
+ super(client);
66
+
67
+ /**
68
+ * Collection of cached quests
69
+ * @type {Collection<string, Quest>}
70
+ */
71
+ this.cache = new Collection();
72
+ }
73
+
74
+ /**
75
+ * Get all available quests for the user
76
+ * @returns {Promise<Object>} Quest data
77
+ */
78
+ async get() {
79
+ const data = await this.client.api.users('@me').quests.get();
80
+
81
+ // Cache quests
82
+ if (data.quests) {
83
+ this.cache.clear();
84
+ data.quests.forEach(questData => {
85
+ const quest = new Quest(questData);
86
+ this.cache.set(quest.id, quest);
87
+ });
88
+ }
89
+
90
+ return data;
91
+ }
92
+
93
+ /**
94
+ * Get user's orb balance (virtual currency)
95
+ * @returns {Promise<Object>} Balance data
96
+ */
97
+ async orbs() {
98
+ const data = await this.client.api.users['@me']['virtual-currency'].balance.get();
99
+ return data;
100
+ }
101
+
102
+ /**
103
+ * Get quest by ID from cache
104
+ * @param {string} id Quest ID
105
+ * @returns {Quest|undefined}
106
+ */
107
+ getQuest(id) {
108
+ return this.cache.get(id);
109
+ }
110
+
111
+ /**
112
+ * Get all cached quests as array
113
+ * @returns {Quest[]}
114
+ */
115
+ list() {
116
+ return Array.from(this.cache.values());
117
+ }
118
+
119
+ /**
120
+ * Get expired quests
121
+ * @param {Date} [date=new Date()] Date to check against
122
+ * @returns {Quest[]}
123
+ */
124
+ getExpired(date = new Date()) {
125
+ return this.list().filter(quest => quest.isExpired(date));
126
+ }
127
+
128
+ /**
129
+ * Get completed quests
130
+ * @returns {Quest[]}
131
+ */
132
+ getCompleted() {
133
+ return this.list().filter(quest => quest.isCompleted());
134
+ }
135
+
136
+ /**
137
+ * Get claimable quests (completed but not claimed)
138
+ * @returns {Quest[]}
139
+ */
140
+ getClaimable() {
141
+ return this.list().filter(quest => quest.isCompleted() && !quest.hasClaimedRewards());
142
+ }
143
+
144
+ /**
145
+ * Get valid quests (not completed, not expired, not blacklisted)
146
+ * @returns {Quest[]}
147
+ */
148
+ filterQuestsValid() {
149
+ return this.list().filter(quest =>
150
+ quest.id !== '1412491570820812933' &&
151
+ !quest.isCompleted() &&
152
+ !quest.isExpired()
153
+ );
154
+ }
155
+
156
+ /**
157
+ * Check if quest exists in cache
158
+ * @param {string} id Quest ID
159
+ * @returns {boolean}
160
+ */
161
+ hasQuest(id) {
162
+ return this.cache.has(id);
163
+ }
164
+
165
+ /**
166
+ * Get application data for given IDs
167
+ * @param {string[]} ids Application IDs
168
+ * @returns {Promise<Object[]>}
169
+ */
170
+ async getApplicationData(ids) {
171
+ const query = new URLSearchParams();
172
+ ids.forEach(id => query.append('application_ids', id));
173
+
174
+ return this.client.api.applications.public.get({ query: query.toString() });
175
+ }
176
+
177
+ /**
178
+ * Enroll in a specific quest
179
+ * @param {string} questId The quest ID to enroll in
180
+ * @param {Object} [options] Enrollment options
181
+ * @param {number} [options.location=11] Location parameter
182
+ * @param {boolean} [options.isTargeted=false] Whether the quest is targeted
183
+ * @param {*} [options.metadataRaw=null] Raw metadata
184
+ * @returns {Promise<Quest|undefined>} Updated quest or undefined
185
+ */
186
+ async acceptQuest(questId, options = {}) {
187
+ const { location = 11, isTargeted = false, metadataRaw = null } = options;
188
+
189
+ const data = await this.client.api.quests(questId).enroll.post({
190
+ data: {
191
+ location,
192
+ is_targeted: isTargeted,
193
+ metadata_raw: metadataRaw
194
+ }
195
+ });
196
+
197
+ const quest = this.getQuest(questId);
198
+ if (quest) {
199
+ quest.updateUserStatus(data);
200
+ }
201
+
202
+ return quest;
203
+ }
204
+
205
+ /**
206
+ * Update progress for a video quest
207
+ * @param {string} questId The quest ID
208
+ * @param {number} timestamp Current progress timestamp
209
+ * @returns {Promise<Object>} Progress update result
210
+ */
211
+ async videoProgress(questId, timestamp) {
212
+ const data = await this.client.api.quests(questId)['video-progress'].post({
213
+ data: { timestamp }
214
+ });
215
+ return data;
216
+ }
217
+
218
+ /**
219
+ * Send heartbeat for desktop quests
220
+ * @param {string} questId The quest ID
221
+ * @param {string} applicationId Application ID
222
+ * @param {boolean} [terminal=false] Whether this is a terminal heartbeat
223
+ * @returns {Promise<Object>} Heartbeat result
224
+ */
225
+ async heartbeat(questId, applicationId, terminal = false) {
226
+ const data = await this.client.api.quests(questId).heartbeat.post({
227
+ data: {
228
+ application_id: applicationId,
229
+ terminal
230
+ }
231
+ });
232
+ return data;
233
+ }
234
+
235
+ /**
236
+ * Helper function for timeout
237
+ * @param {number} ms Milliseconds to wait
238
+ * @returns {Promise<void>}
239
+ * @private
240
+ */
241
+ async timeout(ms) {
242
+ return new Promise(resolve => setTimeout(resolve, ms));
243
+ }
244
+
245
+ /**
246
+ * Complete a quest automatically
247
+ * @param {Quest} quest Quest to complete
248
+ * @returns {Promise<void>}
249
+ */
250
+ async doingQuest(quest) {
251
+ const questName = quest.config.messages?.quest_name || 'Unknown Quest';
252
+
253
+ if (!quest.isEnrolledQuest()) {
254
+ console.log(`Enrolling in quest "${questName}"...`);
255
+ await this.acceptQuest(quest.id);
256
+ }
257
+
258
+ const applicationName = quest.config.application?.name || 'Unknown App';
259
+ const taskConfig = quest.config.task_config;
260
+
261
+ const taskName = [
262
+ 'WATCH_VIDEO',
263
+ 'PLAY_ON_DESKTOP',
264
+ 'STREAM_ON_DESKTOP',
265
+ 'PLAY_ACTIVITY',
266
+ 'WATCH_VIDEO_ON_MOBILE'
267
+ ].find(x => taskConfig.tasks?.[x] != null);
268
+
269
+ if (!taskName) {
270
+ console.log(`Unknown task type for quest "${questName}"`);
271
+ return;
272
+ }
273
+
274
+ const secondsNeeded = taskConfig.tasks[taskName].target;
275
+ let secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0;
276
+
277
+ if (taskName === 'WATCH_VIDEO' || taskName === 'WATCH_VIDEO_ON_MOBILE') {
278
+ const maxFuture = 10;
279
+ const speed = 7;
280
+ const interval = 1;
281
+ const enrolledAt = new Date(quest.userStatus?.enrolled_at).getTime();
282
+ let completed = false;
283
+
284
+ console.log(`Spoofing video for ${questName}.`);
285
+
286
+ while (true) {
287
+ const maxAllowed = Math.floor((Date.now() - enrolledAt) / 1000) + maxFuture;
288
+ const diff = maxAllowed - secondsDone;
289
+ const timestamp = secondsDone + speed;
290
+
291
+ if (diff >= speed) {
292
+ const res = await this.videoProgress(quest.id, Math.min(secondsNeeded, timestamp + Math.random()));
293
+ completed = res.completed_at != null;
294
+ secondsDone = Math.min(secondsNeeded, timestamp);
295
+ }
296
+
297
+ if (timestamp >= secondsNeeded) {
298
+ break;
299
+ }
300
+
301
+ await this.timeout(interval * 1000);
302
+ }
303
+
304
+ if (!completed) {
305
+ await this.videoProgress(quest.id, secondsNeeded);
306
+ }
307
+
308
+ console.log(`Quest "${questName}" completed!`);
309
+
310
+ } else if (taskName === 'PLAY_ON_DESKTOP') {
311
+ const interval = 60;
312
+
313
+ while (!quest.isCompleted()) {
314
+ const secondsDone = quest.userStatus?.progress?.[taskName]?.value || 0;
315
+ const res = await this.heartbeat(quest.id, quest.config.application.id, false);
316
+ quest.updateUserStatus(res);
317
+
318
+ console.log(`Spoofed your game to ${applicationName}. Wait for ${Math.ceil((secondsNeeded - secondsDone) / 60)} more minutes.`);
319
+ await this.timeout(interval * 1000);
320
+ }
321
+
322
+ const res = await this.heartbeat(quest.id, quest.config.application.id, true);
323
+ quest.updateUserStatus(res);
324
+ console.log(`Quest "${questName}" completed!`);
325
+
326
+ } else if (taskName === 'STREAM_ON_DESKTOP') {
327
+ console.log('This no longer works in node for non-video quests. Use the discord desktop app to complete the', questName, 'quest!');
328
+ } else if (taskName === 'PLAY_ACTIVITY') {
329
+ console.log('This quest not supported. Use the discord desktop app to complete the', questName, 'quest!');
330
+ } else {
331
+ console.log('Unknown quest type. Use the discord desktop app to complete the', questName, 'quest!');
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Auto-complete all valid quests
337
+ * @returns {Promise<void>}
338
+ */
339
+ async autoCompleteAll() {
340
+ await this.get(); // Refresh quest data
341
+ const validQuests = this.filterQuestsValid();
342
+
343
+ for (const quest of validQuests) {
344
+ try {
345
+ await this.doingQuest(quest);
346
+ } catch (error) {
347
+ console.error(`Failed to complete quest ${quest.id}:`, error);
348
+ }
349
+ }
350
+ }
351
+
352
+ /**
353
+ * Get cache size
354
+ * @returns {number}
355
+ */
356
+ get size() {
357
+ return this.cache.size;
358
+ }
359
+
360
+ /**
361
+ * Clear quest cache
362
+ */
363
+ clear() {
364
+ this.cache.clear();
365
+ }
366
+
367
+ /**
368
+ * Make QuestManager iterable
369
+ * @returns {IterableIterator<Quest>}
370
+ */
371
+ [Symbol.iterator]() {
372
+ return this.cache.values();
373
+ }
374
+ }
375
+
376
+ module.exports = QuestManager;
@@ -447,12 +447,186 @@ class ClientUser extends User {
447
447
  }
448
448
 
449
449
  /**
450
- * Set pronouns
451
- * @param {?string} pronouns Your pronouns
450
+ * Add a widget to the user's profile
451
+ * @param {string} type Widget type (favorite_games, current_games, played_games, want_to_play_games)
452
+ * @param {string} gameId The game ID to add
453
+ * @param {string} [comment] Optional comment for the game
454
+ * @param {string[]} [tags] Optional tags for the game
455
+ * @returns {Promise<Object>}
456
+ */
457
+ async addWidget(type, gameId, comment = null, tags = []) {
458
+ if (!type || !gameId) {
459
+ throw new TypeError('Widget type and game ID are required');
460
+ }
461
+
462
+ const validTypes = ['favorite_games', 'current_games', 'played_games', 'want_to_play_games'];
463
+ if (!validTypes.includes(type)) {
464
+ throw new TypeError(`Invalid widget type. Must be one of: ${validTypes.join(', ')}`);
465
+ }
466
+
467
+ // Get current widgets first
468
+ const currentWidgets = await this.widgetsList();
469
+
470
+ // Find existing widget of this type or create new one
471
+ let targetWidget = currentWidgets.widgets.find(w => w.data.type === type);
472
+
473
+ if (!targetWidget) {
474
+ // Create new widget if it doesn't exist
475
+ targetWidget = {
476
+ id: Date.now().toString(), // Generate temporary ID
477
+ data: {
478
+ type: type,
479
+ games: []
480
+ }
481
+ };
482
+ currentWidgets.widgets.push(targetWidget);
483
+ }
484
+
485
+ // Add the game if it doesn't already exist
486
+ const existingGame = targetWidget.data.games.find(g => g.game_id === gameId);
487
+ if (!existingGame) {
488
+ const gameData = { game_id: gameId };
489
+ if (comment !== null) gameData.comment = comment;
490
+ if (tags.length > 0) gameData.tags = tags;
491
+
492
+ targetWidget.data.games.push(gameData);
493
+ }
494
+
495
+ // Update widgets via API
496
+ return this.client.api.users['@me'].profile.patch({
497
+ data: { widgets: currentWidgets.widgets }
498
+ });
499
+ }
500
+
501
+ /**
502
+ * Delete a widget or remove a game from a widget
503
+ * @param {string} type Widget type to modify
504
+ * @param {string} [gameId] Optional game ID to remove (if not provided, removes entire widget)
505
+ * @returns {Promise<Object>}
506
+ */
507
+ async delWidget(type, gameId = null) {
508
+ if (!type) {
509
+ throw new TypeError('Widget type is required');
510
+ }
511
+
512
+ const validTypes = ['favorite_games', 'current_games', 'played_games', 'want_to_play_games'];
513
+ if (!validTypes.includes(type)) {
514
+ throw new TypeError(`Invalid widget type. Must be one of: ${validTypes.join(', ')}`);
515
+ }
516
+
517
+ // Get current widgets
518
+ const currentWidgets = await this.widgetsList();
519
+
520
+ if (gameId) {
521
+ // Remove specific game from widget
522
+ const targetWidget = currentWidgets.widgets.find(w => w.data.type === type);
523
+ if (targetWidget) {
524
+ targetWidget.data.games = targetWidget.data.games.filter(g => g.game_id !== gameId);
525
+ }
526
+ } else {
527
+ // Remove entire widget
528
+ currentWidgets.widgets = currentWidgets.widgets.filter(w => w.data.type !== type);
529
+ }
530
+
531
+ // Update widgets via API
532
+ return this.client.api.users['@me'].profile.patch({
533
+ data: { widgets: currentWidgets.widgets }
534
+ });
535
+ }
536
+
537
+ /**
538
+ * Get the list of all widgets for the user
539
+ * @returns {Promise<Object>} Object containing widgets array
540
+ */
541
+ async widgetsList() {
542
+ try {
543
+ const data = await this.client.api.users['@me'].profile.get();
544
+ return data.widgets ? { widgets: data.widgets } : { widgets: [] };
545
+ } catch (error) {
546
+ // If profile endpoint doesn't exist or fails, return empty widgets
547
+ return { widgets: [] };
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Set display name style with font, effect, and colors
553
+ * @param {string|number} fontName Font name or ID
554
+ * @param {string|number} effectName Effect name or ID
555
+ * @param {number|string} color1 Primary color (hex or decimal)
556
+ * @param {number|string} [color2] Secondary color for gradient effects (hex or decimal)
452
557
  * @returns {Promise<ClientUser>}
558
+ * @example
559
+ * // Set Sans font with gradient effect
560
+ * client.user.setNameStyle('Sans', 'Gradient', 7183099, 6082490);
561
+ * // Set Tempo font with solid effect
562
+ * client.user.setNameStyle('Tempo', 'Solid', 7183099);
563
+ * // Using IDs directly
564
+ * client.user.setNameStyle(11, 2, 7183099, 6082490);
453
565
  */
454
- setPronouns(pronouns = '') {
455
- return this.edit({ pronouns });
566
+ async setNameStyle(fontName, effectName, color1, color2 = null) {
567
+ // Font name/ID mapping
568
+ const fontMap = {
569
+ 'Sans': 11,
570
+ 'Tempo': 12,
571
+ 'Sakura': 3,
572
+ 'JellyBean': 4,
573
+ 'Modern': 6,
574
+ 'Medieval': 7,
575
+ '8Bit': 8,
576
+ 'Vampire': 10
577
+ };
578
+
579
+ // Effect name/ID mapping
580
+ const effectMap = {
581
+ 'Solid': 1,
582
+ 'Gradient': 2,
583
+ 'Neon': 3,
584
+ 'Toon': 4,
585
+ 'Pop': 5
586
+ };
587
+
588
+ // Resolve font ID
589
+ let fontId = typeof fontName === 'string' ? fontMap[fontName] : fontName;
590
+ if (!fontId) {
591
+ throw new TypeError(`Invalid font name. Must be one of: ${Object.keys(fontMap).join(', ')} or a valid font ID`);
592
+ }
593
+
594
+ // Resolve effect ID
595
+ let effectId = typeof effectName === 'string' ? effectMap[effectName] : effectName;
596
+ if (!effectId) {
597
+ throw new TypeError(`Invalid effect name. Must be one of: ${Object.keys(effectMap).join(', ')} or a valid effect ID`);
598
+ }
599
+
600
+ // Resolve colors
601
+ const resolveColor = (color) => {
602
+ if (typeof color === 'string') {
603
+ // Handle hex colors
604
+ if (color.startsWith('#')) {
605
+ return parseInt(color.slice(1), 16);
606
+ }
607
+ return parseInt(color, 16);
608
+ }
609
+ return color;
610
+ };
611
+
612
+ const primaryColor = resolveColor(color1);
613
+ const colors = [primaryColor];
614
+
615
+ if (color2 !== null) {
616
+ const secondaryColor = resolveColor(color2);
617
+ colors.push(secondaryColor);
618
+ }
619
+
620
+ // Build the data object
621
+ const data = {
622
+ display_name_font_id: fontId,
623
+ display_name_effect_id: effectId,
624
+ display_name_colors: colors
625
+ };
626
+
627
+ // Send PATCH request to Discord API
628
+ await this.client.api.users('@me').patch({ data });
629
+ return this;
456
630
  }
457
631
 
458
632
  /**
@@ -1605,6 +1605,60 @@ class Guild extends AnonymousGuild {
1605
1605
  };
1606
1606
  }
1607
1607
 
1608
+ /**
1609
+ * Mute this guild
1610
+ * @param {GuildMuteOptions} [options] Options for muting the guild
1611
+ * @returns {Promise<Object>} The updated guild settings
1612
+ * @example
1613
+ * // Mute the guild with default settings
1614
+ * guild.mute();
1615
+ * @example
1616
+ * // Mute the guild with custom options
1617
+ * guild.mute({
1618
+ * muted: true,
1619
+ * suppressRoles: false,
1620
+ * suppressEveryone: true,
1621
+ * muteScheduledEvents: false
1622
+ * });
1623
+ */
1624
+ async mute(options = {}) {
1625
+ const {
1626
+ muted = true,
1627
+ suppressRoles = true,
1628
+ suppressEveryone = true,
1629
+ muteScheduledEvents = true
1630
+ } = options;
1631
+
1632
+ const data = await this.client.api.users('@me').guilds(this.id).settings.patch({
1633
+ data: {
1634
+ muted,
1635
+ suppress_roles: suppressRoles,
1636
+ suppress_everyone: suppressEveryone,
1637
+ mute_scheduled_events: muteScheduledEvents
1638
+ }
1639
+ });
1640
+ return data;
1641
+ }
1642
+
1643
+ /**
1644
+ * Unmute this guild
1645
+ * @returns {Promise<Object>} The updated guild settings
1646
+ * @example
1647
+ * // Unmute the guild
1648
+ * guild.unmute();
1649
+ */
1650
+ async unmute() {
1651
+ const data = await this.client.api.users('@me').guilds(this.id).settings.patch({
1652
+ data: {
1653
+ muted: false,
1654
+ suppress_roles: false,
1655
+ suppress_everyone: false,
1656
+ mute_scheduled_events: false
1657
+ }
1658
+ });
1659
+ return data;
1660
+ }
1661
+
1608
1662
  /**
1609
1663
  * Creates a collection of this guild's roles, sorted by their position and ids.
1610
1664
  * @returns {Collection<Snowflake, Role>}
@@ -800,6 +800,22 @@ class RichPresence extends Activity {
800
800
  return this;
801
801
  }
802
802
 
803
+ /**
804
+ * Set the URL of the state of the activity
805
+ * @param {?string} url The url of the state
806
+ * @returns {RichPresence}
807
+ */
808
+ setStateURL(url){
809
+ if (!url)
810
+ throw new Error('Detail URL must be a url');
811
+
812
+ if (typeof url !== 'string') throw new Error('Detail URL must be a url');
813
+ if (!URL.canParse(url)) throw new Error('Detail URL must be a valid url');
814
+
815
+ this.state_url = url;
816
+ return this;
817
+ }
818
+
803
819
  /**
804
820
  * Set the details of the activity
805
821
  * @param {?string} details The details of the activity
@@ -810,6 +826,22 @@ class RichPresence extends Activity {
810
826
  return this;
811
827
  }
812
828
 
829
+ /**
830
+ * Set the URL of the details of the activity
831
+ * @param {?string} url The url of the details
832
+ * @returns {RichPresence}
833
+ */
834
+ setDetailsURL(url){
835
+ if (!url)
836
+ throw new Error('Detail URL must be a url');
837
+
838
+ if (typeof url !== 'string') throw new Error('Detail URL must be a url');
839
+ if (!URL.canParse(url)) throw new Error('Detail URL must be a valid url');
840
+
841
+ this.details_url = url;
842
+ return this;
843
+ }
844
+
813
845
  /**
814
846
  * @typedef {Object} RichParty
815
847
  * @property {string} id The id of the party
@@ -216,7 +216,9 @@ export class RichPresence extends Activity {
216
216
  public setType(type?: ActivityType): this;
217
217
  public setApplicationId(id?: Snowflake): this;
218
218
  public setDetails(details?: string): this;
219
+ public setDetailsURL(url?: string): this;
219
220
  public setState(state?: string): this;
221
+ public setStateURL(url?: string): this;
220
222
  public setParty(party?: { max: number; current: number; id?: string }): this;
221
223
  public setStartTimestamp(timestamp: Date | number | null): this;
222
224
  public setEndTimestamp(timestamp: Date | number | null): this;
@@ -860,6 +862,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
860
862
  public sessions: SessionManager;
861
863
  public presences: PresenceManager;
862
864
  public billing: BillingManager;
865
+ public quests: QuestManager;
863
866
  public settings: ClientUserSettingManager;
864
867
  public readonly sessionId: If<Ready, string, undefined>;
865
868
  public destroy(): void;
@@ -980,7 +983,13 @@ export class ClientUser extends User {
980
983
  public stopRinging(channel: ChannelResolvable): Promise<void>;
981
984
  public fetchBurstCredit(): Promise<number>;
982
985
  public setPronouns(pronouns?: string | null): Promise<this>;
986
+ public setClan(guild?: GuildIDResolve): Promise<this>;
987
+ public deleteClan(): Promise<this>;
983
988
  public setGlobalName(globalName?: string | null): Promise<this>;
989
+ public addWidget(type: WidgetType, gameId: string, comment?: string | null, tags?: string[]): Promise<any>;
990
+ public delWidget(type: WidgetType, gameId?: string): Promise<any>;
991
+ public widgetsList(): Promise<WidgetsResponse>;
992
+ public setNameStyle(fontName: FontName | number, effectName: EffectName | number, color1: number | string, color2?: number | string | null): Promise<this>;
984
993
  }
985
994
 
986
995
  export class Options extends null {
@@ -1662,6 +1671,8 @@ export class Guild extends AnonymousGuild {
1662
1671
  ): Promise<this>;
1663
1672
  public topEmojis(): Promise<Collection<number, GuildEmoji>>;
1664
1673
  public setVanityCode(code?: string): Promise<this>;
1674
+ public mute(options?: GuildMuteOptions): Promise<any>;
1675
+ public unmute(): Promise<any>;
1665
1676
  }
1666
1677
 
1667
1678
  export class GuildAuditLogs<T extends GuildAuditLogsResolvable = 'ALL'> {
@@ -2637,6 +2648,29 @@ export class BillingManager extends BaseManager {
2637
2648
  public fetchCurrentSubscription(): Promise<Collection<Snowflake, object>>;
2638
2649
  }
2639
2650
 
2651
+ export class QuestManager extends BaseManager {
2652
+ constructor(client: Client);
2653
+ public cache: Collection<string, Quest>;
2654
+ public get(): Promise<QuestData>;
2655
+ public orbs(): Promise<OrbsData>;
2656
+ public getQuest(id: string): Quest | undefined;
2657
+ public list(): Quest[];
2658
+ public getExpired(date?: Date): Quest[];
2659
+ public getCompleted(): Quest[];
2660
+ public getClaimable(): Quest[];
2661
+ public filterQuestsValid(): Quest[];
2662
+ public hasQuest(id: string): boolean;
2663
+ public getApplicationData(ids: string[]): Promise<ApplicationData[]>;
2664
+ public acceptQuest(questId: string, options?: QuestEnrollOptions): Promise<Quest | undefined>;
2665
+ public videoProgress(questId: string, timestamp: number): Promise<any>;
2666
+ public heartbeat(questId: string, applicationId: string, terminal?: boolean): Promise<any>;
2667
+ public doingQuest(quest: Quest): Promise<void>;
2668
+ public autoCompleteAll(): Promise<void>;
2669
+ public readonly size: number;
2670
+ public clear(): void;
2671
+ public [Symbol.iterator](): IterableIterator<Quest>;
2672
+ }
2673
+
2640
2674
  export class Session extends Base {
2641
2675
  constructor(client: Client);
2642
2676
  public id?: string;
@@ -3739,6 +3773,117 @@ export interface Collectibles {
3739
3773
  nameplate: NameplateData | null;
3740
3774
  }
3741
3775
 
3776
+ export type WidgetType = 'favorite_games' | 'current_games' | 'played_games' | 'want_to_play_games';
3777
+
3778
+ export interface WidgetGameData {
3779
+ game_id: string;
3780
+ comment?: string | null;
3781
+ tags?: string[];
3782
+ }
3783
+
3784
+ export interface WidgetData {
3785
+ id: string;
3786
+ data: {
3787
+ type: WidgetType;
3788
+ games: WidgetGameData[];
3789
+ };
3790
+ }
3791
+
3792
+ export interface WidgetsResponse {
3793
+ widgets: WidgetData[];
3794
+ }
3795
+
3796
+ export interface QuestEnrollOptions {
3797
+ location?: number;
3798
+ isTargeted?: boolean;
3799
+ metadataRaw?: any;
3800
+ }
3801
+
3802
+ export interface QuestTaskConfig {
3803
+ tasks?: {
3804
+ WATCH_VIDEO?: { target: number };
3805
+ WATCH_VIDEO_ON_MOBILE?: { target: number };
3806
+ PLAY_ON_DESKTOP?: { target: number };
3807
+ STREAM_ON_DESKTOP?: { target: number };
3808
+ PLAY_ACTIVITY?: { target: number };
3809
+ };
3810
+ }
3811
+
3812
+ export interface QuestUserStatus {
3813
+ enrolled_at?: string;
3814
+ completed_at?: string;
3815
+ claimed_at?: string;
3816
+ progress?: {
3817
+ WATCH_VIDEO?: { value: number };
3818
+ WATCH_VIDEO_ON_MOBILE?: { value: number };
3819
+ PLAY_ON_DESKTOP?: { value: number };
3820
+ STREAM_ON_DESKTOP?: { value: number };
3821
+ PLAY_ACTIVITY?: { value: number };
3822
+ };
3823
+ }
3824
+
3825
+ export interface QuestConfig {
3826
+ expires_at?: string;
3827
+ messages?: {
3828
+ quest_name?: string;
3829
+ };
3830
+ application?: {
3831
+ id: string;
3832
+ name: string;
3833
+ };
3834
+ task_config: QuestTaskConfig;
3835
+ task_config_v2?: QuestTaskConfig;
3836
+ }
3837
+
3838
+ export interface QuestRawData {
3839
+ id: string;
3840
+ config: QuestConfig;
3841
+ user_status?: QuestUserStatus;
3842
+ }
3843
+
3844
+ export class Quest {
3845
+ constructor(data: QuestRawData);
3846
+ public id: string;
3847
+ public config: QuestConfig;
3848
+ public userStatus?: QuestUserStatus;
3849
+ public isExpired(date?: Date): boolean;
3850
+ public isCompleted(): boolean;
3851
+ public hasClaimedRewards(): boolean;
3852
+ public isEnrolledQuest(): boolean;
3853
+ public updateUserStatus(status: Partial<QuestUserStatus>): void;
3854
+ }
3855
+
3856
+ export interface QuestData {
3857
+ quests?: QuestRawData[];
3858
+ }
3859
+
3860
+ export interface OrbsData {
3861
+ balance?: number;
3862
+ }
3863
+
3864
+ export interface ApplicationData {
3865
+ id: string;
3866
+ name: string;
3867
+ icon: string;
3868
+ description: string;
3869
+ executables: {
3870
+ os: string;
3871
+ name: string;
3872
+ is_launcher: boolean;
3873
+ }[];
3874
+ }
3875
+
3876
+ export type FontName = 'Sans' | 'Tempo' | 'Sakura' | 'JellyBean' | 'Modern' | 'Medieval' | '8Bit' | 'Vampire';
3877
+
3878
+ export type EffectName = 'Solid' | 'Gradient' | 'Neon' | 'Toon' | 'Pop';
3879
+
3880
+ export interface GuildMuteOptions {
3881
+ muted?: boolean;
3882
+ suppressRoles?: boolean;
3883
+ suppressEveryone?: boolean;
3884
+ muteScheduledEvents?: boolean;
3885
+ }
3886
+
3742
3887
  export class User extends PartialTextBasedChannel(Base) {
3743
3888
  protected constructor(client: Client, data: RawUserData);
3744
3889
  private _equals(user: APIUser): boolean;