dankgrinder 4.9.0 → 4.9.2

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.
@@ -7,6 +7,7 @@
7
7
  const {
8
8
  LOG, c, getFullText, parseCoins, getAllButtons, getAllSelectMenus,
9
9
  safeClickButton, logMsg, isHoldTight, getHoldTightReason, sleep, humanDelay, needsItem,
10
+ isCV2, ensureCV2,
10
11
  } = require('./utils');
11
12
  const { buyItem } = require('./shop');
12
13
 
@@ -37,6 +38,7 @@ async function runGeneric({ channel, waitForDankMemer, cmdString, cmdName, clien
37
38
  return { result: `hold tight (${reason || 'unknown'})`, coins: 0, holdTightReason: reason };
38
39
  }
39
40
 
41
+ if (isCV2(response)) await ensureCV2(response);
40
42
  logMsg(response, cmdName);
41
43
  const text = getFullText(response);
42
44
  const coins = parseCoins(text);
package/lib/grinder.js CHANGED
@@ -791,6 +791,11 @@ class AccountWorker {
791
791
 
792
792
  // ── Check Balance ───────────────────────────────────────────
793
793
  async checkInventory() {
794
+ if (this._invRunning) return;
795
+ if (this._lastInvCheck && Date.now() - this._lastInvCheck < 300_000) return;
796
+ this._invRunning = true;
797
+ this._lastInvCheck = Date.now();
798
+ this.busy = true;
794
799
  try {
795
800
  this.log('info', 'Checking inventory...');
796
801
  const result = await commands.runInventory({
@@ -800,23 +805,23 @@ class AccountWorker {
800
805
  accountId: this.account.id,
801
806
  redis,
802
807
  });
803
- if (result.items?.length > 0) {
804
- this.log('success', `Inventory: ${result.items.length} items, ⏣ ${(result.totalValue || 0).toLocaleString()} net`);
805
- // Report inventory to API
806
- try {
807
- await fetch(`${API_URL}/api/grinder/inventory`, {
808
- method: 'POST',
809
- headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
810
- body: JSON.stringify({
811
- account_id: this.account.id,
812
- items: result.items,
813
- totalValue: result.totalValue,
814
- }),
815
- });
816
- } catch {}
817
- }
808
+ this.log('success', `Inventory: ${result.items?.length || 0} items, ⏣ ${(result.totalValue || 0).toLocaleString()} net`);
809
+ try {
810
+ await fetch(`${API_URL}/api/grinder/inventory`, {
811
+ method: 'POST',
812
+ headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
813
+ body: JSON.stringify({
814
+ account_id: this.account.id,
815
+ items: result.items || [],
816
+ totalValue: result.totalValue || 0,
817
+ }),
818
+ });
819
+ } catch {}
818
820
  } catch (e) {
819
821
  this.log('error', `Inventory check failed: ${e.message}`);
822
+ } finally {
823
+ this._invRunning = false;
824
+ this.busy = false;
820
825
  }
821
826
  }
822
827
 
@@ -856,23 +861,30 @@ class AccountWorker {
856
861
  bank = parseInt(bankTextMatch[1].replace(/,/g, ''), 10);
857
862
  }
858
863
 
859
- if (wallet > 0 || bank > 0) {
860
- this.stats.balance = wallet;
861
- this.stats.bankBalance = bank;
862
- this.log('bal', `Wallet: ${c.bold}${c.green}⏣ ${wallet.toLocaleString()}${c.reset} Bank: ${c.bold}${c.cyan}⏣ ${bank.toLocaleString()}${c.reset}`);
864
+ this.stats.balance = wallet;
865
+ this.stats.bankBalance = bank;
866
+ this.log('bal', `Wallet: ${c.bold}${c.green}⏣ ${wallet.toLocaleString()}${c.reset} Bank: ${c.bold}${c.cyan}⏣ ${bank.toLocaleString()}${c.reset}`);
867
+
868
+ // Store in Redis for persistence
869
+ if (redis) {
863
870
  try {
864
- await fetch(`${API_URL}/api/grinder/status`, {
865
- method: 'POST',
866
- headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
867
- body: JSON.stringify({
868
- account_id: this.account.id,
869
- balance: wallet,
870
- bank_balance: bank,
871
- total_balance: wallet + bank,
872
- }),
873
- });
874
- } catch { /* silent */ }
871
+ await redis.set(`dkg:bal:${this.account.id}`, JSON.stringify({ wallet, bank, ts: Date.now() }));
872
+ } catch {}
875
873
  }
874
+
875
+ // Always report to dashboard API
876
+ try {
877
+ await fetch(`${API_URL}/api/grinder/status`, {
878
+ method: 'POST',
879
+ headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
880
+ body: JSON.stringify({
881
+ account_id: this.account.id,
882
+ balance: wallet,
883
+ bank_balance: bank,
884
+ total_balance: wallet + bank,
885
+ }),
886
+ });
887
+ } catch { /* silent */ }
876
888
  }
877
889
  }
878
890
 
@@ -881,16 +893,17 @@ class AccountWorker {
881
893
  // handles Hold Tight / cooldowns / item-buying internally.
882
894
  async runCommand(cmdName, prefix) {
883
895
  let cmdString;
884
- const betAmount = Math.max(5000, this.account.bet_amount || 5000);
896
+ const bjBet = Math.max(5000, this.account.bet_amount || 5000);
897
+ const gambBet = Math.max(10000, this.account.bet_amount || 10000);
885
898
 
886
899
  switch (cmdName) {
887
900
  case 'dep max': cmdString = `${prefix} dep max`; break;
888
901
  case 'with max': cmdString = `${prefix} with max`; break;
889
- case 'blackjack': cmdString = `${prefix} bj ${betAmount}`; break;
890
- case 'cointoss': cmdString = `${prefix} cointoss ${betAmount}`; break;
891
- case 'roulette': cmdString = `${prefix} roulette ${betAmount} red`; break;
892
- case 'slots': cmdString = `${prefix} slots ${betAmount}`; break;
893
- case 'snakeeyes': cmdString = `${prefix} snakeeyes ${betAmount}`; break;
902
+ case 'blackjack': cmdString = `${prefix} bj ${bjBet}`; break;
903
+ case 'cointoss': cmdString = `${prefix} cointoss ${gambBet}`; break;
904
+ case 'roulette': cmdString = `${prefix} roulette ${gambBet} red`; break;
905
+ case 'slots': cmdString = `${prefix} slots ${gambBet}`; break;
906
+ case 'snakeeyes': cmdString = `${prefix} snakeeyes ${gambBet}`; break;
894
907
  case 'work shift': cmdString = `${prefix} work shift`; break;
895
908
  case 'weekly': cmdString = `${prefix} weekly`; break;
896
909
  case 'monthly': cmdString = `${prefix} monthly`; break;
@@ -906,7 +919,7 @@ class AccountWorker {
906
919
  client: this.client,
907
920
  safeAnswers: cmdName === 'search' ? safeParseJSON(this.account.search_answers, []) :
908
921
  cmdName === 'crime' ? safeParseJSON(this.account.crime_answers, []) : [],
909
- betAmount,
922
+ betAmount: ['blackjack'].includes(cmdName) ? bjBet : gambBet,
910
923
  accountId: this.account.id,
911
924
  redis,
912
925
  };
@@ -1042,7 +1055,10 @@ class AccountWorker {
1042
1055
  const earned = Math.max(0, cmdResult.coins || 0);
1043
1056
  const spent = Math.max(0, cmdResult.lost || 0);
1044
1057
  if (earned > 0) this.stats.coins += earned;
1045
- if (cmdResult.nextCooldownSec) await this.setCooldown(cmdName, cmdResult.nextCooldownSec);
1058
+ if (cmdResult.nextCooldownSec) {
1059
+ await this.setCooldown(cmdName, cmdResult.nextCooldownSec);
1060
+ this._lastCooldownOverride = cmdResult.nextCooldownSec;
1061
+ }
1046
1062
 
1047
1063
  // Mark time-gated commands as done so we don't re-run this session
1048
1064
  const doneExpiries = { daily: 86400, weekly: 604800, monthly: 2592000, drops: 86400 };
@@ -1065,12 +1081,12 @@ class AccountWorker {
1065
1081
  this.stats.successes++;
1066
1082
  const shortResult = result.substring(0, 30).replace(/\n/g, ' ');
1067
1083
  this.setStatus(`${cmdName} → ${shortResult}`);
1068
- await sendLog(this.username, cmdString, result, 'success');
1084
+ await sendLog(this.username, cmdName, result, 'success');
1069
1085
  reportEarnings(this.account.id, this.username, earned, spent, cmdName);
1070
1086
  } catch (err) {
1071
1087
  this.stats.errors++;
1072
1088
  this.log('error', `${cmdString} failed: ${err.message}`);
1073
- await sendLog(this.username, cmdString, err.message, 'error');
1089
+ await sendLog(this.username, cmdName, err.message, 'error');
1074
1090
  }
1075
1091
  }
1076
1092
 
@@ -1351,7 +1367,9 @@ class AccountWorker {
1351
1367
  const backoffMultiplier = this.failStreak > 5 ? Math.min(this.failStreak - 4, 5) : 1;
1352
1368
 
1353
1369
  if (this.commandQueue && this.running && !shutdownCalled) {
1354
- item.nextRunAt = Date.now() + totalWait * 1000 * backoffMultiplier;
1370
+ const effectiveWait = this._lastCooldownOverride || totalWait;
1371
+ this._lastCooldownOverride = null;
1372
+ item.nextRunAt = Date.now() + effectiveWait * 1000 * backoffMultiplier;
1355
1373
  this.commandQueue.push(item);
1356
1374
  }
1357
1375
 
@@ -1371,7 +1389,7 @@ class AccountWorker {
1371
1389
  this.cycleCount++;
1372
1390
 
1373
1391
  if (this.cycleCount > 0 && this.cycleCount % 10 === 0) this.printStats();
1374
- if (this.cycleCount > 0 && this.cycleCount % 20 === 0) {
1392
+ if (this.cycleCount > 0 && this.cycleCount % 5 === 0) {
1375
1393
  this.busy = true;
1376
1394
  await this.checkBalance();
1377
1395
  this.busy = false;
@@ -1522,8 +1540,39 @@ class AccountWorker {
1522
1540
  this.log('success', `#${chName} · ${enabledCmds.length} cmds`);
1523
1541
  this.setStatus('starting...');
1524
1542
 
1543
+ // Load daily/weekly/monthly done state from Redis
1544
+ if (redis) {
1545
+ for (const cmd of ['daily', 'weekly', 'monthly', 'drops']) {
1546
+ try {
1547
+ const val = await redis.get(`dkg:done:${this.account.id}:${cmd}`);
1548
+ if (val) {
1549
+ const ttlSec = await redis.ttl(`dkg:done:${this.account.id}:${cmd}`);
1550
+ if (ttlSec > 0) {
1551
+ this.doneToday.set(cmd, Date.now() + ttlSec * 1000);
1552
+ this.log('info', `${cmd} already claimed (${Math.round(ttlSec / 3600)}h remaining)`);
1553
+ }
1554
+ }
1555
+ } catch {}
1556
+ }
1557
+ // Load cached balance from Redis
1558
+ try {
1559
+ const balData = await redis.get(`dkg:bal:${this.account.id}`);
1560
+ if (balData) {
1561
+ const { wallet, bank } = JSON.parse(balData);
1562
+ if (wallet > 0 || bank > 0) {
1563
+ this.stats.balance = wallet;
1564
+ this.stats.bankBalance = bank;
1565
+ await fetch(`${API_URL}/api/grinder/status`, {
1566
+ method: 'POST',
1567
+ headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json' },
1568
+ body: JSON.stringify({ account_id: this.account.id, balance: wallet, bank_balance: bank, total_balance: wallet + bank }),
1569
+ }).catch(() => {});
1570
+ }
1571
+ }
1572
+ } catch {}
1573
+ }
1574
+
1525
1575
  await this.checkBalance();
1526
- // Check inventory on startup
1527
1576
  this.checkInventory().catch(() => {});
1528
1577
  this.grindLoop();
1529
1578
  resolve();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "4.9.0",
3
+ "version": "4.9.2",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"