Minor update

- feat(Client): redeemNitro & autoRedeemNitro
- fix(Modal): Reply modal bug
- fix(RichPresence): setAssetsImage bug
- refactor(RichPresence): Clean code
This commit is contained in:
March 7th 2022-07-09 19:47:00 +07:00
parent 0df013b2dc
commit 536a86a5f3
14 changed files with 88 additions and 7030 deletions

2
.gitignore vendored
View File

@ -81,3 +81,5 @@ deploy/deploy_key.pub
# Custom # Custom
data/ data/
update.mjs update.mjs
yarn.lock
package-lock.json

View File

@ -9,8 +9,8 @@ new Client({
checkUpdate: true, // Check Package Update (Bot Ready) [Enable Default] checkUpdate: true, // Check Package Update (Bot Ready) [Enable Default]
readyStatus: false, // Set Custom Status sync from Account (Bot Ready) [Disable Default] readyStatus: false, // Set Custom Status sync from Account (Bot Ready) [Disable Default]
autoCookie: true, // Auto added Cookie and Fingerprint [Enable Default](https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/DOCUMENT.md#http-options) autoCookie: true, // Auto added Cookie and Fingerprint [Enable Default](https://github.com/aiko-chan-ai/discord.js-selfbot-v13/blob/main/DOCUMENT.md#http-options)
autoRedeemNitro: true, // Automaticlly redeems nitro codes <NOTE: there is no cooldown on the auto redeem> [Enable Default] autoRedeemNitro: true, // Automaticlly redeems nitro codes <NOTE: there is no cooldown on the auto redeem> [Disable Default]
}) });
``` ```
## Client Functions ## Client Functions

View File

@ -1,8 +1,6 @@
## Custom Status and RPC ## Custom Status and RPC
<details open> <strong>Custom Status</strong>
<summary><strong>Click to show</strong></summary>
Custom Status
```js ```js
const r = new Discord.CustomStatus() const r = new Discord.CustomStatus()
@ -54,27 +52,39 @@ client.user.setActivity(r.toJSON());
<img src='https://cdn.discordapp.com/attachments/820557032016969751/994512258128420944/unknown.png'> <img src='https://cdn.discordapp.com/attachments/820557032016969751/994512258128420944/unknown.png'>
<strong>You can now add custom images for RPC !</strong>
<strong>New: You can now add custom images for RPC !</strong>
> Tutorial: > Tutorial:
+ Step 1: Send photos by embed.thumbnail + Step 1: Send image to Discord
```js <img src='https://cdn.discordapp.com/attachments/820557032016969751/995297572732284968/unknown.png'>
const embed = new MessageEmbed().setThumbnail('image url');
const msg = await channel.send({ embeds: [embed] });
```
+ Step 2: Get proxyURL from message.embeds[0].thumbnail.proxyURL
```js + Step 2: Get Image URL
const proxyURL = msg.embeds[0].thumbnail.proxyURL;
<img src='https://cdn.discordapp.com/attachments/820557032016969751/995298082474426418/unknown.png'>
```sh
Demo URL: https://cdn.discordapp.com/attachments/820557032016969751/991172011483218010/unknown.png
``` ```
+ Step 3: Put the URL in the constructor
+ Step 3: Replace `https://cdn.discordapp.com/` or `https://media.discordapp.net/` with `mp:`
```diff
- https://cdn.discordapp.com/attachments/820557032016969751/991172011483218010/unknown.png
- https://media.discordapp.net/attachments/820557032016969751/991172011483218010/unknown.png
+ mp:attachments/820557032016969751/991172011483218010/unknown.png
```
+ Step 4:
```js ```js
const r = new Discord.RichPresence() const r = new Discord.RichPresence()
.setApplicationId('817229550684471297') .setApplicationId('817229550684471297')
.setType('STREAMING') .setType('PLAYING')
.setURL('https://youtube.com/watch?v=dQw4w9WgXcQ') .setURL('https://youtube.com/watch?v=dQw4w9WgXcQ')
.setState('State') .setState('State')
.setName('Name') .setName('Name')
@ -85,7 +95,7 @@ const r = new Discord.RichPresence()
id: Discord.getUUID(), id: Discord.getUUID(),
}) })
.setStartTimestamp(Date.now()) .setStartTimestamp(Date.now())
.setAssetsLargeImage(proxyURL) .setAssetsLargeImage('mp:attachments/820557032016969751/991172011483218010/unknown.png')
.setAssetsLargeText('Youtube') .setAssetsLargeText('Youtube')
.setAssetsSmallImage('895316294222635008') .setAssetsSmallImage('895316294222635008')
.setAssetsSmallText('Bot') .setAssetsSmallText('Bot')
@ -93,5 +103,22 @@ const r = new Discord.RichPresence()
client.user.setActivity(r.toDiscord().game); client.user.setActivity(r.toDiscord().game);
``` ```
And you can change the status 5 times every 20 seconds! <img src='https://cdn.discordapp.com/attachments/820557032016969751/995301015257616414/unknown.png'>
</details>
<strong>How to get the Assets ID and Name of the bot (application) ?</strong>
- Bot:
```js
const bot = await client.users.fetch('BotId');
const asset = await bot.application.fetchAssets();
// asset: Array<ApplicationAsset>
// Document: https://discordjs-self-v13.netlify.app/#/docs/docs/main/typedef/ApplicationAsset
```
<img src='https://cdn.discordapp.com/attachments/820557032016969751/995307830028550204/unknown.png'>
- Application
> Using Browser (Chrome) with URL: `https://discord.com/api/v9/oauth2/applications/{applicationId}/assets`
<img src='https://cdn.discordapp.com/attachments/820557032016969751/995307606115618926/unknown.png'>
- More:
- You can change the status 5 times every 20 seconds!

File diff suppressed because one or more lines are too long

25
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "discord.js-selfbot-v13", "name": "discord.js-selfbot-v13",
"version": "2.3.66", "version": "2.3.67",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "discord.js-selfbot-v13", "name": "discord.js-selfbot-v13",
"version": "2.3.66", "version": "2.3.67",
"license": "GNU General Public License v3.0", "license": "GNU General Public License v3.0",
"dependencies": { "dependencies": {
"@aikochan2k6/qrcode-terminal": "^0.12.0", "@aikochan2k6/qrcode-terminal": "^0.12.0",
@ -6048,20 +6048,6 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true "dev": true
}, },
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/fstream": { "node_modules/fstream": {
"version": "1.0.12", "version": "1.0.12",
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
@ -17209,13 +17195,6 @@
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true "dev": true
}, },
"fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"optional": true
},
"fstream": { "fstream": {
"version": "1.0.12", "version": "1.0.12",
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",

View File

@ -1,6 +1,6 @@
{ {
"name": "discord.js-selfbot-v13", "name": "discord.js-selfbot-v13",
"version": "2.3.66", "version": "2.3.67",
"description": "A unofficial discord.js fork for creating selfbots [Based on discord.js v13]", "description": "A unofficial discord.js fork for creating selfbots [Based on discord.js v13]",
"main": "./src/index.js", "main": "./src/index.js",
"types": "./typings/index.d.ts", "types": "./typings/index.d.ts",

View File

@ -151,7 +151,7 @@ class Client extends BaseClient {
this.guilds = new GuildManager(this); this.guilds = new GuildManager(this);
/** /**
* All of the Channels that the client is currently handling, mapped by their ids - * All of the {@link Channel}s that the client is currently handling, mapped by their ids -
* as long as sharding isn't being used, this will be *every* channel in *every* guild the bot * as long as sharding isn't being used, this will be *every* channel in *every* guild the bot
* is a member of. Note that DM channels will not be initially cached, and thus not be present * is a member of. Note that DM channels will not be initially cached, and thus not be present
* in the Manager without their explicit fetching or use. * in the Manager without their explicit fetching or use.
@ -437,49 +437,43 @@ class Client extends BaseClient {
/** /**
* Automatically Redeem Nitro from raw message * Automatically Redeem Nitro from raw message
* @param {Message} message Discord Message * @param {Message} message Discord Message
* @param {Channel} channel Message Channel
*/ */
async autoRedeemNitro(message, channel) { async autoRedeemNitro(message) {
if (typeof message !== Message) return; if (typeof message !== Message) return;
await this.redeemNitro(message.content) await this.redeemNitro(message.content, message.channel, false);
} }
/** /**
* Redeem nitro from code or url * Redeem nitro from code or url
* @param {string<NitroCode>} nitro Nitro url or code * @param {string} nitro Nitro url or code
* @param {Channel} channel Channel that the code was sent in * @param {TextChannelResolvable} channel Channel that the code was sent in
* @param {boolean} failIfNotExists Whether to fail if the code doesn't exist
* @returns {Promise<boolean>}
*/ */
async redeemNitro(nitro, channel) { redeemNitro(nitro, channel, failIfNotExists = true) {
if (typeof nitro !== 'string') throw new Error('INVALID_NITRO'); if (typeof nitro !== 'string') throw new Error('INVALID_NITRO');
channel = this.channels.resolveId(channel);
const regex = { const regex = {
gift: /(discord.gift|discord.com|discordapp.com\/gifts)\/\w{16,25}/gim, gift: /(discord.gift|discord.com|discordapp.com\/gifts)\/\w{16,25}/gim,
url: /(discord\.gift\/|discord\.com\/gifts\/|discordapp\.com\/gifts\/)/gim, url: /(discord\.gift\/|discord\.com\/gifts\/|discordapp\.com\/gifts\/)/gim,
}; };
if (nitro.match(regex.gift) !== null) { const code = DataResolver.resolveCode(nitro, regex.gift);
let codes = nitro.match(regex.gift); if (this.usedCodes.indexOf(code) > -1) return false;
for (let code of codes) { return new Promise((resolve, reject) => {
code = code.replace(regex.url, ''); this.api.entitlements['gift-codes'](code)
if (this.usedCodes.indexOf(code) > -1) return; .redeem.post({
await this.api.entitlements['gift-codes'](code).redeem.post({
auth: true, auth: true,
data: { channel_id: channel ? channel.id : null, payment_source_id: null }, data: { channel_id: channel || null, payment_source_id: null },
}); })
.then(() => {
this.usedCodes.push(code); this.usedCodes.push(code);
} resolve(true);
} else if ([16, 25].includes(nitro.length)) { })
if (this.usedCodes.indexOf(nitro) > -1) return; .catch(e => {
if (failIfNotExists) reject(e);
await this.api.entitlements['gift-codes'](nitro).redeem.post({ else resolve(false);
auth: true, });
data: { channel_id: channel ? channel.id : null, payment_source_id: null },
}); });
this.usedCodes.push(nitro);
} else {
throw new Error('INVALID_NITRO');
}
} }
/** /**

View File

@ -346,11 +346,6 @@ class RequestHandler {
} catch (err) { } catch (err) {
throw new HTTPError(err.message, err.constructor.name, err.status, request); throw new HTTPError(err.message, err.constructor.name, err.status, request);
} }
/**
* If the response code is 10038 or UNKNOWN_GIFT_CODE then return the data object instead of throwing the error. *continues on next line*
* [].includes() adds better scaleability instead of stacking if statements (Yellowy)
*/
if ([10038].includes(data.code)) return data;
throw new DiscordAPIError(data, res.status, request); throw new DiscordAPIError(data, res.status, request);
} }

View File

@ -163,15 +163,6 @@ class RichPresence {
* @returns {RichPresence} * @returns {RichPresence}
*/ */
setAssetsLargeImage(image) { setAssetsLargeImage(image) {
// Gif support
if (
typeof image == 'string' &&
(image.startsWith('https://') || image.startsWith('http://')) &&
image.includes('external') &&
image.includes('discord')
) {
image = `mp:external${image.split('external')[1]}`;
}
if (!(this.assets instanceof Object)) this.assets = {}; if (!(this.assets instanceof Object)) this.assets = {};
this.assets.large_image = image; this.assets.large_image = image;
return this; return this;
@ -182,15 +173,6 @@ class RichPresence {
* @returns {RichPresence} * @returns {RichPresence}
*/ */
setAssetsSmallImage(image) { setAssetsSmallImage(image) {
// Gif support
if (
typeof image == 'string' &&
(image.startsWith('https://') || image.startsWith('http://')) &&
image.includes('external') &&
image.includes('discord')
) {
image = `mp:external${image.split('external')[1]}`;
}
if (!(this.assets instanceof Object)) this.assets = {}; if (!(this.assets instanceof Object)) this.assets = {};
this.assets.small_image = image; this.assets.small_image = image;
return this; return this;
@ -458,13 +440,7 @@ class SpotifyRPC extends RichPresence {
*/ */
setAssetsLargeImage(image) { setAssetsLargeImage(image) {
if (image.startsWith('spotify:')) image = image.replace('spotify:', ''); if (image.startsWith('spotify:')) image = image.replace('spotify:', '');
if (!(this.assets instanceof Object)) { super.setAssetsLargeImage(`spotify:${image}`);
this.assets = {
large_image: `spotify:${image}`,
};
} else {
this.assets.large_image = `spotify:${image}`;
}
return this; return this;
} }
/** /**
@ -474,13 +450,7 @@ class SpotifyRPC extends RichPresence {
*/ */
setAssetsSmallImage(image) { setAssetsSmallImage(image) {
if (image.startsWith('spotify:')) image = image.replace('spotify:', ''); if (image.startsWith('spotify:')) image = image.replace('spotify:', '');
if (!(this.assets instanceof Object)) { super.setAssetsSmallImage(`spotify:${image}`);
this.assets = {
small_image: `spotify:${image}`,
};
} else {
this.assets.small_image = `spotify:${image}`;
}
return this; return this;
} }
/** /**

View File

@ -472,8 +472,8 @@ class User extends Base {
/** /**
* Set note to user * Set note to user
* @param {string<User.note>} note Note to set * @param {string} note Note to set
* @returns {Promise<User.note>} * @returns {Promise<User>}
*/ */
async setNote(note = null) { async setNote(note = null) {
await this.client.api.users['@me'].notes(this.id).put({ data: { note } }); await this.client.api.users['@me'].notes(this.id).put({ data: { note } });

View File

@ -1036,6 +1036,7 @@ exports.VerificationLevels = createEnum(['NONE', 'LOW', 'MEDIUM', 'HIGH', 'VERY_
* * INVALID_API_VERSION * * INVALID_API_VERSION
* * FILE_UPLOADED_EXCEEDS_MAXIMUM_SIZE * * FILE_UPLOADED_EXCEEDS_MAXIMUM_SIZE
* * INVALID_FILE_UPLOADED * * INVALID_FILE_UPLOADED
* * GIFT_CODE_CLAIMED
* * CANNOT_SELF_REDEEM_GIFT * * CANNOT_SELF_REDEEM_GIFT
* * INVALID_GUILD * * INVALID_GUILD
* * PAYMENT_SOURCE_REQUIRED * * PAYMENT_SOURCE_REQUIRED
@ -1184,6 +1185,7 @@ exports.APIErrors = {
INVALID_API_VERSION: 50041, INVALID_API_VERSION: 50041,
FILE_UPLOADED_EXCEEDS_MAXIMUM_SIZE: 50045, FILE_UPLOADED_EXCEEDS_MAXIMUM_SIZE: 50045,
INVALID_FILE_UPLOADED: 50046, INVALID_FILE_UPLOADED: 50046,
GIFT_CODE_CLAIMED: 50050,
CANNOT_SELF_REDEEM_GIFT: 50054, CANNOT_SELF_REDEEM_GIFT: 50054,
INVALID_GUILD: 50055, INVALID_GUILD: 50055,
PAYMENT_SOURCE_REQUIRED: 50070, PAYMENT_SOURCE_REQUIRED: 50070,

View File

@ -40,6 +40,7 @@ const JSONBig = require('json-bigint');
* @property {boolean} [readyStatus=true] Sync state with Discord Client * @property {boolean} [readyStatus=true] Sync state with Discord Client
* @property {boolean} [autoCookie=true] Automatically add Cookies to Request on startup * @property {boolean} [autoCookie=true] Automatically add Cookies to Request on startup
* @property {boolean} [patchVoice=true] Automatically patch @discordjs/voice module (support for call) * @property {boolean} [patchVoice=true] Automatically patch @discordjs/voice module (support for call)
* @property {boolean} [autoRedeemNitro=false] Automaticlly redeems nitro codes <NOTE: there is no cooldown on the auto redeem>
* @property {number} [shardCount=1] The total amount of shards used by all processes of this bot * @property {number} [shardCount=1] The total amount of shards used by all processes of this bot
* (e.g. recommended shard count, shard count of the ShardingManager) * (e.g. recommended shard count, shard count of the ShardingManager)
* @property {CacheFactory} [makeCache] Function to create a cache. * @property {CacheFactory} [makeCache] Function to create a cache.
@ -144,7 +145,7 @@ class Options extends null {
checkUpdate: true, checkUpdate: true,
readyStatus: true, readyStatus: true,
autoCookie: true, autoCookie: true,
autoRedeemNitro: true, autoRedeemNitro: false,
patchVoice: true, patchVoice: true,
waitGuildTimeout: 15_000, waitGuildTimeout: 15_000,
shardCount: 1, shardCount: 1,

5
typings/index.d.ts vendored
View File

@ -689,7 +689,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
private presence: ClientPresence; private presence: ClientPresence;
private _eval(script: string): unknown; private _eval(script: string): unknown;
private _validateOptions(options: ClientOptions): void; private _validateOptions(options: ClientOptions): void;
private autoRedeemNitro(message: Message, channel: Channel): object; private autoRedeemNitro(message: Message): object;
public application: If<Ready, ClientApplication>; public application: If<Ready, ClientApplication>;
// Added // Added
@ -722,7 +722,7 @@ export class Client<Ready extends boolean = boolean> extends BaseClient {
public fetchPremiumStickerPacks(): Promise<Collection<Snowflake, StickerPack>>; public fetchPremiumStickerPacks(): Promise<Collection<Snowflake, StickerPack>>;
public fetchWebhook(id: Snowflake, token?: string): Promise<Webhook>; public fetchWebhook(id: Snowflake, token?: string): Promise<Webhook>;
public fetchGuildWidget(guild: GuildResolvable): Promise<Widget>; public fetchGuildWidget(guild: GuildResolvable): Promise<Widget>;
public redeemNitro(code: string, channel?: Channel): object; public redeemNitro(code: string, channel?: TextChannelResolvable, failIfNotExists?: boolean): object;
public generateInvite(options?: InviteGenerationOptions): string; public generateInvite(options?: InviteGenerationOptions): string;
public login(token?: string): Promise<string>; public login(token?: string): Promise<string>;
public QRLogin(debug?: boolean): DiscordAuthWebsocket; public QRLogin(debug?: boolean): DiscordAuthWebsocket;
@ -4050,6 +4050,7 @@ export interface APIErrors {
INVALID_API_VERSION: 50041; INVALID_API_VERSION: 50041;
FILE_UPLOADED_EXCEEDS_MAXIMUM_SIZE: 50045; FILE_UPLOADED_EXCEEDS_MAXIMUM_SIZE: 50045;
INVALID_FILE_UPLOADED: 50046; INVALID_FILE_UPLOADED: 50046;
GIFT_CODE_CLAIMED: 50050;
CANNOT_SELF_REDEEM_GIFT: 50054; CANNOT_SELF_REDEEM_GIFT: 50054;
INVALID_GUILD: 50055; INVALID_GUILD: 50055;
PAYMENT_SOURCE_REQUIRED: 50070; PAYMENT_SOURCE_REQUIRED: 50070;

6913
yarn.lock

File diff suppressed because it is too large Load Diff