diff --git a/README.md b/README.md index 4fa83ca..9f5aeff 100644 --- a/README.md +++ b/README.md @@ -66,4 +66,7 @@ client.login('token'); - Thanks to . [TheDevYellowy](https://github.com/TheDevYellowy/) for patching this module! ## Need help? -Contact me in Discord [Shiraori#1782] (UserID: 721746046543331449) \ No newline at end of file +Contact me in Discord [Shiraori#1782] (UserID: 721746046543331449) + +## . Vietnamese +- Tóm lại là module này dùng Discord.js v13, API v9 nên chưa chết sớm đâu, cứ dùng đi =)) \ No newline at end of file diff --git a/package.json b/package.json index 84db8e7..33d60a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "discord.js-selfbot-v13", - "version": "0.0.2", + "version": "0.0.3", "description": "A unofficial discord.js fork for creating selfbots [Based on discord.js v13]", "main": "./src/index.js", "types": "./typings/index.d.ts", @@ -46,6 +46,7 @@ "@types/ws": "^8.5.2", "discord-api-types": "^0.27.3", "form-data": "^4.0.0", + "lodash": "^4.17.21", "lodash.snakecase": "^4.1.1", "node-fetch": "^3.2.2", "undici": "^4.15.0", diff --git a/src/client/websocket/handlers/READY.js b/src/client/websocket/handlers/READY.js index 97b99ef..f7db407 100644 --- a/src/client/websocket/handlers/READY.js +++ b/src/client/websocket/handlers/READY.js @@ -5,7 +5,7 @@ const User = require('../../../structures/User'); let ClientUser; module.exports = (client, { d: data }, shard) => { - //console.log(data); + // console.log(data); client.session_id = data.session_id; if (client.user) { @@ -18,6 +18,8 @@ module.exports = (client, { d: data }, shard) => { client.user.setAFK(true); + client.setting.fetch(); + for (const guild of data.guilds) { guild.shardId = shard.id; client.guilds._add(guild); diff --git a/src/errors/Messages.js b/src/errors/Messages.js index ae526a6..483fcbb 100644 --- a/src/errors/Messages.js +++ b/src/errors/Messages.js @@ -186,6 +186,8 @@ const Messages = { INVALID_BOT_METHOD: `Bot accounts cannot use this method`, INVALID_USER_METHOD: `User accounts cannot use this method`, INVALID_LOCALE: 'Unable to select this location', + FOLDER_NOT_FOUND: 'Server directory not found', + FOLDER_POSITION_INVALID: 'The server index in the directory is invalid', }; Messages.AuthenticationFailed = Messages.TOKEN_INVALID; diff --git a/src/managers/ClientUserSettingManager.js b/src/managers/ClientUserSettingManager.js index c00dc6a..d3654ac 100644 --- a/src/managers/ClientUserSettingManager.js +++ b/src/managers/ClientUserSettingManager.js @@ -3,6 +3,7 @@ const CachedManager = require('./CachedManager'); const { default: Collection } = require('@discordjs/collection'); const { Error, TypeError } = require('../errors/DJSError'); +const { remove } = require('lodash'); /** * Manages API methods for users and stores their cache. * @extends {CachedManager} @@ -67,6 +68,11 @@ class ClientUserSettingManager extends CachedManager { // Guild folder and position this.guildMetadata = new Collection(); } + /** + * + * @param {Object} data Raw Data to patch + * @private + */ _patch(data) { this.rawSetting = data; if ('locale' in data) { @@ -177,7 +183,17 @@ class ClientUserSettingManager extends CachedManager { async setTheme(value) { if (this.client.bot) throw new Error('INVALID_BOT_METHOD'); const validValues = ['dark', 'light']; - if (typeof value !== 'string' && typeof value !== 'null' && typeof value !== 'undefined') throw new TypeError('INVALID_TYPE', 'value', 'string | null | undefined', true); + if ( + typeof value !== 'string' && + typeof value !== 'null' && + typeof value !== 'undefined' + ) + throw new TypeError( + 'INVALID_TYPE', + 'value', + 'string | null | undefined', + true, + ); if (!validValues.includes(value)) { value == validValues[0] ? (value = validValues[1]) @@ -225,7 +241,8 @@ class ClientUserSettingManager extends CachedManager { */ async setLocale(value) { if (this.client.bot) throw new Error('INVALID_BOT_METHOD'); - if (typeof value !== 'string') throw new TypeError('INVALID_TYPE', 'value', 'string', true); + if (typeof value !== 'string') + throw new TypeError('INVALID_TYPE', 'value', 'string', true); if (!localeObject[value]) throw new Error('INVALID_LOCALE'); if (localeObject[value] !== this.locale) { await this.edit({ locale: localeObject[value] }); @@ -233,6 +250,81 @@ class ClientUserSettingManager extends CachedManager { return this.locale; } // TODO: Guild positions & folders + // Change Index in Array [Hidden] + /** + * + * @param {Array} array Array + * @param {Number} from Index1 + * @param {Number} to Index2 + * @returns {Array} + * @private + */ + _move(array, from, to) { + array.splice(to, 0, array.splice(from, 1)[0]); + return array; + } + // TODO: Move Guild + // folder to folder + // folder to home + // home to home + // home to folder + /** + * Change Guild Position (from * to Folder or Home) + * @param {GuildIDResolve} guildId guild.id + * @param {Number} newPosition Guild Position + * * **WARNING**: Type = `FOLDER`, newPosition is the guild's index in the Folder. + * @param {number} type Move to folder or home + * * `FOLDER`: 1 + * * `HOME`: 2 + * @param {FolderID} folderId If you want to move to folder + * @private + */ + async guildChangePosition(guildId, newPosition, type, folderId) { + // get Guild default position + // Escape + const oldGuildFolderPosition = this.rawSetting.guild_folders.findIndex( + (value) => value.guild_ids.includes(guildId), + ); + const newGuildFolderPosition = this.rawSetting.guild_folders.findIndex((value) => + value.guild_ids.includes(this.rawSetting.guild_positions[newPosition]), + ); + if (type == 2 || `${type}`.toUpperCase() == 'HOME') { + // Delete GuildID from Folder and create new Folder + // Check it is folder + const folder = this.rawSetting.guild_folders[oldGuildFolderPosition]; + if (folder.id) { + this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids = + this.rawSetting.guild_folders[ + oldGuildFolderPosition + ].guild_ids.filter((v) => v !== guildId); + } + this.rawSetting.guild_folders = this._move( + this.rawSetting.guild_folders, + oldGuildFolderPosition, + newGuildFolderPosition, + ); + this.rawSetting.guild_folders[newGuildFolderPosition].id = null; + } else if (type == 1 || `${type}`.toUpperCase() == 'FOLDER') { + // Delete GuildID from oldFolder + this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids = + this.rawSetting.guild_folders[oldGuildFolderPosition].guild_ids.filter( + (v) => v !== guildId, + ); + // Index new Folder + const folderIndex = this.rawSetting.guild_folders.findIndex( + (value) => value.id == folderId, + ); + const folder = this.rawSetting.guild_folders[folderIndex]; + folder.guild_ids.push(guildId); + folder.guild_ids = [...new Set(folder.guild_ids)]; + folder.guild_ids = this._move( + folder.guild_ids, + folder.guild_ids.findIndex((v) => v == guildId), + newPosition, + ); + } + this.edit({ guild_folders: this.rawSetting.guild_folders }); + } } module.exports = ClientUserSettingManager; diff --git a/src/structures/Guild.js b/src/structures/Guild.js index bd22e98..a9b919a 100644 --- a/src/structures/Guild.js +++ b/src/structures/Guild.js @@ -446,7 +446,8 @@ class Guild extends AnonymousGuild { */ get position() { return ( - this.client.setting.guildMetadata.get(this.id.toString())?.guildIndex || null + this.client.setting.guildMetadata.get(this.id.toString())?.guildIndex || + null ); } @@ -456,9 +457,7 @@ class Guild extends AnonymousGuild { * @readonly */ get folder() { - return ( - this.client.setting.guildMetadata.get(this.id.toString()) || {} - ); + return this.client.setting.guildMetadata.get(this.id.toString()) || {}; } /** @@ -1162,6 +1161,61 @@ class Guild extends AnonymousGuild { return this.edit({ rulesChannel }, reason); } + /** + * Change Guild Position (from * to Folder or Home) + * @param {number} position Guild Position + * * **WARNING**: Type = `FOLDER`, newPosition is the guild's index in the Folder. + * @param {String|Number} type Move to folder or home + * * `FOLDER`: 1 + * * `HOME`: 2 + * @param {String|Number|void|null} folderID If you want to move to folder + * @returns {Promise} + * @example + * // Move guild to folderID 123456, index 1 + * guild.setPosition(1, 'FOLDER', 123456) + * .then(guild => console.log(`Guild moved to folderID ${guild.folder.folderId}`)); + */ + async setPosition(position, type, folderID) { + if (type == 1 || `${type}`.toUpperCase() === 'FOLDER') { + folderID = folderID || this.folder.folderId; + if (!['number', 'string'].includes(typeof folderID)) + throw new TypeError( + 'INVALID_TYPE', + 'folderID', + 'String | Number', + ); + // Get Data from Folder ID + const folder = await this.client.setting.rawSetting.guild_folders.find( + (obj) => obj.id == folderID, + ); + if (!folder) throw new Error('FOLDER_NOT_FOUND'); + if (folder.guild_ids.length - 1 < position || position < 0) + throw new Error('FOLDER_POSITION_INVALID'); + if (position !== folder.guild_ids.indexOf(this.id)) { + await this.client.setting.guildChangePosition( + this.id, + position, + 1, + folderID, + ); + } + } else if (type == 2 || `${type}`.toUpperCase() === 'HOME') { + if (this.client.setting.guild_positions - 1 < position || position < 0) + throw new Error('FOLDER_POSITION_INVALID'); + if (position !== this.position) { + await this.client.setting.guildChangePosition( + this.id, + position, + 2, + null, + ); + } + } else { + throw new TypeError('INVALID_TYPE', 'type', '`Folder`| `Home`'); + } + return this; + } + /** * Edits the community updates channel of the guild. * @param {TextChannelResolvable} publicUpdatesChannel The new community updates channel diff --git a/typings/index.d.ts b/typings/index.d.ts index b6ba788..110db31 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -968,6 +968,7 @@ export class Guild extends AnonymousGuild { public setIcon(icon: BufferResolvable | Base64Resolvable | null, reason?: string): Promise; public setName(name: string, reason?: string): Promise; public setOwner(owner: GuildMemberResolvable, reason?: string): Promise; + public setPosition(position: number, type: FOLDER | HOME, folderID?: FolderID): Promise; public setPreferredLocale(preferredLocale: string, reason?: string): Promise; public setPublicUpdatesChannel(publicUpdatesChannel: TextChannelResolvable | null, reason?: string): Promise; /** @deprecated Use {@link RoleManager.setPositions} instead */