nodebb-plugin-ezoic-infinite 1.8.95 → 1.8.96

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
@@ -29,17 +29,25 @@ function parseBool(v, def = false) {
29
29
  return s === '1' || s === 'true' || s === 'on' || s === 'yes';
30
30
  }
31
31
 
32
+ let _allGroupsCache = null;
33
+ let _allGroupsCacheAt = 0;
34
+ const ALL_GROUPS_TTL = 300_000; // 5 min — admin-only route
35
+
32
36
  async function getAllGroups() {
37
+ const t = Date.now();
38
+ if (_allGroupsCache && (t - _allGroupsCacheAt) < ALL_GROUPS_TTL) return _allGroupsCache;
33
39
  try {
34
40
  let names = await db.getSortedSetRange('groups:createtime', 0, -1);
35
41
  if (!names?.length) {
36
42
  names = await db.getSortedSetRange('groups:visible:createtime', 0, -1);
37
43
  }
38
- return (await groups.getGroupsData(
44
+ _allGroupsCache = (await groups.getGroupsData(
39
45
  (names || []).filter(name => !groups.isPrivilegeGroup(name))
40
46
  ))
41
47
  .filter(g => g?.name)
42
48
  .sort((a, b) => String(a.name).localeCompare(String(b.name), undefined, { sensitivity: 'base' }));
49
+ _allGroupsCacheAt = Date.now();
50
+ return _allGroupsCache;
43
51
  } catch (err) {
44
52
  console.error('[ezoic-infinite] getAllGroups error:', err.message);
45
53
  return [];
@@ -117,6 +125,8 @@ function clearCaches() {
117
125
  _excludeCache.clear();
118
126
  _inlineCfgNormal = null;
119
127
  _inlineCfgExcluded = null;
128
+ _allGroupsCache = null;
129
+ _allGroupsCacheAt = 0;
120
130
  }
121
131
 
122
132
  // ── Client config ────────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.8.95",
3
+ "version": "1.8.96",
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
@@ -81,6 +81,7 @@
81
81
  pageKey: null,
82
82
  kind: null,
83
83
  cfg: null,
84
+ opts: null,
84
85
  poolsReady: false,
85
86
  pools: { topics: [], posts: [], categories: [] },
86
87
  cursors: { topics: 0, posts: 0, categories: 0 },
@@ -132,6 +133,17 @@
132
133
  S.pools.topics = parseIds(cfg.placeholderIds);
133
134
  S.pools.posts = parseIds(cfg.messagePlaceholderIds);
134
135
  S.pools.categories = parseIds(cfg.categoryPlaceholderIds);
136
+ S.opts = {
137
+ enableBetweenAds: normBool(cfg.enableBetweenAds),
138
+ showFirstTopicAd: normBool(cfg.showFirstTopicAd),
139
+ intervalTopics: Math.max(1, parseInt(cfg.intervalPosts, 10) || 3),
140
+ enableCategoryAds: normBool(cfg.enableCategoryAds),
141
+ showFirstCategoryAd: normBool(cfg.showFirstCategoryAd),
142
+ intervalCategories: Math.max(1, parseInt(cfg.intervalCategories, 10) || 3),
143
+ enableMessageAds: normBool(cfg.enableMessageAds),
144
+ showFirstMessageAd: normBool(cfg.showFirstMessageAd),
145
+ messageInterval: Math.max(1, parseInt(cfg.messageIntervalPosts, 10) || 3),
146
+ };
135
147
  S.poolsReady = true;
136
148
  }
137
149
 
@@ -169,6 +181,7 @@
169
181
  for (let i = 0; i < all.length; i++) {
170
182
  const el = all[i];
171
183
  if (!el.isConnected) continue;
184
+ if (el.childElementCount === 0) continue;
172
185
  if (!el.querySelector('[component="post/content"]')) continue;
173
186
  const parent = el.parentElement?.closest(SEL.post);
174
187
  if (parent && parent !== el) continue;
@@ -621,18 +634,19 @@
621
634
  const kind = getKind();
622
635
  if (kind === 'other') return 0;
623
636
 
624
- const exec = (klass, getItems, cfgEnable, cfgInterval, cfgShowFirst, poolKey) => {
625
- if (!normBool(cfgEnable)) return 0;
626
- return injectBetween(klass, getItems(), Math.max(1, parseInt(cfgInterval, 10) || 3), normBool(cfgShowFirst), poolKey);
637
+ const exec = (klass, getItems, enable, interval, showFirst, poolKey) => {
638
+ if (!enable) return 0;
639
+ return injectBetween(klass, getItems(), interval, showFirst, poolKey);
627
640
  };
628
641
 
642
+ const o = S.opts;
629
643
  if (kind === 'topic')
630
- return exec('ezoic-ad-message', getPosts, cfg.enableMessageAds, cfg.messageIntervalPosts, cfg.showFirstMessageAd, 'posts');
644
+ return exec('ezoic-ad-message', getPosts, o.enableMessageAds, o.messageInterval, o.showFirstMessageAd, 'posts');
631
645
  if (kind === 'categoryTopics') {
632
646
  pruneOrphansBetween();
633
- return exec('ezoic-ad-between', getTopics, cfg.enableBetweenAds, cfg.intervalPosts, cfg.showFirstTopicAd, 'topics');
647
+ return exec('ezoic-ad-between', getTopics, o.enableBetweenAds, o.intervalTopics, o.showFirstTopicAd, 'topics');
634
648
  }
635
- return exec('ezoic-ad-categories', getCategories, cfg.enableCategoryAds, cfg.intervalCategories, cfg.showFirstCategoryAd, 'categories');
649
+ return exec('ezoic-ad-categories', getCategories, o.enableCategoryAds, o.intervalCategories, o.showFirstCategoryAd, 'categories');
636
650
  }
637
651
 
638
652
  // ── Scheduler ──────────────────────────────────────────────────────────────
@@ -688,6 +702,7 @@
688
702
  S.domObs?.disconnect(); S.domObs = null;
689
703
  S.io?.disconnect(); S.io = null;
690
704
  S.cfg = null;
705
+ S.opts = null;
691
706
  S.poolsReady = false;
692
707
  S.pools = { topics: [], posts: [], categories: [] };
693
708
  S.cursors = { topics: 0, posts: 0, categories: 0 };
@@ -728,16 +743,21 @@
728
743
  for (const node of m.addedNodes) {
729
744
  if (!(node instanceof Element)) continue;
730
745
  try {
731
- if (node.matches?.(FILL_SEL) || node.querySelector?.(FILL_SEL)) {
732
- const wrap = node.closest?.(`.${WRAP_CLASS}.is-empty`) || m.target?.closest?.(`.${WRAP_CLASS}.is-empty`);
733
- if (wrap) clearEmptyIfFilled(wrap);
746
+ // Check closest first (cheap) before doing FILL_SEL querySelector on every added node
747
+ const emptyWrap = node.closest?.(`.${WRAP_CLASS}.is-empty`) ?? m.target?.closest?.(`.${WRAP_CLASS}.is-empty`);
748
+ if (emptyWrap && (node.matches?.(FILL_SEL) || node.querySelector?.(FILL_SEL))) {
749
+ clearEmptyIfFilled(emptyWrap);
734
750
  }
735
751
  } catch (_) {}
736
752
  try {
737
- const reinserted = node.classList?.contains(WRAP_CLASS) ? [node] : Array.from(node.querySelectorAll?.(`.${WRAP_CLASS}`) || []);
738
- for (const wrap of reinserted) {
739
- const id = parseInt(wrap.getAttribute(ATTR.WRAPID), 10);
740
- if (id > 0) { const ph = wrap.querySelector(`[id^="${PH_PREFIX}"]`); if (ph) try { getIO()?.observe(ph); } catch (_) {} }
753
+ if (node.classList?.contains(WRAP_CLASS)) {
754
+ const id = parseInt(node.getAttribute(ATTR.WRAPID), 10);
755
+ if (id > 0) { const ph = node.querySelector(`[id^="${PH_PREFIX}"]`); if (ph) try { getIO()?.observe(ph); } catch (_) {} }
756
+ } else if (node.childElementCount > 0) {
757
+ for (const wrap of node.querySelectorAll(`.${WRAP_CLASS}`)) {
758
+ const id = parseInt(wrap.getAttribute(ATTR.WRAPID), 10);
759
+ if (id > 0) { const ph = wrap.querySelector(`[id^="${PH_PREFIX}"]`); if (ph) try { getIO()?.observe(ph); } catch (_) {} }
760
+ }
741
761
  }
742
762
  } catch (_) {}
743
763
  if (!needsBurst) {
@@ -866,6 +886,8 @@
866
886
  function retryBoot() {
867
887
  if (RETRY.count >= 12) return;
868
888
  RETRY.count++;
889
+ // On pages that never show ads, no need to retry (unless mid-reload recovery)
890
+ if (!RETRY.scriptReloaded && getKind() === 'other') return;
869
891
  patchShowAds();
870
892
 
871
893
  const ez = window.ezstandalone;