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.
Files changed (3) hide show
  1. package/library.js +11 -139
  2. package/package.json +1 -1
  3. package/plugin.json +1 -1
package/library.js CHANGED
@@ -4,111 +4,20 @@
4
4
 
5
5
 
6
6
 
7
+
8
+
7
9
  /**
8
- * Flatten any link-like markup to plain URLs so Discord auto-linkifies them.
9
- * Supported:
10
- * - [text](url)
11
- * - <a href="url">text</a>
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 flattenLinksToUrls(str) {
15
+ function simplifyMaskedLinks(str) {
16
16
  if (!str || typeof str !== 'string') return str;
17
17
 
18
- const normalizeUrl = (u) => {
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 normalizeUrl(url);
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 normalized = normalizeExcerptLinks(p && p.content);
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: flattenLinksToUrls(excerpt || ''), fields: linkFields } };
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-onekite-discord",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "description": "Discord webhook notifier for Onekite (NodeBB v4.x only)",
5
5
  "main": "library.js",
6
6
  "license": "MIT",
package/plugin.json CHANGED
@@ -31,5 +31,5 @@
31
31
  "acpScripts": [
32
32
  "public/admin.js"
33
33
  ],
34
- "version": "1.0.14"
34
+ "version": "1.0.16"
35
35
  }