dankgrinder 6.19.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.
- package/lib/commands/crime.js +9 -1
- package/lib/commands/search.js +5 -2
- package/lib/grinder.js +276 -112
- package/lib/rawLogger.js +44 -7
- package/package.json +1 -1
package/lib/commands/crime.js
CHANGED
|
@@ -16,11 +16,19 @@ const {
|
|
|
16
16
|
const { Trie, VoseAlias, LRUCache } = require('../structures');
|
|
17
17
|
|
|
18
18
|
const SAFE_CRIME_OPTIONS = Object.freeze([
|
|
19
|
-
|
|
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
|
|
package/lib/commands/search.js
CHANGED
|
@@ -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',
|
|
21
|
-
'closet', '
|
|
23
|
+
'couch', 'pantry', 'fridge', 'kitchen', 'bathroom',
|
|
24
|
+
'closet', 'vacuum', 'toilet', 'sink', 'shower',
|
|
22
25
|
'tree', 'grass', 'bushes', 'garden', 'park', 'backyard',
|
|
23
26
|
]);
|
|
24
27
|
|
package/lib/grinder.js
CHANGED
|
@@ -487,7 +487,7 @@ function renderDashboard() {
|
|
|
487
487
|
lines.push(bEmpty);
|
|
488
488
|
|
|
489
489
|
// ═══════════════════════════════════════════════════════════════
|
|
490
|
-
// STATS PANEL
|
|
490
|
+
// STATS PANEL (split: left = metrics, right = big trend)
|
|
491
491
|
// ═══════════════════════════════════════════════════════════════
|
|
492
492
|
lines.push(bSep);
|
|
493
493
|
lines.push(bEmpty);
|
|
@@ -495,32 +495,44 @@ function renderDashboard() {
|
|
|
495
495
|
// Earnings sparkline data
|
|
496
496
|
const now = Date.now();
|
|
497
497
|
if (now - lastEarningsSample > 8000) { earningsHistory.push(totalCoins); lastEarningsSample = now; }
|
|
498
|
-
const sparkW = Math.min(30, Math.floor(iw * 0.3));
|
|
499
|
-
const spark = drawSparkline(earningsHistory.toArray(), sparkW);
|
|
500
|
-
|
|
501
|
-
// Row 1: Balance + Earned
|
|
502
498
|
const elapsedHrs = (Date.now() - startTime) / 3_600_000;
|
|
503
499
|
const perHr = elapsedHrs > 0.01 ? Math.round(totalCoins / elapsedHrs) : 0;
|
|
504
500
|
const peakFlag = isNewHigh ? ` ${R}${c.bold}* NEW HIGH *${c.reset}` : '';
|
|
505
501
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
// Row 2: Peak + Trend sparkline
|
|
509
|
-
lines.push(bRow(` ${O}★${c.reset} ${D}PEAK${c.reset} ${c.bold}${O}⏣ ${formatCoins(sessionPeakCoins)}${c.reset} ${A}~${c.reset} ${D}TREND${c.reset} ${spark}`));
|
|
510
|
-
|
|
511
|
-
// Row 3: Commands + Success + Rate + Uptime
|
|
502
|
+
// Left column: fixed metrics (left-aligned)
|
|
512
503
|
const cpmVal = globalCmdRate.getRate().toFixed(1);
|
|
513
504
|
const srColor = successRate >= 95 ? G : successRate >= 80 ? Y : R;
|
|
514
|
-
const srBarW = Math.min(15, Math.floor(iw * 0.
|
|
505
|
+
const srBarW = Math.min(15, Math.floor(iw * 0.1));
|
|
515
506
|
const srBar = progressBar(successRate, 100, srBarW, successRate >= 95 ? [52, 211, 153] : successRate >= 80 ? [251, 191, 36] : [239, 68, 68]);
|
|
516
|
-
lines.push(bRow(` ${B}◆${c.reset} ${D}CMDS${c.reset} ${c.bold}${B}${totalCommands}${c.reset} ${srColor}${successRate}%${c.reset} ${srBar} ${Cy}${cpmVal}${c.reset}${D}/min${c.reset} ${Y}◷${c.reset} ${D}UP${c.reset} ${c.bold}${Y}${formatUptime()}${c.reset}`));
|
|
517
|
-
|
|
518
|
-
// Row 4: Memory
|
|
519
507
|
const memMB = Math.round((process.memoryUsage?.rss?.() ?? process.memoryUsage().rss) / 1048576);
|
|
520
508
|
const memCol = memMB > 900 ? [239, 68, 68] : memMB > 600 ? [251, 191, 36] : [52, 211, 153];
|
|
521
|
-
const memBarW = Math.min(
|
|
509
|
+
const memBarW = Math.min(15, Math.floor(iw * 0.1));
|
|
522
510
|
const memBar = progressBar(memMB, 1024, memBarW, memCol, [40, 40, 55]);
|
|
523
|
-
|
|
511
|
+
|
|
512
|
+
// Right column: big trend sparkline
|
|
513
|
+
const sparkW = Math.floor(iw * 0.42);
|
|
514
|
+
const spark = drawSparkline(earningsHistory.toArray(), sparkW);
|
|
515
|
+
|
|
516
|
+
// Build split rows
|
|
517
|
+
const leftHalf = Math.floor(iw * 0.52);
|
|
518
|
+
|
|
519
|
+
// Row 1: Balance + EARNED | TREND (big sparkline)
|
|
520
|
+
const leftRow1 = `${Au}⟐${c.reset} ${D}BALANCE${c.reset} ${c.bold}${Au}⏣ ${formatCoins(totalBalance)}${c.reset} ${G}▲${c.reset} ${D}EARNED${c.reset} ${c.bold}${G}+⏣ ${formatCoins(totalCoins)}${c.reset}${peakFlag}`;
|
|
521
|
+
const rightRow1 = `${A}~${c.reset} ${D}TREND${c.reset} ${spark}`;
|
|
522
|
+
const combined1 = `${leftRow1}${' '.repeat(Math.max(2, leftHalf - leftRow1.replace(RE, '').length))}${rightRow1}`;
|
|
523
|
+
lines.push(bRow(` ${combined1}`));
|
|
524
|
+
|
|
525
|
+
// Row 2: Peak (left)
|
|
526
|
+
const peakRow = `${O}★${c.reset} ${D}PEAK${c.reset} ${c.bold}${O}⏣ ${formatCoins(sessionPeakCoins)}${c.reset}`;
|
|
527
|
+
lines.push(bRow(` ${peakRow}${' '.repeat(Math.max(2, leftHalf - peakRow.replace(RE, '').length))}${Y}◷${c.reset} ${D}UP${c.reset} ${c.bold}${Y}${formatUptime()}${c.reset}`));
|
|
528
|
+
|
|
529
|
+
// Row 3: CMDS (left) + success bar + rate
|
|
530
|
+
const cmdsRow = `${B}◆${c.reset} ${D}CMDS${c.reset} ${c.bold}${B}${totalCommands}${c.reset} ${srColor}${successRate}%${c.reset} ${srBar} ${Cy}${cpmVal}${c.reset}${D}/min${c.reset}`;
|
|
531
|
+
lines.push(bRow(` ${cmdsRow}`));
|
|
532
|
+
|
|
533
|
+
// Row 4: MEM (left)
|
|
534
|
+
const memRow = `${D}≡${c.reset} ${D}MEM${c.reset} ${rgb(memCol[0], memCol[1], memCol[2])}${c.bold}${memMB}MB${c.reset} ${memBar}`;
|
|
535
|
+
lines.push(bRow(` ${memRow}`));
|
|
524
536
|
|
|
525
537
|
lines.push(bEmpty);
|
|
526
538
|
|
|
@@ -1499,7 +1511,7 @@ class AccountWorker {
|
|
|
1499
1511
|
}
|
|
1500
1512
|
}
|
|
1501
1513
|
|
|
1502
|
-
async checkBalance() {
|
|
1514
|
+
async checkBalance(silent = false) {
|
|
1503
1515
|
const prefix = this.account.use_slash ? '/' : 'pls';
|
|
1504
1516
|
const sentAt = Date.now();
|
|
1505
1517
|
|
|
@@ -1594,7 +1606,7 @@ class AccountWorker {
|
|
|
1594
1606
|
|
|
1595
1607
|
this.stats.balance = wallet;
|
|
1596
1608
|
this.stats.bankBalance = bank;
|
|
1597
|
-
this.log('bal', `Wallet: ${c.bold}${c.green}⏣ ${wallet.toLocaleString()}${c.reset} Bank: ${c.bold}${c.cyan}⏣ ${bank.toLocaleString()}${c.reset} Total: ${c.bold}⏣ ${(wallet + bank).toLocaleString()}${c.reset}
|
|
1609
|
+
if (!silent) this.log('bal', `Wallet: ${c.bold}${c.green}⏣ ${wallet.toLocaleString()}${c.reset} Bank: ${c.bold}${c.cyan}⏣ ${bank.toLocaleString()}${c.reset} Total: ${c.bold}⏣ ${(wallet + bank).toLocaleString()}${c.reset}`);
|
|
1598
1610
|
|
|
1599
1611
|
// Store in Redis for persistence
|
|
1600
1612
|
if (redis) {
|
|
@@ -1619,13 +1631,17 @@ class AccountWorker {
|
|
|
1619
1631
|
} catch { /* silent */ }
|
|
1620
1632
|
}
|
|
1621
1633
|
|
|
1622
|
-
// ── Check DM History for deaths/level-ups
|
|
1634
|
+
// ── Check DM History for deaths/level-ups (with retry) ─────
|
|
1623
1635
|
async checkDmHistory() {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1636
|
+
const maxRetries = 3;
|
|
1637
|
+
const delays = [1000, 2000, 4000];
|
|
1638
|
+
let lastError;
|
|
1639
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1640
|
+
try {
|
|
1641
|
+
const dankUser = await this.client.users.fetch(DANK_MEMER_ID);
|
|
1642
|
+
const dm = await dankUser.createDM();
|
|
1643
|
+
this._dmChannelId = dm.id;
|
|
1644
|
+
const recent = await dm.messages.fetch({ limit: 20 });
|
|
1629
1645
|
|
|
1630
1646
|
let deaths = 0, levelUps = 0, currentLevel = 0, lastLifesaverCount = -1;
|
|
1631
1647
|
for (const [, msg] of recent) {
|
|
@@ -1679,11 +1695,16 @@ class AccountWorker {
|
|
|
1679
1695
|
}
|
|
1680
1696
|
}
|
|
1681
1697
|
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1698
|
+
return { deaths, levelUps, currentLevel, lifesavers: lastLifesaverCount, dmChannelId: dm.id };
|
|
1699
|
+
} catch (e) {
|
|
1700
|
+
lastError = e;
|
|
1701
|
+
if (attempt < maxRetries - 1) {
|
|
1702
|
+
await new Promise(r => setTimeout(r, delays[attempt]));
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1686
1705
|
}
|
|
1706
|
+
this.log('debug', `DM check failed after ${maxRetries} attempts: ${lastError.message}`);
|
|
1707
|
+
return { deaths: 0, levelUps: 0, currentLevel: 0, lifesavers: -1 };
|
|
1687
1708
|
}
|
|
1688
1709
|
|
|
1689
1710
|
// ── Run Single Command ──────────────────────────────────────
|
|
@@ -2993,25 +3014,82 @@ async function start(apiKey, apiUrl) {
|
|
|
2993
3014
|
console.log(` ${checks.join(' ')}`);
|
|
2994
3015
|
console.log('');
|
|
2995
3016
|
|
|
2996
|
-
// ──
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3017
|
+
// ── Per-account inline login UI ──────────────────────────────
|
|
3018
|
+
// Track login state per account for inline rendering
|
|
3019
|
+
const loginStates = accounts.map((acc, i) => ({
|
|
3020
|
+
name: acc.label || acc.id || '?',
|
|
3021
|
+
done: false,
|
|
3022
|
+
failed: false,
|
|
3023
|
+
worker: null,
|
|
3024
|
+
workerIdx: i,
|
|
3025
|
+
}));
|
|
3026
|
+
|
|
3027
|
+
// Column widths (visible chars)
|
|
3028
|
+
const terminalW = process.stdout.columns || 90;
|
|
3029
|
+
const colNum = 4; // " # "
|
|
3030
|
+
const colSts = 3; // "ST "
|
|
3031
|
+
const colName = Math.min(24, Math.max(12, Math.floor(terminalW * 0.25)));
|
|
3032
|
+
const colGuild = Math.min(20, Math.max(8, Math.floor(terminalW * 0.2)));
|
|
3033
|
+
const colCmds = 10; // " 20 cmds"
|
|
3034
|
+
const totalVis = colNum + colSts + colName + colGuild + colCmds + 8;
|
|
3035
|
+
|
|
3036
|
+
// Print header + all account lines (initial pending state)
|
|
3037
|
+
console.log(` ${'─'.repeat(totalVis)}`);
|
|
3038
|
+
for (let i = 0; i < loginStates.length; i++) {
|
|
3039
|
+
const s = loginStates[i];
|
|
3040
|
+
const num = `${c.dim}${(i + 1).toString().padStart(colNum - 1)}${c.reset} `;
|
|
3041
|
+
const name = s.name.substring(0, colName).padEnd(colName);
|
|
3042
|
+
console.log(`${num}${c.dim}PN${c.reset} ${name} ${c.dim}${'···'.padEnd(colGuild)}${c.reset} ${c.dim}···${c.reset}`);
|
|
3043
|
+
}
|
|
3044
|
+
console.log(` ${'─'.repeat(totalVis)}`);
|
|
3045
|
+
|
|
3046
|
+
// Draw pending spinners
|
|
3047
|
+
const drawLoginSpinners = () => {
|
|
3048
|
+
for (let i = 0; i < loginStates.length; i++) {
|
|
3049
|
+
const s = loginStates[i];
|
|
3050
|
+
if (s.done || s.failed) continue;
|
|
3051
|
+
const spin = BRAILLE_SPIN[Math.floor(Date.now() / 80) % BRAILLE_SPIN.length];
|
|
3052
|
+
const num = `${c.dim}${(i + 1).toString().padStart(colNum - 1)}${c.reset} `;
|
|
3053
|
+
const name = s.name.substring(0, colName).padEnd(colName);
|
|
3054
|
+
const guild = 'logging in...'.substring(0, colGuild).padEnd(colGuild);
|
|
3055
|
+
process.stdout.write(`\x1b[${i + 2};0H\x1b[2K ${num}${rgb(139, 92, 246)}${spin}${c.reset} ${name} ${c.dim}${guild}${c.reset} ${c.dim}···${c.reset}`);
|
|
3056
|
+
}
|
|
3057
|
+
process.stdout.write(`\x1b[${loginStates.length + 3};0H`);
|
|
3007
3058
|
};
|
|
3059
|
+
const loginSpinnerInterval = setInterval(drawLoginSpinners, 80);
|
|
3060
|
+
|
|
3061
|
+
// Update a line when an account finishes
|
|
3062
|
+
const finalizeLoginLine = (idx, worker) => {
|
|
3063
|
+
const s = loginStates[idx];
|
|
3064
|
+
if (s.done || s.failed) return;
|
|
3065
|
+
s.done = true;
|
|
3066
|
+
s.worker = worker;
|
|
3067
|
+
|
|
3068
|
+
const num = `${c.dim}${(idx + 1).toString().padStart(colNum - 1)}${c.reset} `;
|
|
3069
|
+
const name = (worker.username || s.name || '?').substring(0, colName).padEnd(colName);
|
|
3070
|
+
|
|
3071
|
+
let sts, guild, cmds;
|
|
3072
|
+
if (worker._tokenInvalid) {
|
|
3073
|
+
sts = `${rgb(239, 68, 68)}✗${c.reset}`;
|
|
3074
|
+
guild = 'INVALID'.padEnd(colGuild);
|
|
3075
|
+
cmds = '···';
|
|
3076
|
+
s.failed = true;
|
|
3077
|
+
} else if (worker.channel) {
|
|
3078
|
+
sts = `${rgb(52, 211, 153)}✓${c.reset}`;
|
|
3079
|
+
const gn = (worker.channel.guild?.name || worker.channel.guild?.id || 'DM').substring(0, colGuild);
|
|
3080
|
+
guild = gn.padEnd(colGuild);
|
|
3081
|
+
cmds = `${worker.stats?.commands || 0}cmds`;
|
|
3082
|
+
} else {
|
|
3083
|
+
sts = `${rgb(251, 146, 60)}⏳${c.reset}`;
|
|
3084
|
+
guild = 'timeout'.padEnd(colGuild);
|
|
3085
|
+
cmds = '···';
|
|
3086
|
+
}
|
|
3008
3087
|
|
|
3009
|
-
|
|
3010
|
-
|
|
3088
|
+
const line = ` ${num}${sts} ${name} ${guild} ${cmds}`;
|
|
3089
|
+
process.stdout.write(`\x1b[${idx + 2};0H\x1b[2K${line}`);
|
|
3090
|
+
};
|
|
3011
3091
|
|
|
3012
|
-
// Phase 1: Login
|
|
3013
|
-
const LOGIN_PROGRESS_EVERY = 10;
|
|
3014
|
-
// Reduced delays: 50-150ms between logins (faster startup for 1k+ accounts)
|
|
3092
|
+
// Phase 1: Login in batches of 10
|
|
3015
3093
|
const parsedGapMin = Number.parseInt(String(process.env.LOGIN_GAP_MIN_MS || '50'), 10);
|
|
3016
3094
|
const parsedGapMax = Number.parseInt(String(process.env.LOGIN_GAP_MAX_MS || '150'), 10);
|
|
3017
3095
|
const LOGIN_GAP_MIN_MS = Number.isFinite(parsedGapMin) && parsedGapMin >= 0 ? parsedGapMin : 50;
|
|
@@ -3022,16 +3100,12 @@ async function start(apiKey, apiUrl) {
|
|
|
3022
3100
|
return LOGIN_GAP_MIN_MS + Math.floor(Math.random() * (LOGIN_GAP_MAX_MS - LOGIN_GAP_MIN_MS + 1));
|
|
3023
3101
|
};
|
|
3024
3102
|
|
|
3025
|
-
// Parallel login in batches of 10 to avoid rate limits while being fast
|
|
3026
|
-
// Within each batch, stagger logins by 100-600ms to avoid gateway flood
|
|
3027
3103
|
const BATCH_SIZE = 10;
|
|
3028
3104
|
for (let i = 0; i < accounts.length; i += BATCH_SIZE) {
|
|
3029
3105
|
if (shutdownCalled) break;
|
|
3030
3106
|
const batch = accounts.slice(i, Math.min(i + BATCH_SIZE, accounts.length));
|
|
3031
3107
|
|
|
3032
|
-
// Staggered parallel login: fire each login with a small jitter delay
|
|
3033
3108
|
await Promise.all(batch.map(async (acc, idx) => {
|
|
3034
|
-
// Stagger within batch: 0ms for first, 100-600ms for subsequent
|
|
3035
3109
|
if (idx > 0) {
|
|
3036
3110
|
const jitter = 100 + Math.floor(Math.random() * 500);
|
|
3037
3111
|
await new Promise(r => setTimeout(r, jitter));
|
|
@@ -3039,30 +3113,29 @@ async function start(apiKey, apiUrl) {
|
|
|
3039
3113
|
const worker = new AccountWorker(acc, i + idx);
|
|
3040
3114
|
workers.push(worker);
|
|
3041
3115
|
workerMap.set(acc.id, worker);
|
|
3116
|
+
loginStates[i + idx].worker = worker;
|
|
3042
3117
|
await worker.start();
|
|
3043
|
-
|
|
3118
|
+
finalizeLoginLine(i + idx, worker);
|
|
3044
3119
|
}));
|
|
3045
3120
|
|
|
3046
|
-
// Small gap between batches
|
|
3047
3121
|
if (i + BATCH_SIZE < accounts.length) {
|
|
3048
|
-
|
|
3049
|
-
await new Promise(r => setTimeout(r, gapMs));
|
|
3122
|
+
await new Promise(r => setTimeout(r, randomLoginGap()));
|
|
3050
3123
|
}
|
|
3051
3124
|
|
|
3052
3125
|
hintGC();
|
|
3053
3126
|
}
|
|
3054
3127
|
|
|
3055
|
-
clearInterval(
|
|
3056
|
-
|
|
3057
|
-
process.stdout.write(`\r${c.clearLine}`);
|
|
3058
|
-
console.log(` ${rgb(52, 211, 153)}✓${c.reset} ${c.bold}Login complete${c.reset} ${rgb(52, 211, 153)}${loginDone}/${accounts.length}${c.reset} ${c.dim}accounts connected${c.reset}`);
|
|
3059
|
-
console.log('');
|
|
3128
|
+
clearInterval(loginSpinnerInterval);
|
|
3129
|
+
process.stdout.write(`\x1b[${loginStates.length + 3};0H`);
|
|
3060
3130
|
|
|
3061
|
-
//
|
|
3131
|
+
// Final summary
|
|
3132
|
+
const loginDone = workers.filter(w => !w._tokenInvalid && w.channel).length;
|
|
3062
3133
|
const invalidWorkers = workers.filter(w => w._tokenInvalid);
|
|
3063
3134
|
const timedOutWorkers = workers.filter(w => !w.channel && !w._tokenInvalid);
|
|
3135
|
+
console.log(` ${rgb(52, 211, 153)}✓${c.reset} ${c.bold}Login complete${c.reset} ${rgb(52, 211, 153)}${loginDone}${c.reset}${c.dim}/${c.reset}${c.white}${accounts.length}${c.reset} ${c.dim}accounts connected${c.reset}`);
|
|
3136
|
+
console.log('');
|
|
3137
|
+
|
|
3064
3138
|
if (invalidWorkers.length > 0) {
|
|
3065
|
-
console.log('');
|
|
3066
3139
|
log('warn', `${rgb(239, 68, 68)}${invalidWorkers.length} account(s) have INVALID tokens:${c.reset}`);
|
|
3067
3140
|
for (const w of invalidWorkers) {
|
|
3068
3141
|
log('error', ` ✗ ${w.account.label || w.account.id} — token is invalid or expired`);
|
|
@@ -3076,85 +3149,176 @@ async function start(apiKey, apiUrl) {
|
|
|
3076
3149
|
// Filter out workers with invalid tokens from grinding
|
|
3077
3150
|
const activeWorkers = workers.filter(w => !w._tokenInvalid);
|
|
3078
3151
|
|
|
3079
|
-
// Phase 2:
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3152
|
+
// ── Phase 2: Inventory check with per-account inline rendering ─────────────────
|
|
3153
|
+
const invStates = activeWorkers.map((w, i) => ({
|
|
3154
|
+
name: w.username || w.account.label || '?',
|
|
3155
|
+
idx: i,
|
|
3156
|
+
done: false,
|
|
3157
|
+
failed: false,
|
|
3158
|
+
items: 0,
|
|
3159
|
+
value: 0,
|
|
3160
|
+
attempt: 0,
|
|
3161
|
+
worker: w,
|
|
3162
|
+
}));
|
|
3163
|
+
|
|
3164
|
+
const tw2 = process.stdout.columns || 90;
|
|
3165
|
+
const iColNum = 4;
|
|
3166
|
+
const iColName = Math.min(22, Math.max(10, Math.floor(tw2 * 0.22)));
|
|
3167
|
+
const iColItems = 8;
|
|
3168
|
+
const iColVal = 14;
|
|
3169
|
+
const iColTries = 10;
|
|
3170
|
+
const iTotalVis = iColNum + iColName + iColItems + iColVal + iColTries + 10;
|
|
3171
|
+
|
|
3172
|
+
console.log(` ${'─'.repeat(iTotalVis)}`);
|
|
3173
|
+
for (let i = 0; i < invStates.length; i++) {
|
|
3174
|
+
const s = invStates[i];
|
|
3175
|
+
const num = `${c.dim}${(i + 1).toString().padStart(iColNum - 1)}${c.reset} `;
|
|
3176
|
+
const name = s.name.substring(0, iColName).padEnd(iColName);
|
|
3177
|
+
console.log(`${num}${c.dim}··${c.reset} ${name} ${c.dim}${'checking...'.padEnd(iColItems)}${c.reset} ${c.dim}${'··'.padEnd(iColVal)}${c.reset} ${c.dim}${''.padEnd(iColTries)}${c.reset}`);
|
|
3178
|
+
}
|
|
3179
|
+
console.log(` ${'─'.repeat(iTotalVis)}`);
|
|
3180
|
+
|
|
3181
|
+
let invDone = 0, invFailed = 0;
|
|
3182
|
+
|
|
3183
|
+
const drawInvSpinners = () => {
|
|
3184
|
+
for (let i = 0; i < invStates.length; i++) {
|
|
3185
|
+
const s = invStates[i];
|
|
3186
|
+
if (s.done || s.failed) continue;
|
|
3187
|
+
const spin = BRAILLE_SPIN[Math.floor(Date.now() / 80) % BRAILLE_SPIN.length];
|
|
3188
|
+
const num = `${c.dim}${(i + 1).toString().padStart(iColNum - 1)}${c.reset} `;
|
|
3189
|
+
const name = s.name.substring(0, iColName).padEnd(iColName);
|
|
3190
|
+
const items = 'checking'.substring(0, iColItems).padEnd(iColItems);
|
|
3191
|
+
const val = ''.padEnd(iColVal);
|
|
3192
|
+
const tries = s.attempt > 0 ? `try ${s.attempt}/3` : '';
|
|
3193
|
+
process.stdout.write(`\x1b[${i + 2};0H\x1b[2K ${num}${rgb(34, 211, 238)}${spin}${c.reset} ${name} ${c.dim}${items}${c.reset} ${c.dim}${val}${c.reset} ${c.dim}${tries}${c.reset}`);
|
|
3194
|
+
}
|
|
3195
|
+
process.stdout.write(`\x1b[${invStates.length + 3};0H`);
|
|
3095
3196
|
};
|
|
3197
|
+
const invSpinnerInterval = setInterval(drawInvSpinners, 80);
|
|
3198
|
+
|
|
3199
|
+
const finalizeInvLine = (idx, invRes) => {
|
|
3200
|
+
const s = invStates[idx];
|
|
3201
|
+
if (s.done || s.failed) return;
|
|
3202
|
+
if (invRes?.ok) {
|
|
3203
|
+
s.done = true;
|
|
3204
|
+
invDone++;
|
|
3205
|
+
} else {
|
|
3206
|
+
s.failed = true;
|
|
3207
|
+
invFailed++;
|
|
3208
|
+
}
|
|
3096
3209
|
|
|
3097
|
-
|
|
3210
|
+
const num = `${c.dim}${(idx + 1).toString().padStart(iColNum - 1)}${c.reset} `;
|
|
3211
|
+
const name = s.name.substring(0, iColName).padEnd(iColName);
|
|
3212
|
+
const items = `${invRes?.items?.length || 0}`.padEnd(iColItems);
|
|
3213
|
+
const val = invRes?.ok
|
|
3214
|
+
? `${c.green}⏣${(invRes.totalValue || 0).toLocaleString()}${c.reset}`.padEnd(iColVal + 3)
|
|
3215
|
+
: `${c.dim}··${c.reset}`.padEnd(iColVal);
|
|
3216
|
+
const sts = invRes?.ok ? `${rgb(52, 211, 153)}✓${c.reset}` : `${rgb(239, 68, 68)}✗${c.reset}`;
|
|
3217
|
+
|
|
3218
|
+
const line = ` ${num}${sts} ${name} ${items} ${val}`;
|
|
3219
|
+
process.stdout.write(`\x1b[${idx + 2};0H\x1b[2K${line}`);
|
|
3220
|
+
};
|
|
3098
3221
|
|
|
3099
3222
|
await Promise.all(activeWorkers.map(async (w, i) => {
|
|
3100
3223
|
try {
|
|
3101
|
-
const invRes = await w.checkInventory({
|
|
3102
|
-
|
|
3103
|
-
startupProgress: { current: i + 1, total },
|
|
3104
|
-
requireComplete: true,
|
|
3105
|
-
maxAttempts: 3,
|
|
3106
|
-
});
|
|
3107
|
-
if (invRes?.ok) invDone++;
|
|
3108
|
-
else invFailed++;
|
|
3224
|
+
const invRes = await w.checkInventory({ force: true, requireComplete: true, maxAttempts: 3 });
|
|
3225
|
+
finalizeInvLine(i, invRes);
|
|
3109
3226
|
} catch {
|
|
3110
|
-
|
|
3227
|
+
finalizeInvLine(i, { ok: false });
|
|
3111
3228
|
}
|
|
3112
3229
|
}));
|
|
3113
3230
|
|
|
3114
|
-
clearInterval(
|
|
3115
|
-
process.stdout.write(`\
|
|
3231
|
+
clearInterval(invSpinnerInterval);
|
|
3232
|
+
process.stdout.write(`\x1b[${invStates.length + 3};0H`);
|
|
3116
3233
|
|
|
3117
|
-
// Final summary
|
|
3118
3234
|
if (invFailed > 0) {
|
|
3119
|
-
console.log(` ${rgb(239, 68, 68)}✗${c.reset} ${c.bold}Inventory incomplete${c.reset} ${rgb(52, 211, 153)}${invDone}${c.reset}${c.dim}/${c.reset}${c.white}${
|
|
3235
|
+
console.log(` ${rgb(239, 68, 68)}✗${c.reset} ${c.bold}Inventory incomplete${c.reset} ${rgb(52, 211, 153)}${invDone}${c.reset}${c.dim}/${c.reset}${c.white}${activeWorkers.length}${c.reset} ${c.dim}done, ${rgb(239, 68, 68)}${invFailed} failed${c.reset}`);
|
|
3120
3236
|
log('error', `${c.red}Not starting grind loops — ${invFailed} accounts failed inventory.${c.reset}`);
|
|
3121
3237
|
return;
|
|
3122
3238
|
}
|
|
3123
3239
|
|
|
3124
|
-
console.log(` ${rgb(52, 211, 153)}✓${c.reset} ${c.bold}Inventory complete${c.reset} ${rgb(52, 211, 153)}${invDone}/${
|
|
3240
|
+
console.log(` ${rgb(52, 211, 153)}✓${c.reset} ${c.bold}Inventory complete${c.reset} ${rgb(52, 211, 153)}${invDone}/${activeWorkers.length}${c.reset} ${c.dim}all clear${c.reset}`);
|
|
3125
3241
|
console.log('');
|
|
3126
3242
|
|
|
3127
|
-
// Phase 2.5:
|
|
3128
|
-
|
|
3243
|
+
// ── Phase 2.5: Balance check with inline per-account rendering ─────────────────
|
|
3244
|
+
const balStates = activeWorkers.map((w, i) => ({
|
|
3245
|
+
name: w.username || w.account.label || '?',
|
|
3246
|
+
idx: i,
|
|
3247
|
+
done: false,
|
|
3248
|
+
wallet: 0,
|
|
3249
|
+
bank: 0,
|
|
3250
|
+
worker: w,
|
|
3251
|
+
}));
|
|
3252
|
+
|
|
3253
|
+
const bColNum = 4;
|
|
3254
|
+
const bColName = Math.min(22, Math.max(10, Math.floor(tw2 * 0.22)));
|
|
3255
|
+
const bColWallet = 14;
|
|
3256
|
+
const bColBank = 14;
|
|
3257
|
+
const bColTotal = 14;
|
|
3258
|
+
const bColLs = 4;
|
|
3259
|
+
const bTotalVis = bColNum + bColName + bColWallet + bColBank + bColTotal + bColLs + 12;
|
|
3260
|
+
|
|
3261
|
+
console.log(` ${'─'.repeat(bTotalVis)}`);
|
|
3262
|
+
for (let i = 0; i < balStates.length; i++) {
|
|
3263
|
+
const s = balStates[i];
|
|
3264
|
+
const num = `${c.dim}${(i + 1).toString().padStart(bColNum - 1)}${c.reset} `;
|
|
3265
|
+
const name = s.name.substring(0, bColName).padEnd(bColName);
|
|
3266
|
+
console.log(`${num}${c.dim}··${c.reset} ${name} ${c.dim}${'checking'.padEnd(bColWallet)}${c.reset} ${c.dim}${'··'.padEnd(bColBank)}${c.reset} ${c.dim}${'··'.padEnd(bColTotal)}${c.reset} ${c.dim}♥?${c.reset}`);
|
|
3267
|
+
}
|
|
3268
|
+
console.log(` ${'─'.repeat(bTotalVis)}`);
|
|
3129
3269
|
|
|
3130
3270
|
let balDone = 0;
|
|
3131
|
-
const balProgressInterval = setInterval(() => {
|
|
3132
|
-
const spin = BRAILLE_SPIN[Math.floor(Date.now() / 80) % BRAILLE_SPIN.length];
|
|
3133
|
-
process.stdout.write(`\r ${rgb(34, 211, 238)}${spin}${c.reset} ${c.dim}Balance...${c.reset} ${c.bold}${rgb(52, 211, 153)}${balDone}${c.reset}${c.dim}/${c.reset}${c.white}${activeWorkers.length}${c.reset} `);
|
|
3134
|
-
}, 80);
|
|
3135
3271
|
|
|
3136
|
-
|
|
3272
|
+
const drawBalSpinners = () => {
|
|
3273
|
+
for (let i = 0; i < balStates.length; i++) {
|
|
3274
|
+
const s = balStates[i];
|
|
3275
|
+
if (s.done) continue;
|
|
3276
|
+
const spin = BRAILLE_SPIN[Math.floor(Date.now() / 80) % BRAILLE_SPIN.length];
|
|
3277
|
+
const num = `${c.dim}${(i + 1).toString().padStart(bColNum - 1)}${c.reset} `;
|
|
3278
|
+
const name = s.name.substring(0, bColName).padEnd(bColName);
|
|
3279
|
+
process.stdout.write(`\x1b[${i + 2};0H\x1b[2K ${num}${rgb(251, 191, 36)}${spin}${c.reset} ${name} ${c.dim}${'checking'.padEnd(bColWallet)}${c.reset} ${c.dim}${'··'.padEnd(bColBank)}${c.reset} ${c.dim}${'··'.padEnd(bColTotal)}${c.reset} ${c.dim}♥?${c.reset}`);
|
|
3280
|
+
}
|
|
3281
|
+
process.stdout.write(`\x1b[${balStates.length + 3};0H`);
|
|
3282
|
+
};
|
|
3283
|
+
const balSpinnerInterval = setInterval(drawBalSpinners, 80);
|
|
3284
|
+
|
|
3285
|
+
const finalizeBalLine = (idx, w) => {
|
|
3286
|
+
const s = balStates[idx];
|
|
3287
|
+
if (s.done) return;
|
|
3288
|
+
s.done = true;
|
|
3289
|
+
s.wallet = w.stats?.balance || 0;
|
|
3290
|
+
s.bank = w.stats?.bankBalance || 0;
|
|
3291
|
+
balDone++;
|
|
3292
|
+
|
|
3293
|
+
const num = `${c.dim}${(idx + 1).toString().padStart(bColNum - 1)}${c.reset} `;
|
|
3294
|
+
const name = (w.username || s.name || '?').substring(0, bColName).padEnd(bColName);
|
|
3295
|
+
const ls = w._lifesavers ?? '?';
|
|
3296
|
+
const lsColor = ls === 0 ? rgb(239, 68, 68) : ls <= 2 ? rgb(251, 191, 36) : rgb(52, 211, 153);
|
|
3297
|
+
const wallet = `${c.green}⏣${(s.wallet).toLocaleString()}${c.reset}`.padEnd(bColWallet + 3);
|
|
3298
|
+
const bank = `${c.cyan}⏣${(s.bank).toLocaleString()}${c.reset}`.padEnd(bColBank + 3);
|
|
3299
|
+
const total = `${c.bold}⏣${(s.wallet + s.bank).toLocaleString()}${c.reset}`.padEnd(bColTotal + 3);
|
|
3300
|
+
|
|
3301
|
+
const line = ` ${num}${rgb(52, 211, 153)}✓${c.reset} ${name} ${wallet} ${bank} ${total} ${lsColor}♥${ls}${c.reset}`;
|
|
3302
|
+
process.stdout.write(`\x1b[${idx + 2};0H\x1b[2K${line}`);
|
|
3303
|
+
};
|
|
3304
|
+
|
|
3137
3305
|
await Promise.all(activeWorkers.map(async w => {
|
|
3138
3306
|
try {
|
|
3139
|
-
await w.checkBalance();
|
|
3140
|
-
balDone++;
|
|
3307
|
+
await w.checkBalance(true); // silent: don't spam console during inline rendering
|
|
3141
3308
|
} catch {}
|
|
3309
|
+
const idx = balStates.findIndex(s => s.worker === w);
|
|
3310
|
+
if (idx >= 0) finalizeBalLine(idx, w);
|
|
3142
3311
|
}));
|
|
3143
3312
|
|
|
3144
|
-
clearInterval(
|
|
3145
|
-
process.stdout.write(`\
|
|
3313
|
+
clearInterval(balSpinnerInterval);
|
|
3314
|
+
process.stdout.write(`\x1b[${balStates.length + 3};0H`);
|
|
3146
3315
|
|
|
3147
|
-
//
|
|
3316
|
+
// Balance summary
|
|
3148
3317
|
let totalWallet = 0, totalBank = 0, noLifesaverAccounts = [];
|
|
3149
|
-
for (const
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
totalWallet += wallet;
|
|
3154
|
-
totalBank += bank;
|
|
3155
|
-
const lsColor = ls === 0 ? rgb(239, 68, 68) : ls <= 2 ? rgb(251, 191, 36) : rgb(52, 211, 153);
|
|
3156
|
-
console.log(` ${c.dim}├${c.reset} ${c.bold}${w.username}${c.reset} Wallet: ${c.green}⏣ ${wallet.toLocaleString()}${c.reset} Bank: ${c.cyan}⏣ ${bank.toLocaleString()}${c.reset} Total: ${c.bold}⏣ ${(wallet + bank).toLocaleString()}${c.reset} LS: ${lsColor}${ls}${c.reset}`);
|
|
3157
|
-
if (ls === 0) noLifesaverAccounts.push(w.username);
|
|
3318
|
+
for (const s of balStates) {
|
|
3319
|
+
totalWallet += s.wallet;
|
|
3320
|
+
totalBank += s.bank;
|
|
3321
|
+
if (s.worker._lifesavers === 0) noLifesaverAccounts.push(s.name);
|
|
3158
3322
|
}
|
|
3159
3323
|
console.log(` ${rgb(52, 211, 153)}✓${c.reset} ${c.bold}Balance${c.reset} Total: ${c.bold}${c.green}⏣ ${(totalWallet + totalBank).toLocaleString()}${c.reset} ${c.dim}(wallet: ⏣ ${totalWallet.toLocaleString()} + bank: ⏣ ${totalBank.toLocaleString()})${c.reset}`);
|
|
3160
3324
|
|
package/lib/rawLogger.js
CHANGED
|
@@ -152,18 +152,30 @@ function detectCommand(d) {
|
|
|
152
152
|
if (cv2Text.includes('fishing') || cv2Text.includes('fisherfolk')) return 'fish';
|
|
153
153
|
if (cv2Text.includes('deposit') || cv2Text.includes('bank account')) return 'deposit';
|
|
154
154
|
if (cv2Text.includes('begging') || cv2Text.includes('imagine begging')) return 'beg';
|
|
155
|
-
if (cv2Text.includes('hunting') || cv2Text.includes('went hunting') || cv2Text.includes('hunting rifle')) return 'hunt';
|
|
156
|
-
if (cv2Text.includes('digging') || cv2Text.includes('found nothing while') || cv2Text.includes('you dig')) return 'dig';
|
|
155
|
+
if (cv2Text.includes('hunting') || cv2Text.includes('went hunting') || cv2Text.includes('hunting rifle') || cv2Text.includes('your aim was so bad') || cv2Text.includes('animals laughed') || cv2Text.includes('animals attacked') || cv2Text.includes('barely escaped') || cv2Text.includes('fell asleep in a tree') || cv2Text.includes('caught nothing') || cv2Text.includes('brought back literally nothing') || cv2Text.includes('rifle broke')) return 'hunt';
|
|
156
|
+
if (cv2Text.includes('digging') || cv2Text.includes('found nothing while') || cv2Text.includes('you dig') || cv2Text.includes('dug in the dirt') || cv2Text.includes('brought back') && (cv2Text.includes('ant') || cv2Text.includes('worm') || cv2Text.includes('stickbug') || cv2Text.includes('ladybug'))) return 'dig';
|
|
157
157
|
if (cv2Text.includes('great work') || cv2Text.includes('for your shift') || cv2Text.includes('working as') || cv2Text.includes('work shift') || cv2Text.includes('what color was') || cv2Text.includes('remember words order') || cv2Text.includes('remember the colors') || cv2Text.includes('remember the emojis') || cv2Text.includes('what word was repeated') || cv2Text.includes('unscramble') || cv2Text.includes('remember the number') || cv2Text.includes('click the buttons in correct order') || cv2Text.includes('babysitter') || cv2Text.includes('click the matching')) return 'work';
|
|
158
158
|
if (cv2Text.includes('weekly')) return 'weekly';
|
|
159
159
|
if (cv2Text.includes('daily')) return 'daily';
|
|
160
160
|
if (cv2Text.includes('inventory')) return 'inventory';
|
|
161
161
|
if (cv2Text.includes('profile') || cv2Text.includes('level:')) return 'profile';
|
|
162
|
+
if (cv2Text.includes('balances') && cv2Text.includes('global rank')) return 'balance';
|
|
163
|
+
|
|
164
|
+
// Check content text (plain message content)
|
|
165
|
+
const contentText = (d.content || '').toLowerCase();
|
|
166
|
+
if (contentText.includes('balances') && contentText.includes('global rank')) return 'balance';
|
|
167
|
+
if (contentText.includes('your aim was so bad') || contentText.includes('animals laughed')) return 'hunt';
|
|
168
|
+
if (contentText.includes('imagine going into the woods')) return 'hunt';
|
|
169
|
+
if (contentText.includes('you ran an ad for') && contentText.includes('received')) return 'stream';
|
|
170
|
+
if (contentText.includes('you can\'t interact with your stream')) return 'stream';
|
|
171
|
+
if (contentText.includes('you dug in the dirt') || contentText.includes('found nothing while digging')) return 'dig';
|
|
162
172
|
|
|
163
173
|
// Check embed text
|
|
164
174
|
const embedText = extractEmbedText(d.embeds).toLowerCase();
|
|
165
175
|
// Gambling
|
|
166
176
|
if (embedText.includes('high') && embedText.includes('low') && embedText.includes('secret number')) return 'highlow';
|
|
177
|
+
if (embedText.includes('you won') && embedText.includes('your hint was') && embedText.includes('the hidden number was')) return 'highlow';
|
|
178
|
+
if (embedText.includes('you lost') && embedText.includes('your hint was') && embedText.includes('the hidden number was')) return 'highlow';
|
|
167
179
|
if (embedText.includes('blackjack') || embedText.includes('dealer')) return 'blackjack';
|
|
168
180
|
if (embedText.includes('roulette')) return 'roulette';
|
|
169
181
|
if (embedText.includes('spinning') && embedText.includes('slots')) return 'slots';
|
|
@@ -175,10 +187,18 @@ function detectCommand(d) {
|
|
|
175
187
|
if (embedText.includes('what crime do you want')) return 'crime';
|
|
176
188
|
if (embedText.includes('where do you want to search')) return 'search';
|
|
177
189
|
if (embedText.includes('you searched') || embedText.includes('searched the')) return 'search';
|
|
190
|
+
if (embedText.includes('committed') && (embedText.includes('trespassing') || embedText.includes('identity theft') || embedText.includes('fraud') || embedText.includes('shoplifting') || embedText.includes('dui') || embedText.includes('tax evasion') || embedText.includes('littering') || embedText.includes('cyber bullying') || embedText.includes('grand theft auto') || embedText.includes('drug distribution') || embedText.includes('bank robbing') || embedText.includes('arson') || embedText.includes('murder') || embedText.includes('vandalism') || embedText.includes('jaywalking') || embedText.includes('piracy') || embedText.includes('breaking and entering'))) return 'crime';
|
|
178
191
|
if (embedText.includes('you committed') || embedText.includes('went outside')) return 'crime';
|
|
192
|
+
if (embedText.includes('stole a developer') || embedText.includes('got confused about what trespassing')) return 'crime';
|
|
193
|
+
// Search results (person names) - also check for beg results
|
|
194
|
+
if ((embedText.includes('oh you poor soul') || embedText.includes('take this') || embedText.includes('sure take') || embedText.includes('here\'s a thought') || embedText.includes('nope, nothing') || embedText.includes('no u') || embedText.includes('coins? in this economy')) && (embedText.includes('###') || embedText.includes('charlie chaplin') || embedText.includes('shrek') || embedText.includes('elton john') || embedText.includes('alexa') || embedText.includes('confucius') || embedText.includes('doctor strange') || embedText.includes('rick astley') || embedText.includes('toby turner') || embedText.includes('oprah') || embedText.includes('bruce lee') || embedText.includes('david attenborough') || embedText.includes('honey badger'))) {
|
|
195
|
+
// Check if it's a beg result (has life saver or specific beg text)
|
|
196
|
+
if (embedText.includes('life saver') || embedText.includes('lifesaver')) return 'beg';
|
|
197
|
+
return 'search';
|
|
198
|
+
}
|
|
179
199
|
// Hunt / dig
|
|
180
|
-
if (embedText.includes('hunting') || embedText.includes('came back with') || embedText.includes('hunting rifle') || embedText.includes('dragon\'s fireball') || embedText.includes('dodge the') || embedText.includes('went hunting') || embedText.includes('
|
|
181
|
-
if (embedText.includes('digging') || embedText.includes('you dig') || embedText.includes('
|
|
200
|
+
if (embedText.includes('hunting') || embedText.includes('came back with') || embedText.includes('hunting rifle') || embedText.includes('dragon\'s fireball') || embedText.includes('dodge the') || embedText.includes('went hunting') || embedText.includes('your aim was so bad') || embedText.includes('animals laughed') || embedText.includes('animals attacked') || embedText.includes('barely escaped') || embedText.includes('fell asleep in a tree') || embedText.includes('caught nothing') || embedText.includes('brought back literally nothing') || embedText.includes('rifle broke') || embedText.includes('imagine going into the woods')) return 'hunt';
|
|
201
|
+
if (embedText.includes('digging') || embedText.includes('you dig') || embedText.includes('dug in the dirt') || embedText.includes('found nothing while') || embedText.includes('what are the odds lol') || embedText.includes('brought back') && (embedText.includes('ant') || embedText.includes('worm') || embedText.includes('stickbug') || embedText.includes('ladybug'))) return 'dig';
|
|
182
202
|
// Work — match both minigame prompt AND completion
|
|
183
203
|
if (embedText.includes('work') && (embedText.includes('shift') || embedText.includes('mini-game') || embedText.includes('color') || embedText.includes('what color') || embedText.includes('babysitter') || embedText.includes('great work') || embedText.includes('for your shift'))) return 'work';
|
|
184
204
|
if (embedText.includes('you were given') && embedText.includes('shift')) return 'work';
|
|
@@ -187,11 +207,20 @@ function detectCommand(d) {
|
|
|
187
207
|
// Postmemes
|
|
188
208
|
if (embedText.includes('pick a meme') || embedText.includes('meme posting')) return 'postmemes';
|
|
189
209
|
// Stream
|
|
190
|
-
if (embedText.includes('stream manager') || embedText.includes('go live') || embedText.includes('what game do you want to stream')) return 'stream';
|
|
210
|
+
if (embedText.includes('stream manager') || embedText.includes('go live') || embedText.includes('what game do you want to stream') || embedText.includes('you ran an ad for') || embedText.includes('you received') && embedText.includes('from your sponsors') || embedText.includes('### chat') && embedText.includes('hasanbabi')) return 'stream';
|
|
211
|
+
if (embedText.includes('you can\'t interact with your stream') || embedText.includes('stream can last')) return 'stream';
|
|
191
212
|
// Deposit
|
|
192
213
|
if (embedText.includes('deposited') && embedText.includes('bank balance')) return 'deposit';
|
|
214
|
+
// Balance
|
|
215
|
+
if (embedText.includes('balances') && embedText.includes('global rank') && embedText.includes('net worth')) return 'balance';
|
|
193
216
|
// Trivia
|
|
194
|
-
if (embedText.includes('you have 10 seconds to answer') || embedText.includes('trivia')) return 'trivia';
|
|
217
|
+
if (embedText.includes('you have 10 seconds to answer') || embedText.includes('you have 12 seconds to answer') || embedText.includes('you have 15 seconds to answer') || embedText.includes('trivia') || embedText.includes('difficulty') && embedText.includes('category') && (embedText.includes('correct answer was') || embedText.includes('you got that answer correct'))) return 'trivia';
|
|
218
|
+
if (embedText.includes('who in pulp fiction') || embedText.includes('what was') || embedText.includes('which of')) return 'trivia';
|
|
219
|
+
// Cooldown messages
|
|
220
|
+
if (embedText.includes('you can work again at') || embedText.includes('you can use this command again')) return 'cooldown';
|
|
221
|
+
if (embedText.includes('amount needs to be greater than 0')) return 'cooldown';
|
|
222
|
+
// Premium/upgrade messages
|
|
223
|
+
if (embedText.includes('you can buy the ability to use this command')) return 'premium';
|
|
195
224
|
// Profile / level
|
|
196
225
|
if (embedText.includes('level:') && embedText.includes('experience:')) return 'profile';
|
|
197
226
|
// Shop
|
|
@@ -218,7 +247,15 @@ function parseRawPacket(d, event) {
|
|
|
218
247
|
const embedText = extractEmbedText(d.embeds);
|
|
219
248
|
const isCV2 = !!(d.flags & 32768);
|
|
220
249
|
const isEphemeral = !!(d.flags & 64);
|
|
221
|
-
|
|
250
|
+
|
|
251
|
+
// For UPDATE events, try to preserve the original command classification
|
|
252
|
+
let command = detectCommand(d);
|
|
253
|
+
if (event === 'UPDATE' && command === 'unknown') {
|
|
254
|
+
const existing = memStore.get(d.id);
|
|
255
|
+
if (existing && existing.command && existing.command !== 'unknown') {
|
|
256
|
+
command = existing.command;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
222
259
|
|
|
223
260
|
return {
|
|
224
261
|
id: d.id,
|