nodebb-plugin-onekite-discord 1.0.14 → 1.0.16
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 +11 -139
- package/package.json +1 -1
- package/plugin.json +1 -1
package/library.js
CHANGED
|
@@ -4,111 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
|
|
8
|
+
|
|
7
9
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
* - text(url) / text (url)
|
|
13
|
-
* - bare URLs and www.*
|
|
10
|
+
* Simplified:
|
|
11
|
+
* - Convert masked markdown links: [text](url) -> url
|
|
12
|
+
* - Do NOT modify anything else.
|
|
13
|
+
* Discord will auto-linkify URLs if it can.
|
|
14
14
|
*/
|
|
15
|
-
function
|
|
15
|
+
function simplifyMaskedLinks(str) {
|
|
16
16
|
if (!str || typeof str !== 'string') return str;
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
if (!u) return u;
|
|
20
|
-
let url = String(u).trim();
|
|
21
|
-
url = url.replace(/^<(.+)>$/, '$1');
|
|
22
|
-
url = url.replace(/^https:\//i, 'https://');
|
|
23
|
-
url = url.replace(/^http:\//i, 'http://');
|
|
24
|
-
if (/^www\./i.test(url)) url = 'https://' + url;
|
|
25
|
-
return url;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// HTML links -> URL
|
|
29
|
-
str = str.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>.*?<\/a>/gi, (_m, href) => {
|
|
30
|
-
return normalizeUrl(href);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// Markdown [text](url) -> URL
|
|
18
|
+
// [text](url) -> url (as-is)
|
|
34
19
|
str = str.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, _text, url) => {
|
|
35
|
-
return
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
// text(url) or text (url) -> URL
|
|
39
|
-
str = str.replace(/([^\n\r()]{1,200}?)\s*\((https?:\/\/[^)\s]+|www\.[^)\\s]+)\)/g, (_m, _text, url) => {
|
|
40
|
-
return normalizeUrl(url);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
return str;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
;
|
|
47
|
-
|
|
48
|
-
const push = (text, url) => {
|
|
49
|
-
const u = normalizeUrl(url);
|
|
50
|
-
if (!u) return;
|
|
51
|
-
const key = `${text || ''}||${u}`;
|
|
52
|
-
if (seen.has(key)) return;
|
|
53
|
-
seen.add(key);
|
|
54
|
-
links.push({ text: (text || '').trim(), url: u });
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// HTML links
|
|
58
|
-
str.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>(.*?)<\/a>/gi, (_m, href, text) => {
|
|
59
|
-
push(text, href);
|
|
60
|
-
return _m;
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// Markdown masked links
|
|
64
|
-
str.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, text, url) => {
|
|
65
|
-
push(text, url);
|
|
66
|
-
return _m;
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
// NodeBB rendered: "texte du lien(url)" or "texte du lien (url)"
|
|
70
|
-
str.replace(/([^\n\r()]{1,200}?)\s*\((https?:\/\/[^)\s]+|www\.[^)\s]+)\)/g, (_m, text, url) => {
|
|
71
|
-
push(text, url);
|
|
72
|
-
return _m;
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// Bare URLs (avoid trailing punctuation)
|
|
76
|
-
str.replace(/\b(https?:\/\/[^\s<>()]+)\b/g, (_m, url) => {
|
|
77
|
-
push('', url.replace(/[),.;!?]+$/g, ''));
|
|
78
|
-
return _m;
|
|
79
|
-
});
|
|
80
|
-
str.replace(/\b(www\.[^\s<>()]+)\b/g, (_m, url) => {
|
|
81
|
-
push('', url.replace(/[),.;!?]+$/g, ''));
|
|
82
|
-
return _m;
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
return links;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
?)\s*\((https?:\/\/[^)\s]+|www\.[^)\s]+)\)/g, (_m, text) => String(text).trim());
|
|
89
|
-
|
|
90
|
-
return str;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
;
|
|
94
|
-
|
|
95
|
-
// HTML <a href="...">...</a> -> URL
|
|
96
|
-
str = str.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>.*?<\/a>/gi, (_m, href) => {
|
|
97
|
-
return normalizeUrl(href);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Markdown [text](url) -> URL
|
|
101
|
-
str = str.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_m, _text, url) => {
|
|
102
|
-
return normalizeUrl(url);
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
// Already-rendered form from NodeBB: texte du lien(url) or texte du lien (url)
|
|
106
|
-
// Convert to: "texte du lien https://url" so Discord auto-linkifies.
|
|
107
|
-
str = str.replace(/([^\n\r()]{1,200}?)\s*\((https?:\/\/[^)\s]+|www\.[^)\s]+)\)/g, (_m, text, url) => {
|
|
108
|
-
const cleanText = String(text).trim();
|
|
109
|
-
const cleanUrl = normalizeUrl(url);
|
|
110
|
-
if (!cleanUrl) return _m;
|
|
111
|
-
return cleanText ? `${cleanText} ${cleanUrl}` : cleanUrl;
|
|
20
|
+
return url;
|
|
112
21
|
});
|
|
113
22
|
|
|
114
23
|
return str;
|
|
@@ -155,26 +64,6 @@ function ensureAbsoluteUrl(baseUrl, maybeUrl) {
|
|
|
155
64
|
return s;
|
|
156
65
|
}
|
|
157
66
|
|
|
158
|
-
|
|
159
|
-
function normalizeExcerptLinks(input) {
|
|
160
|
-
if (!input) return '';
|
|
161
|
-
let s = String(input);
|
|
162
|
-
|
|
163
|
-
// Convert HTML anchors to "text (url)" before stripping HTML
|
|
164
|
-
s = s.replace(/<a\s+[^>]*href=["']([^"']+)["'][^>]*>([\s\S]*?)<\/a>/gi, (m, href, inner) => {
|
|
165
|
-
const text = stripHtml(inner).trim() || href;
|
|
166
|
-
return `${text} (${href})`;
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// Convert Markdown links [text](url) to "text (url)"
|
|
170
|
-
s = s.replace(/\[([^\]]+)\]\(([^\s)]+)\)/g, (m, label, url) => `${label} (${url})`);
|
|
171
|
-
|
|
172
|
-
// Fix common malformed scheme "https:/example.com" -> "https://example.com"
|
|
173
|
-
s = s.replace(/\b(https?):\/(?!\/)/g, '$1://');
|
|
174
|
-
|
|
175
|
-
return s;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
67
|
function stripHtml(html) {
|
|
179
68
|
if (!html) return '';
|
|
180
69
|
return String(html)
|
|
@@ -276,8 +165,7 @@ async function getPostExcerpt(pid) {
|
|
|
276
165
|
if (!pid) return '';
|
|
277
166
|
try {
|
|
278
167
|
const p = await posts.getPostFields(pid, ['content']);
|
|
279
|
-
const
|
|
280
|
-
const text = stripHtml(normalized);
|
|
168
|
+
const text = stripHtml(p && p.content);
|
|
281
169
|
return truncate(text, 500);
|
|
282
170
|
} catch {
|
|
283
171
|
return '';
|
|
@@ -308,22 +196,6 @@ async function buildEmbed({ tid, pid, isReply }) {
|
|
|
308
196
|
|
|
309
197
|
const excerpt = await getPostExcerpt(isReply ? pid : topicData.mainPid);
|
|
310
198
|
|
|
311
|
-
// Extract all links and put them in embed fields (Discord supports masked links in fields)
|
|
312
|
-
const extractedLinks = extractDiscordLinks(excerpt || '');
|
|
313
|
-
const linkFields = [];
|
|
314
|
-
const maxFields = 25; // Discord limit
|
|
315
|
-
for (let i = 0; i < extractedLinks.length && linkFields.length < maxFields; i += 1) {
|
|
316
|
-
const { text, url } = extractedLinks[i];
|
|
317
|
-
const label = text && text.length ? text : url;
|
|
318
|
-
// Field values have a 1024 char limit; keep it safe
|
|
319
|
-
const value = `[${label.substring(0, 200)}](${url})`;
|
|
320
|
-
linkFields.push({
|
|
321
|
-
name: `Lien ${linkFields.length + 1}`,
|
|
322
|
-
value: value.substring(0, 1024),
|
|
323
|
-
inline: false,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
|
|
327
199
|
const postForUser = await posts.getPostFields(isReply ? pid : topicData.mainPid, ['uid']);
|
|
328
200
|
const username = await user.getUserField(postForUser.uid, 'username');
|
|
329
201
|
|
|
@@ -331,7 +203,7 @@ for (let i = 0; i < extractedLinks.length && linkFields.length < maxFields; i +=
|
|
|
331
203
|
const embedTitle = `${replyIcon}${safeTitle} – ${username}`.slice(0, 256);
|
|
332
204
|
|
|
333
205
|
// Embed title becomes clickable via embed.url
|
|
334
|
-
return { topicData, content: '', embed: { title: embedTitle, url: targetUrl, description:
|
|
206
|
+
return { topicData, content: '', embed: { title: embedTitle, url: targetUrl, description: simplifyMaskedLinks(excerpt || '') } };
|
|
335
207
|
}
|
|
336
208
|
|
|
337
209
|
function extractTidPid(data) {
|
package/package.json
CHANGED
package/plugin.json
CHANGED