nodebb-plugin-ezoic-infinite 1.8.92 → 1.8.94

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.
package/library.js CHANGED
@@ -93,17 +93,15 @@ async function isUserExcluded(uid, excludedGroups) {
93
93
 
94
94
  _excludeCache.set(key, { value, at: Date.now() });
95
95
  if (_excludeCache.size > 1000) {
96
- const now = Date.now();
97
96
  let toDel = 100;
98
- // Supprimer en priorité les entrées expirées, puis les plus anciennes
97
+ const t = Date.now();
99
98
  for (const [k, v] of _excludeCache) {
100
- if (now - v.at >= EXCLUDE_TTL) { _excludeCache.delete(k); if (--toDel <= 0) break; }
99
+ if (!toDel) break;
100
+ if (t - v.at >= EXCLUDE_TTL) { _excludeCache.delete(k); toDel--; }
101
101
  }
102
- if (toDel > 0) {
103
- for (const k of _excludeCache.keys()) {
104
- _excludeCache.delete(k);
105
- if (--toDel <= 0) break;
106
- }
102
+ for (const k of _excludeCache.keys()) {
103
+ if (!toDel) break;
104
+ _excludeCache.delete(k); toDel--;
107
105
  }
108
106
  }
109
107
 
@@ -119,21 +117,8 @@ function clearCaches() {
119
117
  // ── Client config ────────────────────────────────────────────────────────────
120
118
 
121
119
  function buildClientConfig(settings, excluded) {
122
- return {
123
- excluded,
124
- enableBetweenAds: settings.enableBetweenAds,
125
- showFirstTopicAd: settings.showFirstTopicAd,
126
- placeholderIds: settings.placeholderIds,
127
- intervalPosts: settings.intervalPosts,
128
- enableCategoryAds: settings.enableCategoryAds,
129
- showFirstCategoryAd: settings.showFirstCategoryAd,
130
- categoryPlaceholderIds: settings.categoryPlaceholderIds,
131
- intervalCategories: settings.intervalCategories,
132
- enableMessageAds: settings.enableMessageAds,
133
- showFirstMessageAd: settings.showFirstMessageAd,
134
- messagePlaceholderIds: settings.messagePlaceholderIds,
135
- messageIntervalPosts: settings.messageIntervalPosts,
136
- };
120
+ const { excludedGroups, ...rest } = settings;
121
+ return { excluded, ...rest };
137
122
  }
138
123
 
139
124
  function serializeInlineConfig(cfg) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.8.92",
3
+ "version": "1.8.94",
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
@@ -1,5 +1,5 @@
1
1
  /**
2
- * NodeBB Ezoic Infinite Ads — client.js v2.5.0
2
+ * NodeBB Ezoic Infinite Ads — client.js v2.5.1
3
3
  *
4
4
  * Architecture: proven v50 core + targeted improvements.
5
5
  * Ezoic API: showAds() + destroyPlaceholders() per official docs.
@@ -177,8 +177,8 @@
177
177
  return out;
178
178
  }
179
179
 
180
- const getTopics = () => Array.from(document.querySelectorAll(SEL.topic));
181
- const getCategories = () => Array.from(document.querySelectorAll(SEL.category));
180
+ const getTopics = () => document.querySelectorAll(SEL.topic);
181
+ const getCategories = () => document.querySelectorAll(SEL.category);
182
182
 
183
183
  // ── Anchor keys & wrap registry ────────────────────────────────────────────
184
184
 
@@ -268,9 +268,8 @@
268
268
  }
269
269
 
270
270
  function addWrapTimer(id, ms, fn) {
271
- const timers = S.wrapTimers.get(id) || [];
272
- timers.push(setTimeout(() => { try { fn(); } catch (_) {} }, ms));
273
- S.wrapTimers.set(id, timers);
271
+ if (!S.wrapTimers.has(id)) S.wrapTimers.set(id, []);
272
+ S.wrapTimers.get(id).push(setTimeout(() => { try { fn(); } catch (_) {} }, ms));
274
273
  }
275
274
 
276
275
  function scheduleUncollapseChecks(wrap, id) {
@@ -434,12 +433,13 @@
434
433
 
435
434
  // ── Injection ──────────────────────────────────────────────────────────────
436
435
 
437
- function ordinal(klass, el) {
436
+ function ordinal(klass, el, hint) {
438
437
  const attr = KIND[klass]?.ordinalAttr;
439
438
  if (attr) {
440
439
  const v = el.getAttribute(attr);
441
440
  if (v != null && v !== '' && !isNaN(v)) return parseInt(v, 10);
442
441
  }
442
+ if (hint !== undefined) return hint;
443
443
  const fullSel = KIND[klass]?.sel ?? '';
444
444
  let i = 0;
445
445
  for (const s of el.parentElement?.children ?? []) {
@@ -452,10 +452,11 @@
452
452
  function injectBetween(klass, items, interval, showFirst, poolKey) {
453
453
  if (!items.length) return 0;
454
454
  let inserted = 0;
455
+ let pos = 0;
455
456
  for (const el of items) {
456
457
  if (inserted >= MAX_INSERTS_RUN) break;
457
458
  if (!el?.isConnected) continue;
458
- const ord = ordinal(klass, el);
459
+ const ord = ordinal(klass, el, pos++);
459
460
  if (!(showFirst && ord === 0) && (ord + 1) % interval !== 0) continue;
460
461
  if (adjacentWrap(el)) continue;
461
462
  const key = anchorKey(klass, el);
@@ -608,7 +609,6 @@
608
609
 
609
610
  async function runCore() {
610
611
  if (isBlocked()) return 0;
611
- patchShowAds();
612
612
 
613
613
  const t = now();
614
614
  if (t - _lastGc > 30_000) { _lastGc = t; gcDisconnectedWraps(); }
@@ -886,38 +886,38 @@
886
886
  // in ez-standalone.js → onStandaloneLoadEvent crash). After ~6s, remove and reload
887
887
  // sa.min.js; Ezoic's partial first-run state may let the second run succeed.
888
888
  // Once recovered, re-enqueue all mounted placeholders so showAds() fires.
889
- let _retries = 0;
890
- let _scriptReloaded = false;
891
- let _postReloadShown = false;
889
+ const RETRY = { count: 0, scriptReloaded: false, postReloadShown: false };
892
890
  function retryBoot() {
893
- if (_retries >= 12) return;
894
- _retries++;
891
+ if (RETRY.count >= 12) return;
892
+ RETRY.count++;
895
893
  patchShowAds();
896
894
 
897
895
  const ez = window.ezstandalone;
898
896
  const status = ez?.loadingStatus;
899
897
 
900
898
  // After reload: once Ezoic reaches 'complete', re-call showAds for all mounted placeholders
901
- if (_scriptReloaded && !_postReloadShown && status === 'complete') {
902
- _postReloadShown = true;
899
+ if (RETRY.scriptReloaded && !RETRY.postReloadShown && status === 'complete') {
900
+ RETRY.postReloadShown = true;
903
901
  for (const id of S.mountedIds) { try { enqueueShow(id); } catch (_) {} }
904
902
  return;
905
903
  }
906
904
 
907
- // Normal exit: placeholders mounted, no reload triggered (healthy load)
908
- if (S.mountedIds.size > 0 && !_scriptReloaded) return;
905
+ // Normal exit: placeholders mounted, no reload triggered (healthy load).
906
+ // Exception: if Ezoic status is stuck (not absent and not 'complete'), continue
907
+ // so crash detection below can trigger the sa.min.js reload.
908
+ if (S.mountedIds.size > 0 && !RETRY.scriptReloaded && (!status || status === 'complete')) return;
909
909
  // Exit once reload is done and re-show has been triggered
910
- if (_scriptReloaded && _postReloadShown) return;
910
+ if (RETRY.scriptReloaded && RETRY.postReloadShown) return;
911
911
 
912
- if (!_scriptReloaded) {
912
+ if (!RETRY.scriptReloaded) {
913
913
  // Case 1: sa.min.js never injected (Rocket Loader stripped it, etc.)
914
- const neverInjected = !status && !document.querySelector('script[src*="sa.min.js"]') && _retries <= 3;
914
+ const neverInjected = !status && !document.querySelector('script[src*="sa.min.js"]') && RETRY.count <= 3;
915
915
  // Case 2: cold-start crash — loadingStatus stuck before 'complete' after enough wait.
916
916
  // Do NOT reload when status==='complete' (post-defineScript-failure would re-trigger).
917
917
  const anyFilled = !!document.querySelector(`.${WRAP_CLASS} ${FILL_SEL}`);
918
- const crashed = _retries >= 8 && !anyFilled && status && status !== 'complete';
918
+ const crashed = RETRY.count >= 8 && !anyFilled && status && status !== 'complete';
919
919
  if (neverInjected || crashed) {
920
- _scriptReloaded = true;
920
+ RETRY.scriptReloaded = true;
921
921
  try {
922
922
  if (crashed) {
923
923
  // Remove the broken script before re-adding to avoid a duplicate
@@ -940,7 +940,7 @@
940
940
  S.lastBurstTs = now() - TIMING.BURST_COOLDOWN_MS;
941
941
  requestBurst();
942
942
  }
943
- setTimeout(retryBoot, _retries <= 4 ? 300 : 1000);
943
+ setTimeout(retryBoot, RETRY.count <= 4 ? 300 : 1000);
944
944
  }
945
945
  setTimeout(retryBoot, 250);
946
946