diff --git a/package.json b/package.json
index 5f1af9a..bdf9019 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "discord.js-selfbot-v13",
- "version": "0.2.3",
+ "version": "0.2.4",
"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/structures/User.js b/src/structures/User.js
index 762dfcb..c4d76d4 100644
--- a/src/structures/User.js
+++ b/src/structures/User.js
@@ -13,167 +13,170 @@ const TextBasedChannel = require('./interfaces/TextBasedChannel');
* @extends {Base}
*/
class User extends Base {
- constructor(client, data) {
- super(client);
+ constructor(client, data) {
+ super(client);
- /**
- * The user's id
- * @type {Snowflake}
- */
- this.id = data.id;
+ /**
+ * The user's id
+ * @type {Snowflake}
+ */
+ this.id = data.id;
- this.bot = null;
+ this.bot = null;
- this.system = null;
+ this.system = null;
- this.flags = null;
+ this.flags = null;
- this.friend = client.friends.cache.has(this.id);
+ this.friend = client.friends.cache.has(this.id);
- this.blocked = client.blocked.cache.has(this.id);
+ this.blocked = client.blocked.cache.has(this.id);
- // Code written by https://github.com/aiko-chan-ai
- this.connectedAccounds = [];
- this.premiumSince = null;
- this.premiumGuildSince = null;
- this.mutualGuilds = new Collection();
+ // Code written by https://github.com/aiko-chan-ai
+ this.connectedAccounds = [];
+ this.premiumSince = null;
+ this.premiumGuildSince = null;
+ this.mutualGuilds = new Collection();
- this._patch(data);
- }
+ this._patch(data);
+ }
- _patch(data) {
- if ('username' in data) {
- /**
- * The username of the user
- * @type {?string}
- */
- this.username = data.username;
- } else {
- this.username ??= null;
- }
+ _patch(data) {
+ if ('username' in data) {
+ /**
+ * The username of the user
+ * @type {?string}
+ */
+ this.username = data.username;
+ } else {
+ this.username ??= null;
+ }
- if ('bot' in data) {
- /**
- * Whether or not the user is a bot
- * @type {?boolean}
- */
- this.bot = Boolean(data.bot);
- } else if (!this.partial && typeof this.bot !== 'boolean') {
- this.bot = false;
- }
+ if ('bot' in data) {
+ /**
+ * Whether or not the user is a bot
+ * @type {?boolean}
+ */
+ this.bot = Boolean(data.bot);
+ } else if (!this.partial && typeof this.bot !== 'boolean') {
+ this.bot = false;
+ }
- if ('discriminator' in data) {
- /**
- * A discriminator based on username for the user
- * @type {?string}
- */
- this.discriminator = data.discriminator;
- } else {
- this.discriminator ??= null;
- }
+ if ('discriminator' in data) {
+ /**
+ * A discriminator based on username for the user
+ * @type {?string}
+ */
+ this.discriminator = data.discriminator;
+ } else {
+ this.discriminator ??= null;
+ }
- if ('avatar' in data) {
- /**
- * The user avatar's hash
- * @type {?string}
- */
- this.avatar = data.avatar;
- } else {
- this.avatar ??= null;
- }
+ if ('avatar' in data) {
+ /**
+ * The user avatar's hash
+ * @type {?string}
+ */
+ this.avatar = data.avatar;
+ } else {
+ this.avatar ??= null;
+ }
- if ('banner' in data) {
- /**
- * The user banner's hash
- * The user must be force fetched for this property to be present or be updated
- * @type {?string}
- */
- this.banner = data.banner;
- } else if (this.banner !== null) {
- this.banner ??= undefined;
- }
+ if ('banner' in data) {
+ /**
+ * The user banner's hash
+ * The user must be force fetched for this property to be present or be updated
+ * @type {?string}
+ */
+ this.banner = data.banner;
+ } else if (this.banner !== null) {
+ this.banner ??= undefined;
+ }
- if ('accent_color' in data) {
- /**
- * The base 10 accent color of the user's banner
- * The user must be force fetched for this property to be present or be updated
- * @type {?number}
- */
- this.accentColor = data.accent_color;
- } else if (this.accentColor !== null) {
- this.accentColor ??= undefined;
- }
+ if ('accent_color' in data) {
+ /**
+ * The base 10 accent color of the user's banner
+ * The user must be force fetched for this property to be present or be updated
+ * @type {?number}
+ */
+ this.accentColor = data.accent_color;
+ } else if (this.accentColor !== null) {
+ this.accentColor ??= undefined;
+ }
- if ('system' in data) {
- /**
- * Whether the user is an Official Discord System user (part of the urgent message system)
- * @type {?boolean}
- */
- this.system = Boolean(data.system);
- } else if (!this.partial && typeof this.system !== 'boolean') {
- this.system = false;
- }
+ if ('system' in data) {
+ /**
+ * Whether the user is an Official Discord System user (part of the urgent message system)
+ * @type {?boolean}
+ */
+ this.system = Boolean(data.system);
+ } else if (!this.partial && typeof this.system !== 'boolean') {
+ this.system = false;
+ }
- if ('public_flags' in data) {
- /**
- * The flags for this user
- * @type {?UserFlagsBitField}
- */
- this.flags = new UserFlagsBitField(data.public_flags);
- }
- }
+ if ('public_flags' in data) {
+ /**
+ * The flags for this user
+ * @type {?UserFlagsBitField}
+ */
+ this.flags = new UserFlagsBitField(data.public_flags);
+ }
+ }
- // Code written by https://github.com/aiko-chan-ai
- _ProfilePatch(data) {
- if(!data) return;
+ // Code written by https://github.com/aiko-chan-ai
+ _ProfilePatch(data) {
+ if (!data) return;
- if(data.connected_accounts.length > 0) this.connectedAccounds = data.connected_accounts;
+ if (data.connected_accounts.length > 0)
+ this.connectedAccounds = data.connected_accounts;
- if('premium_since' in data) {
- const date = new Date(data.premium_since);
- this.premiumSince = date.getTime();
- }
+ if ('premium_since' in data) {
+ const date = new Date(data.premium_since);
+ this.premiumSince = date.getTime();
+ }
- if('premium_guild_since' in data) {
- const date = new Date(data.premium_guild_since);
- this.premiumGuildSince = date.getTime();
- }
+ if ('premium_guild_since' in data) {
+ const date = new Date(data.premium_guild_since);
+ this.premiumGuildSince = date.getTime();
+ }
- this.mutualGuilds = new Collection(data.mutual_guilds.map((obj) => [obj.id, obj]));
- }
+ this.mutualGuilds = new Collection(
+ data.mutual_guilds.map((obj) => [obj.id, obj]),
+ );
+ }
- /**
- * Get profile from Discord, if client is in a server with the target.
- *
Code written by https://github.com/aiko-chan-ai
- */
- async getProfile() {
- if(this.client.bot) throw new Error('INVALID_BOT_METHOD');
- try {
- const data = await this.client.api.users(this.id).profile.get();
- this._ProfilePatch(data);
- return this
- } catch (e) {
- throw e
- }
- }
+ /**
+ * Get profile from Discord, if client is in a server with the target.
+ *
Code written by https://github.com/aiko-chan-ai
+ */
+ async getProfile() {
+ if (this.client.bot) throw new Error('INVALID_BOT_METHOD');
+ try {
+ const data = await this.client.api.users(this.id).profile.get();
+ this._ProfilePatch(data);
+ return this;
+ } catch (e) {
+ throw e;
+ }
+ }
- /**
- * Friends the user and send Request [If no request]
- * @returns {Promise} the user object
- */
- async setFriend() {
- return await this.client.api
+ /**
+ * Friends the user and send Request [If no request]
+ * @returns {Promise} the user object
+ */
+ async setFriend() {
+ return await this.client.api
.user('@me')
.relationships[this.id].put({ data: { type: 1 } })
.then((_) => _);
- }
+ }
- /**
- * Send Friend Request to the user
- * @returns {Promise} the user object
- */
- async sendFriendRequest() {
- return await this.client.api
+ /**
+ * Send Friend Request to the user
+ * @returns {Promise} the user object
+ */
+ async sendFriendRequest() {
+ return await this.client.api
.users('@me')
.relationships.post({
data: {
@@ -182,247 +185,256 @@ class User extends Base {
},
})
.then((_) => _);
- }
- /**
- * Blocks the user
- * @returns {Promise} the user object
- */
- async setBlock() {
- return this.client.api
- .users('@me')
- .relationships[this.id].put({data:{type: 2}})
- .then(_ => _)
- }
+ }
+ /**
+ * Blocks the user
+ * @returns {Promise} the user object
+ */
+ async setBlock() {
+ return this.client.api
+ .users('@me')
+ .relationships[this.id].put({ data: { type: 2 } })
+ .then((_) => _);
+ }
- /**
- * Removes the user from your blocks list
- * @returns {Promise} the user object
- */
- async unBlock() {
- return this.client.api
- .users('@me')
- .relationships[this.id].delete
- .then(_ => _)
- }
+ /**
+ * Removes the user from your blocks list
+ * @returns {Promise} the user object
+ */
+ async unBlock() {
+ return this.client.api
+ .users('@me')
+ .relationships[this.id].delete.then((_) => _);
+ }
- /**
- * Removes the user from your friends list
- * @returns {Promise} the user object
- */
- async unFriend() {
- return this.client.api
- .users('@me')
- .relationships[this.id].delete
- .then(_ => _)
- }
+ /**
+ * Removes the user from your friends list
+ * @returns {Promise} the user object
+ */
+ async unFriend() {
+ return this.client.api
+ .users('@me')
+ .relationships[this.id].delete.then((_) => _);
+ }
- /**
- * Whether this User is a partial
- * @type {boolean}
- * @readonly
- */
- get partial() {
- return typeof this.username !== 'string';
- }
+ /**
+ * Whether this User is a partial
+ * @type {boolean}
+ * @readonly
+ */
+ get partial() {
+ return typeof this.username !== 'string';
+ }
- /**
- * The timestamp the user was created at
- * @type {number}
- * @readonly
- */
- get createdTimestamp() {
- return DiscordSnowflake.timestampFrom(this.id);
- }
+ /**
+ * The timestamp the user was created at
+ * @type {number}
+ * @readonly
+ */
+ get createdTimestamp() {
+ return DiscordSnowflake.timestampFrom(this.id);
+ }
- /**
- * The time the user was created at
- * @type {Date}
- * @readonly
- */
- get createdAt() {
- return new Date(this.createdTimestamp);
- }
+ /**
+ * The time the user was created at
+ * @type {Date}
+ * @readonly
+ */
+ get createdAt() {
+ return new Date(this.createdTimestamp);
+ }
- /**
- * A link to the user's avatar.
- * @param {ImageURLOptions} [options={}] Options for the image URL
- * @returns {?string}
- */
- avatarURL(options = {}) {
- return this.avatar && this.client.rest.cdn.avatar(this.id, this.avatar, options);
- }
+ /**
+ * A link to the user's avatar.
+ * @param {ImageURLOptions} [options={}] Options for the image URL
+ * @returns {?string}
+ */
+ avatarURL({ format, size, dynamic } = {}) {
+ if (!this.avatar) return null;
+ return this.client.rest.cdn.Avatar(
+ this.id,
+ this.avatar,
+ format,
+ size,
+ dynamic,
+ );
+ }
- /**
- * If the user is a bot then it'll return the slash commands else return null
- * @readonly
- */
- get slashCommands() {
- if(this.bot) {
- return this.client.api.applications(this.id).commands.get();
- } else return null;
- }
+ /**
+ * If the user is a bot then it'll return the slash commands else return null
+ * @readonly
+ */
+ get slashCommands() {
+ if (this.bot) {
+ return this.client.api.applications(this.id).commands.get();
+ } else return null;
+ }
- /**
- * A link to the user's default avatar
- * @type {string}
- * @readonly
- */
- get defaultAvatarURL() {
- return this.client.rest.cdn.defaultAvatar(this.discriminator % 5);
- }
+ /**
+ * A link to the user's default avatar
+ * @type {string}
+ * @readonly
+ */
+ get defaultAvatarURL() {
+ return this.client.rest.cdn.defaultAvatar(this.discriminator % 5);
+ }
- /**
- * A link to the user's avatar if they have one.
- * Otherwise a link to their default avatar will be returned.
- * @param {ImageURLOptions} [options={}] Options for the Image URL
- * @returns {string}
- */
- displayAvatarURL(options) {
- return this.avatarURL(options) ?? this.defaultAvatarURL;
- }
+ /**
+ * A link to the user's avatar if they have one.
+ * Otherwise a link to their default avatar will be returned.
+ * @param {ImageURLOptions} [options={}] Options for the Image URL
+ * @returns {string}
+ */
+ displayAvatarURL(options) {
+ return this.avatarURL(options) ?? this.defaultAvatarURL;
+ }
- /**
- * The hexadecimal version of the user accent color, with a leading hash
- * The user must be force fetched for this property to be present
- * @type {?string}
- * @readonly
- */
- get hexAccentColor() {
- if (typeof this.accentColor !== 'number') return this.accentColor;
- return `#${this.accentColor.toString(16).padStart(6, '0')}`;
- }
+ /**
+ * The hexadecimal version of the user accent color, with a leading hash
+ * The user must be force fetched for this property to be present
+ * @type {?string}
+ * @readonly
+ */
+ get hexAccentColor() {
+ if (typeof this.accentColor !== 'number') return this.accentColor;
+ return `#${this.accentColor.toString(16).padStart(6, '0')}`;
+ }
- /**
- * A link to the user's banner. See {@link User#banner} for more info
- * @param {ImageURLOptions} [options={}] Options for the image URL
- * @returns {?string}
- */
- bannerURL(options = {}) {
- return this.banner && this.client.rest.cdn.banner(this.id, this.banner, options);
- }
+ /**
+ * A link to the user's banner. See {@link User#banner} for more info
+ * @param {ImageURLOptions} [options={}] Options for the image URL
+ * @returns {?string}
+ */
+ bannerURL(options = {}) {
+ return (
+ this.banner && this.client.rest.cdn.banner(this.id, this.banner, options)
+ );
+ }
- /**
- * The Discord "tag" (e.g. `hydrabolt#0001`) for this user
- * @type {?string}
- * @readonly
- */
- get tag() {
- return typeof this.username === 'string' ? `${this.username}#${this.discriminator}` : null;
- }
+ /**
+ * The Discord "tag" (e.g. `hydrabolt#0001`) for this user
+ * @type {?string}
+ * @readonly
+ */
+ get tag() {
+ return typeof this.username === 'string'
+ ? `${this.username}#${this.discriminator}`
+ : null;
+ }
- /**
- * The DM between the client's user and this user
- * @type {?DMChannel}
- * @readonly
- */
- get dmChannel() {
- return this.client.users.dmChannel(this.id);
- }
+ /**
+ * The DM between the client's user and this user
+ * @type {?DMChannel}
+ * @readonly
+ */
+ get dmChannel() {
+ return this.client.users.dmChannel(this.id);
+ }
- /**
- * Creates a DM channel between the client and the user.
- * @param {boolean} [force=false] Whether to skip the cache check and request the API
- * @returns {Promise}
- */
- createDM(force = false) {
- return this.client.users.createDM(this.id, force);
- }
+ /**
+ * Creates a DM channel between the client and the user.
+ * @param {boolean} [force=false] Whether to skip the cache check and request the API
+ * @returns {Promise}
+ */
+ createDM(force = false) {
+ return this.client.users.createDM(this.id, force);
+ }
- /**
- * Deletes a DM channel (if one exists) between the client and the user. Resolves with the channel if successful.
- * @returns {Promise}
- */
- deleteDM() {
- return this.client.users.deleteDM(this.id);
- }
+ /**
+ * Deletes a DM channel (if one exists) between the client and the user. Resolves with the channel if successful.
+ * @returns {Promise}
+ */
+ deleteDM() {
+ return this.client.users.deleteDM(this.id);
+ }
- /**
- * Checks if the user is equal to another.
- * It compares id, username, discriminator, avatar, banner, accent color, and bot flags.
- * It is recommended to compare equality by using `user.id === user2.id` unless you want to compare all properties.
- * @param {User} user User to compare with
- * @returns {boolean}
- */
- equals(user) {
- return (
- user &&
- this.id === user.id &&
- this.username === user.username &&
- this.discriminator === user.discriminator &&
- this.avatar === user.avatar &&
- this.flags?.bitfield === user.flags?.bitfield &&
- this.banner === user.banner &&
- this.accentColor === user.accentColor
- );
- }
+ /**
+ * Checks if the user is equal to another.
+ * It compares id, username, discriminator, avatar, banner, accent color, and bot flags.
+ * It is recommended to compare equality by using `user.id === user2.id` unless you want to compare all properties.
+ * @param {User} user User to compare with
+ * @returns {boolean}
+ */
+ equals(user) {
+ return (
+ user &&
+ this.id === user.id &&
+ this.username === user.username &&
+ this.discriminator === user.discriminator &&
+ this.avatar === user.avatar &&
+ this.flags?.bitfield === user.flags?.bitfield &&
+ this.banner === user.banner &&
+ this.accentColor === user.accentColor
+ );
+ }
- /**
- * Compares the user with an API user object
- * @param {APIUser} user The API user object to compare
- * @returns {boolean}
- * @private
- */
- _equals(user) {
- return (
- user &&
- this.id === user.id &&
- this.username === user.username &&
- this.discriminator === user.discriminator &&
- this.avatar === user.avatar &&
- this.flags?.bitfield === user.public_flags &&
- ('banner' in user ? this.banner === user.banner : true) &&
- ('accent_color' in user ? this.accentColor === user.accent_color : true)
- );
- }
+ /**
+ * Compares the user with an API user object
+ * @param {APIUser} user The API user object to compare
+ * @returns {boolean}
+ * @private
+ */
+ _equals(user) {
+ return (
+ user &&
+ this.id === user.id &&
+ this.username === user.username &&
+ this.discriminator === user.discriminator &&
+ this.avatar === user.avatar &&
+ this.flags?.bitfield === user.public_flags &&
+ ('banner' in user ? this.banner === user.banner : true) &&
+ ('accent_color' in user ? this.accentColor === user.accent_color : true)
+ );
+ }
- /**
- * Fetches this user's flags.
- * @param {boolean} [force=false] Whether to skip the cache check and request the API
- * @returns {Promise}
- */
- fetchFlags(force = false) {
- return this.client.users.fetchFlags(this.id, { force });
- }
+ /**
+ * Fetches this user's flags.
+ * @param {boolean} [force=false] Whether to skip the cache check and request the API
+ * @returns {Promise}
+ */
+ fetchFlags(force = false) {
+ return this.client.users.fetchFlags(this.id, { force });
+ }
- /**
- * Fetches this user.
- * @param {boolean} [force=true] Whether to skip the cache check and request the API
- * @returns {Promise}
- */
- fetch(force = true) {
- return this.client.users.fetch(this.id, { force });
- }
+ /**
+ * Fetches this user.
+ * @param {boolean} [force=true] Whether to skip the cache check and request the API
+ * @returns {Promise}
+ */
+ fetch(force = true) {
+ return this.client.users.fetch(this.id, { force });
+ }
- /**
- * When concatenated with a string, this automatically returns the user's mention instead of the User object.
- * @returns {string}
- * @example
- * // Logs: Hello from <@123456789012345678>!
- * console.log(`Hello from ${user}!`);
- */
- toString() {
- return `<@${this.id}>`;
- }
+ /**
+ * When concatenated with a string, this automatically returns the user's mention instead of the User object.
+ * @returns {string}
+ * @example
+ * // Logs: Hello from <@123456789012345678>!
+ * console.log(`Hello from ${user}!`);
+ */
+ toString() {
+ return `<@${this.id}>`;
+ }
- toJSON(...props) {
- const json = super.toJSON(
- {
- createdTimestamp: true,
- defaultAvatarURL: true,
- hexAccentColor: true,
- tag: true,
- },
- ...props,
- );
- json.avatarURL = this.avatarURL();
- json.displayAvatarURL = this.displayAvatarURL();
- json.bannerURL = this.banner ? this.bannerURL() : this.banner;
- return json;
- }
+ toJSON(...props) {
+ const json = super.toJSON(
+ {
+ createdTimestamp: true,
+ defaultAvatarURL: true,
+ hexAccentColor: true,
+ tag: true,
+ },
+ ...props,
+ );
+ json.avatarURL = this.avatarURL();
+ json.displayAvatarURL = this.displayAvatarURL();
+ json.bannerURL = this.banner ? this.bannerURL() : this.banner;
+ return json;
+ }
- // These are here only for documentation purposes - they are implemented by TextBasedChannel
- /* eslint-disable no-empty-function */
- send() {}
+ // These are here only for documentation purposes - they are implemented by TextBasedChannel
+ /* eslint-disable no-empty-function */
+ send() {}
}
TextBasedChannel.applyToClass(User);
diff --git a/src/util/Constants.js b/src/util/Constants.js
index 63a780a..6bbe129 100644
--- a/src/util/Constants.js
+++ b/src/util/Constants.js
@@ -200,6 +200,12 @@ exports.Events = {
GUILD_SCHEDULED_EVENT_USER_REMOVE: 'guildScheduledEventUserRemove',
};
+const AllowedImageFormats = ['webp', 'png', 'jpg', 'jpeg', 'gif'];
+
+const AllowedImageSizes = [
+ 16, 32, 56, 64, 96, 128, 256, 300, 512, 600, 1024, 2048, 4096,
+];
+
function makeImageUrl(root, { format = 'webp', size } = {}) {
if (!['undefined', 'number'].includes(typeof size)) throw new TypeError('INVALID_TYPE', 'size', 'number');
if (format && !AllowedImageFormats.includes(format)) throw new Error('IMAGE_FORMAT', format);
diff --git a/src/util/Options.js b/src/util/Options.js
index def5ee1..5be7be5 100644
--- a/src/util/Options.js
+++ b/src/util/Options.js
@@ -101,7 +101,7 @@ class Options extends null {
$browser: 'Chrome',
$device: 'ASUS ROG Phone 5',
},
- version: 9,
+ version: 10,
},
http: {
headers: {