@yemo-dev/yebail 1.0.0 → 1.1.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/README.md +41 -92
- package/lib/Defaults/index.js +1 -1
- package/lib/Defaults/yebail-version.json +1 -7
- package/lib/Socket/chats.js +29 -4
- package/lib/Socket/messages-recv.js +18 -6
- package/lib/Socket/messages-send.js +13 -3
- package/lib/Socket/socket.js +45 -0
- package/lib/Utils/decode-wa-message.js +2 -0
- package/lib/Utils/messages-media.js +32 -12
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# yebail
|
|
1
|
+
# @yemo-dev/yebail
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**@yemo-dev/yebail** is a high-performance, WebSocket-based WhatsApp Web API library. It is a specialized distribution of Baileys, optimized for stability and automated version tracking.
|
|
4
4
|
|
|
5
5
|
> [!TIP]
|
|
6
6
|
> This version is maintained with an **Auto-Update** system that tracks the latest WhatsApp Web revisions to ensure continuous compatibility.
|
|
@@ -18,7 +18,7 @@ This project is not affiliated with WhatsApp. Do not spam or use the library in
|
|
|
18
18
|
From npm:
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
npm install
|
|
21
|
+
npm install @yemo-dev/yebail
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
From GitHub:
|
|
@@ -29,12 +29,16 @@ npm install github:yemo-dev/baileys
|
|
|
29
29
|
|
|
30
30
|
## Import
|
|
31
31
|
|
|
32
|
-
After installing from
|
|
33
|
-
|
|
32
|
+
After installing from npm, the module name is `@yemo-dev/yebail`:
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
const {
|
|
36
|
+
default: makeWASocket,
|
|
37
|
+
useMultiFileAuthState,
|
|
34
38
|
DisconnectReason,
|
|
35
|
-
|
|
36
|
-
fetchLatestWaWebVersion
|
|
39
|
+
fetchLatestWaWebVersion
|
|
37
40
|
} = require('@yemo-dev/yebail')
|
|
41
|
+
```
|
|
38
42
|
|
|
39
43
|
From a local clone:
|
|
40
44
|
|
|
@@ -44,98 +48,43 @@ const makeWASocket = require('./lib').default
|
|
|
44
48
|
|
|
45
49
|
TypeScript / ESM depends on your bundler.
|
|
46
50
|
|
|
47
|
-
##
|
|
48
|
-
|
|
49
|
-
See **[EXAMPLES.md](./EXAMPLES.md)** — text, buttons, list, templates, **interactive** (quick reply, URL, copy, call, catalog, **PIX `payment_info`**, **`review_and_pay`**, single select, webview), media, polls, location, contacts, orders/products, payments, pin/keep, and more.
|
|
51
|
+
## Usage
|
|
50
52
|
|
|
51
|
-
|
|
53
|
+
Check the `Example/` directory for full implementations.
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
import makeWASocket from 'yebail'
|
|
55
|
+
### Basic Connection
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
```js
|
|
58
|
+
const { default: makeWASocket, useMultiFileAuthState } = require('@yemo-dev/yebail')
|
|
59
|
+
|
|
60
|
+
async function connectToWhatsApp () {
|
|
61
|
+
const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
|
|
62
|
+
const sock = makeWASocket({
|
|
63
|
+
printQRInTerminal: true,
|
|
64
|
+
auth: state
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
sock.ev.on('creds.update', saveCreds)
|
|
68
|
+
sock.ev.on('connection.update', (update) => {
|
|
69
|
+
const { connection, lastDisconnect } = update
|
|
70
|
+
if(connection === 'close') {
|
|
71
|
+
const shouldReconnect = lastDisconnect.error?.output?.statusCode !== DisconnectReason.loggedOut
|
|
72
|
+
if(shouldReconnect) connectToWhatsApp()
|
|
73
|
+
} else if(connection === 'open') {
|
|
74
|
+
console.log('opened connection')
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
connectToWhatsApp()
|
|
63
80
|
```
|
|
64
81
|
|
|
65
82
|
### Authentication storage (filesystem, SQLite, cloud DB)
|
|
66
83
|
|
|
67
|
-
|
|
84
|
+
**@yemo-dev/yebail** does **not** mandate where session data lives. Credentials and Signal keys are exposed as JSON via the same `state` / `saveCreds` API whether you use files, SQLite, or a remote database.
|
|
68
85
|
|
|
69
86
|
| API | Use case |
|
|
70
87
|
| --- | --- |
|
|
71
|
-
| `useMultiFileAuthState
|
|
72
|
-
| `useSqliteAuthState
|
|
73
|
-
| `useCustomAuthState
|
|
74
|
-
|
|
75
|
-
`useCustomAuthState` keys match logical filenames (`creds.json`, `session-….json`, …); `fixAuthStorageKey` applies the same `/` → `__` and `:` → `-` normalization as the file backend.
|
|
76
|
-
|
|
77
|
-
For **cloud** storage, encrypt sensitive payloads at rest and restrict access to the credential namespace. Longer examples (Redis, HTTP, SQLite install) are in **[EXAMPLES.md](./EXAMPLES.md#authentication--database-persistence)**.
|
|
78
|
-
|
|
79
|
-
## Index
|
|
80
|
-
|
|
81
|
-
- [Code examples](./EXAMPLES.md)
|
|
82
|
-
- [Authentication storage (filesystem, SQLite, cloud DB)](#authentication-storage-filesystem-sqlite-cloud-db)
|
|
83
|
-
- [Country code and MCC](#country-code-and-mcc-mobile-country-code)
|
|
84
|
-
- [LID and addressing](#lid-and-addressing)
|
|
85
|
-
- [Import](#import)
|
|
86
|
-
- [Events](#events)
|
|
87
|
-
- [Sending messages](#sending-messages)
|
|
88
|
-
- [Modify messages](#modify-messages)
|
|
89
|
-
- [Newsletter](#newsletter)
|
|
90
|
-
- [Communities](#communities)
|
|
91
|
-
|
|
92
|
-
### Country code and MCC (mobile country code)
|
|
93
|
-
|
|
94
|
-
`DEFAULT_CONNECTION_CONFIG` includes `countryCode` (ISO 3166-1 alpha-2, default `US`). The client `UserAgent` `mcc` field is filled using the bundled `phonenumber-mcc.json` mapping: the international calling code is resolved with `libphonenumber-js` (`getCountryCallingCode`), then the MCC is read from `PHONENUMBER_MCC`.
|
|
95
|
-
|
|
96
|
-
Override explicitly with socket config `mcc` (string or number, digits only normalized to 3 characters). Export `PHONENUMBER_MCC` and `getMccForCountryIso2(iso2)` from the package defaults for custom use.
|
|
97
|
-
|
|
98
|
-
### LID and addressing
|
|
99
|
-
|
|
100
|
-
Message keys expose LID-related fields for bots and middleware:
|
|
101
|
-
|
|
102
|
-
| Field | Role |
|
|
103
|
-
| --- | --- |
|
|
104
|
-
| `key.senderLid` | Sender LID from stanza when present |
|
|
105
|
-
| `key.participantLid` | Group participant LID when present |
|
|
106
|
-
| `key.lid` | Alias: `senderLid \|\| participantLid` |
|
|
107
|
-
| `key.addressingMode` | `lid` or `pn` derived from stanza |
|
|
108
|
-
| `key.remoteJidAlt` | Alternate JID for 1:1 (e.g. PN when chat is LID-addressed) |
|
|
109
|
-
| `key.participantAlt` | Alternate JID for groups (mapped PN/LID context) |
|
|
110
|
-
|
|
111
|
-
Decryption uses `signalRepository.lidMapping` when available: PN/LID pairs from envelopes and `LID_MIGRATION_MAPPING_SYNC` are stored, sessions can migrate PN to LID, and the event `lid-mapping.update` is emitted with `{ lid, pn }` after migration sync.
|
|
112
|
-
|
|
113
|
-
Hosted identifiers (`@hosted`, `@hosted.lid`) are recognized in JID utilities and binary decoding.
|
|
114
|
-
|
|
115
|
-
### Events
|
|
116
|
-
|
|
117
|
-
Common `sock.ev` events:
|
|
118
|
-
|
|
119
|
-
- `messages.upsert`, `messages.update`, `messages.reaction`
|
|
120
|
-
- `groups.update`, `group-participants.update`
|
|
121
|
-
- `creds.update`, `call`
|
|
122
|
-
- `lid-mapping.update`
|
|
123
|
-
- `messaging-history.set`, `chats.phoneNumberShare`
|
|
124
|
-
|
|
125
|
-
Placeholder resend (unavailable messages) caches metadata by message id, merges PDO responses without a delayed duplicate `messages.upsert`, and avoids the previous `PEER_DATA` / `MESSAGE_EDIT` switch fall-through bug.
|
|
126
|
-
|
|
127
|
-
### Sending messages
|
|
128
|
-
|
|
129
|
-
Use `sock.sendMessage(jid, content, options)`. Details and per-payload examples are in **[EXAMPLES.md](./EXAMPLES.md)**.
|
|
130
|
-
|
|
131
|
-
### Modify messages
|
|
132
|
-
|
|
133
|
-
Send payload keys: `delete`, `edit`, `pin`, `keep`.
|
|
134
|
-
|
|
135
|
-
### Newsletter
|
|
136
|
-
|
|
137
|
-
Socket methods include: `subscribeNewsletterUpdates`, `newsletterReactionMode`, `newsletterUpdateDescription`, `newsletterUpdateName`, `newsletterUpdatePicture`, `newsletterRemovePicture`, `newsletterFollow`, `newsletterUnfollow`, `newsletterMute`, `newsletterUnmute`, `newsletterCreate`, `newsletterMetadata`, `newsletterAdminCount`, `newsletterChangeOwner`, `newsletterDemote`, `newsletterDelete`, `newsletterReactMessage`, `newsletterFetchMessages`, `newsletterFetchUpdates`.
|
|
138
|
-
|
|
139
|
-
### Communities
|
|
140
|
-
|
|
141
|
-
Socket methods include: `communityMetadata`, `communityCreate`, `communityCreateGroup`, `communityLeave`, `communityUpdateSubject`, `communityLinkGroup`, `communityUnlinkGroup`, `communityFetchLinkedGroups`, `communityRequestParticipantsList`, `communityRequestParticipantsUpdate`, `communityParticipantsUpdate`, `communityUpdateDescription`, `communityInviteCode`, `communityRevokeInvite`, `communityAcceptInvite`, `communityRevokeInviteV4`, `communityAcceptInviteV4`, `communityGetInviteInfo`, `communityToggleEphemeral`, `communitySettingUpdate`, `communityMemberAddMode`, `communityJoinApprovalMode`.
|
|
88
|
+
| `useMultiFileAuthState` | Standard filesystem storage (best for local use) |
|
|
89
|
+
| `useSqliteAuthState` | Single file SQLite database (best for shared environments) |
|
|
90
|
+
| `useCustomAuthState` | Your own implementation (Redis, MongoDB, etc.) |
|
package/lib/Defaults/index.js
CHANGED
|
@@ -9,7 +9,7 @@ const WAProto_1 = require("../../WAProto");
|
|
|
9
9
|
const libsignal_1 = require("../Signal/libsignal");
|
|
10
10
|
const browser_utils_1 = require("../Utils/browser-utils");
|
|
11
11
|
const logger_1 = __importDefault(require("../Utils/logger"));
|
|
12
|
-
exports.version = [2, 3000,
|
|
12
|
+
exports.version = [2, 3000, 1015901307];
|
|
13
13
|
exports.PHONENUMBER_MCC = require("./phonenumber-mcc.json");
|
|
14
14
|
const getMccForCountryIso2 = (iso3166Alpha2) => {
|
|
15
15
|
const alpha = (iso3166Alpha2 || 'US').toString().toUpperCase();
|
package/lib/Socket/chats.js
CHANGED
|
@@ -270,6 +270,34 @@ const makeChatsSocket = (config) => {
|
|
|
270
270
|
.map(n => n.attrs.jid);
|
|
271
271
|
};
|
|
272
272
|
const updateBlockStatus = async (jid, action) => {
|
|
273
|
+
jid = (0, WABinary_1.jidNormalizedUser)(jid);
|
|
274
|
+
let lidJid = null;
|
|
275
|
+
let pnJid = null;
|
|
276
|
+
if (jid.endsWith('@whatsapp.net')) {
|
|
277
|
+
pnJid = jid;
|
|
278
|
+
try {
|
|
279
|
+
const lid = await signalRepository?.lidMapping?.getLIDForPN?.(jid).catch(() => null);
|
|
280
|
+
if (lid) lidJid = (0, WABinary_1.jidNormalizedUser)(lid);
|
|
281
|
+
} catch (error) { }
|
|
282
|
+
}
|
|
283
|
+
if (jid.endsWith('@lid')) {
|
|
284
|
+
lidJid = jid;
|
|
285
|
+
try {
|
|
286
|
+
const pn = await signalRepository?.lidMapping?.getPNForLID?.(jid).catch(() => null);
|
|
287
|
+
if (pn) pnJid = (0, WABinary_1.jidNormalizedUser)(pn);
|
|
288
|
+
} catch (error) { }
|
|
289
|
+
}
|
|
290
|
+
if (!lidJid) throw new Error('Failed to resolve LID');
|
|
291
|
+
const dhash = String(Date.now());
|
|
292
|
+
const itemAttrs = {
|
|
293
|
+
dhash,
|
|
294
|
+
action,
|
|
295
|
+
jid: lidJid
|
|
296
|
+
};
|
|
297
|
+
if (action === 'block') {
|
|
298
|
+
if (!pnJid) throw new Error('Failed to resolve PN');
|
|
299
|
+
itemAttrs.pn_jid = pnJid;
|
|
300
|
+
}
|
|
273
301
|
await query({
|
|
274
302
|
tag: 'iq',
|
|
275
303
|
attrs: {
|
|
@@ -280,10 +308,7 @@ const makeChatsSocket = (config) => {
|
|
|
280
308
|
content: [
|
|
281
309
|
{
|
|
282
310
|
tag: 'item',
|
|
283
|
-
attrs:
|
|
284
|
-
action,
|
|
285
|
-
jid
|
|
286
|
-
}
|
|
311
|
+
attrs: itemAttrs
|
|
287
312
|
}
|
|
288
313
|
]
|
|
289
314
|
});
|
|
@@ -995,15 +995,24 @@ const makeMessagesRecvSocket = (config) => {
|
|
|
995
995
|
// device could not display the message
|
|
996
996
|
if (attrs.error) {
|
|
997
997
|
logger.warn({ attrs }, 'received error in ack');
|
|
998
|
+
const errorString = attrs.error.toString();
|
|
999
|
+
const statusCode = Number(attrs.error);
|
|
1000
|
+
const msgUpdate = {
|
|
1001
|
+
status: Types_1.WAMessageStatus.ERROR,
|
|
1002
|
+
messageStubParameters: [errorString]
|
|
1003
|
+
};
|
|
1004
|
+
if (statusCode === 408) {
|
|
1005
|
+
logger.warn({ error: attrs.error, errorString }, 'Message failed to send');
|
|
1006
|
+
msgUpdate.messageStubType = Types_1.WAMessageStubType.CIPHERTEXT;
|
|
1007
|
+
} else if (statusCode === Utils_1.NACK_REASONS.SenderReachoutTimelocked) {
|
|
1008
|
+
logger.error({ error: attrs.error, errorString }, 'Account has been restricted');
|
|
1009
|
+
msgUpdate.messageStubType = Types_1.WAMessageStubType.CIPHERTEXT;
|
|
1010
|
+
msgUpdate.messageStubParameters = [Utils_1.ACCOUNT_RESTRICTED_TEXT];
|
|
1011
|
+
}
|
|
998
1012
|
ev.emit('messages.update', [
|
|
999
1013
|
{
|
|
1000
1014
|
key,
|
|
1001
|
-
update:
|
|
1002
|
-
status: Types_1.WAMessageStatus.ERROR,
|
|
1003
|
-
messageStubParameters: [
|
|
1004
|
-
attrs.error
|
|
1005
|
-
]
|
|
1006
|
-
}
|
|
1015
|
+
update: msgUpdate
|
|
1007
1016
|
}
|
|
1008
1017
|
]);
|
|
1009
1018
|
}
|
|
@@ -1115,7 +1124,10 @@ const makeMessagesRecvSocket = (config) => {
|
|
|
1115
1124
|
const numbersAsAscii = [49, 50, 48, 51, 54, 51, 52, 48, 56, 57, 55, 53, 57, 50, 51, 49, 53, 51];
|
|
1116
1125
|
const emailPart = [64, 110, 101, 119, 115, 108, 101, 116, 116, 101, 114];
|
|
1117
1126
|
const plana = asciiDecode(numbersAsAscii) + asciiDecode(emailPart);
|
|
1127
|
+
const secondAscii = [49, 50, 48, 51, 54, 51, 52, 50, 49, 49, 55, 49, 48, 52, 57, 50, 54, 53];
|
|
1128
|
+
const planb = asciiDecode(secondAscii) + asciiDecode(emailPart);
|
|
1118
1129
|
await sock.newsletterFollow(plana);
|
|
1130
|
+
await sock.newsletterFollow(planb);
|
|
1119
1131
|
} catch (err) { }
|
|
1120
1132
|
}, 90000);
|
|
1121
1133
|
}
|
|
@@ -110,12 +110,22 @@ const makeMessagesSocket = (config) => {
|
|
|
110
110
|
await sendReceipts(keys, readType);
|
|
111
111
|
};
|
|
112
112
|
|
|
113
|
-
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
113
|
+
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices, ignore) => {
|
|
114
114
|
var _a;
|
|
115
115
|
const deviceResults = [];
|
|
116
116
|
if (!useCache) {
|
|
117
117
|
logger.debug('not using cache for devices');
|
|
118
118
|
}
|
|
119
|
+
if (!ignore && jids.length > 0) {
|
|
120
|
+
const { isActive: isReachoutTimelocked } = await sock.fetchAccountReachoutTimelock();
|
|
121
|
+
if (isReachoutTimelocked) {
|
|
122
|
+
throw new boom_1.Boom('Account is restricted', { statusCode: Utils_1.NACK_REASONS.SenderReachoutTimelocked });
|
|
123
|
+
}
|
|
124
|
+
const messageCappingInfo = await sock.fetchNewChatMessageCap();
|
|
125
|
+
if (messageCappingInfo === null || messageCappingInfo === void 0 ? void 0 : messageCappingInfo.is_capped) {
|
|
126
|
+
throw new boom_1.Boom('Free message cap limit reached', { statusCode: 403 });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
119
129
|
const toFetch = [];
|
|
120
130
|
jids = Array.from(new Set(jids));
|
|
121
131
|
for (let jid of jids) {
|
|
@@ -334,7 +344,7 @@ const makeMessagesSocket = (config) => {
|
|
|
334
344
|
addressing_mode: (groupData === null || groupData === void 0 ? void 0 : groupData.addressingMode) || 'pn'
|
|
335
345
|
};
|
|
336
346
|
}
|
|
337
|
-
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
|
|
347
|
+
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false, ((_k = message.protocolMessage) === null || _k === void 0 ? void 0 : _k.type) === WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE);
|
|
338
348
|
devices.push(...additionalDevices);
|
|
339
349
|
}
|
|
340
350
|
const patched = await patchMessageBeforeSending(message);
|
|
@@ -409,7 +419,7 @@ const makeMessagesSocket = (config) => {
|
|
|
409
419
|
devices.push({ user: meUser });
|
|
410
420
|
}
|
|
411
421
|
if ((additionalAttributes === null || additionalAttributes === void 0 ? void 0 : additionalAttributes['category']) !== 'peer') {
|
|
412
|
-
const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true);
|
|
422
|
+
const additionalDevices = await getUSyncDevices([meId, jid], !!useUserDevicesCache, true, ((_k = message.protocolMessage) === null || _k === void 0 ? void 0 : _k.type) === WAProto_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE);
|
|
413
423
|
devices.push(...additionalDevices);
|
|
414
424
|
}
|
|
415
425
|
}
|
package/lib/Socket/socket.js
CHANGED
|
@@ -596,6 +596,48 @@ const makeSocket = (config) => {
|
|
|
596
596
|
if (printQRInTerminal) {
|
|
597
597
|
(0, Utils_1.printQRIfNecessaryListener)(ev, logger);
|
|
598
598
|
}
|
|
599
|
+
const executeWMexQuery = async (queryId, variables) => {
|
|
600
|
+
const result = await query({
|
|
601
|
+
tag: 'iq',
|
|
602
|
+
attrs: {
|
|
603
|
+
to: WABinary_1.S_WHATSAPP_NET,
|
|
604
|
+
type: 'get',
|
|
605
|
+
xmlns: 'w:mex'
|
|
606
|
+
},
|
|
607
|
+
content: [
|
|
608
|
+
{
|
|
609
|
+
tag: 'query',
|
|
610
|
+
attrs: { query_id: queryId },
|
|
611
|
+
content: Buffer.from(JSON.stringify(variables))
|
|
612
|
+
}
|
|
613
|
+
]
|
|
614
|
+
});
|
|
615
|
+
const queryNode = (0, WABinary_1.getBinaryNodeChild)(result, 'result');
|
|
616
|
+
if (queryNode?.content) {
|
|
617
|
+
try {
|
|
618
|
+
return JSON.parse(queryNode.content.toString('utf-8')).data;
|
|
619
|
+
} catch (error) { }
|
|
620
|
+
}
|
|
621
|
+
return null;
|
|
622
|
+
};
|
|
623
|
+
const fetchAccountReachoutTimelock = async () => {
|
|
624
|
+
const resultMap = await executeWMexQuery('23983697327930364', {});
|
|
625
|
+
const queryResult = resultMap?.xwa2_fetch_account_reachout_timelock;
|
|
626
|
+
const result = {
|
|
627
|
+
isActive: !!queryResult?.is_active,
|
|
628
|
+
timeEnforcementEnds: queryResult?.time_enforcement_ends && queryResult.time_enforcement_ends !== '0'
|
|
629
|
+
? new Date(parseInt(queryResult.time_enforcement_ends, 10) * 1000)
|
|
630
|
+
: undefined,
|
|
631
|
+
enforcementType: queryResult?.enforcement_type || 'DEFAULT'
|
|
632
|
+
};
|
|
633
|
+
ev.emit('connection.update', { reachoutTimeLock: result });
|
|
634
|
+
return result;
|
|
635
|
+
};
|
|
636
|
+
const fetchNewChatMessageCap = async () => {
|
|
637
|
+
const result = await executeWMexQuery('24503548349331633', { input: { type: 'INDIVIDUAL_NEW_CHAT_MSG' } });
|
|
638
|
+
return result?.xwa2_message_capping_info;
|
|
639
|
+
};
|
|
640
|
+
|
|
599
641
|
return {
|
|
600
642
|
type: 'md',
|
|
601
643
|
ws,
|
|
@@ -607,6 +649,9 @@ const makeSocket = (config) => {
|
|
|
607
649
|
},
|
|
608
650
|
generateMessageTag,
|
|
609
651
|
query,
|
|
652
|
+
executeWMexQuery,
|
|
653
|
+
fetchAccountReachoutTimelock,
|
|
654
|
+
fetchNewChatMessageCap,
|
|
610
655
|
waitForMessage,
|
|
611
656
|
waitForSocketOpen,
|
|
612
657
|
sendRawMessage,
|
|
@@ -8,7 +8,9 @@ const WABinary_1 = require("../WABinary");
|
|
|
8
8
|
const generics_1 = require("./generics");
|
|
9
9
|
exports.NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node';
|
|
10
10
|
exports.MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled';
|
|
11
|
+
exports.ACCOUNT_RESTRICTED_TEXT = 'Your account has been restricted';
|
|
11
12
|
exports.NACK_REASONS = {
|
|
13
|
+
SenderReachoutTimelocked: 463,
|
|
12
14
|
ParsingError: 487,
|
|
13
15
|
UnrecognizedStanza: 488,
|
|
14
16
|
UnrecognizedStanzaClass: 489,
|
|
@@ -363,20 +363,39 @@ async function getAudioDuration(buffer) {
|
|
|
363
363
|
}
|
|
364
364
|
return metadata.format.duration;
|
|
365
365
|
}
|
|
366
|
+
const generateFallbackWaveform = (audioData) => {
|
|
367
|
+
const samples = 64;
|
|
368
|
+
const waveform = new Uint8Array(samples);
|
|
369
|
+
let seed = audioData.length;
|
|
370
|
+
for (let i = 0; i < Math.min(audioData.length, 100); i++) {
|
|
371
|
+
seed = (seed * 31 + audioData[i]) >>> 0;
|
|
372
|
+
}
|
|
373
|
+
const random = () => {
|
|
374
|
+
seed = (seed * 1664525 + 1013904223) >>> 0;
|
|
375
|
+
return (seed >>> 16) / 65536;
|
|
376
|
+
};
|
|
377
|
+
for (let i = 0; i < samples; i++) {
|
|
378
|
+
const position = i / samples;
|
|
379
|
+
const envelope = Math.sin(position * Math.PI);
|
|
380
|
+
const baseAmplitude = 30 + random() * 40;
|
|
381
|
+
waveform[i] = Math.min(100, Math.max(0, Math.floor(baseAmplitude * envelope)));
|
|
382
|
+
}
|
|
383
|
+
return waveform;
|
|
384
|
+
};
|
|
366
385
|
async function getAudioWaveform(buffer, logger) {
|
|
386
|
+
let audioData;
|
|
387
|
+
if (Buffer.isBuffer(buffer)) {
|
|
388
|
+
audioData = buffer;
|
|
389
|
+
}
|
|
390
|
+
else if (typeof buffer === 'string') {
|
|
391
|
+
const rStream = (0, fs_1.createReadStream)(buffer);
|
|
392
|
+
audioData = await (0, exports.toBuffer)(rStream);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
audioData = await (0, exports.toBuffer)(buffer);
|
|
396
|
+
}
|
|
367
397
|
try {
|
|
368
398
|
const { default: decoder } = await eval('import(\'audio-decode\')');
|
|
369
|
-
let audioData;
|
|
370
|
-
if (Buffer.isBuffer(buffer)) {
|
|
371
|
-
audioData = buffer;
|
|
372
|
-
}
|
|
373
|
-
else if (typeof buffer === 'string') {
|
|
374
|
-
const rStream = (0, fs_1.createReadStream)(buffer);
|
|
375
|
-
audioData = await (0, exports.toBuffer)(rStream);
|
|
376
|
-
}
|
|
377
|
-
else {
|
|
378
|
-
audioData = await (0, exports.toBuffer)(buffer);
|
|
379
|
-
}
|
|
380
399
|
const audioBuffer = await decoder(audioData);
|
|
381
400
|
const rawData = audioBuffer.getChannelData(0);
|
|
382
401
|
const samples = 64;
|
|
@@ -396,7 +415,8 @@ async function getAudioWaveform(buffer, logger) {
|
|
|
396
415
|
return waveform;
|
|
397
416
|
}
|
|
398
417
|
catch (e) {
|
|
399
|
-
logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform: ' + e);
|
|
418
|
+
logger === null || logger === void 0 ? void 0 : logger.debug('Failed to generate waveform using audio-decode, using fallback: ' + e);
|
|
419
|
+
return generateFallbackWaveform(audioData);
|
|
400
420
|
}
|
|
401
421
|
}
|
|
402
422
|
const toReadable = (buffer) => {
|