diff --git a/.DS_Store b/.DS_Store index be0f4a7..01a419b 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/README.md b/README.md index a024c71..a64667c 100644 --- a/README.md +++ b/README.md @@ -62,14 +62,15 @@ ``` - Send text messages & quote another message using ``` javascript - client.sendTextMessage(id, "oh hello there", quotedMessage) + const options = {quoted: quotedMessage} + client.sendTextMessage(id, "oh hello there", options) ``` ``` quotedMessage ``` is a message object - Send a media (image, video, sticker, pdf) message using ``` javascript const buffer = fs.readFileSync("example/ma_gif.mp4") // load some gif - const info = {gif: true, caption: "hello!"} // some metadata & caption - client.sendMediaMessage(id, buffer, WhatsAppWeb.MessageType.video, info) + const options = {gif: true, caption: "hello!"} // some metadata & caption + client.sendMediaMessage(id, buffer, WhatsAppWeb.MessageType.video, options) ``` - The thumbnail can be generated automatically for images & stickers. Though, to automatically generate thumbnails for videos, you need to have ``` ffmpeg ``` installed on your system - ```mediaBuffer``` is just a Buffer containing the contents of the media you want to send @@ -82,23 +83,25 @@ WhatsAppWeb.MessageType.sticker // a sticker message ] ``` - - ```info``` is a JSON object, providing some information about the media. It can have the following __optional__ values: - ``` javascript - info = { - caption: "hello there!", // the caption to send with the media (cannot be sent with stickers though) - thumbnail: null, /* has to be a base 64 encoded JPEG if you want to send a custom thumb, - or set to null if you don't want to send a thumbnail. - Do not enter this field if you want to automatically generate a thumb - */ - mimetype: "application/pdf", /* specify the type of media (optional for all media types except documents), - for pdf files => set to "application/pdf", - for txt files => set to "application/txt" - etc. - */ - gif: true // only applicable to video messages, if the video should be treated as a GIF - } - ``` - Tested formats: png, jpeg, webp (sticker), mp4, ogg + ```options``` is a JSON object, providing some information about the message. It can have the following __optional__ values: + ``` javascript + info = { + caption: "hello there!", // (for media messages) the caption to send with the media (cannot be sent with stickers though) + thumbnail: null, /* (for media messages) has to be a base 64 encoded JPEG if you want to send a custom thumb, + or set to null if you don't want to send a thumbnail. + Do not enter this field if you want to automatically generate a thumb + */ + mimetype: "application/pdf", /* (for media messages) specify the type of media (optional for all media types except documents), + for pdf files => set to "application/pdf", + for txt files => set to "application/txt" + etc. + */ + gif: true, // (for video messages) if the video should be treated as a GIF + quoted: quotedMessage, // the message you want to quote (can used with sending all kinds of messages now) + timestamp: Date() // optional, if you want to manually set the timestamp of the message + } + ``` ``` id ``` is the WhatsApp id of the person or group you're sending the message to. It must be in the format ```[country code][phone number]@s.whatsapp.net```, for example ```+19999999999@s.whatsapp.net``` for people. For groups, it must be in the format ``` 123456789-123345@g.us ```. * __Sending Read Receipts__ diff --git a/WhatsAppWeb.Send.js b/WhatsAppWeb.Send.js index 43431ef..a196b2c 100644 --- a/WhatsAppWeb.Send.js +++ b/WhatsAppWeb.Send.js @@ -36,46 +36,38 @@ module.exports = { * Send a text message * @param {string} id the JID of the person/group you're sending the message to * @param {string} txt the actual text of the message - * @param {object} [quoted] the message you may wanna quote along with this message - * @param {Date} [timestamp] optionally set the timestamp of the message in Unix time MS + * @param {object} [options] some additional options + * @param {object} [options.quoted] the message you may wanna quote along with this message + * @param {Date} [options.timestamp] optionally set the timestamp of the message in Unix time MS * @return {Promise<[object, object]>} */ - sendTextMessage: function (id, txt, quoted, timestamp) { + sendTextMessage: function (id, txt, options) { if (typeof txt !== "string") { return Promise.reject("expected text to be a string") } let message - if (quoted) { - message = { - extendedTextMessage: { - text: txt, - contextInfo: { - participant: quoted.key.remoteJid, - stanzaId: quoted.key.id, - quotedMessage: quoted.message - } - } - } + if (options.quoted) { + message = {extendedTextMessage: { text: txt }} } else { message = {conversation: txt} } - - return this.sendMessage(id, message, timestamp) + return this.sendMessage(id, message, options) }, /** * Send a media message * @param {string} id the JID of the person/group you're sending the message to * @param {Buffer} buffer the buffer of the actual media you're sending * @param {string} mediaType the type of media, can be one of [imageMessage, documentMessage, stickerMessage, videoMessage] - * @param {Object} [info] object to hold some metadata or caption about the media - * @param {string} [info.caption] caption to go along with the media - * @param {string} [info.thumbnail] base64 encoded thumbnail for the media - * @param {string} [info.mimetype] specify the Mimetype of the media (required for document messages) - * @param {boolean} [info.gif] whether the media is a gif or not, only valid for video messages - * @param {Date} [timestamp] optionally set the timestamp of the message in Unix time MS + * @param {Object} [options] additional information about the message + * @param {string} [options.caption] caption to go along with the media + * @param {string} [options.thumbnail] base64 encoded thumbnail for the media + * @param {string} [options.mimetype] specify the Mimetype of the media (required for document messages) + * @param {boolean} [options.gif] whether the media is a gif or not, only valid for video messages + * @param {object} [options.quoted] the message you may wanna quote along with this message + * @param {Date} [options.timestamp] optionally set the timestamp of the message in Unix time MS * @return {Promise<[object, object]>} */ - sendMediaMessage: function (id, buffer, mediaType, info, timestamp) { + sendMediaMessage: function (id, buffer, mediaType, options) { // path to upload the media const mediaPathMap = { imageMessage: "/mms/image", @@ -92,20 +84,20 @@ module.exports = { audioMessage: "audio/ogg; codecs=opus", stickerMessage: "image/webp" } - if (!info) { - info = {} + if (!options) { + options = {} } if (mediaType === "conversation" || mediaType === "extendedTextMessage") { return Promise.reject("use sendTextMessage() to send text messages") } - if (mediaType === "documentMessage" && !info.mimetype) { + if (mediaType === "documentMessage" && !options.mimetype) { return Promise.reject("mimetype required to send a document") } - if (mediaType === "stickerMessage" && info.caption) { + if (mediaType === "stickerMessage" && options.caption) { return Promise.reject("cannot send a caption with a sticker") } - if (!info.mimetype) { - info.mimetype = defaultMimetypeMap[mediaType] + if (!options.mimetype) { + options.mimetype = defaultMimetypeMap[mediaType] } // generate a media key @@ -118,7 +110,7 @@ module.exports = { // url safe Base64 encode the SHA256 hash of the body const fileEncSha256B64 = Utils.sha256(body).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/\=+$/, '') - return Utils.generateThumbnail(buffer, mediaType, info) + return Utils.generateThumbnail(buffer, mediaType, options) .then (() => this.query(["query", "mediaConn"])) // send a query JSON to obtain the url & auth token to upload our media .then (([json,_]) => { json = json.media_conn @@ -141,19 +133,19 @@ module.exports = { .then (url => { let message = {} message[mediaType] = { - caption: info.caption, + caption: options.caption, url: url, mediaKey: mediaKey.toString('base64'), - mimetype: info.mimetype, + mimetype: options.mimetype, fileEncSha256: fileEncSha256B64, fileSha256: fileSha256.toString('base64'), fileLength: buffer.length, - jpegThumbnail: info.thumbnail + jpegThumbnail: options.thumbnail } - if (mediaType === "videoMessage" && info.gif) { - message[mediaType].gifPlayback = info.gif + if (mediaType === "videoMessage" && options.gif) { + message[mediaType].gifPlayback = options.gif } - return this.sendMessage(id, message, timestamp) + return this.sendMessage(id, message, options) }) }, /** @@ -161,14 +153,33 @@ module.exports = { * @private * @param {string} id who to send the message to * @param {object} message like, the message - * @param {Date} [timestamp] timestamp for the message + * @param {object} [options] some additional options + * @param {object} [options.quoted] the message you may wanna quote along with this message + * @param {Date} [options.timestamp] timestamp for the message * @return {Promise<[object, object]>} array of the recieved JSON & the query JSON */ - sendMessage: function (id, message, timestamp) { - if (!timestamp) { // if no timestamp was provided, - timestamp = new Date() // set timestamp to now + sendMessage: function (id, message, options) { + if (!options.timestamp) { // if no timestamp was provided, + options.timestamp = new Date() // set timestamp to now } - timestamp = timestamp.getTime()/1000 + const timestamp = options.timestamp.getTime()/1000 + const quoted = options.quoted + if (quoted) { + const key = Object.keys(message)[0] + const participant = quoted.key.participant || quoted.key.remoteJid + message[key].contextInfo = { + participant: participant, + stanzaId: quoted.key.id, + quotedMessage: quoted.message + } + // if a participant is quoted, then it must be a group + // hence, remoteJid of group must also be entered + if (quoted.key.participant) { + message[key].contextInfo.remoteJid = quoted.key.remoteJid + } + } + console.log(JSON.stringify(quoted)) + console.log(JSON.stringify(message)) let messageJSON = { key: { @@ -180,13 +191,15 @@ module.exports = { messageTimestamp: timestamp, status: "ERROR" } + if (id.includes ("@g.us")) { messageJSON.participant = this.userMetaData.id } const json = [ "action", {epoch: this.msgCount.toString(), type: "relay"}, - [ ["message", null, messageJSON] ]] + [ ["message", null, messageJSON] ] + ] return this.query(json, [16, 128], null, messageJSON.key.id) }, /** diff --git a/WhatsAppWeb.Session.js b/WhatsAppWeb.Session.js index 02de394..720e83b 100644 --- a/WhatsAppWeb.Session.js +++ b/WhatsAppWeb.Session.js @@ -124,12 +124,14 @@ module.exports = { // de-register the callbacks, so that they don't get called again this.deregisterCallback (["action", "add:last"]) this.deregisterCallback (["action", "add:before"]) + this.deregisterCallback (["action", "add:unread"]) resolve () } } // wait for actual messages to load, "last" is the most recent message, "before" contains prior messages this.registerCallback (["action", "add:last"], chatUpdate) this.registerCallback (["action", "add:before"], chatUpdate) + this.registerCallback (["action", "add:unread"], chatUpdate) }) const waitForChats = this.registerCallbackOneTime (["response", "type:chat"]).then (json => { chats = json[2] // chats data (log json to see what it looks like) diff --git a/example/.DS_Store b/example/.DS_Store index 87af765..f9d4071 100644 Binary files a/example/.DS_Store and b/example/.DS_Store differ diff --git a/example/example.js b/example/example.js index 7730b93..d3a9905 100644 --- a/example/example.js +++ b/example/example.js @@ -59,15 +59,14 @@ client.connect (authInfo, 30*1000) // connect or timeout in 30 seconds .then (() => client.updatePresence(m.key.remoteJid, WhatsAppWeb.Presence.available)) // tell them we're available .then (() => client.updatePresence(m.key.remoteJid, WhatsAppWeb.Presence.composing)) // tell them we're composing .then (() => { // send the message - if (Math.random() > 0.5) { // choose at random - return client.sendTextMessage(m.key.remoteJid, "hello!", m) // send a "hello!" & quote the message recieved + let options = {quoted: m} + if (Math.random() > 0.7) { // choose at random + return client.sendTextMessage(m.key.remoteJid, "hello!", options) // send a "hello!" & quote the message recieved } else { - const buffer = fs.readFileSync("./ma_gif.mp4") // load the gif - const info = { - gif: true, // the video is a gif - caption: "hello!" // the caption - } - return client.sendMediaMessage (m.key.remoteJid, buffer, WhatsAppWeb.MessageType.video, info) // send this gif! + const buffer = fs.readFileSync("example/ma_gif.mp4") // load the gif + options.gif = true // the video is a gif + options.caption = "hello!" // the caption + return client.sendMediaMessage (m.key.remoteJid, buffer, WhatsAppWeb.MessageType.video, options) // send this gif! } }) .then (([m, q]) => { // check if it went successfully diff --git a/example/meme.jpeg b/example/meme.jpeg new file mode 100644 index 0000000..e09535b Binary files /dev/null and b/example/meme.jpeg differ