mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
Added link previews
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import WAConnection from '../WAConnection/WAConnection'
|
import WAConnection from '../WAConnection/WAConnection'
|
||||||
import { MessageStatus, MessageStatusUpdate, PresenceUpdate, Presence, ChatModification, WABroadcastListInfo, WAUrlInfo } from './Constants'
|
import { MessageStatusUpdate, PresenceUpdate, Presence, WABroadcastListInfo } from './Constants'
|
||||||
import {
|
import {
|
||||||
WAMessage,
|
WAMessage,
|
||||||
WANode,
|
WANode,
|
||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
WAFlag,
|
WAFlag,
|
||||||
MessageLogLevel,
|
MessageLogLevel,
|
||||||
} from '../WAConnection/Constants'
|
} from '../WAConnection/Constants'
|
||||||
import { proto } from '../../WAMessage/WAMessage'
|
|
||||||
|
|
||||||
export default class WhatsAppWebBase extends WAConnection {
|
export default class WhatsAppWebBase extends WAConnection {
|
||||||
/** Set the callback for message status updates (when a message is delivered, read etc.) */
|
/** Set the callback for message status updates (when a message is delivered, read etc.) */
|
||||||
@@ -186,13 +185,4 @@ export default class WhatsAppWebBase extends WAConnection {
|
|||||||
const json = ['action', {epoch: this.msgCount.toString(), type: 'set'}, nodes]
|
const json = ['action', {epoch: this.msgCount.toString(), type: 'set'}, nodes]
|
||||||
return this.queryExpecting200(json, [WAMetric.group, WAFlag.ignore]) as Promise<{status: number}>
|
return this.queryExpecting200(json, [WAMetric.group, WAFlag.ignore]) as Promise<{status: number}>
|
||||||
}
|
}
|
||||||
/** Query a string to check if it has a url, if it does, return required info */
|
|
||||||
async urlQuery (text: string) {
|
|
||||||
const query = ['query', {type: 'url', url: text, epoch: this.msgCount.toString()}, null]
|
|
||||||
const response = await this.queryExpecting200 (query, [26, WAFlag.ignore])
|
|
||||||
if (response[1]) {
|
|
||||||
response[1].jpegThumbnail = response[2]
|
|
||||||
}
|
|
||||||
return response[1] as WAUrlInfo
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,3 +136,4 @@ export interface WALocationMessage {
|
|||||||
}
|
}
|
||||||
export type WAContactMessage = proto.ContactMessage
|
export type WAContactMessage = proto.ContactMessage
|
||||||
export type WAMessageKey = proto.IMessageKey
|
export type WAMessageKey = proto.IMessageKey
|
||||||
|
export type WATextMessage = proto.ExtendedTextMessage
|
||||||
|
|||||||
@@ -12,9 +12,11 @@ import {
|
|||||||
WAMessageKey,
|
WAMessageKey,
|
||||||
ChatModification,
|
ChatModification,
|
||||||
MessageInfo,
|
MessageInfo,
|
||||||
|
WATextMessage,
|
||||||
|
WAUrlInfo,
|
||||||
} from './Constants'
|
} from './Constants'
|
||||||
import { generateMessageID, sha256, hmacSign, aesEncrypWithIV, randomBytes } from '../WAConnection/Utils'
|
import { generateMessageID, sha256, hmacSign, aesEncrypWithIV, randomBytes } from '../WAConnection/Utils'
|
||||||
import { WAMessageContent, WAMetric, WAFlag, WANode, WAMessage } from '../WAConnection/Constants'
|
import { WAMessageContent, WAMetric, WAFlag, WANode, WAMessage, WAMessageProto } from '../WAConnection/Constants'
|
||||||
import { validateJIDForSending, generateThumbnail, getMediaKeys } from './Utils'
|
import { validateJIDForSending, generateThumbnail, getMediaKeys } from './Utils'
|
||||||
import { proto } from '../../WAMessage/WAMessage'
|
import { proto } from '../../WAMessage/WAMessage'
|
||||||
|
|
||||||
@@ -100,6 +102,23 @@ export default class WhatsAppWebMessages extends WhatsAppWebGroups {
|
|||||||
const actual = await this.loadConversation (jid, 1, index)
|
const actual = await this.loadConversation (jid, 1, index)
|
||||||
return actual[0]
|
return actual[0]
|
||||||
}
|
}
|
||||||
|
/** Query a string to check if it has a url, if it does, return required extended text message */
|
||||||
|
async generateLinkPreview (text: string) {
|
||||||
|
const query = ['query', {type: 'url', url: text, epoch: this.msgCount.toString()}, null]
|
||||||
|
const response = await this.queryExpecting200 (query, [26, WAFlag.ignore])
|
||||||
|
|
||||||
|
if (response[1]) response[1].jpegThumbnail = response[2]
|
||||||
|
const data = response[1] as WAUrlInfo
|
||||||
|
|
||||||
|
const content = {text} as WATextMessage
|
||||||
|
content.canonicalUrl = data['canonical-url']
|
||||||
|
content.matchedText = data['matched-text']
|
||||||
|
content.jpegThumbnail = data.jpegThumbnail
|
||||||
|
content.description = data.description
|
||||||
|
content.title = data.title
|
||||||
|
content.previewType = 0
|
||||||
|
return content
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Search WhatsApp messages with a given text string
|
* Search WhatsApp messages with a given text string
|
||||||
* @param txt the search string
|
* @param txt the search string
|
||||||
@@ -170,21 +189,24 @@ export default class WhatsAppWebMessages extends WhatsAppWebGroups {
|
|||||||
}
|
}
|
||||||
async sendMessage(
|
async sendMessage(
|
||||||
id: string,
|
id: string,
|
||||||
message: string | WALocationMessage | WAContactMessage | Buffer,
|
message: string | WATextMessage | WALocationMessage | WAContactMessage | Buffer,
|
||||||
type: MessageType,
|
type: MessageType,
|
||||||
options: MessageOptions = {},
|
options: MessageOptions = {},
|
||||||
) {
|
) {
|
||||||
if (options.validateID === true || !('validateID' in options)) {
|
if (options.validateID === true || !('validateID' in options)) {
|
||||||
validateJIDForSending (id)
|
validateJIDForSending (id)
|
||||||
}
|
}
|
||||||
let m: any = {}
|
let m: WAMessageContent = {}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MessageType.text:
|
case MessageType.text:
|
||||||
case MessageType.extendedText:
|
case MessageType.extendedText:
|
||||||
if (typeof message !== 'string') {
|
if (typeof message === 'string') {
|
||||||
throw new Error('expected message to be a string')
|
m.extendedTextMessage = {text: message}
|
||||||
|
} else if ('text' in message) {
|
||||||
|
m.extendedTextMessage = message as WATextMessage
|
||||||
|
} else {
|
||||||
|
throw new Error ('message needs to be a string or object with property \'text\'')
|
||||||
}
|
}
|
||||||
m.extendedTextMessage = { text: message }
|
|
||||||
break
|
break
|
||||||
case MessageType.location:
|
case MessageType.location:
|
||||||
case MessageType.liveLocation:
|
case MessageType.liveLocation:
|
||||||
@@ -197,7 +219,7 @@ export default class WhatsAppWebMessages extends WhatsAppWebGroups {
|
|||||||
m = await this.prepareMediaMessage(message as Buffer, type, options)
|
m = await this.prepareMediaMessage(message as Buffer, type, options)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return this.sendGenericMessage(id, m as WAMessageContent, options)
|
return this.sendGenericMessage(id, m, options)
|
||||||
}
|
}
|
||||||
/** Prepare a media message for sending */
|
/** Prepare a media message for sending */
|
||||||
protected async prepareMediaMessage(buffer: Buffer, mediaType: MessageType, options: MessageOptions = {}) {
|
protected async prepareMediaMessage(buffer: Buffer, mediaType: MessageType, options: MessageOptions = {}) {
|
||||||
@@ -283,7 +305,7 @@ export default class WhatsAppWebMessages extends WhatsAppWebGroups {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
message[key].caption = options?.caption
|
message[key].caption = options?.caption
|
||||||
message[key].jpegThumbnail = options?.thumbnail
|
if (!message[key].jpegThumbnail) message[key].jpegThumbnail = options?.thumbnail
|
||||||
|
|
||||||
const messageJSON = {
|
const messageJSON = {
|
||||||
key: {
|
key: {
|
||||||
@@ -293,7 +315,8 @@ export default class WhatsAppWebMessages extends WhatsAppWebGroups {
|
|||||||
},
|
},
|
||||||
message: message,
|
message: message,
|
||||||
messageTimestamp: timestamp,
|
messageTimestamp: timestamp,
|
||||||
participant: id.includes('@g.us') ? this.userMetaData.id : null
|
participant: id.includes('@g.us') ? this.userMetaData.id : null,
|
||||||
|
status: WAMessageProto.proto.WebMessageInfo.WEB_MESSAGE_INFO_STATUS.PENDING
|
||||||
}
|
}
|
||||||
const json = ['action', {epoch: this.msgCount.toString(), type: 'relay'}, [['message', null, messageJSON]]]
|
const json = ['action', {epoch: this.msgCount.toString(), type: 'relay'}, [['message', null, messageJSON]]]
|
||||||
const response = await this.queryExpecting200(json, [WAMetric.message, WAFlag.ignore], null, messageJSON.key.id)
|
const response = await this.queryExpecting200(json, [WAMetric.message, WAFlag.ignore], null, messageJSON.key.id)
|
||||||
|
|||||||
@@ -33,6 +33,14 @@ WAClientTest('Messages', (client) => {
|
|||||||
const message = await sendAndRetreiveMessage(client, 'hello fren', MessageType.text)
|
const message = await sendAndRetreiveMessage(client, 'hello fren', MessageType.text)
|
||||||
assert.strictEqual(message.message.conversation, 'hello fren')
|
assert.strictEqual(message.message.conversation, 'hello fren')
|
||||||
})
|
})
|
||||||
|
it('should send a link preview', async () => {
|
||||||
|
const content = await client.generateLinkPreview ('hello this is from https://www.github.com/adiwajshing/Baileys')
|
||||||
|
const message = await sendAndRetreiveMessage(client, content, MessageType.text)
|
||||||
|
const received = message.message.extendedTextMessage
|
||||||
|
assert.strictEqual(received.text, content.text)
|
||||||
|
|
||||||
|
fs.writeFileSync ('Media/received-thumb.jpeg', content.jpegThumbnail)
|
||||||
|
})
|
||||||
it('should quote a message', async () => {
|
it('should quote a message', async () => {
|
||||||
const messages = await client.loadConversation(testJid, 2)
|
const messages = await client.loadConversation(testJid, 2)
|
||||||
const message = await sendAndRetreiveMessage(client, 'hello fren 2', MessageType.extendedText, {
|
const message = await sendAndRetreiveMessage(client, 'hello fren 2', MessageType.extendedText, {
|
||||||
@@ -109,12 +117,6 @@ WAClientTest('Misc', (client) => {
|
|||||||
it('should return the stories', async () => {
|
it('should return the stories', async () => {
|
||||||
await client.getStories()
|
await client.getStories()
|
||||||
})
|
})
|
||||||
it('should return a preview', async () => {
|
|
||||||
const info = await client.urlQuery ('fren have you seen https://www.github.com/adiwajshing/Baileys')
|
|
||||||
assert.equal (info["matched-text"], 'https://www.github.com/adiwajshing/Baileys')
|
|
||||||
|
|
||||||
await assert.rejects (() => client.urlQuery('oh hello there'))
|
|
||||||
})
|
|
||||||
it('should return the profile picture', async () => {
|
it('should return the profile picture', async () => {
|
||||||
const response = await client.getProfilePicture(testJid)
|
const response = await client.getProfilePicture(testJid)
|
||||||
assert.ok(response)
|
assert.ok(response)
|
||||||
|
|||||||
@@ -60,8 +60,9 @@ const extractVideoThumb = async (
|
|||||||
})
|
})
|
||||||
}) as Promise<void>
|
}) as Promise<void>
|
||||||
|
|
||||||
/** generates a thumbnail for a given media, if required */
|
export const compressImage = async (buffer: Buffer) => sharp(buffer).resize(48, 48).jpeg().toBuffer()
|
||||||
|
|
||||||
|
/** generates a thumbnail for a given media, if required */
|
||||||
export async function generateThumbnail(buffer: Buffer, mediaType: MessageType, info: MessageOptions) {
|
export async function generateThumbnail(buffer: Buffer, mediaType: MessageType, info: MessageOptions) {
|
||||||
if (info.thumbnail === null || info.thumbnail) {
|
if (info.thumbnail === null || info.thumbnail) {
|
||||||
// don't do anything if the thumbnail is already provided, or is null
|
// don't do anything if the thumbnail is already provided, or is null
|
||||||
@@ -69,7 +70,7 @@ export async function generateThumbnail(buffer: Buffer, mediaType: MessageType,
|
|||||||
throw new Error('audio messages cannot have thumbnails')
|
throw new Error('audio messages cannot have thumbnails')
|
||||||
}
|
}
|
||||||
} else if (mediaType === MessageType.image || mediaType === MessageType.sticker) {
|
} else if (mediaType === MessageType.image || mediaType === MessageType.sticker) {
|
||||||
const buff = await sharp(buffer).resize(48, 48).jpeg().toBuffer()
|
const buff = await compressImage (buffer)
|
||||||
info.thumbnail = buff.toString('base64')
|
info.thumbnail = buff.toString('base64')
|
||||||
} else if (mediaType === MessageType.video) {
|
} else if (mediaType === MessageType.video) {
|
||||||
const filename = './' + randomBytes(5).toString('hex') + '.mp4'
|
const filename = './' + randomBytes(5).toString('hex') + '.mp4'
|
||||||
|
|||||||
Reference in New Issue
Block a user