nodebb-plugin-ezoic-infinite 1.8.96 → 1.8.97

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.
@@ -4,7 +4,10 @@
4
4
  "WebFetch(domain:registry.npmjs.org)",
5
5
  "Bash(curl -sL \"https://registry.npmjs.org/nodebb-plugin-ezoic-infinite/-/nodebb-plugin-ezoic-infinite-1.8.81.tgz\" -o /tmp/ezoic-1.8.81.tgz && tar -tzf /tmp/ezoic-1.8.81.tgz)",
6
6
  "Bash(tar -xzf /tmp/ezoic-1.8.81.tgz -C /tmp/ package/library.js package/public/client.js package/package.json)",
7
- "Bash(cd /tmp && curl -sL \"https://registry.npmjs.org/nodebb-plugin-ezoic-infinite/-/nodebb-plugin-ezoic-infinite-1.8.81.tgz\" -o ezoic-1.8.81.tgz && tar -xzf ezoic-1.8.81.tgz && echo \"Extracted OK\")"
7
+ "Bash(cd /tmp && curl -sL \"https://registry.npmjs.org/nodebb-plugin-ezoic-infinite/-/nodebb-plugin-ezoic-infinite-1.8.81.tgz\" -o ezoic-1.8.81.tgz && tar -xzf ezoic-1.8.81.tgz && echo \"Extracted OK\")",
8
+ "Bash(node -e \"require\\(''./library.js''\\)\")",
9
+ "Bash(node --check \"C:\\\\Users\\\\arnau\\\\OneDrive\\\\Dev\\\\nodebb-plugin-onekite-ezoic\\\\public\\\\client.js\")",
10
+ "Bash(node --check \"C:\\\\Users\\\\arnau\\\\OneDrive\\\\Dev\\\\nodebb-plugin-onekite-ezoic\\\\library.js\")"
8
11
  ]
9
12
  }
10
13
  }
package/library.js CHANGED
@@ -101,15 +101,10 @@ async function isUserExcluded(uid, excludedGroups) {
101
101
 
102
102
  _excludeCache.set(key, { value, at: Date.now() });
103
103
  if (_excludeCache.size > 1000) {
104
- let toDel = 100;
105
- const t = Date.now();
106
- for (const [k, v] of _excludeCache) {
107
- if (!toDel) break;
108
- if (t - v.at >= EXCLUDE_TTL) { _excludeCache.delete(k); toDel--; }
109
- }
104
+ let n = 100;
110
105
  for (const k of _excludeCache.keys()) {
111
- if (!toDel) break;
112
- _excludeCache.delete(k); toDel--;
106
+ if (!n--) break;
107
+ _excludeCache.delete(k);
113
108
  }
114
109
  }
115
110
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.8.96",
3
+ "version": "1.8.97",
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
@@ -34,7 +34,7 @@
34
34
  SHOW_TIMEOUT_MS: 4_500,
35
35
  SHOW_RELEASE_MS: 700,
36
36
  RECYCLE_DELAY_MS: 300,
37
- UNCOLLAPSE_CHECK_MS: [500, 3_000, 10_000],
37
+ UNCOLLAPSE_CHECK_MS: [500, 5_000],
38
38
  };
39
39
 
40
40
  const MAX_INSERTS_RUN = 6;
@@ -105,6 +105,12 @@
105
105
 
106
106
  const isBlocked = () => now() < S.blockedUntil;
107
107
 
108
+ // ── Posts cache (burst-scoped) ─────────────────────────────────────────────
109
+
110
+ let _postsCache = null;
111
+ let _postsCacheTs = 0;
112
+ const POSTS_CACHE_MS = 200;
113
+
108
114
  function mutate(fn) {
109
115
  S.mutGuard++;
110
116
  try { fn(); } finally { S.mutGuard--; }
@@ -176,6 +182,8 @@
176
182
  // ── DOM queries ────────────────────────────────────────────────────────────
177
183
 
178
184
  function getPosts() {
185
+ const t = now();
186
+ if (_postsCache && t - _postsCacheTs < POSTS_CACHE_MS) return _postsCache;
179
187
  const all = document.querySelectorAll(SEL.post);
180
188
  const out = [];
181
189
  for (let i = 0; i < all.length; i++) {
@@ -188,6 +196,8 @@
188
196
  if (el.getAttribute('component') === 'post/parent') continue;
189
197
  out.push(el);
190
198
  }
199
+ _postsCache = out;
200
+ _postsCacheTs = t;
191
201
  return out;
192
202
  }
193
203
 
@@ -256,17 +266,14 @@
256
266
  const cfg = KIND[klass];
257
267
  if (!cfg) return false;
258
268
  const parent = wrap.parentElement;
259
- if (parent) {
260
- const sel = `${cfg.baseTag || ''}[${cfg.anchorAttr}="${anchorId}"]`;
261
- for (const sib of parent.children) {
262
- if (sib !== wrap) {
263
- try { if (sib.matches(sel)) return sib.isConnected; } catch (_) {}
264
- }
269
+ if (!parent) return false;
270
+ const sel = `${cfg.baseTag || ''}[${cfg.anchorAttr}="${anchorId}"]`;
271
+ for (const sib of parent.children) {
272
+ if (sib !== wrap) {
273
+ try { if (sib.matches(sel)) return sib.isConnected; } catch (_) {}
265
274
  }
266
275
  }
267
- try {
268
- return document.querySelector(`${cfg.sel}[${cfg.anchorAttr}="${anchorId}"]`)?.isConnected === true;
269
- } catch (_) { return false; }
276
+ return false;
270
277
  }
271
278
 
272
279
  const adjacentWrap = el => wrapIsLive(el.nextElementSibling) || wrapIsLive(el.previousElementSibling);
@@ -489,9 +496,12 @@
489
496
 
490
497
  // ── IntersectionObserver ───────────────────────────────────────────────────
491
498
 
499
+ let _ioMobile = null;
500
+
492
501
  function getIO() {
493
502
  if (S.io) return S.io;
494
503
  try {
504
+ _ioMobile = isMobile();
495
505
  S.io = new IntersectionObserver(entries => {
496
506
  for (const e of entries) {
497
507
  if (!e.isIntersecting) continue;
@@ -501,7 +511,7 @@
501
511
  }
502
512
  }, {
503
513
  root: null,
504
- rootMargin: isMobile() ? IO_MARGIN_MOBILE : IO_MARGIN_DESKTOP,
514
+ rootMargin: _ioMobile ? IO_MARGIN_MOBILE : IO_MARGIN_DESKTOP,
505
515
  threshold: 0,
506
516
  });
507
517
  } catch (_) { S.io = null; }
@@ -700,7 +710,8 @@
700
710
  for (const timers of S.wrapTimers.values()) { for (const t of timers) clearTimeout(t); }
701
711
  S.wrapTimers.clear();
702
712
  S.domObs?.disconnect(); S.domObs = null;
703
- S.io?.disconnect(); S.io = null;
713
+ S.io?.disconnect(); S.io = null; _ioMobile = null;
714
+ _postsCache = null; _postsCacheTs = 0;
704
715
  S.cfg = null;
705
716
  S.opts = null;
706
717
  S.poolsReady = false;
@@ -767,9 +778,12 @@
767
778
  }
768
779
  }
769
780
  }
770
- if (needsBurst) requestBurst();
781
+ if (needsBurst) { _postsCacheTs = 0; requestBurst(); }
771
782
  });
772
- try { S.domObs.observe(document.body, { childList: true, subtree: true }); } catch (_) {}
783
+ try {
784
+ const target = document.getElementById('content') || document.body;
785
+ S.domObs.observe(target, { childList: true, subtree: true });
786
+ } catch (_) {}
773
787
  }
774
788
 
775
789
  // ── TCF / CMP Protection ───────────────────────────────────────────────────
@@ -830,6 +844,8 @@
830
844
  S.pageKey = pageKey(); S.kind = null; S.blockedUntil = 0;
831
845
  ensureTcfLocator(); protectAriaHidden();
832
846
  patchShowAds(); getIO(); ensureDomObserver();
847
+ RETRY.count = 0; RETRY.scriptReloaded = false; RETRY.postReloadShown = false; RETRY.gen++;
848
+ setTimeout(() => retryBoot(RETRY.gen), 250);
833
849
  requestBurst();
834
850
  });
835
851
  // action:ajaxify.contentLoaded et action:category.loaded ne passent pas par hooks → jQuery uniquement
@@ -841,7 +857,7 @@
841
857
  try {
842
858
  require(['hooks'], hooks => {
843
859
  if (typeof hooks?.on !== 'function') return;
844
- for (const ev of ['action:ajaxify.end', 'action:posts.loaded', 'action:topics.loaded', 'action:categories.loaded', 'action:topic.loaded'])
860
+ for (const ev of ['action:posts.loaded', 'action:topics.loaded', 'action:categories.loaded', 'action:topic.loaded'])
845
861
  try { hooks.on(ev, () => { if (!isBlocked()) requestBurst(); }); } catch (_) {}
846
862
  });
847
863
  } catch (_) {}
@@ -855,6 +871,21 @@
855
871
  }, { passive: true });
856
872
  }
857
873
 
874
+ function bindResize() {
875
+ let timer = null;
876
+ window.addEventListener('resize', () => {
877
+ clearTimeout(timer);
878
+ timer = setTimeout(() => {
879
+ if (!S.io || _ioMobile === null) return;
880
+ const m = isMobile();
881
+ if (m === _ioMobile) return;
882
+ S.io.disconnect(); S.io = null; _ioMobile = null;
883
+ getIO();
884
+ for (const id of S.mountedIds) observePh(id);
885
+ }, 250);
886
+ }, { passive: true });
887
+ }
888
+
858
889
  // ── Boot ───────────────────────────────────────────────────────────────────
859
890
 
860
891
  S.pageKey = pageKey();
@@ -865,6 +896,7 @@
865
896
  ensureDomObserver();
866
897
  bindNodeBB();
867
898
  bindScroll();
899
+ bindResize();
868
900
  S.blockedUntil = 0;
869
901
  if (document.readyState === 'complete') {
870
902
  requestBurst();
@@ -882,8 +914,9 @@
882
914
  // in ez-standalone.js → onStandaloneLoadEvent crash). After ~6s, remove and reload
883
915
  // sa.min.js; Ezoic's partial first-run state may let the second run succeed.
884
916
  // Once recovered, re-enqueue all mounted placeholders so showAds() fires.
885
- const RETRY = { count: 0, scriptReloaded: false, postReloadShown: false };
886
- function retryBoot() {
917
+ const RETRY = { count: 0, scriptReloaded: false, postReloadShown: false, gen: 0 };
918
+ function retryBoot(gen) {
919
+ if (gen !== RETRY.gen) return;
887
920
  if (RETRY.count >= 12) return;
888
921
  RETRY.count++;
889
922
  // On pages that never show ads, no need to retry (unless mid-reload recovery)
@@ -938,8 +971,8 @@
938
971
  S.lastBurstTs = now() - TIMING.BURST_COOLDOWN_MS;
939
972
  requestBurst();
940
973
  }
941
- setTimeout(retryBoot, RETRY.count <= 4 ? 300 : 1000);
974
+ setTimeout(() => retryBoot(gen), RETRY.count <= 4 ? 300 : 1000);
942
975
  }
943
- setTimeout(retryBoot, 250);
976
+ setTimeout(() => retryBoot(RETRY.gen), 250);
944
977
 
945
978
  })();