djs-selfbot-v13 3.7.3 → 3.7.5

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/README.md CHANGED
@@ -29,6 +29,7 @@
29
29
  ### Guild Management
30
30
  - `guild.mute(options?)` - Mute a guild completely (suppress all notifications)
31
31
  - `guild.unmute()` - Unmute a guild (restore all notifications)
32
+ - - `guild.markRead(readStates?)` - Mark all channels in a guild as read
32
33
 
33
34
  ### Developer Applications
34
35
  - `client.developers.get(withTeamApplications?)` - Fetch all developer applications owned by the user
@@ -79,6 +80,18 @@
79
80
  - `client.quests.getClaimable()` - Get claimable quests
80
81
  - `client.quests.filterQuestsValid()` - Filter valid quests
81
82
 
83
+ ### Message Search
84
+ - `channel.search(options?)` - Search for messages in a channel with advanced filters
85
+ - `authorId` - Search by specific author
86
+ - `mentions` - Search for messages mentioning a user
87
+ - `has` - Search for messages containing: `image`, `video`, `link`, `embed`, `sound`, `poll`, `sticker`, `snapshot`
88
+ - `pinned` - Search only pinned messages
89
+ - `sortBy` - Sort by `timestamp` or `relevance`
90
+ - `sortOrder` - Sort order `desc` or `asc`
91
+ - `offset` - Pagination offset
92
+ - `limit` - Limit number of results
93
+
94
+
82
95
  </details>
83
96
 
84
97
  > [!WARNING]
@@ -123,6 +136,43 @@ client.on('ready', async () => {
123
136
  client.login('token');
124
137
  ```
125
138
 
139
+ ### Advanced Examples
140
+
141
+ #### Message Search
142
+ ```js
143
+ // Search for messages with images in a channel
144
+ const results = await channel.search({ has: ['image'] });
145
+
146
+ // Search for messages by a specific author
147
+ const userMessages = await channel.search({
148
+ authorId: '123456789012345678',
149
+ limit: 10
150
+ });
151
+
152
+ // Search for pinned messages
153
+ const pinnedMessages = await channel.search({ pinned: true });
154
+
155
+ // Search for messages with multiple filters
156
+ const complexSearch = await channel.search({
157
+ has: ['link', 'embed'],
158
+ sortBy: 'timestamp',
159
+ sortOrder: 'desc',
160
+ offset: 20
161
+ });
162
+ ```
163
+
164
+ #### Guild Read State Management
165
+ ```js
166
+ // Mark all channels in a guild as read
167
+ await guild.markRead();
168
+
169
+ // Mark specific channels as read
170
+ await guild.markRead([
171
+ { channel_id: '123456789012345678', message_id: '987654321098765432' },
172
+ { channel_id: '876543210987654321', message_id: '123456789012345678' }
173
+ ]);
174
+ ```
175
+
126
176
  ## Get Token ?
127
177
 
128
178
  - Based: [findByProps](https://discord.com/channels/603970300668805120/1085682686607249478/1085682686607249478)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "djs-selfbot-v13",
3
- "version": "3.7.3",
3
+ "version": "3.7.5",
4
4
  "description": "An unofficial discord.js fork for creating selfbots",
5
5
  "main": "./src/index.js",
6
6
  "types": "./typings/index.d.ts",
@@ -55,6 +55,7 @@
55
55
  "@discordjs/collection": "^2.1.1",
56
56
  "@sapphire/async-queue": "^1.5.5",
57
57
  "@sapphire/shapeshift": "^4.0.0",
58
+ "debug": "^4.4.3",
58
59
  "discord-api-types": "^0.38.15",
59
60
  "fetch-cookie": "^3.1.0",
60
61
  "find-process": "^2.0.0",
@@ -76,7 +76,7 @@ class QuestManager extends BaseManager {
76
76
  * @returns {Promise<Object>} Quest data
77
77
  */
78
78
  async get() {
79
- const data = await this.client.api.users('@me').quests.get();
79
+ const data = await this.client.api.quests('@me').get();
80
80
 
81
81
  // Cache quests
82
82
  if (data.quests) {
@@ -250,12 +250,9 @@ class QuestManager extends BaseManager {
250
250
  async doingQuest(quest) {
251
251
  const questName = quest.config.messages?.quest_name || 'Unknown Quest';
252
252
 
253
- if (!quest.isEnrolledQuest()) {
254
- console.log(`Enrolling in quest "${questName}"...`);
253
+ if (!quest.isEnrolledQuest())
255
254
  await this.acceptQuest(quest.id);
256
- }
257
255
 
258
- const applicationName = quest.config.application?.name || 'Unknown App';
259
256
  const taskConfig = quest.config.task_config;
260
257
 
261
258
  const taskName = [
@@ -266,10 +263,9 @@ class QuestManager extends BaseManager {
266
263
  'WATCH_VIDEO_ON_MOBILE'
267
264
  ].find(x => taskConfig.tasks?.[x] != null);
268
265
 
269
- if (!taskName) {
270
- console.log(`Unknown task type for quest "${questName}"`);
271
- return;
272
- }
266
+ if (!taskName)
267
+ return console.log(`Unknown task type for quest "${questName}"`);
268
+
273
269
 
274
270
  const secondsNeeded = taskConfig.tasks[taskName].target;
275
271
  let secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0;
@@ -281,8 +277,6 @@ class QuestManager extends BaseManager {
281
277
  const enrolledAt = new Date(quest.userStatus?.enrolled_at).getTime();
282
278
  let completed = false;
283
279
 
284
- console.log(`Spoofing video for ${questName}.`);
285
-
286
280
  while (true) {
287
281
  const maxAllowed = Math.floor((Date.now() - enrolledAt) / 1000) + maxFuture;
288
282
  const diff = maxAllowed - secondsDone;
@@ -305,8 +299,6 @@ class QuestManager extends BaseManager {
305
299
  await this.videoProgress(quest.id, secondsNeeded);
306
300
  }
307
301
 
308
- console.log(`Quest "${questName}" completed!`);
309
-
310
302
  } else if (taskName === 'PLAY_ON_DESKTOP') {
311
303
  const interval = 60;
312
304
 
@@ -315,20 +307,11 @@ class QuestManager extends BaseManager {
315
307
  const res = await this.heartbeat(quest.id, quest.config.application.id, false);
316
308
  quest.updateUserStatus(res);
317
309
 
318
- console.log(`Spoofed your game to ${applicationName}. Wait for ${Math.ceil((secondsNeeded - secondsDone) / 60)} more minutes.`);
319
310
  await this.timeout(interval * 1000);
320
311
  }
321
312
 
322
313
  const res = await this.heartbeat(quest.id, quest.config.application.id, true);
323
314
  quest.updateUserStatus(res);
324
- console.log(`Quest "${questName}" completed!`);
325
-
326
- } else if (taskName === 'STREAM_ON_DESKTOP') {
327
- console.log('This no longer works in node for non-video quests. Use the discord desktop app to complete the', questName, 'quest!');
328
- } else if (taskName === 'PLAY_ACTIVITY') {
329
- console.log('This quest not supported. Use the discord desktop app to complete the', questName, 'quest!');
330
- } else {
331
- console.log('Unknown quest type. Use the discord desktop app to complete the', questName, 'quest!');
332
315
  }
333
316
  }
334
317
 
@@ -1659,6 +1659,37 @@ class Guild extends AnonymousGuild {
1659
1659
  return data;
1660
1660
  }
1661
1661
 
1662
+ /**
1663
+ * Mark all channels in this guild as read
1664
+ * @param {MarkReadOptions[]} [readStates] Array of read states to mark as read
1665
+ * @returns {Promise<Object>} The response from Discord
1666
+ * @example
1667
+ * // Mark all channels as read
1668
+ * guild.markRead();
1669
+ *
1670
+ * // Mark specific channels as read
1671
+ * guild.markRead([
1672
+ * { channel_id: '123456789012345678', message_id: '987654321098765432' }
1673
+ * ]);
1674
+ */
1675
+ async markRead(readStates = []) {
1676
+ // If no readStates provided, get all channels in guild
1677
+ if (readStates.length === 0) {
1678
+ const channels = this.channels.cache.filter(c => c.isTextBased());
1679
+ readStates = channels.map(channel => ({
1680
+ channel_id: channel.id,
1681
+ message_id: channel.lastMessageId || '0',
1682
+ read_state_type: 0
1683
+ }));
1684
+ }
1685
+
1686
+ const data = await this.client.api['read-states']['ack-bulk'].post({
1687
+ data: readStates
1688
+ });
1689
+
1690
+ return data;
1691
+ }
1692
+
1662
1693
  /**
1663
1694
  * Creates a collection of this guild's roles, sorted by their position and ids.
1664
1695
  * @returns {Collection<Snowflake, Role>}
@@ -396,19 +396,66 @@ class TextBasedChannel {
396
396
  * .then(messages => console.log(`Found ${messages.length} messages`))
397
397
  * .catch(console.error);
398
398
  */
399
- async search(limit, user) {
400
- const userId = this.client.users.resolveId(user);
401
- if (!userId) throw new Error('INVALID_TYPE', 'user', 'UserResolvable');
399
+ /**
400
+ * Search for messages in this channel
401
+ * @param {ChannelSearchOptions} [options] Search options
402
+ * @returns {Promise<Object>} The search results
403
+ * @example
404
+ * // Search for messages by author
405
+ * channel.search({ authorId: '123456789012345678' });
406
+ *
407
+ * // Search for messages with images
408
+ * channel.search({ has: ['image'] });
409
+ *
410
+ * // Search for pinned messages
411
+ * channel.search({ pinned: true });
412
+ */
413
+ async search(options = {}) {
414
+ const {
415
+ authorId,
416
+ mentions,
417
+ has = [],
418
+ pinned,
419
+ sortBy = 'timestamp',
420
+ sortOrder = 'desc',
421
+ offset = 0,
422
+ limit
423
+ } = options;
424
+
425
+ const params = new URLSearchParams({
426
+ channel_id: this.id,
427
+ sort_by: sortBy,
428
+ sort_order: sortOrder,
429
+ offset: offset.toString()
430
+ });
431
+
432
+ if (authorId) params.append('author_id', authorId);
433
+ if (mentions) params.append('mentions', mentions);
434
+ if (pinned) params.append('pinned', 'true');
402
435
 
403
- const res = await fetch(`https://ptb.discord.com/api/v9/${this.guild ? `guilds/${this.guild.id}` : `channels/${this.id}`}/messages/search?author_id=${userId}&channel_id=${this.id}&sort_by=timestamp&sort_order=desc&offset=0`, {
436
+ // Add 'has' parameters
437
+ for (const hasType of has) {
438
+ params.append('has', hasType);
439
+ }
440
+
441
+ const endpoint = this.guild
442
+ ? `guilds/${this.guild.id}/messages/search`
443
+ : `channels/${this.id}/messages/search`;
444
+
445
+ const res = await fetch(`https://ptb.discord.com/api/v9/${endpoint}?${params}`, {
404
446
  method: 'GET',
405
447
  headers: { authorization: this.client.token }
406
448
  });
407
-
449
+
408
450
  if (!res.ok) return false;
409
-
451
+
410
452
  const data = await res.json();
411
- return data.messages.splice(0, limit);
453
+
454
+ if (limit && data.messages) {
455
+ data.messages = data.messages.slice(0, limit);
456
+ }
457
+
458
+ return data;
412
459
  }
413
460
 
414
461
  /**
@@ -945,6 +945,23 @@ export interface AcceptInviteOptions {
945
945
  bypassVerify: boolean;
946
946
  }
947
947
 
948
+ export interface ChannelSearchOptions {
949
+ authorId?: Snowflake;
950
+ mentions?: Snowflake;
951
+ has?: ('image' | 'video' | 'link' | 'embed' | 'sound' | 'poll' | 'sticker' | 'snapshot')[];
952
+ pinned?: boolean;
953
+ sortBy?: 'timestamp' | 'relevance';
954
+ sortOrder?: 'desc' | 'asc';
955
+ offset?: number;
956
+ limit?: number;
957
+ }
958
+
959
+ export interface MarkReadOptions {
960
+ channel_id: Snowflake;
961
+ message_id: Snowflake;
962
+ read_state_type?: number;
963
+ }
964
+
948
965
  export type OAuth2AuthorizeOptions = {
949
966
  guild_id?: Snowflake;
950
967
  permissions?: string;
@@ -1684,6 +1701,7 @@ export class Guild extends AnonymousGuild {
1684
1701
  public setVanityCode(code?: string): Promise<this>;
1685
1702
  public mute(options?: GuildMuteOptions): Promise<any>;
1686
1703
  public unmute(): Promise<any>;
1704
+ public markRead(readStates?: MarkReadOptions[]): Promise<any>;
1687
1705
  }
1688
1706
 
1689
1707
  export class GuildAuditLogs<T extends GuildAuditLogsResolvable = 'ALL'> {
@@ -5225,6 +5243,7 @@ export interface TextBasedChannelFields extends PartialTextBasedChannelFields {
5225
5243
  fetchWebhooks(): Promise<Collection<Snowflake, Webhook>>;
5226
5244
  sendTyping(): Promise<{ message_send_cooldown_ms: number; thread_create_cooldown_ms: number } | undefined>;
5227
5245
  sendSlash(target: UserResolvable, commandName: string, ...args: any[]): Promise<Message | Modal>;
5246
+ search(options?: ChannelSearchOptions): Promise<any>;
5228
5247
  }
5229
5248
 
5230
5249
  export function PartialWebhookMixin<T>(Base?: Constructable<T>): Constructable<T & PartialWebhookFields>;