nodebb-plugin-ezoic-infinite 1.7.36 → 1.7.38

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.
Files changed (3) hide show
  1. package/library.js +71 -48
  2. package/package.json +1 -1
  3. package/plugin.json +5 -1
package/library.js CHANGED
@@ -1,12 +1,14 @@
1
1
  'use strict';
2
2
 
3
- const meta = require.main.require('./src/meta');
3
+ const meta = require.main.require('./src/meta');
4
4
  const groups = require.main.require('./src/groups');
5
- const db = require.main.require('./src/database');
5
+ const db = require.main.require('./src/database');
6
6
 
7
7
  const SETTINGS_KEY = 'ezoic-infinite';
8
8
  const plugin = {};
9
9
 
10
+ // ── Helpers ────────────────────────────────────────────────────────────────
11
+
10
12
  function normalizeExcludedGroups(value) {
11
13
  if (!value) return [];
12
14
  if (Array.isArray(value)) return value;
@@ -27,14 +29,16 @@ async function getAllGroups() {
27
29
  }
28
30
  const filtered = names.filter(name => !groups.isPrivilegeGroup(name));
29
31
  const data = await groups.getGroupsData(filtered);
30
- // Filter out nulls (groups deleted between the sorted-set read and getGroupsData)
31
32
  const valid = data.filter(g => g && g.name);
32
33
  valid.sort((a, b) => String(a.name).localeCompare(String(b.name), undefined, { sensitivity: 'base' }));
33
34
  return valid;
34
35
  }
35
- let _settingsCache = null;
36
+
37
+ // ── Settings cache (30s TTL) ────────────────────────────────────────────────
38
+
39
+ let _settingsCache = null;
36
40
  let _settingsCacheAt = 0;
37
- const SETTINGS_TTL = 30000; // 30s
41
+ const SETTINGS_TTL = 30_000;
38
42
 
39
43
  async function getSettings() {
40
44
  const now = Date.now();
@@ -42,25 +46,19 @@ async function getSettings() {
42
46
  const s = await meta.settings.get(SETTINGS_KEY);
43
47
  _settingsCacheAt = Date.now();
44
48
  _settingsCache = {
45
- // Between-post ads (simple blocks) in category topic list
46
- enableBetweenAds: parseBool(s.enableBetweenAds, true),
47
- showFirstTopicAd: parseBool(s.showFirstTopicAd, false),
48
- placeholderIds: (s.placeholderIds || '').trim(),
49
- intervalPosts: Math.max(1, parseInt(s.intervalPosts, 10) || 6),
50
-
51
- // Home/categories list ads (between categories on / or /categories)
52
- enableCategoryAds: parseBool(s.enableCategoryAds, false),
53
- showFirstCategoryAd: parseBool(s.showFirstCategoryAd, false),
49
+ enableBetweenAds: parseBool(s.enableBetweenAds, true),
50
+ showFirstTopicAd: parseBool(s.showFirstTopicAd, false),
51
+ placeholderIds: (s.placeholderIds || '').trim(),
52
+ intervalPosts: Math.max(1, parseInt(s.intervalPosts, 10) || 6),
53
+ enableCategoryAds: parseBool(s.enableCategoryAds, false),
54
+ showFirstCategoryAd: parseBool(s.showFirstCategoryAd, false),
54
55
  categoryPlaceholderIds: (s.categoryPlaceholderIds || '').trim(),
55
- intervalCategories: Math.max(1, parseInt(s.intervalCategories, 10) || 4),
56
-
57
- // "Ad message" between replies (looks like a post)
58
- enableMessageAds: parseBool(s.enableMessageAds, false),
59
- showFirstMessageAd: parseBool(s.showFirstMessageAd, false),
60
- messagePlaceholderIds: (s.messagePlaceholderIds || '').trim(),
61
- messageIntervalPosts: Math.max(1, parseInt(s.messageIntervalPosts, 10) || 3),
62
-
63
- excludedGroups: normalizeExcludedGroups(s.excludedGroups),
56
+ intervalCategories: Math.max(1, parseInt(s.intervalCategories, 10) || 4),
57
+ enableMessageAds: parseBool(s.enableMessageAds, false),
58
+ showFirstMessageAd: parseBool(s.showFirstMessageAd, false),
59
+ messagePlaceholderIds: (s.messagePlaceholderIds || '').trim(),
60
+ messageIntervalPosts: Math.max(1, parseInt(s.messageIntervalPosts, 10) || 3),
61
+ excludedGroups: normalizeExcludedGroups(s.excludedGroups),
64
62
  };
65
63
  return _settingsCache;
66
64
  }
@@ -71,58 +69,83 @@ async function isUserExcluded(uid, excludedGroups) {
71
69
  return (userGroups[0] || []).some(g => excludedGroups.includes(g.name));
72
70
  }
73
71
 
72
+ // ── Scripts Ezoic ──────────────────────────────────────────────────────────
73
+
74
+ const EZOIC_SCRIPTS = `<script data-cfasync="false" src="https://cmp.gatekeeperconsent.com/min.js"></script>
75
+ <script data-cfasync="false" src="https://the.gatekeeperconsent.com/cmp.min.js"></script>
76
+ <script async src="//www.ezojs.com/ezoic/sa.min.js"></script>
77
+ <script>
78
+ window.ezstandalone = window.ezstandalone || {};
79
+ ezstandalone.cmd = ezstandalone.cmd || [];
80
+ </script>`;
81
+
82
+ // ── Hooks ──────────────────────────────────────────────────────────────────
83
+
74
84
  plugin.onSettingsSet = function (data) {
75
- // Invalider le cache dès que les settings de ce plugin sont sauvegardés via l'ACP
76
- if (data && data.hash === SETTINGS_KEY) {
77
- _settingsCache = null;
78
- }
85
+ if (data && data.hash === SETTINGS_KEY) _settingsCache = null;
79
86
  };
80
87
 
81
88
  plugin.addAdminNavigation = async (header) => {
82
89
  header.plugins = header.plugins || [];
83
- header.plugins.push({
84
- route: '/plugins/ezoic-infinite',
85
- icon: 'fa-ad',
86
- name: 'Ezoic Infinite Ads'
87
- });
90
+ header.plugins.push({ route: '/plugins/ezoic-infinite', icon: 'fa-ad', name: 'Ezoic Infinite Ads' });
88
91
  return header;
89
92
  };
90
93
 
94
+ /**
95
+ * Injecte les scripts Ezoic via res.locals.postHeader.
96
+ *
97
+ * NodeBB v4 insère res.locals.postHeader directement après le header rendu
98
+ * (src/middleware/render.js) : `results.header + (res.locals.postHeader || '')`
99
+ * C'est le point d'injection natif pour du HTML arbitraire post-<head>.
100
+ *
101
+ * Le hook filter:middleware.buildHeader expose data.locals = res.locals,
102
+ * et est appelé avant le rendu de chaque page non-API.
103
+ */
104
+ plugin.injectEzoicScripts = async (data) => {
105
+ try {
106
+ const settings = await getSettings();
107
+ const uid = data.req?.uid ?? 0;
108
+ const excluded = await isUserExcluded(uid, settings.excludedGroups);
109
+ if (!excluded) {
110
+ data.locals.postHeader = (data.locals.postHeader || '') + EZOIC_SCRIPTS;
111
+ }
112
+ } catch (_) {}
113
+ return data;
114
+ };
115
+
91
116
  plugin.init = async ({ router, middleware }) => {
92
117
  async function render(req, res) {
93
- const settings = await getSettings();
118
+ const settings = await getSettings();
94
119
  const allGroups = await getAllGroups();
95
-
96
120
  res.render('admin/plugins/ezoic-infinite', {
97
121
  title: 'Ezoic Infinite Ads',
98
122
  ...settings,
99
123
  enableBetweenAds_checked: settings.enableBetweenAds ? 'checked' : '',
100
- enableMessageAds_checked: settings.enableMessageAds ? 'checked' : '',
124
+ enableMessageAds_checked: settings.enableMessageAds ? 'checked' : '',
101
125
  allGroups,
102
126
  });
103
127
  }
104
128
 
105
- router.get('/admin/plugins/ezoic-infinite', middleware.admin.buildHeader, render);
129
+ router.get('/admin/plugins/ezoic-infinite', middleware.admin.buildHeader, render);
106
130
  router.get('/api/admin/plugins/ezoic-infinite', render);
107
131
 
108
132
  router.get('/api/plugins/ezoic-infinite/config', async (req, res) => {
109
133
  const settings = await getSettings();
110
134
  const excluded = await isUserExcluded(req.uid, settings.excludedGroups);
111
-
112
135
  res.json({
113
136
  excluded,
114
- enableBetweenAds: settings.enableBetweenAds,
115
- showFirstTopicAd: settings.showFirstTopicAd,
116
- placeholderIds: settings.placeholderIds,
117
- intervalPosts: settings.intervalPosts,
118
- enableCategoryAds: settings.enableCategoryAds,
119
- showFirstCategoryAd: settings.showFirstCategoryAd,
137
+ enableBetweenAds: settings.enableBetweenAds,
138
+ showFirstTopicAd: settings.showFirstTopicAd,
139
+ placeholderIds: settings.placeholderIds,
140
+ intervalPosts: settings.intervalPosts,
141
+ enableCategoryAds: settings.enableCategoryAds,
142
+ showFirstCategoryAd: settings.showFirstCategoryAd,
120
143
  categoryPlaceholderIds: settings.categoryPlaceholderIds,
121
- intervalCategories: settings.intervalCategories,
122
- enableMessageAds: settings.enableMessageAds,
123
- showFirstMessageAd: settings.showFirstMessageAd,
124
- messagePlaceholderIds: settings.messagePlaceholderIds,
125
- messageIntervalPosts: settings.messageIntervalPosts,
144
+ intervalCategories: settings.intervalCategories,
145
+ enableMessageAds: settings.enableMessageAds,
146
+ showFirstMessageAd: settings.showFirstMessageAd,
147
+ messagePlaceholderIds: settings.messagePlaceholderIds,
148
+ messageIntervalPosts: settings.messageIntervalPosts,
126
149
  });
127
150
  });
128
151
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-ezoic-infinite",
3
- "version": "1.7.36",
3
+ "version": "1.7.38",
4
4
  "description": "Production-ready Ezoic infinite ads integration for NodeBB 4.x",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/plugin.json CHANGED
@@ -15,6 +15,10 @@
15
15
  {
16
16
  "hook": "action:settings.set",
17
17
  "method": "onSettingsSet"
18
+ },
19
+ {
20
+ "hook": "filter:middleware.buildHeader",
21
+ "method": "injectEzoicScripts"
18
22
  }
19
23
  ],
20
24
  "staticDirs": {
@@ -30,4 +34,4 @@
30
34
  "css": [
31
35
  "public/style.css"
32
36
  ]
33
- }
37
+ }