dankgrinder 5.13.0 → 5.14.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.
@@ -30,6 +30,35 @@ async function refetchMsg(channel, msgId) {
30
30
  try { return await channel.messages.fetch(msgId); } catch { return null; }
31
31
  }
32
32
 
33
+ function messageStateSignature(msg) {
34
+ const text = normalizeLower(stripAnsi(getFullText(msg))).slice(0, 220);
35
+ const btnSig = getAllButtons(msg)
36
+ .map(b => `${(b.label || '').toLowerCase()}|${(b.customId || b.custom_id || '').toLowerCase()}|${b.disabled ? '1' : '0'}`)
37
+ .sort()
38
+ .join(';')
39
+ .slice(0, 300);
40
+ return `${text}||${btnSig}`;
41
+ }
42
+
43
+ async function waitForStreamTransition({ channel, waitForDankMemer, prevMsg, timeoutMs = 12000 }) {
44
+ const start = Date.now();
45
+ const prevSig = messageStateSignature(prevMsg);
46
+ while (Date.now() - start < timeoutMs) {
47
+ const evt = await waitForDankMemer(1500);
48
+ if (evt) {
49
+ await hydrate(evt);
50
+ if (messageStateSignature(evt) !== prevSig) return evt;
51
+ }
52
+
53
+ const fresh = await refetchMsg(channel, prevMsg.id);
54
+ if (fresh) {
55
+ await hydrate(fresh);
56
+ if (messageStateSignature(fresh) !== prevSig) return fresh;
57
+ }
58
+ }
59
+ return null;
60
+ }
61
+
33
62
  function getGoLiveButton(msg) {
34
63
  const buttons = getAllButtons(msg);
35
64
  return buttons.find(b => !b.disabled && (b.label || '').toLowerCase().includes('go live')) || null;
@@ -176,14 +205,46 @@ async function runStream({ channel, waitForDankMemer, client }) {
176
205
  LOG.info('[stream] Clicking "Go Live"');
177
206
  await humanDelay(100, 250);
178
207
  try {
208
+ const before = response;
179
209
  const liveResult = await safeClickButton(response, goLiveBtn);
180
- const next = liveResult || (await waitForDankMemer(7000)) || (await refetchMsg(channel, response.id));
210
+ const next = liveResult || (await waitForStreamTransition({
211
+ channel,
212
+ waitForDankMemer,
213
+ prevMsg: before,
214
+ timeoutMs: 12000,
215
+ }));
181
216
  if (next) {
182
217
  response = next;
183
218
  await hydrate(response);
184
219
  logMsg(response, `stream-go-live-${step}`);
185
220
  continue;
186
221
  }
222
+
223
+ // Some accounts open setup first; try a fallback non-destructive button once.
224
+ const fallbackBtn = getAllButtons(response).find(b =>
225
+ !b.disabled &&
226
+ b.label &&
227
+ ((b.label || '').toLowerCase().includes('view setup') || (b.label || '').toLowerCase().includes('setup'))
228
+ );
229
+ if (fallbackBtn) {
230
+ LOG.info('[stream] Go Live transition not detected; trying setup fallback');
231
+ await humanDelay(80, 180);
232
+ try {
233
+ const fallbackRes = await safeClickButton(response, fallbackBtn);
234
+ const afterFallback = fallbackRes || (await waitForStreamTransition({
235
+ channel,
236
+ waitForDankMemer,
237
+ prevMsg: before,
238
+ timeoutMs: 8000,
239
+ }));
240
+ if (afterFallback) {
241
+ response = afterFallback;
242
+ await hydrate(response);
243
+ logMsg(response, `stream-setup-fallback-${step}`);
244
+ continue;
245
+ }
246
+ } catch {}
247
+ }
187
248
  } catch (e) {
188
249
  LOG.error(`[stream] Go Live click failed: ${e.message}`);
189
250
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dankgrinder",
3
- "version": "5.13.0",
3
+ "version": "5.14.0",
4
4
  "description": "Dank Memer automation engine — grind coins while you sleep",
5
5
  "bin": {
6
6
  "dankgrinder": "bin/dankgrinder.js"