diff --git a/package.json b/package.json index c52de34..7d326da 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discord.js-selfbot-v13", - "version": "1.3.1", + "version": "1.3.2", "description": "A unofficial discord.js fork for creating selfbots [Based on discord.js v13]", "main": "./src/index.js", "types": "./typings/index.d.ts", diff --git a/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js b/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js new file mode 100644 index 00000000..950678e --- /dev/null +++ b/src/client/websocket/handlers/GUILD_MEMBER_LIST_UPDATE.js @@ -0,0 +1,34 @@ +'use strict'; + +const { Collection } = require('@discordjs/collection'); +const { Events } = require('../../../util/Constants'); + +module.exports = (client, { d: data }) => { + // console.log(data); + // console.log(data.ops[0]) + const guild = client.guilds.cache.get(data.guild_id); + if (!guild) return; + const members = new Collection(); + for (const object of data.ops) { + if (object.op == 'SYNC') { + for (const member_ of object.items) { + const member = member_.member; + if (!member) continue; + members.set(member.user.id, guild.members._add(member)); + if (member.presence) + guild.presences._add(Object.assign(member.presence, { guild })); + } + } else if (object.op == 'INVALIDATE') { + console.warn(`Invalidate [${object.range[0]}, ${object.range[1]}]`); + } else if (object.op == 'UPDATE' || object.op == 'INSERT') { + const member = object.item.member; + if (!member) continue; + members.set(member.user.id, guild.members._add(member)); + if (member.presence) + guild.presences._add(Object.assign(member.presence, { guild })); + } else if (object.op == 'DELETE') { + // nothing; + } + } + client.emit(Events.GUILD_MEMBER_LIST_UPDATE, members, guild, data); +}; diff --git a/src/client/websocket/handlers/READY.js b/src/client/websocket/handlers/READY.js index 3b81f8a..354c190 100644 --- a/src/client/websocket/handlers/READY.js +++ b/src/client/websocket/handlers/READY.js @@ -52,6 +52,11 @@ module.exports = (client, { d: data }, shard) => { client.users.cache.set(client.user.id, client.user); } + console.log(` +${chalk.yellow( + `Can you take a look at this notice and give me your opinion?\nhttps://github.com/aiko-chan-ai/discord.js-selfbot-v13/issues/29`, +)}`); + client.user.setAFK(false); client.setting.fetch().then(async (res) => { diff --git a/src/client/websocket/handlers/index.js b/src/client/websocket/handlers/index.js index 65880ad..e37b01f 100644 --- a/src/client/websocket/handlers/index.js +++ b/src/client/websocket/handlers/index.js @@ -1,61 +1,68 @@ 'use strict'; const handlers = Object.fromEntries([ - ['READY', require('./READY')], - ['RESUMED', require('./RESUMED')], - ['APPLICATION_COMMAND_CREATE', require('./APPLICATION_COMMAND_CREATE')], - ['APPLICATION_COMMAND_DELETE', require('./APPLICATION_COMMAND_DELETE')], - ['APPLICATION_COMMAND_UPDATE', require('./APPLICATION_COMMAND_UPDATE')], - ['GUILD_CREATE', require('./GUILD_CREATE')], - ['GUILD_DELETE', require('./GUILD_DELETE')], - ['GUILD_UPDATE', require('./GUILD_UPDATE')], - ['INVITE_CREATE', require('./INVITE_CREATE')], - ['INVITE_DELETE', require('./INVITE_DELETE')], - ['GUILD_MEMBER_ADD', require('./GUILD_MEMBER_ADD')], - ['GUILD_MEMBER_REMOVE', require('./GUILD_MEMBER_REMOVE')], - ['GUILD_MEMBER_UPDATE', require('./GUILD_MEMBER_UPDATE')], - ['GUILD_MEMBERS_CHUNK', require('./GUILD_MEMBERS_CHUNK')], + ['READY', require('./READY')], + ['RESUMED', require('./RESUMED')], + ['APPLICATION_COMMAND_CREATE', require('./APPLICATION_COMMAND_CREATE')], + ['APPLICATION_COMMAND_DELETE', require('./APPLICATION_COMMAND_DELETE')], + ['APPLICATION_COMMAND_UPDATE', require('./APPLICATION_COMMAND_UPDATE')], + ['GUILD_CREATE', require('./GUILD_CREATE')], + ['GUILD_DELETE', require('./GUILD_DELETE')], + ['GUILD_UPDATE', require('./GUILD_UPDATE')], + ['INVITE_CREATE', require('./INVITE_CREATE')], + ['INVITE_DELETE', require('./INVITE_DELETE')], + ['GUILD_MEMBER_ADD', require('./GUILD_MEMBER_ADD')], + ['GUILD_MEMBER_REMOVE', require('./GUILD_MEMBER_REMOVE')], + ['GUILD_MEMBER_UPDATE', require('./GUILD_MEMBER_UPDATE')], + ['GUILD_MEMBERS_CHUNK', require('./GUILD_MEMBERS_CHUNK')], + ['GUILD_MEMBER_LIST_UPDATE', require('./GUILD_MEMBER_LIST_UPDATE.js')], ['GUILD_INTEGRATIONS_UPDATE', require('./GUILD_INTEGRATIONS_UPDATE')], - ['GUILD_ROLE_CREATE', require('./GUILD_ROLE_CREATE')], - ['GUILD_ROLE_DELETE', require('./GUILD_ROLE_DELETE')], - ['GUILD_ROLE_UPDATE', require('./GUILD_ROLE_UPDATE')], - ['GUILD_BAN_ADD', require('./GUILD_BAN_ADD')], - ['GUILD_BAN_REMOVE', require('./GUILD_BAN_REMOVE')], - ['GUILD_EMOJIS_UPDATE', require('./GUILD_EMOJIS_UPDATE')], - ['CHANNEL_CREATE', require('./CHANNEL_CREATE')], - ['CHANNEL_DELETE', require('./CHANNEL_DELETE')], - ['CHANNEL_UPDATE', require('./CHANNEL_UPDATE')], - ['CHANNEL_PINS_UPDATE', require('./CHANNEL_PINS_UPDATE')], - ['MESSAGE_CREATE', require('./MESSAGE_CREATE')], - ['MESSAGE_DELETE', require('./MESSAGE_DELETE')], - ['MESSAGE_UPDATE', require('./MESSAGE_UPDATE')], - ['MESSAGE_DELETE_BULK', require('./MESSAGE_DELETE_BULK')], - ['MESSAGE_REACTION_ADD', require('./MESSAGE_REACTION_ADD')], - ['MESSAGE_REACTION_REMOVE', require('./MESSAGE_REACTION_REMOVE')], - ['MESSAGE_REACTION_REMOVE_ALL', require('./MESSAGE_REACTION_REMOVE_ALL')], - ['MESSAGE_REACTION_REMOVE_EMOJI', require('./MESSAGE_REACTION_REMOVE_EMOJI')], - ['THREAD_CREATE', require('./THREAD_CREATE')], - ['THREAD_UPDATE', require('./THREAD_UPDATE')], - ['THREAD_DELETE', require('./THREAD_DELETE')], - ['THREAD_LIST_SYNC', require('./THREAD_LIST_SYNC')], - ['THREAD_MEMBER_UPDATE', require('./THREAD_MEMBER_UPDATE')], - ['THREAD_MEMBERS_UPDATE', require('./THREAD_MEMBERS_UPDATE')], - ['USER_UPDATE', require('./USER_UPDATE')], - ['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')], - ['TYPING_START', require('./TYPING_START')], - ['VOICE_STATE_UPDATE', require('./VOICE_STATE_UPDATE')], - ['VOICE_SERVER_UPDATE', require('./VOICE_SERVER_UPDATE')], - ['WEBHOOKS_UPDATE', require('./WEBHOOKS_UPDATE')], - ['INTERACTION_CREATE', require('./INTERACTION_CREATE')], - ['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')], - ['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')], - ['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')], - ['GUILD_STICKERS_UPDATE', require('./GUILD_STICKERS_UPDATE')], - ['GUILD_SCHEDULED_EVENT_CREATE', require('./GUILD_SCHEDULED_EVENT_CREATE')], - ['GUILD_SCHEDULED_EVENT_UPDATE', require('./GUILD_SCHEDULED_EVENT_UPDATE')], - ['GUILD_SCHEDULED_EVENT_DELETE', require('./GUILD_SCHEDULED_EVENT_DELETE')], - ['GUILD_SCHEDULED_EVENT_USER_ADD', require('./GUILD_SCHEDULED_EVENT_USER_ADD')], - ['GUILD_SCHEDULED_EVENT_USER_REMOVE', require('./GUILD_SCHEDULED_EVENT_USER_REMOVE')], + ['GUILD_ROLE_CREATE', require('./GUILD_ROLE_CREATE')], + ['GUILD_ROLE_DELETE', require('./GUILD_ROLE_DELETE')], + ['GUILD_ROLE_UPDATE', require('./GUILD_ROLE_UPDATE')], + ['GUILD_BAN_ADD', require('./GUILD_BAN_ADD')], + ['GUILD_BAN_REMOVE', require('./GUILD_BAN_REMOVE')], + ['GUILD_EMOJIS_UPDATE', require('./GUILD_EMOJIS_UPDATE')], + ['CHANNEL_CREATE', require('./CHANNEL_CREATE')], + ['CHANNEL_DELETE', require('./CHANNEL_DELETE')], + ['CHANNEL_UPDATE', require('./CHANNEL_UPDATE')], + ['CHANNEL_PINS_UPDATE', require('./CHANNEL_PINS_UPDATE')], + ['MESSAGE_CREATE', require('./MESSAGE_CREATE')], + ['MESSAGE_DELETE', require('./MESSAGE_DELETE')], + ['MESSAGE_UPDATE', require('./MESSAGE_UPDATE')], + ['MESSAGE_DELETE_BULK', require('./MESSAGE_DELETE_BULK')], + ['MESSAGE_REACTION_ADD', require('./MESSAGE_REACTION_ADD')], + ['MESSAGE_REACTION_REMOVE', require('./MESSAGE_REACTION_REMOVE')], + ['MESSAGE_REACTION_REMOVE_ALL', require('./MESSAGE_REACTION_REMOVE_ALL')], + ['MESSAGE_REACTION_REMOVE_EMOJI', require('./MESSAGE_REACTION_REMOVE_EMOJI')], + ['THREAD_CREATE', require('./THREAD_CREATE')], + ['THREAD_UPDATE', require('./THREAD_UPDATE')], + ['THREAD_DELETE', require('./THREAD_DELETE')], + ['THREAD_LIST_SYNC', require('./THREAD_LIST_SYNC')], + ['THREAD_MEMBER_UPDATE', require('./THREAD_MEMBER_UPDATE')], + ['THREAD_MEMBERS_UPDATE', require('./THREAD_MEMBERS_UPDATE')], + ['USER_UPDATE', require('./USER_UPDATE')], + ['PRESENCE_UPDATE', require('./PRESENCE_UPDATE')], + ['TYPING_START', require('./TYPING_START')], + ['VOICE_STATE_UPDATE', require('./VOICE_STATE_UPDATE')], + ['VOICE_SERVER_UPDATE', require('./VOICE_SERVER_UPDATE')], + ['WEBHOOKS_UPDATE', require('./WEBHOOKS_UPDATE')], + ['INTERACTION_CREATE', require('./INTERACTION_CREATE')], + ['STAGE_INSTANCE_CREATE', require('./STAGE_INSTANCE_CREATE')], + ['STAGE_INSTANCE_UPDATE', require('./STAGE_INSTANCE_UPDATE')], + ['STAGE_INSTANCE_DELETE', require('./STAGE_INSTANCE_DELETE')], + ['GUILD_STICKERS_UPDATE', require('./GUILD_STICKERS_UPDATE')], + ['GUILD_SCHEDULED_EVENT_CREATE', require('./GUILD_SCHEDULED_EVENT_CREATE')], + ['GUILD_SCHEDULED_EVENT_UPDATE', require('./GUILD_SCHEDULED_EVENT_UPDATE')], + ['GUILD_SCHEDULED_EVENT_DELETE', require('./GUILD_SCHEDULED_EVENT_DELETE')], + [ + 'GUILD_SCHEDULED_EVENT_USER_ADD', + require('./GUILD_SCHEDULED_EVENT_USER_ADD'), + ], + [ + 'GUILD_SCHEDULED_EVENT_USER_REMOVE', + require('./GUILD_SCHEDULED_EVENT_USER_REMOVE'), + ], ]); module.exports = handlers; diff --git a/src/errors/Messages.js b/src/errors/Messages.js index 625b891..d8dbe5e 100644 --- a/src/errors/Messages.js +++ b/src/errors/Messages.js @@ -206,6 +206,7 @@ const Messages = { MESSAGE_ID_NOT_FOUND: 'Message ID not found', MESSAGE_EMBED_LINK_LENGTH: 'Message content with embed link length is too long', + GUILD_MEMBERS_FETCH: (msg) => `${msg}` }; for (const [name, message] of Object.entries(Messages)) register(name, message); diff --git a/src/managers/GuildMemberManager.js b/src/managers/GuildMemberManager.js index 9a1ddb9..aea350e 100644 --- a/src/managers/GuildMemberManager.js +++ b/src/managers/GuildMemberManager.js @@ -419,17 +419,67 @@ class GuildMemberManager extends CachedManager { return new Promise((resolve, reject) => { if (!query && !user_ids) query = ''; if (nonce.length > 32) throw new RangeError('MEMBER_FETCH_NONCE_LENGTH'); - this.guild.shard.send({ - op: Opcodes.REQUEST_GUILD_MEMBERS, - d: { - guild_id: this.guild.id, - presences, - user_ids, - query, - nonce, - limit, - }, - }); + if (this.guild.me.permissions.has('ADMINISTRATOR') || this.guild.me.permissions.has('KICK_MEMBERS') || this.guild.me.permissions.has('BAN_MEMBERS') || this.guild.me.permissions.has('MANAGE_ROLES')) { + this.guild.shard.send({ + op: Opcodes.REQUEST_GUILD_MEMBERS, + d: { + guild_id: this.guild.id, + presences, + user_ids, + query, + nonce, + limit, + }, + }); + } else { + console.log('send lazy quest') + let channel; + let channels = this.guild.channels.cache.filter(c => c.isText()); + channels = channels.filter(c => c.permissionsFor(this.guild.me).has('VIEW_CHANNEL')); + if (!channels.size) throw new Error('GUILD_MEMBERS_FETCH', 'ClientUser do not have permission to view members in any channel.'); + const channels_allowed_everyone = channels.filter((c) => + c.permissionsFor(this.guild.roles.everyone).has('VIEW_CHANNEL'), + ); + channel = channels_allowed_everyone.first() ?? channels.first(); + // create array limit [0, 99] + const list = []; + let allMember = this.guild.memberCount; + if (allMember < 100) { + list.push([[0, 99]]); + } else if (allMember < 200) { + list.push([[0, 99], [100, 199]]); + } else if (allMember < 300) { + list.push([[0, 99], [100, 199], [200, 299]]); + } else { + let x = 100; + for (let i = 0; i < allMember; i++) { + if (x > allMember) { + i = allMember; + continue; + } + list.push([ + [0, 99], + [x, x + 99], + [x + 100, x + 199], + ]); + x = x + 200; + } + } + Promise.all(list.map(async (l) => { + this.guild.shard.send({ + op: Opcodes.LAZY_REQUEST, + d: { + guild_id: this.guild.id, + typing: true, + threads: false, + activities: true, + channels: { + [channel.id]: l, + }, + }, + }); + })) + } const fetchedMembers = new Collection(); let i = 0; const handler = (members, _, chunk) => { @@ -442,6 +492,7 @@ class GuildMemberManager extends CachedManager { if (members.size < 1_000 || (limit && fetchedMembers.size >= limit) || i === chunk.count) { clearTimeout(timeout); this.client.removeListener(Events.GUILD_MEMBERS_CHUNK, handler); + this.client.removeListener(Events.GUILD_MEMBER_LIST_UPDATE, handler); this.client.decrementMaxListeners(); let fetched = fetchedMembers; if (user_ids && !Array.isArray(user_ids) && fetched.size) fetched = fetched.first(); @@ -450,11 +501,13 @@ class GuildMemberManager extends CachedManager { }; const timeout = setTimeout(() => { this.client.removeListener(Events.GUILD_MEMBERS_CHUNK, handler); + this.client.removeListener(Events.GUILD_MEMBER_LIST_UPDATE, handler); this.client.decrementMaxListeners(); reject(new Error('GUILD_MEMBERS_TIMEOUT')); }, time).unref(); this.client.incrementMaxListeners(); this.client.on(Events.GUILD_MEMBERS_CHUNK, handler); + this.client.on(Events.GUILD_MEMBER_LIST_UPDATE, handler); }); } } diff --git a/src/util/Constants.js b/src/util/Constants.js index 1cd4736..78a1a56 100644 --- a/src/util/Constants.js +++ b/src/util/Constants.js @@ -254,18 +254,33 @@ exports.Status = { }; exports.Opcodes = { - DISPATCH: 0, - HEARTBEAT: 1, - IDENTIFY: 2, - STATUS_UPDATE: 3, - VOICE_STATE_UPDATE: 4, - VOICE_GUILD_PING: 5, - RESUME: 6, - RECONNECT: 7, - REQUEST_GUILD_MEMBERS: 8, - INVALID_SESSION: 9, - HELLO: 10, - HEARTBEAT_ACK: 11, + DISPATCH: 0, // # Receive dispatches an event + HEARTBEAT: 1, // # Send/Receive used for ping checking + IDENTIFY: 2, // # Send used for client handshake + STATUS_UPDATE: 3, // # Send used to update the client status + VOICE_STATE_UPDATE: 4, // # Send used to join/move/leave voice channels + VOICE_GUILD_PING: 5, // # Send used for voice ping checking + RESUME: 6, // # Send used to resume a closed connection + RECONNECT: 7, // # Receive used to tell when to reconnect (sometimes...) + REQUEST_GUILD_MEMBERS: 8, // # Send used to request guild members (when searching for members in the search bar of a guild) + INVALID_SESSION: 9, // # Receive used to notify client they have an invalid session id + HELLO: 10, // # Receive sent immediately after connecting, contains heartbeat and server debug information + HEARTBEAT_ACK: 11, // # Sent immediately following a client heartbeat that was received + // GUILD_SYNC: 12, // # Receive guild_sync but not used anymore + /** Add some opcode from Discum + /* @extends https://github.com/Merubokkusu/Discord-S.C.U.M/blob/master/discum/gateway/gateway.py#L56 + */ + DM_UPDATE: 13, // # Send used to get dm features + LAZY_REQUEST: 14, // # Send discord responds back with GUILD_MEMBER_LIST_UPDATE type SYNC... + LOBBY_CONNECT: 15, + LOBBY_DISCONNECT: 16, + LOBBY_VOICE_STATE_UPDATE: 17, // # Receive + STREAM_CREATE: 18, + STREAM_DELETE: 19, + STREAM_WATCH: 20, + STREAM_PING: 21, // # Send + STREAM_SET_PAUSED: 22, + REQUEST_APPLICATION_COMMANDS: 24, // # Send request application/bot cmds (user, message, and slash cmds) }; exports.Events = { @@ -295,6 +310,7 @@ exports.Events = { GUILD_MEMBER_UPDATE: 'guildMemberUpdate', GUILD_MEMBER_AVAILABLE: 'guildMemberAvailable', GUILD_MEMBERS_CHUNK: 'guildMembersChunk', + GUILD_MEMBER_LIST_UPDATE: 'guildMemberListUpdate', GUILD_INTEGRATIONS_UPDATE: 'guildIntegrationsUpdate', GUILD_ROLE_CREATE: 'roleCreate', GUILD_ROLE_DELETE: 'roleDelete',