nodebb-plugin-ezoic-infinite 1.8.93 → 1.8.95
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 +20 -27
- package/package.json +1 -1
- package/public/client.js +23 -49
package/library.js
CHANGED
|
@@ -93,47 +93,37 @@ 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
|
-
|
|
97
|
+
const t = Date.now();
|
|
99
98
|
for (const [k, v] of _excludeCache) {
|
|
100
|
-
if (
|
|
99
|
+
if (!toDel) break;
|
|
100
|
+
if (t - v.at >= EXCLUDE_TTL) { _excludeCache.delete(k); toDel--; }
|
|
101
101
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
|
|
110
108
|
return value;
|
|
111
109
|
}
|
|
112
110
|
|
|
111
|
+
let _inlineCfgNormal = null;
|
|
112
|
+
let _inlineCfgExcluded = null;
|
|
113
|
+
|
|
113
114
|
function clearCaches() {
|
|
114
115
|
_settingsCache = null;
|
|
115
116
|
_settingsCacheAt = 0;
|
|
116
117
|
_excludeCache.clear();
|
|
118
|
+
_inlineCfgNormal = null;
|
|
119
|
+
_inlineCfgExcluded = null;
|
|
117
120
|
}
|
|
118
121
|
|
|
119
122
|
// ── Client config ────────────────────────────────────────────────────────────
|
|
120
123
|
|
|
121
124
|
function buildClientConfig(settings, excluded) {
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
};
|
|
125
|
+
const { excludedGroups, ...rest } = settings;
|
|
126
|
+
return { excluded, ...rest };
|
|
137
127
|
}
|
|
138
128
|
|
|
139
129
|
function serializeInlineConfig(cfg) {
|
|
@@ -191,8 +181,12 @@ plugin.injectEzoicHead = async (data) => {
|
|
|
191
181
|
const uid = data.req?.uid ?? 0;
|
|
192
182
|
const excluded = await isUserExcluded(uid, settings.excludedGroups);
|
|
193
183
|
|
|
184
|
+
if (!_inlineCfgNormal) {
|
|
185
|
+
_inlineCfgNormal = serializeInlineConfig(buildClientConfig(settings, false));
|
|
186
|
+
_inlineCfgExcluded = serializeInlineConfig(buildClientConfig(settings, true));
|
|
187
|
+
}
|
|
188
|
+
|
|
194
189
|
if (excluded) {
|
|
195
|
-
const cfg = buildClientConfig(settings, true);
|
|
196
190
|
const stub = '<script data-cfasync="false">'
|
|
197
191
|
+ 'window._ezaq=window._ezaq||{};'
|
|
198
192
|
+ 'window.ezstandalone=window.ezstandalone||{};'
|
|
@@ -200,14 +194,13 @@ plugin.injectEzoicHead = async (data) => {
|
|
|
200
194
|
+ '</script>';
|
|
201
195
|
data.templateData.customHTML =
|
|
202
196
|
stub + '\n' +
|
|
203
|
-
|
|
197
|
+
_inlineCfgExcluded +
|
|
204
198
|
(data.templateData.customHTML || '');
|
|
205
199
|
} else {
|
|
206
|
-
const cfg = buildClientConfig(settings, false);
|
|
207
200
|
data.templateData.customHTML =
|
|
208
201
|
HEAD_PRECONNECTS + '\n' +
|
|
209
202
|
EZOIC_SCRIPTS + '\n' +
|
|
210
|
-
|
|
203
|
+
_inlineCfgNormal +
|
|
211
204
|
(data.templateData.customHTML || '');
|
|
212
205
|
}
|
|
213
206
|
} catch (err) {
|
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* NodeBB Ezoic Infinite Ads — client.js v2.5.
|
|
2
|
+
* NodeBB Ezoic Infinite Ads — client.js v2.5.2
|
|
3
3
|
*
|
|
4
4
|
* Architecture: proven v50 core + targeted improvements.
|
|
5
5
|
* Ezoic API: showAds() + destroyPlaceholders() per official docs.
|
|
6
6
|
* Key features: O(1) recycle via wrapsByClass, MutationObserver fill detect,
|
|
7
7
|
* conservative empty check, aria-hidden + TCF protection, retry boot for
|
|
8
8
|
* Cloudflare/async timing.
|
|
9
|
+
* v2.5.2: removed redundant warmNetwork() — preconnects are server-injected.
|
|
9
10
|
*/
|
|
10
11
|
(function nbbEzoicInfinite() {
|
|
11
12
|
'use strict';
|
|
@@ -177,8 +178,8 @@
|
|
|
177
178
|
return out;
|
|
178
179
|
}
|
|
179
180
|
|
|
180
|
-
const getTopics = () =>
|
|
181
|
-
const getCategories = () =>
|
|
181
|
+
const getTopics = () => document.querySelectorAll(SEL.topic);
|
|
182
|
+
const getCategories = () => document.querySelectorAll(SEL.category);
|
|
182
183
|
|
|
183
184
|
// ── Anchor keys & wrap registry ────────────────────────────────────────────
|
|
184
185
|
|
|
@@ -268,9 +269,8 @@
|
|
|
268
269
|
}
|
|
269
270
|
|
|
270
271
|
function addWrapTimer(id, ms, fn) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
S.wrapTimers.set(id, timers);
|
|
272
|
+
if (!S.wrapTimers.has(id)) S.wrapTimers.set(id, []);
|
|
273
|
+
S.wrapTimers.get(id).push(setTimeout(() => { try { fn(); } catch (_) {} }, ms));
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
function scheduleUncollapseChecks(wrap, id) {
|
|
@@ -434,12 +434,13 @@
|
|
|
434
434
|
|
|
435
435
|
// ── Injection ──────────────────────────────────────────────────────────────
|
|
436
436
|
|
|
437
|
-
function ordinal(klass, el) {
|
|
437
|
+
function ordinal(klass, el, hint) {
|
|
438
438
|
const attr = KIND[klass]?.ordinalAttr;
|
|
439
439
|
if (attr) {
|
|
440
440
|
const v = el.getAttribute(attr);
|
|
441
441
|
if (v != null && v !== '' && !isNaN(v)) return parseInt(v, 10);
|
|
442
442
|
}
|
|
443
|
+
if (hint !== undefined) return hint;
|
|
443
444
|
const fullSel = KIND[klass]?.sel ?? '';
|
|
444
445
|
let i = 0;
|
|
445
446
|
for (const s of el.parentElement?.children ?? []) {
|
|
@@ -452,10 +453,11 @@
|
|
|
452
453
|
function injectBetween(klass, items, interval, showFirst, poolKey) {
|
|
453
454
|
if (!items.length) return 0;
|
|
454
455
|
let inserted = 0;
|
|
456
|
+
let pos = 0;
|
|
455
457
|
for (const el of items) {
|
|
456
458
|
if (inserted >= MAX_INSERTS_RUN) break;
|
|
457
459
|
if (!el?.isConnected) continue;
|
|
458
|
-
const ord = ordinal(klass, el);
|
|
460
|
+
const ord = ordinal(klass, el, pos++);
|
|
459
461
|
if (!(showFirst && ord === 0) && (ord + 1) % interval !== 0) continue;
|
|
460
462
|
if (adjacentWrap(el)) continue;
|
|
461
463
|
const key = anchorKey(klass, el);
|
|
@@ -608,7 +610,6 @@
|
|
|
608
610
|
|
|
609
611
|
async function runCore() {
|
|
610
612
|
if (isBlocked()) return 0;
|
|
611
|
-
patchShowAds();
|
|
612
613
|
|
|
613
614
|
const t = now();
|
|
614
615
|
if (t - _lastGc > 30_000) { _lastGc = t; gcDisconnectedWraps(); }
|
|
@@ -798,30 +799,6 @@
|
|
|
798
799
|
try { window.__nbbAriaObs.observe(document.body, { attributes: true, attributeFilter: ['aria-hidden'] }); } catch (_) {}
|
|
799
800
|
}
|
|
800
801
|
|
|
801
|
-
// ── Network warmup ─────────────────────────────────────────────────────────
|
|
802
|
-
|
|
803
|
-
let _warmed = false;
|
|
804
|
-
function warmNetwork() {
|
|
805
|
-
if (_warmed) return;
|
|
806
|
-
_warmed = true;
|
|
807
|
-
const head = document.head;
|
|
808
|
-
if (!head) return;
|
|
809
|
-
for (const [rel, href, cors] of [
|
|
810
|
-
['preconnect', 'https://g.ezoic.net', true ],
|
|
811
|
-
['preconnect', 'https://go.ezoic.net', true ],
|
|
812
|
-
['preconnect', 'https://securepubads.g.doubleclick.net', true ],
|
|
813
|
-
['preconnect', 'https://pagead2.googlesyndication.com', true ],
|
|
814
|
-
['dns-prefetch', 'https://g.ezoic.net', false],
|
|
815
|
-
['dns-prefetch', 'https://securepubads.g.doubleclick.net', false],
|
|
816
|
-
]) {
|
|
817
|
-
if (head.querySelector(`link[rel="${rel}"][href="${href}"]`)) continue;
|
|
818
|
-
const l = document.createElement('link');
|
|
819
|
-
l.rel = rel; l.href = href;
|
|
820
|
-
if (cors) l.crossOrigin = 'anonymous';
|
|
821
|
-
head.appendChild(l);
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
|
|
825
802
|
// ── Bindings ───────────────────────────────────────────────────────────────
|
|
826
803
|
|
|
827
804
|
function bindNodeBB() {
|
|
@@ -832,7 +809,7 @@
|
|
|
832
809
|
$(window).on('action:ajaxify.end.nbbEzoic', () => {
|
|
833
810
|
S.pageKey = pageKey(); S.kind = null; S.blockedUntil = 0;
|
|
834
811
|
ensureTcfLocator(); protectAriaHidden();
|
|
835
|
-
|
|
812
|
+
patchShowAds(); getIO(); ensureDomObserver();
|
|
836
813
|
requestBurst();
|
|
837
814
|
});
|
|
838
815
|
// action:ajaxify.contentLoaded et action:category.loaded ne passent pas par hooks → jQuery uniquement
|
|
@@ -863,7 +840,6 @@
|
|
|
863
840
|
S.pageKey = pageKey();
|
|
864
841
|
ensureTcfLocator();
|
|
865
842
|
protectAriaHidden();
|
|
866
|
-
warmNetwork();
|
|
867
843
|
patchShowAds();
|
|
868
844
|
getIO();
|
|
869
845
|
ensureDomObserver();
|
|
@@ -886,20 +862,18 @@
|
|
|
886
862
|
// in ez-standalone.js → onStandaloneLoadEvent crash). After ~6s, remove and reload
|
|
887
863
|
// sa.min.js; Ezoic's partial first-run state may let the second run succeed.
|
|
888
864
|
// Once recovered, re-enqueue all mounted placeholders so showAds() fires.
|
|
889
|
-
|
|
890
|
-
let _scriptReloaded = false;
|
|
891
|
-
let _postReloadShown = false;
|
|
865
|
+
const RETRY = { count: 0, scriptReloaded: false, postReloadShown: false };
|
|
892
866
|
function retryBoot() {
|
|
893
|
-
if (
|
|
894
|
-
|
|
867
|
+
if (RETRY.count >= 12) return;
|
|
868
|
+
RETRY.count++;
|
|
895
869
|
patchShowAds();
|
|
896
870
|
|
|
897
871
|
const ez = window.ezstandalone;
|
|
898
872
|
const status = ez?.loadingStatus;
|
|
899
873
|
|
|
900
874
|
// After reload: once Ezoic reaches 'complete', re-call showAds for all mounted placeholders
|
|
901
|
-
if (
|
|
902
|
-
|
|
875
|
+
if (RETRY.scriptReloaded && !RETRY.postReloadShown && status === 'complete') {
|
|
876
|
+
RETRY.postReloadShown = true;
|
|
903
877
|
for (const id of S.mountedIds) { try { enqueueShow(id); } catch (_) {} }
|
|
904
878
|
return;
|
|
905
879
|
}
|
|
@@ -907,19 +881,19 @@
|
|
|
907
881
|
// Normal exit: placeholders mounted, no reload triggered (healthy load).
|
|
908
882
|
// Exception: if Ezoic status is stuck (not absent and not 'complete'), continue
|
|
909
883
|
// so crash detection below can trigger the sa.min.js reload.
|
|
910
|
-
if (S.mountedIds.size > 0 && !
|
|
884
|
+
if (S.mountedIds.size > 0 && !RETRY.scriptReloaded && (!status || status === 'complete')) return;
|
|
911
885
|
// Exit once reload is done and re-show has been triggered
|
|
912
|
-
if (
|
|
886
|
+
if (RETRY.scriptReloaded && RETRY.postReloadShown) return;
|
|
913
887
|
|
|
914
|
-
if (!
|
|
888
|
+
if (!RETRY.scriptReloaded) {
|
|
915
889
|
// Case 1: sa.min.js never injected (Rocket Loader stripped it, etc.)
|
|
916
|
-
const neverInjected = !status && !document.querySelector('script[src*="sa.min.js"]') &&
|
|
890
|
+
const neverInjected = !status && !document.querySelector('script[src*="sa.min.js"]') && RETRY.count <= 3;
|
|
917
891
|
// Case 2: cold-start crash — loadingStatus stuck before 'complete' after enough wait.
|
|
918
892
|
// Do NOT reload when status==='complete' (post-defineScript-failure would re-trigger).
|
|
919
893
|
const anyFilled = !!document.querySelector(`.${WRAP_CLASS} ${FILL_SEL}`);
|
|
920
|
-
const crashed =
|
|
894
|
+
const crashed = RETRY.count >= 8 && !anyFilled && status && status !== 'complete';
|
|
921
895
|
if (neverInjected || crashed) {
|
|
922
|
-
|
|
896
|
+
RETRY.scriptReloaded = true;
|
|
923
897
|
try {
|
|
924
898
|
if (crashed) {
|
|
925
899
|
// Remove the broken script before re-adding to avoid a duplicate
|
|
@@ -942,7 +916,7 @@
|
|
|
942
916
|
S.lastBurstTs = now() - TIMING.BURST_COOLDOWN_MS;
|
|
943
917
|
requestBurst();
|
|
944
918
|
}
|
|
945
|
-
setTimeout(retryBoot,
|
|
919
|
+
setTimeout(retryBoot, RETRY.count <= 4 ? 300 : 1000);
|
|
946
920
|
}
|
|
947
921
|
setTimeout(retryBoot, 250);
|
|
948
922
|
|