whalibmob 5.5.83 → 5.5.86
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/README.md +37 -0
- package/cli.js +38 -9
- package/lib/Client.js +566 -95
- package/lib/MediaService.js +3 -0
- package/lib/MediaThumbnail.js +394 -0
- package/lib/messages/MessageSender.js +112 -44
- package/lib/proto/MessageProto.js +110 -10
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -157,6 +157,7 @@ npm install -g whalibmob
|
|
|
157
157
|
- [Quoted Reply](#quoted-reply)
|
|
158
158
|
- [Location Message](#location-message)
|
|
159
159
|
- [Contact Message (vCard)](#contact-message-vcard)
|
|
160
|
+
- [Call Link](#call-link)
|
|
160
161
|
- [Media Messages](#media-messages)
|
|
161
162
|
- [Image Message](#image-message)
|
|
162
163
|
- [Video Message](#video-message)
|
|
@@ -1137,6 +1138,7 @@ const { id, encKey } = await client.sendPoll(
|
|
|
1137
1138
|
1 // voters may pick 1 option (0 = unlimited)
|
|
1138
1139
|
)
|
|
1139
1140
|
// encKey (32-byte Buffer) is needed to decrypt incoming poll votes
|
|
1141
|
+
// (also returned as `messageSecret`, which is the name the protocol uses)
|
|
1140
1142
|
```
|
|
1141
1143
|
|
|
1142
1144
|
### Quoted Reply
|
|
@@ -1181,6 +1183,12 @@ await client.sendLocation('919634847671@s.whatsapp.net', 48.8566, 2.3522, {
|
|
|
1181
1183
|
await client.sendLocation('120363000000000000@g.us', 51.5074, -0.1278, {
|
|
1182
1184
|
name: 'London'
|
|
1183
1185
|
})
|
|
1186
|
+
|
|
1187
|
+
// with a map image for the bubble — WhatsApp draws a blank card without one
|
|
1188
|
+
await client.sendLocation('919634847671@s.whatsapp.net', 48.8566, 2.3522, {
|
|
1189
|
+
name: 'Eiffel Tower',
|
|
1190
|
+
thumbnail: jpegBuffer
|
|
1191
|
+
})
|
|
1184
1192
|
```
|
|
1185
1193
|
|
|
1186
1194
|
### Contact Message (vCard)
|
|
@@ -1200,8 +1208,37 @@ const vcard = [
|
|
|
1200
1208
|
await client.sendContact('919634847671@s.whatsapp.net', 'Alice Smith', vcard)
|
|
1201
1209
|
```
|
|
1202
1210
|
|
|
1211
|
+
### Call Link
|
|
1212
|
+
|
|
1213
|
+
Ask WhatsApp for a link that lets someone join a call by tapping it, instead of
|
|
1214
|
+
being rung. Returns the token, the shareable link and the media type.
|
|
1215
|
+
|
|
1216
|
+
```js
|
|
1217
|
+
const { link } = await client.createCallLink('video')
|
|
1218
|
+
// https://call.whatsapp.com/video/XXXXXXXX
|
|
1219
|
+
|
|
1220
|
+
// audio is the default
|
|
1221
|
+
const audio = await client.createCallLink()
|
|
1222
|
+
|
|
1223
|
+
// schedule it — startTime is seconds since the epoch
|
|
1224
|
+
await client.createCallLink('video', { startTime: 1800000000 })
|
|
1225
|
+
|
|
1226
|
+
// create it and send it in one step
|
|
1227
|
+
await client.sendCallLink('919634847671@s.whatsapp.net', 'video', {
|
|
1228
|
+
text: 'Join me here:'
|
|
1229
|
+
})
|
|
1230
|
+
```
|
|
1231
|
+
|
|
1203
1232
|
## Media Messages
|
|
1204
1233
|
|
|
1234
|
+
Photos and videos are sent with an inline preview so they show up in the chat
|
|
1235
|
+
directly, rather than as a placeholder the recipient has to tap. The dimensions
|
|
1236
|
+
are read out of the file header with no dependency at all. The preview itself
|
|
1237
|
+
uses `jimp` (installed automatically as an optional dependency) or `sharp` if
|
|
1238
|
+
you have it; failing both, a photo that carries an EXIF thumbnail still gets
|
|
1239
|
+
one. Video previews need `ffmpeg` on PATH — on Termux, `pkg install ffmpeg`.
|
|
1240
|
+
Without any of these the media still sends, just without the preview.
|
|
1241
|
+
|
|
1205
1242
|
### Image Message
|
|
1206
1243
|
|
|
1207
1244
|
```js
|
package/cli.js
CHANGED
|
@@ -362,7 +362,9 @@ const HELP = `
|
|
|
362
362
|
|
|
363
363
|
Contacts
|
|
364
364
|
/whatsapp <phone...> check which numbers have WhatsApp
|
|
365
|
-
/picture <jid>
|
|
365
|
+
/picture <jid> [file] profile picture URL; downloads it when a file is given
|
|
366
|
+
/read <jid> <msgId...> mark messages as read (blue ticks)
|
|
367
|
+
/autoread on|off auto-send read receipts for incoming messages
|
|
366
368
|
/contact about <jid> get bio/status text of a contact
|
|
367
369
|
|
|
368
370
|
Chats
|
|
@@ -393,7 +395,7 @@ const HELP = `
|
|
|
393
395
|
/group desc <jid> <text> change description
|
|
394
396
|
/group invite <jid> get invite link
|
|
395
397
|
/group revoke <jid> revoke invite link
|
|
396
|
-
/group join <code>
|
|
398
|
+
/group join <code|link> join by invite code or full link
|
|
397
399
|
/group invite-info <code|url> preview group metadata from invite link
|
|
398
400
|
/group photo <jid> <file> change group picture (JPEG)
|
|
399
401
|
/group meta <jid> query group metadata + participants
|
|
@@ -1003,11 +1005,37 @@ async function handleLine(line) {
|
|
|
1003
1005
|
}
|
|
1004
1006
|
|
|
1005
1007
|
case '/picture': {
|
|
1008
|
+
requireConn();
|
|
1009
|
+
const jid = normalizeJid(p[1]);
|
|
1010
|
+
const dest = p[2];
|
|
1011
|
+
if (!jid) { fail('usage: /picture <jid> [file]'); break; }
|
|
1012
|
+
const info = await _client.queryPictureInfo(jid);
|
|
1013
|
+
if (!info || !info.url) { out(' (no picture or private)'); break; }
|
|
1014
|
+
out(' ' + info.url);
|
|
1015
|
+
if (info.id) out(' id ' + info.id);
|
|
1016
|
+
if (!dest) break;
|
|
1017
|
+
const buf = await _client.downloadProfilePicture(jid);
|
|
1018
|
+
if (!buf) { fail('download returned nothing'); break; }
|
|
1019
|
+
require('fs').writeFileSync(dest, buf);
|
|
1020
|
+
out(' saved ' + dest + ' (' + buf.length + ' bytes)');
|
|
1021
|
+
break;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
case '/read': {
|
|
1006
1025
|
requireConn();
|
|
1007
1026
|
const jid = normalizeJid(p[1]);
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1027
|
+
const ids = p.slice(2);
|
|
1028
|
+
if (!jid || !ids.length) { fail('usage: /read <jid> <msgId...>'); break; }
|
|
1029
|
+
_client.markRead(jid, ids);
|
|
1030
|
+
out('marked read ' + ids.length + ' message(s) in ' + jid);
|
|
1031
|
+
break;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
case '/autoread': {
|
|
1035
|
+
const val = (p[1] || '').toLowerCase();
|
|
1036
|
+
if (val !== 'on' && val !== 'off') { fail('usage: /autoread on|off'); break; }
|
|
1037
|
+
if (_client) _client.autoRead = (val === 'on');
|
|
1038
|
+
out('auto read receipts ' + val);
|
|
1011
1039
|
break;
|
|
1012
1040
|
}
|
|
1013
1041
|
|
|
@@ -1232,14 +1260,15 @@ async function handleLine(line) {
|
|
|
1232
1260
|
else if (sub === 'revoke') {
|
|
1233
1261
|
const gj = asGroupJid(p[2]);
|
|
1234
1262
|
if (!gj) { fail('usage: /group revoke <jid>'); break; }
|
|
1235
|
-
await _client.revokeGroupInvite(gj);
|
|
1263
|
+
const fresh = await _client.revokeGroupInvite(gj);
|
|
1236
1264
|
out('invite link revoked');
|
|
1265
|
+
if (fresh) out(' new link ' + fresh);
|
|
1237
1266
|
}
|
|
1238
1267
|
else if (sub === 'join') {
|
|
1239
1268
|
const code = p[2];
|
|
1240
|
-
if (!code) { fail('usage: /group join <code>'); break; }
|
|
1241
|
-
const
|
|
1242
|
-
out('joined ' +
|
|
1269
|
+
if (!code) { fail('usage: /group join <code|link>'); break; }
|
|
1270
|
+
const r = await _client.joinGroupWithLink(code);
|
|
1271
|
+
out((r.pendingApproval ? 'join request sent ' : 'joined ') + r.jid);
|
|
1243
1272
|
}
|
|
1244
1273
|
else if (sub === 'invite-info') {
|
|
1245
1274
|
const code = p[2];
|