nodebb-plugin-ezoic-infinite 1.9.3 → 1.9.5
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 +43 -30
- package/package.json +1 -1
- package/public/client.js +3 -2
- package/public/templates/admin/plugins/ezoic-infinite.tpl +11 -11
package/library.js
CHANGED
|
@@ -83,27 +83,30 @@ async function getSettings() {
|
|
|
83
83
|
if (_settingsInflight) return _settingsInflight;
|
|
84
84
|
const gen = _settingsGen;
|
|
85
85
|
_settingsInflight = (async () => {
|
|
86
|
+
let data = null;
|
|
86
87
|
try {
|
|
87
88
|
const s = await meta.settings.get(SETTINGS_KEY);
|
|
89
|
+
data = {
|
|
90
|
+
enableBetweenAds: parseBool(s.enableBetweenAds, true),
|
|
91
|
+
showFirstTopicAd: parseBool(s.showFirstTopicAd, false),
|
|
92
|
+
placeholderIds: (s.placeholderIds || '').trim(),
|
|
93
|
+
intervalPosts: Math.max(1, parseInt(s.intervalPosts, 10) || 6),
|
|
94
|
+
enableCategoryAds: parseBool(s.enableCategoryAds, false),
|
|
95
|
+
showFirstCategoryAd: parseBool(s.showFirstCategoryAd, false),
|
|
96
|
+
categoryPlaceholderIds: (s.categoryPlaceholderIds || '').trim(),
|
|
97
|
+
intervalCategories: Math.max(1, parseInt(s.intervalCategories, 10) || 4),
|
|
98
|
+
enableMessageAds: parseBool(s.enableMessageAds, false),
|
|
99
|
+
showFirstMessageAd: parseBool(s.showFirstMessageAd, false),
|
|
100
|
+
messagePlaceholderIds: (s.messagePlaceholderIds || '').trim(),
|
|
101
|
+
messageIntervalPosts: Math.max(1, parseInt(s.messageIntervalPosts, 10) || 3),
|
|
102
|
+
excludedGroups: normalizeExcludedGroups(s.excludedGroups),
|
|
103
|
+
};
|
|
104
|
+
data.excludedSet = new Set(data.excludedGroups);
|
|
88
105
|
if (_settingsGen === gen) {
|
|
89
106
|
_settingsCacheAt = Date.now();
|
|
90
|
-
_settingsCache =
|
|
91
|
-
enableBetweenAds: parseBool(s.enableBetweenAds, true),
|
|
92
|
-
showFirstTopicAd: parseBool(s.showFirstTopicAd, false),
|
|
93
|
-
placeholderIds: (s.placeholderIds || '').trim(),
|
|
94
|
-
intervalPosts: Math.max(1, parseInt(s.intervalPosts, 10) || 6),
|
|
95
|
-
enableCategoryAds: parseBool(s.enableCategoryAds, false),
|
|
96
|
-
showFirstCategoryAd: parseBool(s.showFirstCategoryAd, false),
|
|
97
|
-
categoryPlaceholderIds: (s.categoryPlaceholderIds || '').trim(),
|
|
98
|
-
intervalCategories: Math.max(1, parseInt(s.intervalCategories, 10) || 4),
|
|
99
|
-
enableMessageAds: parseBool(s.enableMessageAds, false),
|
|
100
|
-
showFirstMessageAd: parseBool(s.showFirstMessageAd, false),
|
|
101
|
-
messagePlaceholderIds: (s.messagePlaceholderIds || '').trim(),
|
|
102
|
-
messageIntervalPosts: Math.max(1, parseInt(s.messageIntervalPosts, 10) || 3),
|
|
103
|
-
excludedGroups: normalizeExcludedGroups(s.excludedGroups),
|
|
104
|
-
};
|
|
107
|
+
_settingsCache = data;
|
|
105
108
|
}
|
|
106
|
-
return _settingsCache;
|
|
109
|
+
return _settingsCache || data;
|
|
107
110
|
} finally {
|
|
108
111
|
if (_settingsGen === gen) _settingsInflight = null;
|
|
109
112
|
}
|
|
@@ -111,7 +114,7 @@ async function getSettings() {
|
|
|
111
114
|
return _settingsInflight;
|
|
112
115
|
}
|
|
113
116
|
|
|
114
|
-
async function isUserExcluded(uid, excludedGroups) {
|
|
117
|
+
async function isUserExcluded(uid, excludedGroups, excludedSet) {
|
|
115
118
|
if (!uid || !excludedGroups.length) return false;
|
|
116
119
|
|
|
117
120
|
const key = `${uid}|${excludedGroups.join('|')}`;
|
|
@@ -119,16 +122,21 @@ async function isUserExcluded(uid, excludedGroups) {
|
|
|
119
122
|
const hit = _excludeCache.get(key);
|
|
120
123
|
if (hit && (t - hit.at) < EXCLUDE_TTL) return hit.value;
|
|
121
124
|
|
|
122
|
-
const excludedSet = new Set(excludedGroups);
|
|
123
125
|
const userGroups = await groups.getUserGroups([uid]);
|
|
124
126
|
const value = (userGroups[0] || []).some(g => excludedSet.has(g.name));
|
|
125
127
|
|
|
126
128
|
_excludeCache.set(key, { value, at: Date.now() });
|
|
127
129
|
if (_excludeCache.size > 1000) {
|
|
128
|
-
|
|
129
|
-
for (const k of _excludeCache
|
|
130
|
-
if (
|
|
131
|
-
|
|
130
|
+
const expire = Date.now() - EXCLUDE_TTL;
|
|
131
|
+
for (const [k, v] of _excludeCache) {
|
|
132
|
+
if (v.at < expire) _excludeCache.delete(k);
|
|
133
|
+
}
|
|
134
|
+
if (_excludeCache.size > 900) {
|
|
135
|
+
let n = 100;
|
|
136
|
+
for (const k of _excludeCache.keys()) {
|
|
137
|
+
if (!n--) break;
|
|
138
|
+
_excludeCache.delete(k);
|
|
139
|
+
}
|
|
132
140
|
}
|
|
133
141
|
}
|
|
134
142
|
|
|
@@ -146,16 +154,13 @@ function clearCaches() {
|
|
|
146
154
|
_excludeCache.clear();
|
|
147
155
|
_inlineCfgNormal = null;
|
|
148
156
|
_inlineCfgExcluded = null;
|
|
149
|
-
|
|
150
|
-
_allGroupsCache = null;
|
|
151
|
-
_allGroupsCacheAt = 0;
|
|
152
|
-
_allGroupsInflight = null;
|
|
157
|
+
// _allGroupsCache is NOT cleared: the group list is independent of plugin settings.
|
|
153
158
|
}
|
|
154
159
|
|
|
155
160
|
// ── Client config ────────────────────────────────────────────────────────────
|
|
156
161
|
|
|
157
162
|
function buildClientConfig(settings, excluded) {
|
|
158
|
-
const { excludedGroups, ...rest } = settings;
|
|
163
|
+
const { excludedGroups, excludedSet, ...rest } = settings;
|
|
159
164
|
return { excluded, ...rest };
|
|
160
165
|
}
|
|
161
166
|
|
|
@@ -166,12 +171,20 @@ function serializeInlineConfig(cfg) {
|
|
|
166
171
|
// ── Head injection ───────────────────────────────────────────────────────────
|
|
167
172
|
|
|
168
173
|
const HEAD_PRECONNECTS = [
|
|
174
|
+
// Ezoic ad serving
|
|
169
175
|
'<link rel="preconnect" href="https://g.ezoic.net" crossorigin>',
|
|
170
176
|
'<link rel="preconnect" href="https://go.ezoic.net" crossorigin>',
|
|
171
177
|
'<link rel="preconnect" href="https://securepubads.g.doubleclick.net" crossorigin>',
|
|
172
178
|
'<link rel="preconnect" href="https://pagead2.googlesyndication.com" crossorigin>',
|
|
179
|
+
// Synchronous blocking scripts — preconnect to establish TCP+TLS before the parser reaches them
|
|
180
|
+
'<link rel="preconnect" href="https://cmp.gatekeeperconsent.com" crossorigin>',
|
|
181
|
+
'<link rel="preconnect" href="https://the.gatekeeperconsent.com" crossorigin>',
|
|
182
|
+
'<link rel="preconnect" href="https://www.ezojs.com" crossorigin>',
|
|
173
183
|
'<link rel="dns-prefetch" href="https://g.ezoic.net">',
|
|
174
184
|
'<link rel="dns-prefetch" href="https://securepubads.g.doubleclick.net">',
|
|
185
|
+
'<link rel="dns-prefetch" href="https://cmp.gatekeeperconsent.com">',
|
|
186
|
+
'<link rel="dns-prefetch" href="https://the.gatekeeperconsent.com">',
|
|
187
|
+
'<link rel="dns-prefetch" href="https://www.ezojs.com">',
|
|
175
188
|
].join('\n');
|
|
176
189
|
|
|
177
190
|
// Working config: sa.min.js loaded synchronously (no async).
|
|
@@ -189,7 +202,7 @@ const EZOIC_SCRIPTS = [
|
|
|
189
202
|
'<script data-cfasync="false" src="https://cmp.gatekeeperconsent.com/min.js"></script>',
|
|
190
203
|
'<script data-cfasync="false" src="https://the.gatekeeperconsent.com/cmp.min.js"></script>',
|
|
191
204
|
'<script data-cfasync="false" src="//www.ezojs.com/ezoic/sa.min.js"></script>',
|
|
192
|
-
'<script src="//ezoicanalytics.com/analytics.js"></script>',
|
|
205
|
+
'<script async src="//ezoicanalytics.com/analytics.js"></script>',
|
|
193
206
|
].join('\n');
|
|
194
207
|
|
|
195
208
|
// ── Hooks ────────────────────────────────────────────────────────────────────
|
|
@@ -217,7 +230,7 @@ plugin.injectEzoicHead = async (data) => {
|
|
|
217
230
|
|
|
218
231
|
const settings = await getSettings();
|
|
219
232
|
const uid = data.req?.uid ?? 0;
|
|
220
|
-
const excluded = await isUserExcluded(uid, settings.excludedGroups);
|
|
233
|
+
const excluded = await isUserExcluded(uid, settings.excludedGroups, settings.excludedSet);
|
|
221
234
|
|
|
222
235
|
if (!_inlineCfgNormal) {
|
|
223
236
|
_inlineCfgNormal = serializeInlineConfig(buildClientConfig(settings, false));
|
|
@@ -272,7 +285,7 @@ plugin.init = async ({ router, middleware }) => {
|
|
|
272
285
|
router.get('/api/plugins/ezoic-infinite/config', async (req, res) => {
|
|
273
286
|
try {
|
|
274
287
|
const settings = await getSettings();
|
|
275
|
-
const excluded = await isUserExcluded(req.uid, settings.excludedGroups);
|
|
288
|
+
const excluded = await isUserExcluded(req.uid, settings.excludedGroups, settings.excludedSet);
|
|
276
289
|
res.json(buildClientConfig(settings, excluded));
|
|
277
290
|
} catch (err) {
|
|
278
291
|
console.error('[ezoic-infinite] config API error:', err.message);
|
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
BURST_COOLDOWN_MS: 200,
|
|
33
33
|
BLOCK_DURATION_MS: 1_000,
|
|
34
34
|
SHOW_TIMEOUT_MS: 4_500,
|
|
35
|
-
SHOW_RELEASE_MS:
|
|
35
|
+
SHOW_RELEASE_MS: 50,
|
|
36
36
|
RECYCLE_DELAY_MS: 50,
|
|
37
37
|
UNCOLLAPSE_CHECK_MS: [500, 5_000],
|
|
38
38
|
};
|
|
@@ -580,7 +580,8 @@
|
|
|
580
580
|
scheduleEmptyCheck(id, t);
|
|
581
581
|
setTimeout(() => { clearTimeout(timer); release(); }, TIMING.SHOW_RELEASE_MS);
|
|
582
582
|
};
|
|
583
|
-
|
|
583
|
+
const ezReady = ez.loadingStatus === 'complete';
|
|
584
|
+
typeof ez.cmd?.push === 'function' && !ezReady ? ez.cmd.push(doShow) : doShow();
|
|
584
585
|
} catch (_) { clearTimeout(timer); release(); }
|
|
585
586
|
}
|
|
586
587
|
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
<div class="form-check mb-3">
|
|
8
8
|
<input class="form-check-input" type="checkbox" id="enableBetweenAds" name="enableBetweenAds" {enableBetweenAds_checked}>
|
|
9
9
|
<label class="form-check-label" for="enableBetweenAds">Activer les pubs entre les posts</label>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
<div class="form-check mt-2">
|
|
11
|
+
<input class="form-check-input" type="checkbox" name="showFirstTopicAd" {showFirstTopicAd_checked} />
|
|
12
|
+
<label class="form-check-label">Afficher une pub après le 1er sujet</label>
|
|
13
|
+
</div>
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
16
|
<div class="mb-3">
|
|
@@ -52,13 +52,13 @@
|
|
|
52
52
|
<h4 class="mt-3">Pubs “message” entre les réponses</h4>
|
|
53
53
|
<p class="form-text">Insère un bloc qui ressemble à un post, toutes les N réponses (dans une page topic).</p>
|
|
54
54
|
|
|
55
|
-
<div class
|
|
56
|
-
<input class
|
|
57
|
-
<label class
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
<div class=”form-check mb-3”>
|
|
56
|
+
<input class=”form-check-input” type=”checkbox” id=”enableMessageAds” name=”enableMessageAds” {enableMessageAds_checked}>
|
|
57
|
+
<label class=”form-check-label” for=”enableMessageAds”>Activer les pubs “message”</label>
|
|
58
|
+
<div class=”form-check mt-2”>
|
|
59
|
+
<input class=”form-check-input” type=”checkbox” name=”showFirstMessageAd” {showFirstMessageAd_checked} />
|
|
60
|
+
<label class=”form-check-label”>Afficher une pub après le 1er message</label>
|
|
61
|
+
</div>
|
|
62
62
|
</div>
|
|
63
63
|
|
|
64
64
|
<div class="mb-3">
|