dankgrinder 6.17.0 → 6.21.0

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.
@@ -64,7 +64,7 @@ async function clickAndRefetch(channel, msg, btn) {
64
64
  LOG.error(`[adventure] Click error: ${e.message}`);
65
65
  return null;
66
66
  }
67
- await sleep(250);
67
+ await sleep(100);
68
68
  return await refetchMsg(channel, msg.id);
69
69
  }
70
70
 
@@ -174,7 +174,7 @@ async function playAdventureRounds(channel, msg) {
174
174
  const choice = pickSafeChoice(choices);
175
175
  if (choice) {
176
176
  LOG.info(`[adventure] → Choosing: "${choice.label}"`);
177
- await sleep(100);
177
+ await sleep(50);
178
178
  const afterChoice = await clickAndRefetch(channel, current, choice);
179
179
  if (afterChoice) {
180
180
  current = afterChoice;
@@ -208,7 +208,7 @@ async function playAdventureRounds(channel, msg) {
208
208
  } else if (nextBtnNow && nextBtnNow.disabled) {
209
209
  // Next is disabled but no choices found — might be loading
210
210
  LOG.debug(`[adventure] Next disabled, no choices — waiting...`);
211
- await sleep(300);
211
+ await sleep(150);
212
212
  const refreshed = await refetchMsg(channel, current.id);
213
213
  if (refreshed) {
214
214
  current = refreshed;
@@ -221,7 +221,7 @@ async function playAdventureRounds(channel, msg) {
221
221
  // No next button at all
222
222
  LOG.debug(`[adventure] No Next button — checking if done`);
223
223
  if (isAdventureDone(current)) break;
224
- await sleep(500);
224
+ await sleep(200);
225
225
  const refreshed = await refetchMsg(channel, current.id);
226
226
  if (refreshed) {
227
227
  current = refreshed;
@@ -374,7 +374,7 @@ async function runAdventure({ channel, waitForDankMemer, client }) {
374
374
  } catch (e) {
375
375
  LOG.error(`[adventure] Select error: ${e.message}`);
376
376
  }
377
- await sleep(300);
377
+ await sleep(150);
378
378
  }
379
379
  }
380
380
 
@@ -16,11 +16,19 @@ const {
16
16
  const { Trie, VoseAlias, LRUCache } = require('../structures');
17
17
 
18
18
  const SAFE_CRIME_OPTIONS = Object.freeze([
19
- 'tax evasion', 'fraud', 'cybercrime', 'hacking', 'identity theft',
19
+ // 100% safe (from logs analysis)
20
+ 'identity theft', 'fraud', 'littering',
21
+ // 67% safe
22
+ 'dui',
23
+ // Other potentially safe options
24
+ 'tax evasion', 'cybercrime', 'hacking',
20
25
  'money laundering', 'tax fraud', 'insurance fraud', 'scam',
21
26
  ]);
22
27
 
23
28
  const RISKY_CRIME_OPTIONS = Object.freeze([
29
+ // 0% safe (from logs)
30
+ 'cyber bullying', 'trespassing', 'shoplifting',
31
+ // Known dangerous
24
32
  'murder', 'arson', 'assault', 'kidnap', 'terrorism',
25
33
  ]);
26
34
 
@@ -63,7 +63,7 @@ async function runPostMemes({ channel, waitForDankMemer }) {
63
63
  if (initLower.includes('cannot post another meme') || initLower.includes('dead meme') ||
64
64
  initLower.includes('another meme for another')) {
65
65
  const minMatch = initText.match(RE_COOLDOWN_MIN);
66
- const cdSec = minMatch ? parseInt(minMatch[1]) * 60 : 120;
66
+ const cdSec = minMatch ? parseInt(minMatch[1]) * 60 : 150;
67
67
  LOG.warn(`[pm] Cooldown: ${cdSec}s`);
68
68
  return { result: `pm cooldown ${cdSec}s`, coins: 0, nextCooldownSec: cdSec };
69
69
  }
@@ -110,7 +110,7 @@ async function runPostMemes({ channel, waitForDankMemer }) {
110
110
  try {
111
111
  await response.selectMenu(locRowIdx, [opt.value]);
112
112
  } catch (e) { LOG.error(`[pm] Platform select error: ${e.message}`); }
113
- await sleep(300);
113
+ await sleep(100);
114
114
  const updated = await refetchMsg(channel, msgId);
115
115
  if (updated) { response = updated; logMsg(response, 'pm-after-platform'); }
116
116
  }
@@ -123,7 +123,7 @@ async function runPostMemes({ channel, waitForDankMemer }) {
123
123
  try {
124
124
  await response.selectMenu(kindRowIdx, [opt.value]);
125
125
  } catch (e) { LOG.error(`[pm] Kind select error: ${e.message}`); }
126
- await sleep(300);
126
+ await sleep(100);
127
127
  const updated = await refetchMsg(channel, msgId);
128
128
  if (updated) { response = updated; logMsg(response, 'pm-after-kind'); }
129
129
  }
@@ -136,7 +136,7 @@ async function runPostMemes({ channel, waitForDankMemer }) {
136
136
  LOG.info(`[pm] Clicking "${postBtn.label}"...`);
137
137
  try {
138
138
  await safeClickButton(response, postBtn);
139
- await sleep(300);
139
+ await sleep(100);
140
140
  const final = await refetchMsg(channel, msgId);
141
141
  if (final) {
142
142
  logMsg(final, 'pm-result');
@@ -16,9 +16,12 @@ const {
16
16
  const { VoseAlias, Trie, EMA, LRUCache } = require('../structures');
17
17
 
18
18
  const SAFE_SEARCH_LOCATIONS = Object.freeze([
19
+ // 100% safe (from logs analysis)
20
+ 'shoe', 'washer', 'attic', 'pocket',
21
+ // Other safe locations
19
22
  'sofa', 'mailbox', 'dog', 'car', 'dresser', 'laundromat', 'bed',
20
- 'couch', 'pantry', 'fridge', 'kitchen', 'bathroom', 'attic',
21
- 'closet', 'shoe', 'vacuum', 'toilet', 'sink', 'shower',
23
+ 'couch', 'pantry', 'fridge', 'kitchen', 'bathroom',
24
+ 'closet', 'vacuum', 'toilet', 'sink', 'shower',
22
25
  'tree', 'grass', 'bushes', 'garden', 'park', 'backyard',
23
26
  ]);
24
27
 
@@ -230,10 +230,10 @@ async function runStream({ channel, waitForDankMemer, client }) {
230
230
  for (const item of itemsToBuy) {
231
231
  const bought = await buyItem({ channel, waitForDankMemer, client, itemName: item, quantity: 1 });
232
232
  if (!bought) return { result: `need ${item} (buy failed)`, coins: 0, nextCooldownSec: 1800 };
233
- await humanDelay(500, 1000);
233
+ await humanDelay(200, 400);
234
234
  }
235
235
 
236
- await sleep(2000);
236
+ await sleep(800);
237
237
  await channel.send('pls stream');
238
238
  response = await waitForDankMemer(12000);
239
239
  if (!response) return { result: 'no response after buy', coins: 0, nextCooldownSec: 180 };
@@ -256,7 +256,7 @@ async function runStream({ channel, waitForDankMemer, client }) {
256
256
 
257
257
  const selected = await selectRandomStreamOption(response);
258
258
  if (selected) {
259
- await humanDelay(150, 350);
259
+ await humanDelay(80, 180);
260
260
  const updatedAfterSelect = (await waitForDankMemer(5000)) || (await refetchMsg(channel, response.id));
261
261
  if (updatedAfterSelect) {
262
262
  response = updatedAfterSelect;
@@ -294,7 +294,7 @@ async function runStream({ channel, waitForDankMemer, client }) {
294
294
  }
295
295
  }
296
296
 
297
- await sleep(300);
297
+ await sleep(150);
298
298
  const fresh = await refetchMsg(channel, response.id);
299
299
  if (fresh) {
300
300
  response = fresh;
@@ -305,7 +305,7 @@ async function runStream({ channel, waitForDankMemer, client }) {
305
305
  }
306
306
 
307
307
  LOG.info('[stream] Clicking "Go Live"');
308
- await humanDelay(100, 250);
308
+ await humanDelay(50, 120);
309
309
  try {
310
310
  const before = response;
311
311
  const liveResult = await safeClickButton(response, goLiveBtn);
@@ -340,7 +340,7 @@ async function runStream({ channel, waitForDankMemer, client }) {
340
340
  );
341
341
  if (fallbackBtn) {
342
342
  LOG.info('[stream] Go Live transition not detected; trying setup fallback');
343
- await humanDelay(80, 180);
343
+ await humanDelay(40, 100);
344
344
  try {
345
345
  const fallbackRes = await safeClickButton(response, fallbackBtn);
346
346
  const afterFallback = fallbackRes || (await waitForStreamTransition({
@@ -376,7 +376,7 @@ async function runStream({ channel, waitForDankMemer, client }) {
376
376
  const action = pickRandom(actions);
377
377
  const actionAt = new Date();
378
378
  LOG.info(`[stream] Live action: "${action.label}"`);
379
- await humanDelay(120, 320);
379
+ await humanDelay(60, 150);
380
380
  try {
381
381
  const clicked = await safeClickButton(response, action);
382
382
  let updated = clicked || (await waitForDankMemer(6000)) || (await refetchMsg(channel, response.id));
@@ -311,49 +311,66 @@ function findSelectMenuOption(msg, label) {
311
311
  // Safe button click — tries library methods first, falls back to raw HTTP for CV2.
312
312
  // When CV2 fallback is used, waits for the message to update so callers always
313
313
  // get the updated message back (instead of null, which broke multi-round games).
314
- async function safeClickButton(msg, button) {
314
+ async function safeClickButton(msg, button, retries = 2) {
315
315
  // Skip LINK buttons (external URLs) — they have style=LINK/5 and no customId
316
316
  if (button.style === 'LINK' || button.style === 5 || (!button.customId && !button.custom_id && typeof button.click !== 'function')) {
317
317
  return null;
318
318
  }
319
- if (typeof button.click === 'function') {
320
- return button.click();
321
- }
322
- const id = button.customId || button.custom_id;
323
- if (id && typeof msg.clickButton === 'function') {
319
+
320
+ for (let attempt = 0; attempt <= retries; attempt++) {
324
321
  try {
325
- return await msg.clickButton(id);
326
- } catch {
327
- // Fall through to CV2 raw interaction fallback.
328
- }
329
- }
330
- // CV2 fallback: send interaction via raw HTTP, then wait for the message
331
- // to update so we can return the updated message to the caller.
332
- if (id) {
333
- const interactionAck = await clickCV2Button(msg, id);
334
- if (interactionAck) msg._lastInteractionAck = interactionAck;
335
- // Wait for Dank Memer to process the interaction and update the message
336
- const updatedMsg = await new Promise((resolve) => {
337
- const timeout = setTimeout(() => {
338
- msg.client?.removeListener?.('messageUpdate', handler);
339
- resolve(null);
340
- }, 8000);
341
- const handler = (_, newMsg) => {
342
- if (newMsg.id === msg.id) {
343
- clearTimeout(timeout);
344
- msg.client?.removeListener?.('messageUpdate', handler);
345
- resolve(newMsg);
322
+ if (typeof button.click === 'function') {
323
+ return await button.click();
324
+ }
325
+ const id = button.customId || button.custom_id;
326
+ if (id && typeof msg.clickButton === 'function') {
327
+ try {
328
+ return await msg.clickButton(id);
329
+ } catch {
330
+ // Fall through to CV2 raw interaction fallback.
346
331
  }
347
- };
348
- msg.client?.on?.('messageUpdate', handler);
349
- });
350
- if (updatedMsg) {
351
- await ensureCV2(updatedMsg);
352
- return updatedMsg;
332
+ }
333
+ // CV2 fallback: send interaction via raw HTTP, then wait for the message
334
+ // to update so we can return the updated message to the caller.
335
+ if (id) {
336
+ const interactionAck = await clickCV2Button(msg, id);
337
+ if (interactionAck) msg._lastInteractionAck = interactionAck;
338
+ // Wait for Dank Memer to process the interaction and update the message
339
+ const updatedMsg = await new Promise((resolve) => {
340
+ const timeout = setTimeout(() => {
341
+ msg.client?.removeListener?.('messageUpdate', handler);
342
+ resolve(null);
343
+ }, 6000);
344
+ const handler = (_, newMsg) => {
345
+ if (newMsg.id === msg.id) {
346
+ clearTimeout(timeout);
347
+ msg.client?.removeListener?.('messageUpdate', handler);
348
+ resolve(newMsg);
349
+ }
350
+ };
351
+ msg.client?.on?.('messageUpdate', handler);
352
+ });
353
+ if (updatedMsg) {
354
+ await ensureCV2(updatedMsg);
355
+ return updatedMsg;
356
+ }
357
+ // Retry if we got null
358
+ if (attempt < retries) {
359
+ await new Promise(r => setTimeout(r, 300 + attempt * 200));
360
+ continue;
361
+ }
362
+ return null;
363
+ }
364
+ throw new Error('No click method available on button');
365
+ } catch (err) {
366
+ if (attempt < retries) {
367
+ await new Promise(r => setTimeout(r, 300 + attempt * 200));
368
+ continue;
369
+ }
370
+ throw err;
353
371
  }
354
- return null;
355
372
  }
356
- throw new Error('No click method available on button');
373
+ return null;
357
374
  }
358
375
 
359
376
  // ── Hold Tight Detection ─────────────────────────────────────