nodebb-plugin-ezoic-infinite 1.8.1 → 1.8.3

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 +79 -20
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
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
@@ -80,17 +80,19 @@
80
80
  // Tunables (stables en prod)
81
81
  const MIN_PRUNE_AGE_MS = 8_000; // délai de grâce avant pruning (stabilisation DOM)
82
82
  const MAX_INSERTS_RUN = 10; // plus réactif si NodeBB injecte en rafale
83
- const MAX_INFLIGHT = 2; // max showAds() simultanés (garde-fou)
83
+ const MAX_INFLIGHT = 4; // max showAds() simultanés (garde-fou)
84
84
  const MAX_SHOW_BATCH = 4; // ids max par appel showAds(...ids)
85
- const SHOW_THROTTLE_MS = 500; // anti-spam showAds() par id (plus réactif)
86
- const SHOW_RELEASE_MS = 300; // relâche inflight après showAds() batché
85
+ const SHOW_THROTTLE_MS = 600; // anti-spam showAds() par id (plus réactif)
86
+ const SHOW_RELEASE_MS = 700; // relâche inflight après showAds() batché
87
87
  const SHOW_FAILSAFE_MS = 7000; // relâche forcée si stack pub lente
88
- const BATCH_FLUSH_MS = 30; // micro-buffer pour regrouper les ids proches
89
- const BURST_COOLDOWN_MS = 100; // délai min entre deux déclenchements de burst
88
+ const BATCH_FLUSH_MS = 40; // micro-buffer pour regrouper les ids proches
89
+ const MAX_DESTROY_BATCH = 4; // ids max par destroyPlaceholders(...ids)
90
+ const DESTROY_FLUSH_MS = 30; // micro-buffer destroy pour lisser les rafales
91
+ const BURST_COOLDOWN_MS = 120; // délai min entre deux déclenchements de burst
90
92
 
91
93
  // Marges IO larges et fixes — observer créé une seule fois au boot
92
- const IO_MARGIN_DESKTOP = '3000px 0px 3000px 0px';
93
- const IO_MARGIN_MOBILE = '2000px 0px 2000px 0px';
94
+ const IO_MARGIN_DESKTOP = '2500px 0px 2500px 0px';
95
+ const IO_MARGIN_MOBILE = '3500px 0px 3500px 0px';
94
96
 
95
97
  const SEL = {
96
98
  post: '[component="post"][data-pid]',
@@ -131,9 +133,13 @@
131
133
  pending: [], // ids en attente de slot inflight
132
134
  pendingSet: new Set(),
133
135
  showBatchTimer: 0,
136
+ destroyBatchTimer: 0,
137
+ destroyPending: [],
138
+ destroyPendingSet: new Set(),
134
139
  sweepQueued: false,
135
140
  wrapByKey: new Map(), // anchorKey → wrap DOM node
136
- ezActiveIds: new Set(), // ids déjà passés à showAds/displayMore
141
+ ezActiveIds: new Set(), // ids actifs côté plugin (wrap présent / récemment show)
142
+ ezShownSinceDestroy: new Set(), // ids déjà show depuis le dernier destroy Ezoic
137
143
  scrollDir: 1, // 1=bas, -1=haut
138
144
  scrollSpeed: 0, // px/s approx (EMA)
139
145
  lastScrollY: 0,
@@ -197,15 +203,60 @@
197
203
  S.mutGuard++;
198
204
  try { fn(); } finally { S.mutGuard--; }
199
205
  }
206
+ function scheduleDestroyFlush() {
207
+ if (S.destroyBatchTimer) return;
208
+ S.destroyBatchTimer = setTimeout(() => {
209
+ S.destroyBatchTimer = 0;
210
+ flushDestroyBatch();
211
+ }, DESTROY_FLUSH_MS);
212
+ }
213
+
214
+ function flushDestroyBatch() {
215
+ if (!S.destroyPending.length) return;
216
+ const ids = [];
217
+ while (S.destroyPending.length && ids.length < MAX_DESTROY_BATCH) {
218
+ const id = S.destroyPending.shift();
219
+ S.destroyPendingSet.delete(id);
220
+ if (!Number.isFinite(id) || id <= 0) continue;
221
+ ids.push(id);
222
+ }
223
+ if (ids.length) {
224
+ try {
225
+ const ez = window.ezstandalone;
226
+ const run = () => { try { ez?.destroyPlaceholders?.(ids); } catch (_) {} };
227
+ try { (typeof ez?.cmd?.push === 'function') ? ez.cmd.push(run) : run(); } catch (_) {}
228
+ } catch (_) {}
229
+ }
230
+ if (S.destroyPending.length) scheduleDestroyFlush();
231
+ }
232
+
200
233
  function destroyEzoicId(id) {
201
234
  if (!Number.isFinite(id) || id <= 0) return;
202
235
  if (!S.ezActiveIds.has(id)) return;
203
- try {
204
- const ez = window.ezstandalone;
205
- const run = () => { try { ez?.destroyPlaceholders?.([id]); } catch (_) {} };
206
- try { (typeof ez?.cmd?.push === 'function') ? ez.cmd.push(run) : run(); } catch (_) {}
207
- } catch (_) {}
208
236
  S.ezActiveIds.delete(id);
237
+ if (!S.destroyPendingSet.has(id)) {
238
+ S.destroyPending.push(id);
239
+ S.destroyPendingSet.add(id);
240
+ }
241
+ scheduleDestroyFlush();
242
+ }
243
+
244
+ function destroyBeforeReuse(ids) {
245
+ const out = [];
246
+ const toDestroy = [];
247
+ const seen = new Set();
248
+ for (const raw of (ids || [])) {
249
+ const id = parseInt(raw, 10);
250
+ if (!Number.isFinite(id) || id <= 0 || seen.has(id)) continue;
251
+ seen.add(id);
252
+ out.push(id);
253
+ if (S.ezShownSinceDestroy.has(id)) toDestroy.push(id);
254
+ }
255
+ if (toDestroy.length) {
256
+ try { window.ezstandalone?.destroyPlaceholders?.(toDestroy); } catch (_) {}
257
+ for (const id of toDestroy) S.ezShownSinceDestroy.delete(id);
258
+ }
259
+ return out;
209
260
  }
210
261
 
211
262
 
@@ -452,14 +503,15 @@ function recycleAndMove(klass, targetEl, newKey) {
452
503
  S.wrapByKey.set(newKey, best);
453
504
 
454
505
  const doDestroy = () => {
455
- if (S.ezActiveIds.has(id)) {
506
+ if (S.ezShownSinceDestroy.has(id)) {
456
507
  try { ez.destroyPlaceholders([id]); } catch (_) {}
457
- S.ezActiveIds.delete(id);
508
+ S.ezShownSinceDestroy.delete(id);
458
509
  }
459
- setTimeout(doDefine, 300);
510
+ S.ezActiveIds.delete(id);
511
+ setTimeout(doDefine, 330);
460
512
  };
461
513
  const doDefine = () => { try { ez.define([id]); } catch (_) {} setTimeout(doDisplay, 300); };
462
- const doDisplay = () => { try { ez.displayMore([id]); S.ezActiveIds.add(id); } catch (_) {} };
514
+ const doDisplay = () => { try { ez.displayMore([id]); S.ezActiveIds.add(id); S.ezShownSinceDestroy.add(id); } catch (_) {} };
463
515
  try { (typeof ez.cmd?.push === 'function') ? ez.cmd.push(doDestroy) : doDestroy(); } catch (_) {}
464
516
 
465
517
  return { id, wrap: best };
@@ -500,7 +552,7 @@ function recycleAndMove(klass, targetEl, newKey) {
500
552
  const ph = w.querySelector(`[id^="${PH_PREFIX}"]`);
501
553
  if (ph instanceof Element) S.io?.unobserve(ph);
502
554
  const id = parseInt(w.getAttribute(A_WRAPID), 10);
503
- if (Number.isFinite(id)) { destroyEzoicId(id); S.mountedIds.delete(id); }
555
+ if (Number.isFinite(id)) { S.ezActiveIds.delete(id); S.mountedIds.delete(id); }
504
556
  const key = w.getAttribute(A_ANCHOR);
505
557
  if (key && S.wrapByKey.get(key) === w) S.wrapByKey.delete(key);
506
558
  w.remove();
@@ -694,9 +746,12 @@ function startShowBatch(ids) {
694
746
  window.ezstandalone = window.ezstandalone || {};
695
747
  const ez = window.ezstandalone;
696
748
  const doShow = () => {
697
- try { ez.showAds(...valid); } catch (_) {}
698
- for (const id of valid) {
749
+ const prepared = destroyBeforeReuse(valid);
750
+ if (!prepared.length) { setTimeout(() => { clearTimeout(timer); release(); }, SHOW_RELEASE_MS); return; }
751
+ try { ez.showAds(...prepared); } catch (_) {}
752
+ for (const id of prepared) {
699
753
  S.ezActiveIds.add(id);
754
+ S.ezShownSinceDestroy.add(id);
700
755
  }
701
756
  setTimeout(() => { clearTimeout(timer); release(); }, SHOW_RELEASE_MS);
702
757
  };
@@ -839,10 +894,14 @@ function startShowBatch(ids) {
839
894
  S.lastShow.clear();
840
895
  S.wrapByKey.clear();
841
896
  S.ezActiveIds.clear();
897
+ S.ezShownSinceDestroy.clear();
842
898
  S.inflight = 0;
843
899
  S.pending = [];
844
900
  S.pendingSet.clear();
845
901
  if (S.showBatchTimer) { clearTimeout(S.showBatchTimer); S.showBatchTimer = 0; }
902
+ if (S.destroyBatchTimer) { clearTimeout(S.destroyBatchTimer); S.destroyBatchTimer = 0; }
903
+ S.destroyPending = [];
904
+ S.destroyPendingSet.clear();
846
905
  S.burstActive = false;
847
906
  S.runQueued = false;
848
907
  S.sweepQueued = false;