nodebb-plugin-ezoic-infinite 1.8.2 → 1.8.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/public/client.js +86 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.8.2",
3
+ "version": "1.8.4",
4
4
  "description": "Production-ready Ezoic infinite ads integration for NodeBB 4.x",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/public/client.js CHANGED
@@ -89,6 +89,10 @@
89
89
  const MAX_DESTROY_BATCH = 4; // ids max par destroyPlaceholders(...ids)
90
90
  const DESTROY_FLUSH_MS = 30; // micro-buffer destroy pour lisser les rafales
91
91
  const BURST_COOLDOWN_MS = 120; // délai min entre deux déclenchements de burst
92
+ const PAGE_WARMUP_MS = 700; // laisse NodeBB rendre le contenu avant les premiers showAds
93
+ const CONTENT_SETTLE_WINDOW_MS = 350;
94
+ const CONTENT_SETTLE_MAX_DELAY_MS = 1500;
95
+ const CONTENT_GROWTH_THRESHOLD_PX = 120;
92
96
 
93
97
  // Marges IO larges et fixes — observer créé une seule fois au boot
94
98
  const IO_MARGIN_DESKTOP = '2500px 0px 2500px 0px';
@@ -138,7 +142,8 @@
138
142
  destroyPendingSet: new Set(),
139
143
  sweepQueued: false,
140
144
  wrapByKey: new Map(), // anchorKey → wrap DOM node
141
- ezActiveIds: new Set(), // ids déjà passés à showAds/displayMore
145
+ ezActiveIds: new Set(), // ids actifs côté plugin (wrap présent / récemment show)
146
+ ezShownSinceDestroy: new Set(), // ids déjà show depuis le dernier destroy Ezoic
142
147
  scrollDir: 1, // 1=bas, -1=haut
143
148
  scrollSpeed: 0, // px/s approx (EMA)
144
149
  lastScrollY: 0,
@@ -148,6 +153,10 @@
148
153
  burstDeadline: 0,
149
154
  burstCount: 0,
150
155
  lastBurstTs: 0,
156
+ pageWarmUntil: 0,
157
+ settleDelaySince: 0,
158
+ contentSampleH: 0,
159
+ contentSampleTs: 0,
151
160
  };
152
161
 
153
162
  let blockedUntil = 0;
@@ -240,6 +249,54 @@ function destroyEzoicId(id) {
240
249
  scheduleDestroyFlush();
241
250
  }
242
251
 
252
+ function destroyBeforeReuse(ids) {
253
+ const out = [];
254
+ const toDestroy = [];
255
+ const seen = new Set();
256
+ for (const raw of (ids || [])) {
257
+ const id = parseInt(raw, 10);
258
+ if (!Number.isFinite(id) || id <= 0 || seen.has(id)) continue;
259
+ seen.add(id);
260
+ out.push(id);
261
+ if (S.ezShownSinceDestroy.has(id)) toDestroy.push(id);
262
+ }
263
+ if (toDestroy.length) {
264
+ try { window.ezstandalone?.destroyPlaceholders?.(toDestroy); } catch (_) {}
265
+ for (const id of toDestroy) S.ezShownSinceDestroy.delete(id);
266
+ }
267
+ return out;
268
+ }
269
+
270
+
271
+ function getContentHeight() {
272
+ try {
273
+ const c = document.getElementById('content') || document.querySelector('main#panel') || document.body;
274
+ if (!c) return 0;
275
+ return Math.max(c.scrollHeight || 0, c.offsetHeight || 0);
276
+ } catch (_) { return 0; }
277
+ }
278
+
279
+ function getShowSettleDelayMs(now = ts()) {
280
+ try {
281
+ if (S.pageWarmUntil && now < S.pageWarmUntil) return Math.max(0, Math.min(120, S.pageWarmUntil - now));
282
+ const h = getContentHeight();
283
+ const prevH = S.contentSampleH || 0;
284
+ const prevTs = S.contentSampleTs || 0;
285
+ S.contentSampleH = h;
286
+ S.contentSampleTs = now;
287
+ if (!prevTs || h <= 0) { S.settleDelaySince = 0; return 0; }
288
+ const grew = h - prevH;
289
+ const recent = (now - prevTs) <= CONTENT_SETTLE_WINDOW_MS;
290
+ if (recent && grew >= CONTENT_GROWTH_THRESHOLD_PX) {
291
+ if (!S.settleDelaySince) S.settleDelaySince = now;
292
+ if ((now - S.settleDelaySince) < CONTENT_SETTLE_MAX_DELAY_MS) return CONTENT_SETTLE_WINDOW_MS;
293
+ } else {
294
+ S.settleDelaySince = 0;
295
+ }
296
+ } catch (_) {}
297
+ return 0;
298
+ }
299
+
243
300
 
244
301
  // ── Config ─────────────────────────────────────────────────────────────────
245
302
 
@@ -484,11 +541,15 @@ function recycleAndMove(klass, targetEl, newKey) {
484
541
  S.wrapByKey.set(newKey, best);
485
542
 
486
543
  const doDestroy = () => {
487
- if (S.ezActiveIds.has(id)) destroyEzoicId(id);
544
+ if (S.ezShownSinceDestroy.has(id)) {
545
+ try { ez.destroyPlaceholders([id]); } catch (_) {}
546
+ S.ezShownSinceDestroy.delete(id);
547
+ }
548
+ S.ezActiveIds.delete(id);
488
549
  setTimeout(doDefine, 330);
489
550
  };
490
551
  const doDefine = () => { try { ez.define([id]); } catch (_) {} setTimeout(doDisplay, 300); };
491
- const doDisplay = () => { try { ez.displayMore([id]); S.ezActiveIds.add(id); } catch (_) {} };
552
+ const doDisplay = () => { try { ez.displayMore([id]); S.ezActiveIds.add(id); S.ezShownSinceDestroy.add(id); } catch (_) {} };
492
553
  try { (typeof ez.cmd?.push === 'function') ? ez.cmd.push(doDestroy) : doDestroy(); } catch (_) {}
493
554
 
494
555
  return { id, wrap: best };
@@ -529,7 +590,7 @@ function recycleAndMove(klass, targetEl, newKey) {
529
590
  const ph = w.querySelector(`[id^="${PH_PREFIX}"]`);
530
591
  if (ph instanceof Element) S.io?.unobserve(ph);
531
592
  const id = parseInt(w.getAttribute(A_WRAPID), 10);
532
- if (Number.isFinite(id)) { destroyEzoicId(id); S.mountedIds.delete(id); }
593
+ if (Number.isFinite(id)) { S.ezActiveIds.delete(id); S.mountedIds.delete(id); }
533
594
  const key = w.getAttribute(A_ANCHOR);
534
595
  if (key && S.wrapByKey.get(key) === w) S.wrapByKey.delete(key);
535
596
  w.remove();
@@ -657,17 +718,19 @@ function enqueueShow(id) {
657
718
  scheduleDrainQueue();
658
719
  }
659
720
 
660
- function scheduleDrainQueue() {
721
+ function scheduleDrainQueue(delayMs = BATCH_FLUSH_MS) {
661
722
  if (isBlocked()) return;
662
723
  if (S.showBatchTimer) return;
663
724
  S.showBatchTimer = setTimeout(() => {
664
725
  S.showBatchTimer = 0;
665
726
  drainQueue();
666
- }, BATCH_FLUSH_MS);
727
+ }, Math.max(0, delayMs|0));
667
728
  }
668
729
 
669
730
  function drainQueue() {
670
731
  if (isBlocked()) return;
732
+ const settleDelay = getShowSettleDelayMs();
733
+ if (settleDelay > 0) { scheduleDrainQueue(Math.max(BATCH_FLUSH_MS, settleDelay)); return; }
671
734
  const free = Math.max(0, MAX_INFLIGHT - S.inflight);
672
735
  if (!free || !S.pending.length) return;
673
736
 
@@ -723,9 +786,12 @@ function startShowBatch(ids) {
723
786
  window.ezstandalone = window.ezstandalone || {};
724
787
  const ez = window.ezstandalone;
725
788
  const doShow = () => {
726
- try { ez.showAds(...valid); } catch (_) {}
727
- for (const id of valid) {
789
+ const prepared = destroyBeforeReuse(valid);
790
+ if (!prepared.length) { setTimeout(() => { clearTimeout(timer); release(); }, SHOW_RELEASE_MS); return; }
791
+ try { ez.showAds(...prepared); } catch (_) {}
792
+ for (const id of prepared) {
728
793
  S.ezActiveIds.add(id);
794
+ S.ezShownSinceDestroy.add(id);
729
795
  }
730
796
  setTimeout(() => { clearTimeout(timer); release(); }, SHOW_RELEASE_MS);
731
797
  };
@@ -868,6 +934,7 @@ function startShowBatch(ids) {
868
934
  S.lastShow.clear();
869
935
  S.wrapByKey.clear();
870
936
  S.ezActiveIds.clear();
937
+ S.ezShownSinceDestroy.clear();
871
938
  S.inflight = 0;
872
939
  S.pending = [];
873
940
  S.pendingSet.clear();
@@ -881,6 +948,10 @@ function startShowBatch(ids) {
881
948
  S.scrollSpeed = 0;
882
949
  S.lastScrollY = 0;
883
950
  S.lastScrollTs = 0;
951
+ S.pageWarmUntil = 0;
952
+ S.settleDelaySince = 0;
953
+ S.contentSampleH = 0;
954
+ S.contentSampleTs = 0;
884
955
  }
885
956
 
886
957
  // ── MutationObserver ───────────────────────────────────────────────────────
@@ -986,6 +1057,10 @@ function startShowBatch(ids) {
986
1057
  S.pageKey = pageKey();
987
1058
  blockedUntil = 0;
988
1059
  muteConsole(); ensureTcfLocator(); warmNetwork();
1060
+ S.pageWarmUntil = ts() + PAGE_WARMUP_MS;
1061
+ S.settleDelaySince = 0;
1062
+ S.contentSampleH = getContentHeight();
1063
+ S.contentSampleTs = ts();
989
1064
  patchShowAds(); getIO(); ensureDomObserver(); sweepDeadWraps(); requestBurst();
990
1065
  });
991
1066
 
@@ -1041,6 +1116,9 @@ function startShowBatch(ids) {
1041
1116
  ensureDomObserver();
1042
1117
  bindNodeBB();
1043
1118
  bindScroll();
1119
+ S.pageWarmUntil = ts() + PAGE_WARMUP_MS;
1120
+ S.contentSampleH = getContentHeight();
1121
+ S.contentSampleTs = ts();
1044
1122
  blockedUntil = 0;
1045
1123
  requestBurst();
1046
1124