nodebb-plugin-ezoic-infinite 1.8.98 → 1.9.0
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 +72 -42
- package/package.json +1 -1
- package/public/client.js +18 -12
package/library.js
CHANGED
|
@@ -29,36 +29,50 @@ function parseBool(v, def = false) {
|
|
|
29
29
|
return s === '1' || s === 'true' || s === 'on' || s === 'yes';
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
let _allGroupsCache
|
|
33
|
-
let _allGroupsCacheAt
|
|
34
|
-
|
|
32
|
+
let _allGroupsCache = null;
|
|
33
|
+
let _allGroupsCacheAt = 0;
|
|
34
|
+
let _allGroupsInflight = null;
|
|
35
|
+
let _allGroupsGen = 0;
|
|
36
|
+
const ALL_GROUPS_TTL = 300_000; // 5 min — admin-only route
|
|
35
37
|
|
|
36
38
|
async function getAllGroups() {
|
|
37
39
|
const t = Date.now();
|
|
38
40
|
if (_allGroupsCache && (t - _allGroupsCacheAt) < ALL_GROUPS_TTL) return _allGroupsCache;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
if (_allGroupsInflight) return _allGroupsInflight;
|
|
42
|
+
const gen = _allGroupsGen;
|
|
43
|
+
_allGroupsInflight = (async () => {
|
|
44
|
+
try {
|
|
45
|
+
let names = await db.getSortedSetRange('groups:createtime', 0, -1);
|
|
46
|
+
if (!names?.length) {
|
|
47
|
+
names = await db.getSortedSetRange('groups:visible:createtime', 0, -1);
|
|
48
|
+
}
|
|
49
|
+
const data = (await groups.getGroupsData(
|
|
50
|
+
(names || []).filter(name => !groups.isPrivilegeGroup(name))
|
|
51
|
+
))
|
|
52
|
+
.filter(g => g?.name)
|
|
53
|
+
.sort((a, b) => String(a.name).localeCompare(String(b.name), undefined, { sensitivity: 'base' }));
|
|
54
|
+
if (_allGroupsGen === gen) {
|
|
55
|
+
_allGroupsCache = data;
|
|
56
|
+
_allGroupsCacheAt = Date.now();
|
|
57
|
+
}
|
|
58
|
+
return _allGroupsCache || data;
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error('[ezoic-infinite] getAllGroups error:', err.message);
|
|
61
|
+
return [];
|
|
62
|
+
} finally {
|
|
63
|
+
if (_allGroupsGen === gen) _allGroupsInflight = null;
|
|
43
64
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
))
|
|
47
|
-
.filter(g => g?.name)
|
|
48
|
-
.sort((a, b) => String(a.name).localeCompare(String(b.name), undefined, { sensitivity: 'base' }));
|
|
49
|
-
_allGroupsCacheAt = Date.now();
|
|
50
|
-
return _allGroupsCache;
|
|
51
|
-
} catch (err) {
|
|
52
|
-
console.error('[ezoic-infinite] getAllGroups error:', err.message);
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
65
|
+
})();
|
|
66
|
+
return _allGroupsInflight;
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
// ── Settings cache ───────────────────────────────────────────────────────────
|
|
58
70
|
|
|
59
|
-
let _settingsCache
|
|
60
|
-
let _settingsCacheAt
|
|
61
|
-
|
|
71
|
+
let _settingsCache = null;
|
|
72
|
+
let _settingsCacheAt = 0;
|
|
73
|
+
let _settingsInflight = null;
|
|
74
|
+
let _settingsGen = 0;
|
|
75
|
+
const SETTINGS_TTL = 30_000;
|
|
62
76
|
|
|
63
77
|
const _excludeCache = new Map();
|
|
64
78
|
const EXCLUDE_TTL = 60_000;
|
|
@@ -66,25 +80,35 @@ const EXCLUDE_TTL = 60_000;
|
|
|
66
80
|
async function getSettings() {
|
|
67
81
|
const t = Date.now();
|
|
68
82
|
if (_settingsCache && (t - _settingsCacheAt) < SETTINGS_TTL) return _settingsCache;
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
if (_settingsInflight) return _settingsInflight;
|
|
84
|
+
const gen = _settingsGen;
|
|
85
|
+
_settingsInflight = (async () => {
|
|
86
|
+
try {
|
|
87
|
+
const s = await meta.settings.get(SETTINGS_KEY);
|
|
88
|
+
if (_settingsGen === gen) {
|
|
89
|
+
_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
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return _settingsCache;
|
|
107
|
+
} finally {
|
|
108
|
+
if (_settingsGen === gen) _settingsInflight = null;
|
|
109
|
+
}
|
|
110
|
+
})();
|
|
111
|
+
return _settingsInflight;
|
|
88
112
|
}
|
|
89
113
|
|
|
90
114
|
async function isUserExcluded(uid, excludedGroups) {
|
|
@@ -115,13 +139,17 @@ let _inlineCfgNormal = null;
|
|
|
115
139
|
let _inlineCfgExcluded = null;
|
|
116
140
|
|
|
117
141
|
function clearCaches() {
|
|
118
|
-
|
|
119
|
-
|
|
142
|
+
_settingsGen++;
|
|
143
|
+
_settingsCache = null;
|
|
144
|
+
_settingsCacheAt = 0;
|
|
145
|
+
_settingsInflight = null;
|
|
120
146
|
_excludeCache.clear();
|
|
121
147
|
_inlineCfgNormal = null;
|
|
122
148
|
_inlineCfgExcluded = null;
|
|
149
|
+
_allGroupsGen++;
|
|
123
150
|
_allGroupsCache = null;
|
|
124
151
|
_allGroupsCacheAt = 0;
|
|
152
|
+
_allGroupsInflight = null;
|
|
125
153
|
}
|
|
126
154
|
|
|
127
155
|
// ── Client config ────────────────────────────────────────────────────────────
|
|
@@ -215,6 +243,8 @@ plugin.injectEzoicHead = async (data) => {
|
|
|
215
243
|
};
|
|
216
244
|
|
|
217
245
|
plugin.init = async ({ router, middleware }) => {
|
|
246
|
+
getSettings().catch(() => {});
|
|
247
|
+
|
|
218
248
|
async function render(req, res) {
|
|
219
249
|
const settings = await getSettings();
|
|
220
250
|
const allGroups = await getAllGroups();
|
package/package.json
CHANGED
package/public/client.js
CHANGED
|
@@ -101,6 +101,7 @@
|
|
|
101
101
|
burstDeadline: 0,
|
|
102
102
|
burstCount: 0,
|
|
103
103
|
lastBurstTs: 0,
|
|
104
|
+
cleaningUp: false,
|
|
104
105
|
};
|
|
105
106
|
|
|
106
107
|
const isBlocked = () => now() < S.blockedUntil;
|
|
@@ -121,10 +122,8 @@
|
|
|
121
122
|
|
|
122
123
|
async function fetchConfig() {
|
|
123
124
|
if (S.cfg) return S.cfg;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (inline && typeof inline === 'object') { S.cfg = inline; return S.cfg; }
|
|
127
|
-
} catch (_) {}
|
|
125
|
+
const inline = window.__nbbEzoicCfg;
|
|
126
|
+
if (inline && typeof inline === 'object') { S.cfg = inline; return S.cfg; }
|
|
128
127
|
try {
|
|
129
128
|
const ctrl = new AbortController();
|
|
130
129
|
const t = setTimeout(() => ctrl.abort(), 5_000);
|
|
@@ -205,14 +204,14 @@
|
|
|
205
204
|
function getTopics() {
|
|
206
205
|
const t = now();
|
|
207
206
|
if (_topicsCache && t - _topicsCacheTs < POSTS_CACHE_MS) return _topicsCache;
|
|
208
|
-
_topicsCache = document.querySelectorAll(SEL.topic);
|
|
207
|
+
_topicsCache = Array.from(document.querySelectorAll(SEL.topic));
|
|
209
208
|
_topicsCacheTs = t;
|
|
210
209
|
return _topicsCache;
|
|
211
210
|
}
|
|
212
211
|
function getCategories() {
|
|
213
212
|
const t = now();
|
|
214
213
|
if (_catsCache && t - _catsCacheTs < POSTS_CACHE_MS) return _catsCache;
|
|
215
|
-
_catsCache = document.querySelectorAll(SEL.category);
|
|
214
|
+
_catsCache = Array.from(document.querySelectorAll(SEL.category));
|
|
216
215
|
_catsCacheTs = t;
|
|
217
216
|
return _catsCache;
|
|
218
217
|
}
|
|
@@ -435,15 +434,19 @@
|
|
|
435
434
|
if (ph instanceof Element) S.io?.unobserve(ph);
|
|
436
435
|
const id = parseInt(w.getAttribute(ATTR.WRAPID), 10);
|
|
437
436
|
if (Number.isFinite(id)) {
|
|
438
|
-
S.mountedIds.delete(id);
|
|
439
|
-
S.lastShow.delete(id);
|
|
440
437
|
const timers = S.wrapTimers.get(id);
|
|
441
438
|
if (timers) { for (const t of timers) clearTimeout(t); S.wrapTimers.delete(id); }
|
|
439
|
+
if (!S.cleaningUp) {
|
|
440
|
+
S.mountedIds.delete(id);
|
|
441
|
+
S.lastShow.delete(id);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if (!S.cleaningUp) {
|
|
445
|
+
const key = w.getAttribute(ATTR.ANCHOR);
|
|
446
|
+
if (key && S.wrapByKey.get(key) === w) S.wrapByKey.delete(key);
|
|
447
|
+
const colonIdx = key?.indexOf(':') ?? -1;
|
|
448
|
+
if (colonIdx > 0) S.wrapsByClass.get(key.slice(0, colonIdx))?.delete(w);
|
|
442
449
|
}
|
|
443
|
-
const key = w.getAttribute(ATTR.ANCHOR);
|
|
444
|
-
if (key && S.wrapByKey.get(key) === w) S.wrapByKey.delete(key);
|
|
445
|
-
const colonIdx = key?.indexOf(':') ?? -1;
|
|
446
|
-
if (colonIdx > 0) S.wrapsByClass.get(key.slice(0, colonIdx))?.delete(w);
|
|
447
450
|
w.remove();
|
|
448
451
|
} catch (_) {}
|
|
449
452
|
}
|
|
@@ -722,9 +725,12 @@
|
|
|
722
725
|
const ez = window.ezstandalone;
|
|
723
726
|
if (typeof ez?.destroyPlaceholders === 'function') ez.destroyPlaceholders();
|
|
724
727
|
} catch (_) {}
|
|
728
|
+
S.cleaningUp = true;
|
|
725
729
|
mutate(() => {
|
|
726
730
|
for (const w of document.querySelectorAll(`.${WRAP_CLASS}`)) dropWrap(w);
|
|
727
731
|
});
|
|
732
|
+
S.cleaningUp = false;
|
|
733
|
+
// Safety net: wrapTimers should be empty after dropWrap loop, but clear any orphans.
|
|
728
734
|
for (const timers of S.wrapTimers.values()) { for (const t of timers) clearTimeout(t); }
|
|
729
735
|
S.wrapTimers.clear();
|
|
730
736
|
S.domObs?.disconnect(); S.domObs = null;
|