djs-selfbot-v13 3.7.15 → 3.7.17
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/package.json +1 -1
- package/src/rest/APIRequest.js +0 -2
- package/src/structures/BaseGuildVoiceChannel.js +1 -12
- package/src/structures/ClientPresence.js +28 -4
- package/src/structures/ClientUser.js +63 -1
- package/src/structures/Guild.js +43 -0
- package/src/structures/User.js +1 -0
- package/typings/index.d.ts +3 -0
package/package.json
CHANGED
package/src/rest/APIRequest.js
CHANGED
|
@@ -16,9 +16,7 @@ class APIRequest {
|
|
|
16
16
|
this.route = options.route;
|
|
17
17
|
this.options = options;
|
|
18
18
|
this.retries = 0;
|
|
19
|
-
|
|
20
19
|
this.fullUserAgent = this.client.options.http.headers['User-Agent'];
|
|
21
|
-
|
|
22
20
|
this.client.options.ws.properties.browser_user_agent = this.fullUserAgent;
|
|
23
21
|
|
|
24
22
|
let queryString = '';
|
|
@@ -223,19 +223,8 @@ class BaseGuildVoiceChannel extends GuildChannel {
|
|
|
223
223
|
return this.edit({ videoQualityMode }, reason);
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
-
// These are here only for documentation purposes - they are implemented by TextBasedChannel
|
|
227
|
-
/* eslint-disable no-empty-function */
|
|
228
|
-
get lastMessage() {}
|
|
229
|
-
send() {}
|
|
230
|
-
sendTyping() {}
|
|
231
|
-
createMessageCollector() {}
|
|
232
|
-
awaitMessages() {}
|
|
233
|
-
fetchWebhooks() {}
|
|
234
|
-
createWebhook() {}
|
|
235
|
-
setRateLimitPerUser() {}
|
|
236
|
-
setNSFW() {}
|
|
237
226
|
}
|
|
238
227
|
|
|
239
228
|
TextBasedChannel.applyToClass(BaseGuildVoiceChannel, true, ['lastPinAt']);
|
|
240
229
|
|
|
241
|
-
module.exports = BaseGuildVoiceChannel;
|
|
230
|
+
module.exports = BaseGuildVoiceChannel;
|
|
@@ -41,20 +41,44 @@ class ClientPresence extends Presence {
|
|
|
41
41
|
since: typeof since === 'number' && !Number.isNaN(since) ? this.since : 0,
|
|
42
42
|
status: status ?? this.status,
|
|
43
43
|
};
|
|
44
|
+
|
|
45
|
+
// Récupère le custom status actuellement en cache pour ne pas l'écraser
|
|
46
|
+
// lors d'un setActivity / setStatus qui ne touche pas au custom status
|
|
47
|
+
const existingCustom = this.activities?.find(a =>
|
|
48
|
+
CustomStatusActivityTypes.includes(a.type),
|
|
49
|
+
);
|
|
50
|
+
|
|
44
51
|
if (activities?.length) {
|
|
52
|
+
let hasCustom = false;
|
|
45
53
|
for (const [i, activity] of activities.entries()) {
|
|
46
54
|
if (typeof activity.name !== 'string') throw new TypeError('INVALID_TYPE', `activities[${i}].name`, 'string');
|
|
47
55
|
|
|
48
56
|
activity.type ??= ActivityTypes.PLAYING;
|
|
49
57
|
if (typeof activity.type === 'string') activity.type = ActivityTypes[activity.type];
|
|
50
58
|
|
|
51
|
-
if (CustomStatusActivityTypes.includes(activity.type)
|
|
52
|
-
|
|
53
|
-
activity.
|
|
59
|
+
if (CustomStatusActivityTypes.includes(activity.type)) {
|
|
60
|
+
hasCustom = true;
|
|
61
|
+
if (!activity.state) {
|
|
62
|
+
activity.state = activity.name;
|
|
63
|
+
activity.name = 'Custom Status';
|
|
64
|
+
}
|
|
54
65
|
}
|
|
55
66
|
|
|
56
67
|
data.activities.push(activity);
|
|
57
68
|
}
|
|
69
|
+
|
|
70
|
+
// Si le tableau d'activités passé ne contient pas de custom status,
|
|
71
|
+
// réinjecte celui du cache pour ne pas le perdre
|
|
72
|
+
if (!hasCustom && existingCustom) {
|
|
73
|
+
data.activities.unshift({
|
|
74
|
+
type: typeof existingCustom.type === 'string'
|
|
75
|
+
? ActivityTypes[existingCustom.type]
|
|
76
|
+
: existingCustom.type,
|
|
77
|
+
name: existingCustom.name ?? 'Custom Status',
|
|
78
|
+
state: existingCustom.state ?? null,
|
|
79
|
+
emoji: existingCustom.emoji ?? null,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
58
82
|
} else if (!activities && (status || afk || since) && this.activities.length) {
|
|
59
83
|
data.activities.push(
|
|
60
84
|
...this.activities.map(a => {
|
|
@@ -74,4 +98,4 @@ module.exports = ClientPresence;
|
|
|
74
98
|
/**
|
|
75
99
|
* @external APIPresence
|
|
76
100
|
* @see {@link https://discord.com/developers/docs/rich-presence/how-to#updating-presence-update-presence-payload-fields}
|
|
77
|
-
*/
|
|
101
|
+
*/
|
|
@@ -267,6 +267,68 @@ class ClientUser extends User {
|
|
|
267
267
|
return this.setPresence({ afk, shardId });
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Sets the custom status of the client user.
|
|
272
|
+
* Updates both the Gateway (local real-time display) and the REST API (account persistence).
|
|
273
|
+
* @param {CustomStatus|CustomStatusOptions|string|null} options
|
|
274
|
+
* A `CustomStatus` instance, an options object, a plain string for the state, or `null` to clear.
|
|
275
|
+
* @param {string} [options.state] Text displayed as the status
|
|
276
|
+
* @param {EmojiIdentifierResolvable} [options.emoji] Emoji shown next to the text
|
|
277
|
+
* @param {string} [options.expiresAt] ISO8601 date at which Discord auto-clears the status
|
|
278
|
+
* @param {number|number[]} [options.shardId] Shard(s) to broadcast the Gateway update on
|
|
279
|
+
* @returns {Promise<ClientPresence>}
|
|
280
|
+
* @example
|
|
281
|
+
* // With text + unicode emoji
|
|
282
|
+
* await client.user.setCustomStatus({ state: 'Coding...', emoji: '💻' });
|
|
283
|
+
* @example
|
|
284
|
+
* // Plain string shorthand
|
|
285
|
+
* await client.user.setCustomStatus('Taking a break');
|
|
286
|
+
* @example
|
|
287
|
+
* // Clear the custom status
|
|
288
|
+
* await client.user.setCustomStatus(null);
|
|
289
|
+
*/
|
|
290
|
+
async setCustomStatus(options, shardId) {
|
|
291
|
+
const { CustomStatus } = require('../structures/Presence');
|
|
292
|
+
|
|
293
|
+
// ── 1. Normalise l'entrée ─────────────────────────────────────────────
|
|
294
|
+
let activity = null; // null = effacer
|
|
295
|
+
let restPayload = null;
|
|
296
|
+
|
|
297
|
+
if (options !== null && options !== undefined) {
|
|
298
|
+
if (typeof options === 'string') options = { state: options };
|
|
299
|
+
|
|
300
|
+
// Supporte un objet CustomStatus existant (déjà construit par l'utilisateur)
|
|
301
|
+
const cs = options instanceof CustomStatus
|
|
302
|
+
? options
|
|
303
|
+
: new CustomStatus(this.client, {
|
|
304
|
+
state: options.state ?? null,
|
|
305
|
+
emoji: options.emoji ? { name: options.emoji } : undefined,
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
activity = cs.toJSON(); // { name, type, state, emoji }
|
|
309
|
+
|
|
310
|
+
restPayload = {
|
|
311
|
+
text: cs.state ?? null,
|
|
312
|
+
emoji_name: cs.emoji?.name ?? null,
|
|
313
|
+
emoji_id: cs.emoji?.id ?? null,
|
|
314
|
+
expires_at: options.expiresAt ?? null,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// ── 2. Gateway — visible localement en temps réel ────────────────────
|
|
319
|
+
const presenceActivities = activity ? [activity] : [];
|
|
320
|
+
const presence = this.setPresence({ activities: presenceActivities, shardId });
|
|
321
|
+
|
|
322
|
+
// ── 3. REST — persistance sur le compte Discord ───────────────────────
|
|
323
|
+
await this.client.api.users('@me').settings.patch({ data: { custom_status: restPayload } })
|
|
324
|
+
.catch(err => {
|
|
325
|
+
// Non bloquant : on ne veut pas casser setPresence si l'endpoint échoue
|
|
326
|
+
this.client.emit('warn', `[setCustomStatus] REST patch failed: ${err?.message ?? err}`);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
return presence;
|
|
330
|
+
}
|
|
331
|
+
|
|
270
332
|
/**
|
|
271
333
|
* Sets the banner of the logged in client.
|
|
272
334
|
* @param {?(BufferResolvable|Base64Resolvable)} banner The new banner
|
|
@@ -688,4 +750,4 @@ class ClientUser extends User {
|
|
|
688
750
|
}
|
|
689
751
|
}
|
|
690
752
|
|
|
691
|
-
module.exports = ClientUser;
|
|
753
|
+
module.exports = ClientUser;
|
package/src/structures/Guild.js
CHANGED
|
@@ -1752,6 +1752,49 @@ class Guild extends AnonymousGuild {
|
|
|
1752
1752
|
return data;
|
|
1753
1753
|
}
|
|
1754
1754
|
|
|
1755
|
+
/**
|
|
1756
|
+
* Get the number of members that would be pruned
|
|
1757
|
+
* @param {number} [days=7] Number of days of inactivity
|
|
1758
|
+
* @param {string[]} [includeRoles=[]] Role IDs to include in the prune
|
|
1759
|
+
* @returns {Promise<number>} The number of members that would be pruned
|
|
1760
|
+
*/
|
|
1761
|
+
async pruneCount(days = 7, includeRoles = []) {
|
|
1762
|
+
const query = { days };
|
|
1763
|
+
|
|
1764
|
+
if (includeRoles.length > 0) {
|
|
1765
|
+
query.include_roles = includeRoles.join('&include_roles=');
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
const params = new URLSearchParams({ days: days.toString() });
|
|
1769
|
+
if (includeRoles.length > 0) {
|
|
1770
|
+
for (const roleId of includeRoles) {
|
|
1771
|
+
params.append('include_roles', roleId);
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
const data = await this.client.api.guilds(this.id)['prune/v2'].get({ query: Object.fromEntries(params) });
|
|
1776
|
+
return data.pruned;
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
/**
|
|
1780
|
+
* Prune inactive members from the guild
|
|
1781
|
+
* @param {number} [days=7] Number of days of inactivity
|
|
1782
|
+
* @param {string[]} [includeRoles=[]] Role IDs to include in the prune
|
|
1783
|
+
* @param {boolean} [computePruneCount=false] Whether to return the number of pruned members
|
|
1784
|
+
* @returns {Promise<number|null>} The number of pruned members, or null if computePruneCount is false
|
|
1785
|
+
*/
|
|
1786
|
+
async pruneMembers(days = 7, includeRoles = [], computePruneCount = false) {
|
|
1787
|
+
const data = await this.client.api.guilds(this.id).prune.post({
|
|
1788
|
+
data: {
|
|
1789
|
+
days,
|
|
1790
|
+
compute_prune_count: computePruneCount,
|
|
1791
|
+
include_roles: includeRoles
|
|
1792
|
+
}
|
|
1793
|
+
});
|
|
1794
|
+
return data.pruned ?? null;
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
|
|
1755
1798
|
/**
|
|
1756
1799
|
* Creates a collection of this guild's roles, sorted by their position and ids.
|
|
1757
1800
|
* @returns {Collection<Snowflake, Role>}
|
package/src/structures/User.js
CHANGED
|
@@ -465,6 +465,7 @@ class User extends Base {
|
|
|
465
465
|
this.globalName === user.global_name &&
|
|
466
466
|
this.avatar === user.avatar &&
|
|
467
467
|
this.flags?.bitfield === user.public_flags &&
|
|
468
|
+
('bio' in data ? this.bio = data.bio : true)
|
|
468
469
|
('banner' in user ? this.banner === user.banner : true) &&
|
|
469
470
|
('accent_color' in user ? this.accentColor === user.accent_color : true) &&
|
|
470
471
|
('avatar_decoration_data' in user
|
package/typings/index.d.ts
CHANGED
|
@@ -1716,6 +1716,8 @@ export class Guild extends AnonymousGuild {
|
|
|
1716
1716
|
rulesChannel?: GuildTextChannelResolvable,
|
|
1717
1717
|
reason?: string,
|
|
1718
1718
|
): Promise<this>;
|
|
1719
|
+
public pruneMembers(days?: number, includeRoles?: string[], computePruneCount?: boolean): Promise<number | null>;
|
|
1720
|
+
public pruneCount(days?: number, includeRoles?: string[]): Promise<number>;
|
|
1719
1721
|
public topEmojis(): Promise<Collection<number, GuildEmoji>>;
|
|
1720
1722
|
public setVanityCode(code?: string): Promise<this>;
|
|
1721
1723
|
public mute(options?: GuildMuteOptions): Promise<any>;
|
|
@@ -3994,6 +3996,7 @@ export class User extends PartialTextBasedChannel(Base) {
|
|
|
3994
3996
|
public readonly avatarDecoration: string | null;
|
|
3995
3997
|
public avatarDecorationData: AvatarDecorationData | null;
|
|
3996
3998
|
public banner: string | null | undefined;
|
|
3999
|
+
public bio?: string | null;
|
|
3997
4000
|
public bannerColor: string | null | undefined;
|
|
3998
4001
|
public bot: boolean;
|
|
3999
4002
|
public readonly createdAt: Date;
|