@kanaraa/baileys 3.2.0 → 3.4.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/lib/Socket/groups.js +18 -11
- package/lib/Utils/link-preview.js +99 -61
- package/package.json +3 -7
package/lib/Socket/groups.js
CHANGED
|
@@ -16,9 +16,23 @@ export const makeGroupsSocket = (config) => {
|
|
|
16
16
|
},
|
|
17
17
|
content
|
|
18
18
|
});
|
|
19
|
-
const
|
|
19
|
+
const fetchJoinRequests = async (jid) => {
|
|
20
|
+
const req = await groupQuery(jid, 'get', [
|
|
21
|
+
{
|
|
22
|
+
tag: 'membership_approval_requests',
|
|
23
|
+
attrs: {}
|
|
24
|
+
}
|
|
25
|
+
]);
|
|
26
|
+
const node = getBinaryNodeChild(req, 'membership_approval_requests');
|
|
27
|
+
return getBinaryNodeChildren(node, 'membership_approval_request').map(v => v.attrs);
|
|
28
|
+
};
|
|
29
|
+
const groupMetadata = async (jid, opts = {}) => {
|
|
20
30
|
const result = await groupQuery(jid, 'get', [{ tag: 'query', attrs: { request: 'interactive' } }]);
|
|
21
|
-
|
|
31
|
+
const metadata = extractGroupMetadata(result);
|
|
32
|
+
if (opts.joinRequests) {
|
|
33
|
+
metadata.joinRequests = await fetchJoinRequests(jid).catch(() => []);
|
|
34
|
+
}
|
|
35
|
+
return metadata;
|
|
22
36
|
};
|
|
23
37
|
const groupFetchAllParticipating = async () => {
|
|
24
38
|
const result = await query({
|
|
@@ -103,15 +117,7 @@ export const makeGroupsSocket = (config) => {
|
|
|
103
117
|
]);
|
|
104
118
|
},
|
|
105
119
|
groupRequestParticipantsList: async (jid) => {
|
|
106
|
-
|
|
107
|
-
{
|
|
108
|
-
tag: 'membership_approval_requests',
|
|
109
|
-
attrs: {}
|
|
110
|
-
}
|
|
111
|
-
]);
|
|
112
|
-
const node = getBinaryNodeChild(result, 'membership_approval_requests');
|
|
113
|
-
const participants = getBinaryNodeChildren(node, 'membership_approval_request');
|
|
114
|
-
return participants.map(v => v.attrs);
|
|
120
|
+
return fetchJoinRequests(jid).catch(() => []);
|
|
115
121
|
},
|
|
116
122
|
groupRequestParticipantsUpdate: async (jid, participants, action) => {
|
|
117
123
|
const result = await groupQuery(jid, 'set', [
|
|
@@ -342,5 +348,6 @@ export const extractGroupMetadata = (result) => {
|
|
|
342
348
|
}),
|
|
343
349
|
ephemeralDuration: eph ? +eph : undefined
|
|
344
350
|
};
|
|
351
|
+
metadata.admins = metadata.participants.filter(p => p.admin);
|
|
345
352
|
return metadata;
|
|
346
353
|
};
|
|
@@ -1,84 +1,122 @@
|
|
|
1
1
|
import { prepareWAMessageMedia } from './messages.js';
|
|
2
2
|
import { extractImageThumb, getHttpStream } from './messages-media.js';
|
|
3
|
+
|
|
3
4
|
const THUMBNAIL_WIDTH_PX = 192;
|
|
4
|
-
|
|
5
|
+
|
|
6
|
+
const htmlDecode = (s) => s
|
|
7
|
+
.replace(/&#x([0-9a-f]+);/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
|
|
8
|
+
.replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(Number(dec)))
|
|
9
|
+
.replace(/"/g, '"')
|
|
10
|
+
.replace(/'/g, "'")
|
|
11
|
+
.replace(/</g, '<')
|
|
12
|
+
.replace(/>/g, '>')
|
|
13
|
+
.replace(/&/g, '&');
|
|
14
|
+
|
|
15
|
+
const getMetaContent = (html, keys) => {
|
|
16
|
+
const pattern = new RegExp(`<meta[^>]+(?:property|name)=["'](?:${keys.join('|')})["'][^>]*content=["']([^"']*)["']`, 'i');
|
|
17
|
+
const match = html.match(pattern);
|
|
18
|
+
if (match) return htmlDecode(match[1]);
|
|
19
|
+
const reversed = new RegExp(`<meta[^>]+content=["']([^"']*)["'][^>]*(?:property|name)=["'](?:${keys.join('|')})["']`, 'i');
|
|
20
|
+
const alt = html.match(reversed);
|
|
21
|
+
if (alt) return htmlDecode(alt[1]);
|
|
22
|
+
return null;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const getTitle = (html) => {
|
|
26
|
+
const meta = getMetaContent(html, ['og:title', 'twitter:title']);
|
|
27
|
+
if (meta) return meta;
|
|
28
|
+
const match = html.match(/<title[^>]*>([^<]*)<\/title>/i);
|
|
29
|
+
return match ? htmlDecode(match[1].trim()) : null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const getFavicon = (html, baseUrl) => {
|
|
33
|
+
const match = html.match(/<link[^>]+href=["']([^"']+)["'][^>]*rel=["'](?:shortcut\s+)?icon["']/i) ||
|
|
34
|
+
html.match(/<link[^>]+rel=["'](?:shortcut\s+)?icon["'][^>]*href=["']([^"']+)["']/i);
|
|
35
|
+
const href = match ? match[1] || match[2] : null;
|
|
36
|
+
try {
|
|
37
|
+
return new URL(href || '/favicon.ico', baseUrl).href;
|
|
38
|
+
} catch {
|
|
39
|
+
return href || `${baseUrl}/favicon.ico`;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
5
43
|
const getCompressedJpegThumbnail = async (url, { thumbnailWidth, fetchOpts }) => {
|
|
6
44
|
const stream = await getHttpStream(url, fetchOpts);
|
|
7
45
|
const result = await extractImageThumb(stream, thumbnailWidth);
|
|
8
46
|
return result;
|
|
9
47
|
};
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
48
|
+
|
|
49
|
+
const fetchPage = async (url, fetchOpts = {}) => {
|
|
50
|
+
const controller = new AbortController();
|
|
51
|
+
const timer = setTimeout(() => controller.abort(), fetchOpts.timeout || 3000);
|
|
52
|
+
try {
|
|
53
|
+
const response = await fetch(url, {
|
|
54
|
+
method: 'GET',
|
|
55
|
+
redirect: 'follow',
|
|
56
|
+
signal: controller.signal,
|
|
57
|
+
headers: {
|
|
58
|
+
'user-agent': 'WhatsApp/2.24.6.77',
|
|
59
|
+
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
60
|
+
...(fetchOpts.headers || {})
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
throw new Error(`HTTP ${response.status}`);
|
|
65
|
+
}
|
|
66
|
+
const html = await response.text();
|
|
67
|
+
return {
|
|
68
|
+
html,
|
|
69
|
+
finalUrl: response.url || url
|
|
70
|
+
};
|
|
71
|
+
} finally {
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
16
76
|
export const getUrlInfo = async (text, opts = {
|
|
17
77
|
thumbnailWidth: THUMBNAIL_WIDTH_PX,
|
|
18
78
|
fetchOpts: { timeout: 3000 }
|
|
19
79
|
}) => {
|
|
20
80
|
try {
|
|
21
|
-
// retries
|
|
22
|
-
let retries = 0;
|
|
23
|
-
const maxRetry = 5;
|
|
24
|
-
const { getLinkPreview } = await import('link-preview-js');
|
|
25
81
|
let previewLink = text;
|
|
26
|
-
if (!
|
|
82
|
+
if (!previewLink.startsWith('https://') && !previewLink.startsWith('http://')) {
|
|
27
83
|
previewLink = 'https://' + previewLink;
|
|
28
84
|
}
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
description: info.description,
|
|
57
|
-
originalThumbnailUrl: image
|
|
58
|
-
};
|
|
59
|
-
if (opts.uploadImage) {
|
|
60
|
-
const { imageMessage } = await prepareWAMessageMedia({ image: { url: image } }, {
|
|
61
|
-
upload: opts.uploadImage,
|
|
62
|
-
mediaTypeOverride: 'thumbnail-link',
|
|
63
|
-
options: opts.fetchOpts
|
|
64
|
-
});
|
|
65
|
-
urlInfo.jpegThumbnail = imageMessage?.jpegThumbnail ? Buffer.from(imageMessage.jpegThumbnail) : undefined;
|
|
66
|
-
urlInfo.highQualityThumbnail = imageMessage || undefined;
|
|
85
|
+
const { html, finalUrl } = await fetchPage(previewLink, opts.fetchOpts);
|
|
86
|
+
const title = getTitle(html);
|
|
87
|
+
if (!title) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
const description = getMetaContent(html, ['og:description', 'twitter:description', 'description']);
|
|
91
|
+
const image = getMetaContent(html, ['og:image', 'twitter:image']);
|
|
92
|
+
const favicon = getFavicon(html, finalUrl);
|
|
93
|
+
const urlInfo = {
|
|
94
|
+
'canonical-url': finalUrl,
|
|
95
|
+
'matched-text': text,
|
|
96
|
+
title,
|
|
97
|
+
description,
|
|
98
|
+
originalThumbnailUrl: image || favicon
|
|
99
|
+
};
|
|
100
|
+
if (opts.uploadImage) {
|
|
101
|
+
const { imageMessage } = await prepareWAMessageMedia({ image: { url: urlInfo.originalThumbnailUrl } }, {
|
|
102
|
+
upload: opts.uploadImage,
|
|
103
|
+
mediaTypeOverride: 'thumbnail-link',
|
|
104
|
+
options: opts.fetchOpts
|
|
105
|
+
});
|
|
106
|
+
urlInfo.jpegThumbnail = imageMessage?.jpegThumbnail ? Buffer.from(imageMessage.jpegThumbnail) : undefined;
|
|
107
|
+
urlInfo.highQualityThumbnail = imageMessage || undefined;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
try {
|
|
111
|
+
urlInfo.jpegThumbnail = (await getCompressedJpegThumbnail(urlInfo.originalThumbnailUrl, opts)).buffer;
|
|
67
112
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
urlInfo.jpegThumbnail = image ? (await getCompressedJpegThumbnail(image, opts)).buffer : undefined;
|
|
71
|
-
}
|
|
72
|
-
catch (error) {
|
|
73
|
-
opts.logger?.debug({ err: error.stack, url: previewLink }, 'error in generating thumbnail');
|
|
74
|
-
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
opts.logger?.debug({ err: error.stack, url: previewLink }, 'error in generating thumbnail');
|
|
75
115
|
}
|
|
76
|
-
return urlInfo;
|
|
77
116
|
}
|
|
117
|
+
return urlInfo;
|
|
78
118
|
}
|
|
79
119
|
catch (error) {
|
|
80
|
-
|
|
81
|
-
throw error;
|
|
82
|
-
}
|
|
120
|
+
opts.logger?.debug({ err: error.stack, url: text }, 'error in generating link preview');
|
|
83
121
|
}
|
|
84
122
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanaraa/baileys",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.4.0",
|
|
5
5
|
"description": "Modded Baileys v7, Rebuilt on top of official @whiskeysockets/baileys 7.0.0-rc13, with the interactive & rich-message content types (buttons, lists, carousel, cards, shop/collection, native flow, AI rich response, sticker packs, admin invite, payments, etc.).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"whatsapp",
|
|
@@ -43,10 +43,9 @@
|
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"adm-zip": "^0.5.10",
|
|
45
45
|
"audio-decode": "^2.1.3",
|
|
46
|
-
"fluent-ffmpeg": "^2.1.
|
|
46
|
+
"fluent-ffmpeg": "^2.1.3",
|
|
47
47
|
"jimp": "^1.6.1",
|
|
48
|
-
"
|
|
49
|
-
"sharp": "*"
|
|
48
|
+
"sharp": "^0.35.3"
|
|
50
49
|
},
|
|
51
50
|
"peerDependenciesMeta": {
|
|
52
51
|
"adm-zip": {
|
|
@@ -61,9 +60,6 @@
|
|
|
61
60
|
"jimp": {
|
|
62
61
|
"optional": true
|
|
63
62
|
},
|
|
64
|
-
"link-preview-js": {
|
|
65
|
-
"optional": true
|
|
66
|
-
},
|
|
67
63
|
"sharp": {
|
|
68
64
|
"optional": true
|
|
69
65
|
}
|