mirror of
https://github.com/EvolutionAPI/evolution-api.git
synced 2025-07-14 09:51:24 -06:00
feat: route to send Sticker
This commit is contained in:
parent
84f6394f1f
commit
a08bbab9dc
@ -14,6 +14,7 @@
|
|||||||
* Now the api key can be exposed in fetch instances if the EXPOSE_IN_FETCH_INSTANCES variable is set to true
|
* Now the api key can be exposed in fetch instances if the EXPOSE_IN_FETCH_INSTANCES variable is set to true
|
||||||
* Added option to generate qrcode as soon as the instance is created
|
* Added option to generate qrcode as soon as the instance is created
|
||||||
* The created instance token can now also be optionally defined manually in the creation endpoint
|
* The created instance token can now also be optionally defined manually in the creation endpoint
|
||||||
|
* Route to send Sticker
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
"qrcode": "^1.5.1",
|
"qrcode": "^1.5.1",
|
||||||
"qrcode-terminal": "^0.12.0",
|
"qrcode-terminal": "^0.12.0",
|
||||||
"redis": "^4.6.5",
|
"redis": "^4.6.5",
|
||||||
|
"sharp": "^0.30.7",
|
||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -210,6 +210,24 @@ export const mediaMessageSchema: JSONSchema7 = {
|
|||||||
required: ['mediaMessage', 'number'],
|
required: ['mediaMessage', 'number'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const stickerMessageSchema: JSONSchema7 = {
|
||||||
|
$id: v4(),
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
number: { ...numberDefinition },
|
||||||
|
options: { ...optionsSchema },
|
||||||
|
stickerMessage: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
image: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['image'],
|
||||||
|
...isNotEmpty('image'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['stickerMessage', 'number'],
|
||||||
|
};
|
||||||
|
|
||||||
export const audioMessageSchema: JSONSchema7 = {
|
export const audioMessageSchema: JSONSchema7 = {
|
||||||
$id: v4(),
|
$id: v4(),
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
SendMediaDto,
|
SendMediaDto,
|
||||||
SendPollDto,
|
SendPollDto,
|
||||||
SendReactionDto,
|
SendReactionDto,
|
||||||
|
SendStickerDto,
|
||||||
SendTextDto,
|
SendTextDto,
|
||||||
} from '../dto/sendMessage.dto';
|
} from '../dto/sendMessage.dto';
|
||||||
import { WAMonitoringService } from '../services/monitor.service';
|
import { WAMonitoringService } from '../services/monitor.service';
|
||||||
@ -32,6 +33,13 @@ export class SendMessageController {
|
|||||||
throw new BadRequestException('Owned media must be a url or base64');
|
throw new BadRequestException('Owned media must be a url or base64');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async sendSticker({ instanceName }: InstanceDto, data: SendStickerDto) {
|
||||||
|
if (isURL(data.stickerMessage.image) || isBase64(data.stickerMessage.image)) {
|
||||||
|
return await this.waMonitor.waInstances[instanceName].mediaSticker(data);
|
||||||
|
}
|
||||||
|
throw new BadRequestException('Owned media must be a url or base64');
|
||||||
|
}
|
||||||
|
|
||||||
public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto) {
|
public async sendWhatsAppAudio({ instanceName }: InstanceDto, data: SendAudioDto) {
|
||||||
if (isURL(data.audioMessage.audio) || isBase64(data.audioMessage.audio)) {
|
if (isURL(data.audioMessage.audio) || isBase64(data.audioMessage.audio)) {
|
||||||
return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data);
|
return await this.waMonitor.waInstances[instanceName].audioWhatsapp(data);
|
||||||
|
@ -62,6 +62,12 @@ export class MediaMessage {
|
|||||||
export class SendMediaDto extends Metadata {
|
export class SendMediaDto extends Metadata {
|
||||||
mediaMessage: MediaMessage;
|
mediaMessage: MediaMessage;
|
||||||
}
|
}
|
||||||
|
class Sticker {
|
||||||
|
image: string;
|
||||||
|
}
|
||||||
|
export class SendStickerDto extends Metadata {
|
||||||
|
stickerMessage: Sticker;
|
||||||
|
}
|
||||||
|
|
||||||
class Audio {
|
class Audio {
|
||||||
audio: string;
|
audio: string;
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
mediaMessageSchema,
|
mediaMessageSchema,
|
||||||
pollMessageSchema,
|
pollMessageSchema,
|
||||||
reactionMessageSchema,
|
reactionMessageSchema,
|
||||||
|
stickerMessageSchema,
|
||||||
textMessageSchema,
|
textMessageSchema,
|
||||||
} from '../../validate/validate.schema';
|
} from '../../validate/validate.schema';
|
||||||
import {
|
import {
|
||||||
@ -21,6 +22,7 @@ import {
|
|||||||
SendMediaDto,
|
SendMediaDto,
|
||||||
SendPollDto,
|
SendPollDto,
|
||||||
SendReactionDto,
|
SendReactionDto,
|
||||||
|
SendStickerDto,
|
||||||
SendTextDto,
|
SendTextDto,
|
||||||
} from '../dto/sendMessage.dto';
|
} from '../dto/sendMessage.dto';
|
||||||
import { sendMessageController } from '../whatsapp.module';
|
import { sendMessageController } from '../whatsapp.module';
|
||||||
@ -131,6 +133,16 @@ export class MessageRouter extends RouterBroker {
|
|||||||
sendMessageController.sendLinkPreview(instance, data),
|
sendMessageController.sendLinkPreview(instance, data),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return res.status(HttpStatus.CREATED).json(response);
|
||||||
|
})
|
||||||
|
.post(this.routerPath('sendSticker'), ...guards, async (req, res) => {
|
||||||
|
const response = await this.dataValidate<SendStickerDto>({
|
||||||
|
request: req,
|
||||||
|
schema: stickerMessageSchema,
|
||||||
|
ClassRef: SendStickerDto,
|
||||||
|
execute: (instance, data) => sendMessageController.sendSticker(instance, data),
|
||||||
|
});
|
||||||
|
|
||||||
return res.status(HttpStatus.CREATED).json(response);
|
return res.status(HttpStatus.CREATED).json(response);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,7 @@ import {
|
|||||||
SendTextDto,
|
SendTextDto,
|
||||||
SendPollDto,
|
SendPollDto,
|
||||||
SendLinkPreviewDto,
|
SendLinkPreviewDto,
|
||||||
|
SendStickerDto,
|
||||||
} from '../dto/sendMessage.dto';
|
} from '../dto/sendMessage.dto';
|
||||||
import { arrayUnique, isBase64, isURL } from 'class-validator';
|
import { arrayUnique, isBase64, isURL } from 'class-validator';
|
||||||
import {
|
import {
|
||||||
@ -118,6 +119,8 @@ import { WebhookRaw } from '../models/webhook.model';
|
|||||||
import { dbserver } from '../../db/db.connect';
|
import { dbserver } from '../../db/db.connect';
|
||||||
import NodeCache from 'node-cache';
|
import NodeCache from 'node-cache';
|
||||||
import { useMultiFileAuthStateRedisDb } from '../../utils/use-multi-file-auth-state-redis-db';
|
import { useMultiFileAuthStateRedisDb } from '../../utils/use-multi-file-auth-state-redis-db';
|
||||||
|
import { promisify } from 'util';
|
||||||
|
import sharp from 'sharp';
|
||||||
|
|
||||||
export class WAStartupService {
|
export class WAStartupService {
|
||||||
constructor(
|
constructor(
|
||||||
@ -783,7 +786,6 @@ export class WAStartupService {
|
|||||||
},
|
},
|
||||||
|
|
||||||
'messages.update': async (args: WAMessageUpdate[], database: Database) => {
|
'messages.update': async (args: WAMessageUpdate[], database: Database) => {
|
||||||
console.log('messages.update args: ', args);
|
|
||||||
const status: Record<number, wa.StatusMessage> = {
|
const status: Record<number, wa.StatusMessage> = {
|
||||||
0: 'ERROR',
|
0: 'ERROR',
|
||||||
1: 'PENDING',
|
1: 'PENDING',
|
||||||
@ -1050,7 +1052,12 @@ export class WAStartupService {
|
|||||||
quoted,
|
quoted,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!message['audio'] && !message['poll'] && !message['linkPreview']) {
|
if (
|
||||||
|
!message['audio'] &&
|
||||||
|
!message['poll'] &&
|
||||||
|
!message['linkPreview'] &&
|
||||||
|
!message['sticker']
|
||||||
|
) {
|
||||||
if (!message['audio']) {
|
if (!message['audio']) {
|
||||||
return await this.client.sendMessage(
|
return await this.client.sendMessage(
|
||||||
sender,
|
sender,
|
||||||
@ -1195,6 +1202,41 @@ export class WAStartupService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async convertToWebP(image: string) {
|
||||||
|
try {
|
||||||
|
let imagePath: string;
|
||||||
|
const outputPath = `${join(process.cwd(), 'temp', 'sticker.webp')}`;
|
||||||
|
|
||||||
|
if (isBase64(image)) {
|
||||||
|
const base64Data = image.replace(/^data:image\/(jpeg|png|gif);base64,/, '');
|
||||||
|
const imageBuffer = Buffer.from(base64Data, 'base64');
|
||||||
|
imagePath = `${join(process.cwd(), 'temp', 'temp-sticker.png')}`;
|
||||||
|
await sharp(imageBuffer).toFile(imagePath);
|
||||||
|
} else {
|
||||||
|
const response = await axios.get(image, { responseType: 'arraybuffer' });
|
||||||
|
const imageBuffer = Buffer.from(response.data, 'binary');
|
||||||
|
imagePath = `${join(process.cwd(), 'temp', 'temp-sticker.png')}`;
|
||||||
|
await sharp(imageBuffer).toFile(imagePath);
|
||||||
|
}
|
||||||
|
await sharp(imagePath).webp().toFile(outputPath);
|
||||||
|
|
||||||
|
return outputPath;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao converter a imagem para WebP:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async mediaSticker(data: SendStickerDto) {
|
||||||
|
const convert = await this.convertToWebP(data.stickerMessage.image);
|
||||||
|
return await this.sendMessageWithTyping(
|
||||||
|
data.number,
|
||||||
|
{
|
||||||
|
sticker: { url: convert },
|
||||||
|
},
|
||||||
|
data?.options,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public async mediaMessage(data: SendMediaDto) {
|
public async mediaMessage(data: SendMediaDto) {
|
||||||
const generate = await this.prepareMediaMessage(data.mediaMessage);
|
const generate = await this.prepareMediaMessage(data.mediaMessage);
|
||||||
|
|
||||||
|
BIN
temp/sticker.webp
Normal file
BIN
temp/sticker.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
BIN
temp/temp-sticker.png
Normal file
BIN
temp/temp-sticker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.4 KiB |
Loading…
Reference in New Issue
Block a user