mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
Added support for sending + toggling disappearing messages
This commit is contained in:
26
README.md
26
README.md
@@ -254,8 +254,7 @@ To note:
|
||||
``` ts
|
||||
const info: MessageOptions = {
|
||||
quoted: quotedMessage, // the message you want to quote
|
||||
contextInfo: { forwardingScore: 2, isForwarded: true }, // some random context info
|
||||
// (can show a forwarded message with this too)
|
||||
contextInfo: { forwardingScore: 2, isForwarded: true }, // some random context info (can show a forwarded message with this too)
|
||||
timestamp: Date(), // optional, if you want to manually set the timestamp of the message
|
||||
caption: "hello there!", // (for media messages) the caption to send with the media (cannot be sent with stickers though)
|
||||
thumbnail: "23GD#4/==", /* (for location & media messages) has to be a base 64 encoded JPEG if you want to send a custom thumb,
|
||||
@@ -263,13 +262,16 @@ To note:
|
||||
Do not enter this field if you want to automatically generate a thumb
|
||||
*/
|
||||
mimetype: Mimetype.pdf, /* (for media messages) specify the type of media (optional for all media types except documents),
|
||||
import {Mimetype} from '@adiwajshing/baileys'
|
||||
import {Mimetype} from '@adiwajshing/baileys'
|
||||
*/
|
||||
filename: 'somefile.pdf', // (for media messages) file name for the media
|
||||
/* will send audio messages as voice notes, if set to true */
|
||||
ptt: true,
|
||||
// will detect links & generate a link preview automatically (default true)
|
||||
detectLinks: true
|
||||
detectLinks: true,
|
||||
/** Should it send as a disappearing messages.
|
||||
* By default 'chat' -- which follows the setting of the chat */
|
||||
sendEphemeral: 'chat'
|
||||
}
|
||||
```
|
||||
## Forwarding Messages
|
||||
@@ -359,6 +361,22 @@ await conn.modifyChat (jid, ChatModification.delete) // will delete the chat (ca
|
||||
|
||||
**Note:** to unmute or unpin a chat, one must pass the timestamp of the pinning or muting. This is returned by the pin & mute functions. This is also available in the `WAChat` objects of the respective chats, as a `mute` or `pin` property.
|
||||
|
||||
## Disappearing Messages
|
||||
|
||||
``` ts
|
||||
const jid = '1234@s.whatsapp.net' // can also be a group
|
||||
// turn on disappearing messages
|
||||
await conn.toggleDisappearingMessages(
|
||||
jid,
|
||||
WA_DEFAULT_EPHEMERAL // this is 1 week in seconds -- how long you want messages to appear for
|
||||
)
|
||||
// will automatically send as a disappearing message
|
||||
await conn.sendMessage(jid, 'Hello poof!', MessageType.text)
|
||||
// turn off disappearing messages
|
||||
await conn.toggleDisappearingMessages(jid, 0)
|
||||
|
||||
```
|
||||
|
||||
## Misc
|
||||
|
||||
- To load chats in a paginated manner
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@adiwajshing/baileys",
|
||||
"version": "3.3.2",
|
||||
"version": "3.4.0",
|
||||
"description": "WhatsApp Web API",
|
||||
"homepage": "https://github.com/adiwajshing/Baileys",
|
||||
"main": "lib/WAConnection/WAConnection.js",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Presence, ChatModification, delay, newMessagesDB } from '../WAConnection/WAConnection'
|
||||
import { Presence, ChatModification, delay, newMessagesDB, WA_DEFAULT_EPHEMERAL, MessageType } from '../WAConnection/WAConnection'
|
||||
import { promises as fs } from 'fs'
|
||||
import * as assert from 'assert'
|
||||
import fetch from 'node-fetch'
|
||||
import { WAConnectionTest, testJid, assertChatDBIntegrity } from './Common'
|
||||
import { WAConnectionTest, testJid, assertChatDBIntegrity, sendAndRetreiveMessage } from './Common'
|
||||
|
||||
WAConnectionTest('Misc', conn => {
|
||||
|
||||
@@ -197,4 +197,65 @@ WAConnectionTest('Misc', conn => {
|
||||
|
||||
await task
|
||||
})
|
||||
|
||||
it('should toggle disappearing messages', async () => {
|
||||
let chat = conn.chats.get(testJid)
|
||||
if (!chat) {
|
||||
// wait for chats
|
||||
await new Promise(resolve => (
|
||||
conn.once('chats-received', () => resolve())
|
||||
))
|
||||
chat = conn.chats.get(testJid)
|
||||
}
|
||||
|
||||
const waitForChatUpdate = (ephemeralOn: boolean) => (
|
||||
new Promise(resolve => (
|
||||
conn.on('chat-update', ({ jid, ephemeral }) => {
|
||||
if (jid === testJid && typeof ephemeral !== 'undefined') {
|
||||
assert.strictEqual(!!(+ephemeral), ephemeralOn)
|
||||
assert.strictEqual(!!(+chat.ephemeral), ephemeralOn)
|
||||
resolve()
|
||||
conn.removeAllListeners('chat-update')
|
||||
}
|
||||
})
|
||||
))
|
||||
)
|
||||
const toggleDisappearingMessages = async (on: boolean) => {
|
||||
const update = waitForChatUpdate(on)
|
||||
await conn.toggleDisappearingMessages(testJid, on ? WA_DEFAULT_EPHEMERAL : 0)
|
||||
await update
|
||||
}
|
||||
|
||||
if (!chat.eph_setting_ts) {
|
||||
await toggleDisappearingMessages(true)
|
||||
}
|
||||
|
||||
await delay(1000)
|
||||
|
||||
let msg = await sendAndRetreiveMessage(
|
||||
conn,
|
||||
'This will go poof 😱',
|
||||
MessageType.text
|
||||
)
|
||||
assert.ok(msg.message?.ephemeralMessage)
|
||||
|
||||
const contextInfo = msg.message?.ephemeralMessage?.message?.extendedTextMessage?.contextInfo
|
||||
assert.strictEqual(contextInfo.expiration, chat.ephemeral)
|
||||
assert.strictEqual(+contextInfo.ephemeralSettingTimestamp, +chat.eph_setting_ts)
|
||||
// test message deletion
|
||||
await conn.deleteMessage(testJid, msg.key)
|
||||
|
||||
await delay(1000)
|
||||
|
||||
await toggleDisappearingMessages(false)
|
||||
|
||||
await delay(1000)
|
||||
|
||||
msg = await sendAndRetreiveMessage(
|
||||
conn,
|
||||
'This will not go poof 😔',
|
||||
MessageType.text
|
||||
)
|
||||
assert.ok(msg.message.extendedTextMessage)
|
||||
})
|
||||
})
|
||||
@@ -438,6 +438,23 @@ export class WAConnection extends Base {
|
||||
update && Object.assign(chatUpdate, update)
|
||||
}
|
||||
}
|
||||
|
||||
const ephemeralProtocolMsg = message.message?.ephemeralMessage?.message?.protocolMessage
|
||||
if (
|
||||
ephemeralProtocolMsg &&
|
||||
ephemeralProtocolMsg.type === WAMessageProto.ProtocolMessage.ProtocolMessageType.EPHEMERAL_SETTING
|
||||
) {
|
||||
chatUpdate.eph_setting_ts = message.messageTimestamp.toString()
|
||||
chatUpdate.ephemeral = ephemeralProtocolMsg.ephemeralExpiration.toString()
|
||||
|
||||
if (ephemeralProtocolMsg.ephemeralExpiration) {
|
||||
chat.eph_setting_ts = chatUpdate.eph_setting_ts
|
||||
chat.ephemeral = chatUpdate.ephemeral
|
||||
} else {
|
||||
delete chat.eph_setting_ts
|
||||
delete chat.ephemeral
|
||||
}
|
||||
}
|
||||
|
||||
const messages = chat.messages
|
||||
const protocolMessage = message.message?.protocolMessage
|
||||
@@ -471,7 +488,7 @@ export class WAConnection extends Base {
|
||||
messages.delete (messages.all()[0]) // delete oldest messages
|
||||
}
|
||||
// only update if it's an actual message
|
||||
if (message.message) {
|
||||
if (message.message && !ephemeralProtocolMsg) {
|
||||
this.chatUpdateTime (chat, +toNumber(message.messageTimestamp))
|
||||
chatUpdate.t = chat.t
|
||||
}
|
||||
@@ -515,7 +532,7 @@ export class WAConnection extends Base {
|
||||
const announce = message.messageStubParameters[0] === 'on' ? 'true' : 'false'
|
||||
emitGroupUpdate({ announce })
|
||||
break
|
||||
case WA_MESSAGE_STUB_TYPE.GROUP_CHANGE_ANNOUNCE:
|
||||
case WA_MESSAGE_STUB_TYPE.GROUP_CHANGE_RESTRICT:
|
||||
const restrict = message.messageStubParameters[0] === 'on' ? 'true' : 'false'
|
||||
emitGroupUpdate({ restrict })
|
||||
break
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
WALocationMessage,
|
||||
WAContactMessage,
|
||||
WATextMessage,
|
||||
WAMessageContent, WAMetric, WAFlag, WAMessage, BaileysError, WA_MESSAGE_STATUS_TYPE, WAMessageProto, MediaConnInfo, MessageTypeProto, URL_REGEX, WAUrlInfo
|
||||
WAMessageContent, WAMetric, WAFlag, WAMessage, BaileysError, WA_MESSAGE_STATUS_TYPE, WAMessageProto, MediaConnInfo, MessageTypeProto, URL_REGEX, WAUrlInfo, WA_DEFAULT_EPHEMERAL
|
||||
} from './Constants'
|
||||
import { generateMessageID, sha256, hmacSign, aesEncrypWithIV, randomBytes, generateThumbnail, getMediaKeys, decodeMediaMessageBuffer, extensionForMediaMessage, whatsappID, unixTimestampSeconds, getAudioDuration } from './Utils'
|
||||
import { Mutex } from './Mutex'
|
||||
@@ -47,6 +47,22 @@ export class WAConnection extends Base {
|
||||
const preparedMessage = this.prepareMessageFromContent(id, content, options)
|
||||
return preparedMessage
|
||||
}
|
||||
/**
|
||||
* Toggles disappearing messages for the given chat
|
||||
*
|
||||
* @param jid the chat to toggle
|
||||
* @param ephemeralExpiration 0 to disable, enter any positive number to enable disappearing messages for the specified duration;
|
||||
* For the default see WA_DEFAULT_EPHEMERAL
|
||||
*/
|
||||
async toggleDisappearingMessages(jid: string, ephemeralExpiration?: number, opts: { waitForAck: boolean } = { waitForAck: true }) {
|
||||
const message = this.prepareMessageFromContent(
|
||||
jid,
|
||||
this.prepareDisappearingMessageSettingContent(ephemeralExpiration),
|
||||
{}
|
||||
)
|
||||
await this.relayWAMessage(message, opts)
|
||||
return message
|
||||
}
|
||||
/** Prepares the message content */
|
||||
async prepareMessageContent (message: string | WATextMessage | WALocationMessage | WAContactMessage | Buffer, type: MessageType, options: MessageOptions) {
|
||||
let m: WAMessageContent = {}
|
||||
@@ -85,6 +101,20 @@ export class WAConnection extends Base {
|
||||
}
|
||||
return WAMessageProto.Message.fromObject (m)
|
||||
}
|
||||
prepareDisappearingMessageSettingContent(ephemeralExpiration?: number) {
|
||||
ephemeralExpiration = ephemeralExpiration || 0
|
||||
const content: WAMessageContent = {
|
||||
ephemeralMessage: {
|
||||
message: {
|
||||
protocolMessage: {
|
||||
type: WAMessageProto.ProtocolMessage.ProtocolMessageType.EPHEMERAL_SETTING,
|
||||
ephemeralExpiration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return WAMessageProto.Message.fromObject(content)
|
||||
}
|
||||
/** Prepare a media message for sending */
|
||||
async prepareMessageMedia(buffer: Buffer, mediaType: MessageType, options: MessageOptions = {}) {
|
||||
await this.waitForConnection ()
|
||||
@@ -175,7 +205,7 @@ export class WAConnection extends Base {
|
||||
/** prepares a WAMessage for sending from the given content & options */
|
||||
prepareMessageFromContent(id: string, message: WAMessageContent, options: MessageOptions) {
|
||||
if (!options.timestamp) options.timestamp = new Date() // set timestamp to now
|
||||
|
||||
if (typeof options.sendEphemeral === 'undefined') options.sendEphemeral = 'chat'
|
||||
// prevent an annoying bug (WA doesn't accept sending messages with '@c.us')
|
||||
id = whatsappID (id)
|
||||
|
||||
@@ -202,6 +232,28 @@ export class WAConnection extends Base {
|
||||
if (options?.thumbnail) {
|
||||
message[key].jpegThumbnail = Buffer.from(options.thumbnail, 'base64')
|
||||
}
|
||||
|
||||
const chat = this.chats.get(id)
|
||||
if (
|
||||
// if we want to send a disappearing message
|
||||
((options?.sendEphemeral === 'chat' && chat?.ephemeral) ||
|
||||
options?.sendEphemeral === true) &&
|
||||
// and it's not a protocol message -- delete, toggle disappear message
|
||||
key !== 'protocolMessage' &&
|
||||
// already not converted to disappearing message
|
||||
key !== 'ephemeralMessage'
|
||||
) {
|
||||
message[key].contextInfo = {
|
||||
...(message[key].contextInfo || {}),
|
||||
expiration: chat?.ephemeral || WA_DEFAULT_EPHEMERAL,
|
||||
ephemeralSettingTimestamp: chat?.eph_setting_ts
|
||||
}
|
||||
message = {
|
||||
ephemeralMessage: {
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
message = WAMessageProto.Message.fromObject (message)
|
||||
|
||||
const messageJSON = {
|
||||
|
||||
@@ -7,6 +7,7 @@ export const WS_URL = 'wss://web.whatsapp.com/ws'
|
||||
export const DEFAULT_ORIGIN = 'https://web.whatsapp.com'
|
||||
|
||||
export const KEEP_ALIVE_INTERVAL_MS = 20*1000
|
||||
export const WA_DEFAULT_EPHEMERAL = 7*24*60*60
|
||||
|
||||
// export the WAMessage Prototypes
|
||||
export { proto as WAMessageProto }
|
||||
@@ -224,6 +225,10 @@ export interface WAChat {
|
||||
spam: 'false' | 'true'
|
||||
modify_tag: string
|
||||
name?: string
|
||||
/** when ephemeral messages were toggled on */
|
||||
eph_setting_ts?: string
|
||||
/** how long each message lasts for */
|
||||
ephemeral?: string
|
||||
|
||||
// Baileys added properties
|
||||
messages: KeyedDB<WAMessage, string>
|
||||
@@ -367,6 +372,9 @@ export interface MessageOptions {
|
||||
forceNewMediaOptions?: boolean
|
||||
/** Wait for the message to be sent to the server (default true) */
|
||||
waitForAck?: boolean
|
||||
/** Should it send as a disappearing messages.
|
||||
* By default 'chat' -- which follows the setting of the chat */
|
||||
sendEphemeral?: 'chat' | boolean
|
||||
}
|
||||
export interface WABroadcastListInfo {
|
||||
status: number
|
||||
|
||||
Reference in New Issue
Block a user