Skip to content

Commit a4e7baa

Browse files
committed
feat: send ptv message
1 parent 0fdc47e commit a4e7baa

File tree

6 files changed

+107
-15
lines changed

6 files changed

+107
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* Add indexes to improve performance in Evolution
2121
* Add logical or permanent message deletion based on env config
2222
* Add support for fetching multiple instances by key
23+
* Update instance.controller.ts to filter by instanceName
2324

2425
# 2.1.2 (2024-10-06 10:09)
2526

src/api/controllers/sendMessage.controller.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
SendLocationDto,
88
SendMediaDto,
99
SendPollDto,
10+
SendPtvDto,
1011
SendReactionDto,
1112
SendStatusDto,
1213
SendStickerDto,
@@ -39,6 +40,13 @@ export class SendMessageController {
3940
throw new BadRequestException('Owned media must be a url or base64');
4041
}
4142

43+
public async sendPtv({ instanceName }: InstanceDto, data: SendPtvDto, file?: any) {
44+
if (file || isURL(data?.video) || isBase64(data?.video)) {
45+
return await this.waMonitor.waInstances[instanceName].ptvMessage(data, file);
46+
}
47+
throw new BadRequestException('Owned media must be a url or base64');
48+
}
49+
4250
public async sendSticker({ instanceName }: InstanceDto, data: SendStickerDto, file?: any) {
4351
if (file || isURL(data.sticker) || isBase64(data.sticker)) {
4452
return await this.waMonitor.waInstances[instanceName].mediaSticker(data, file);

src/api/dto/sendMessage.dto.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export class SendPollDto extends Metadata {
7070
messageSecret?: Uint8Array;
7171
}
7272

73-
export type MediaType = 'image' | 'document' | 'video' | 'audio';
73+
export type MediaType = 'image' | 'document' | 'video' | 'audio' | 'ptv';
7474

7575
export class SendMediaDto extends Metadata {
7676
mediatype: MediaType;
@@ -82,6 +82,10 @@ export class SendMediaDto extends Metadata {
8282
media: string;
8383
}
8484

85+
export class SendPtvDto extends Metadata {
86+
video: string;
87+
}
88+
8589
export class SendStickerDto extends Metadata {
8690
sticker: string;
8791
}

src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
SendLocationDto,
4343
SendMediaDto,
4444
SendPollDto,
45+
SendPtvDto,
4546
SendReactionDto,
4647
SendStatusDto,
4748
SendStickerDto,
@@ -309,7 +310,7 @@ export class BaileysStartupService extends ChannelStartupService {
309310
qrcodeTerminal.generate(qr, { small: true }, (qrcode) =>
310311
this.logger.log(
311312
`\n{ instance: ${this.instance.name} pairingCode: ${this.instance.qrcode.pairingCode}, qrcodeCount: ${this.instance.qrcode.count} }\n` +
312-
qrcode,
313+
qrcode,
313314
),
314315
);
315316

@@ -913,18 +914,18 @@ export class BaileysStartupService extends ChannelStartupService {
913914

914915
const messagesRepository = new Set(
915916
chatwootImport.getRepositoryMessagesCache(instance) ??
916-
(
917-
await this.prismaRepository.message.findMany({
918-
select: { key: true },
919-
where: { instanceId: this.instanceId },
920-
})
921-
).map((message) => {
922-
const key = message.key as {
923-
id: string;
924-
};
925-
926-
return key.id;
927-
}),
917+
(
918+
await this.prismaRepository.message.findMany({
919+
select: { key: true },
920+
where: { instanceId: this.instanceId },
921+
})
922+
).map((message) => {
923+
const key = message.key as {
924+
id: string;
925+
};
926+
927+
return key.id;
928+
}),
928929
);
929930

930931
if (chatwootImport.getRepositoryMessagesCache(instance) === null) {
@@ -2052,6 +2053,7 @@ export class BaileysStartupService extends ChannelStartupService {
20522053
messageSent?.message?.imageMessage ||
20532054
messageSent?.message?.videoMessage ||
20542055
messageSent?.message?.stickerMessage ||
2056+
messageSent?.message?.ptvMessage ||
20552057
messageSent?.message?.documentMessage ||
20562058
messageSent?.message?.documentWithCaptionMessage ||
20572059
messageSent?.message?.audioMessage;
@@ -2397,9 +2399,11 @@ export class BaileysStartupService extends ChannelStartupService {
23972399

23982400
private async prepareMediaMessage(mediaMessage: MediaMessage) {
23992401
try {
2402+
const type = mediaMessage.mediatype === 'ptv' ? 'video' : mediaMessage.mediatype;
2403+
24002404
const prepareMedia = await prepareWAMessageMedia(
24012405
{
2402-
[mediaMessage.mediatype]: isURL(mediaMessage.media)
2406+
[type]: isURL(mediaMessage.media)
24032407
? { url: mediaMessage.media }
24042408
: Buffer.from(mediaMessage.media, 'base64'),
24052409
} as any,
@@ -2453,6 +2457,10 @@ export class BaileysStartupService extends ChannelStartupService {
24532457
}
24542458
}
24552459

2460+
if (mediaMessage.mediatype === 'ptv') {
2461+
prepareMedia[mediaType] = prepareMedia[type + 'Message'];
2462+
}
2463+
24562464
prepareMedia[mediaType].caption = mediaMessage?.caption;
24572465
prepareMedia[mediaType].mimetype = mimetype;
24582466
prepareMedia[mediaType].fileName = mediaMessage.fileName;
@@ -2564,6 +2572,37 @@ export class BaileysStartupService extends ChannelStartupService {
25642572
return mediaSent;
25652573
}
25662574

2575+
public async ptvMessage(data: SendPtvDto, file?: any, isIntegration = false) {
2576+
const mediaData: SendMediaDto = {
2577+
number: data.number,
2578+
media: data.video,
2579+
mediatype: 'ptv',
2580+
delay: data?.delay,
2581+
quoted: data?.quoted,
2582+
mentionsEveryOne: data?.mentionsEveryOne,
2583+
mentioned: data?.mentioned,
2584+
};
2585+
2586+
if (file) mediaData.media = file.buffer.toString('base64');
2587+
2588+
const generate = await this.prepareMediaMessage(mediaData);
2589+
2590+
const mediaSent = await this.sendMessageWithTyping(
2591+
data.number,
2592+
{ ...generate.message },
2593+
{
2594+
delay: data?.delay,
2595+
presence: 'composing',
2596+
quoted: data?.quoted,
2597+
mentionsEveryOne: data?.mentionsEveryOne,
2598+
mentioned: data?.mentioned,
2599+
},
2600+
isIntegration,
2601+
);
2602+
2603+
return mediaSent;
2604+
}
2605+
25672606
public async processAudioMp4(audio: string) {
25682607
let inputStream: PassThrough;
25692608

src/api/routes/sendMessage.router.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
SendLocationDto,
88
SendMediaDto,
99
SendPollDto,
10+
SendPtvDto,
1011
SendReactionDto,
1112
SendStatusDto,
1213
SendStickerDto,
@@ -22,6 +23,7 @@ import {
2223
locationMessageSchema,
2324
mediaMessageSchema,
2425
pollMessageSchema,
26+
ptvMessageSchema,
2527
reactionMessageSchema,
2628
statusMessageSchema,
2729
stickerMessageSchema,
@@ -71,6 +73,18 @@ export class MessageRouter extends RouterBroker {
7173

7274
return res.status(HttpStatus.CREATED).json(response);
7375
})
76+
.post(this.routerPath('sendPtv'), ...guards, upload.single('file'), async (req, res) => {
77+
const bodyData = req.body;
78+
79+
const response = await this.dataValidate<SendPtvDto>({
80+
request: req,
81+
schema: ptvMessageSchema,
82+
ClassRef: SendPtvDto,
83+
execute: (instance) => sendMessageController.sendPtv(instance, bodyData, req.file as any),
84+
});
85+
86+
return res.status(HttpStatus.CREATED).json(response);
87+
})
7488
.post(this.routerPath('sendWhatsAppAudio'), ...guards, upload.single('file'), async (req, res) => {
7589
const bodyData = req.body;
7690

src/validate/message.schema.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,32 @@ export const mediaMessageSchema: JSONSchema7 = {
122122
required: ['number', 'mediatype'],
123123
};
124124

125+
export const ptvMessageSchema: JSONSchema7 = {
126+
$id: v4(),
127+
type: 'object',
128+
properties: {
129+
number: { ...numberDefinition },
130+
video: { type: 'string' },
131+
delay: {
132+
type: 'integer',
133+
description: 'Enter a value in milliseconds',
134+
},
135+
quoted: { ...quotedOptionsSchema },
136+
everyOne: { type: 'boolean', enum: [true, false] },
137+
mentioned: {
138+
type: 'array',
139+
minItems: 1,
140+
uniqueItems: true,
141+
items: {
142+
type: 'string',
143+
pattern: '^\\d+',
144+
description: '"mentioned" must be an array of numeric strings',
145+
},
146+
},
147+
},
148+
required: ['number'],
149+
};
150+
125151
export const audioMessageSchema: JSONSchema7 = {
126152
$id: v4(),
127153
type: 'object',

0 commit comments

Comments
 (0)