Skip to content

Commit fbccf2e

Browse files
committed
feat: send pix button
1 parent 23640a7 commit fbccf2e

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
"jsonschema": "^1.4.1",
7474
"link-preview-js": "^3.0.4",
7575
"long": "^5.2.3",
76+
"mediainfo.js": "^0.3.2",
7677
"mime": "^3.0.0",
7778
"minio": "^8.0.1",
7879
"multer": "^1.4.5-lts.1",

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

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,70 @@ import qrcodeTerminal from 'qrcode-terminal';
141141
import sharp from 'sharp';
142142
import { PassThrough } from 'stream';
143143
import { v4 } from 'uuid';
144+
import { Readable } from 'stream';
144145

145146
const groupMetadataCache = new CacheService(new CacheEngine(configService, 'groups').getEngine());
146147

148+
// Adicione a função getVideoDuration no início do arquivo
149+
async function getVideoDuration(input: Buffer | string | Readable): Promise<number> {
150+
const MediaInfoFactory = (await import('mediainfo.js')).default;
151+
const mediainfo = await MediaInfoFactory({ format: 'JSON' });
152+
153+
let fileSize: number;
154+
let readChunk: (size: number, offset: number) => Promise<Buffer>;
155+
156+
if (Buffer.isBuffer(input)) {
157+
fileSize = input.length;
158+
readChunk = async (size: number, offset: number): Promise<Buffer> => {
159+
return input.slice(offset, offset + size);
160+
};
161+
} else if (typeof input === 'string') {
162+
const fs = await import('fs');
163+
const stat = await fs.promises.stat(input);
164+
fileSize = stat.size;
165+
const fd = await fs.promises.open(input, 'r');
166+
167+
readChunk = async (size: number, offset: number): Promise<Buffer> => {
168+
const buffer = Buffer.alloc(size);
169+
await fd.read(buffer, 0, size, offset);
170+
return buffer;
171+
};
172+
173+
try {
174+
const result = await mediainfo.analyzeData(() => fileSize, readChunk);
175+
const jsonResult = JSON.parse(result);
176+
177+
const generalTrack = jsonResult.media.track.find((t: any) => t['@type'] === 'General');
178+
const duration = generalTrack.Duration;
179+
180+
return Math.round(parseFloat(duration));
181+
} finally {
182+
await fd.close();
183+
}
184+
} else if (input instanceof Readable) {
185+
const chunks: Buffer[] = [];
186+
for await (const chunk of input) {
187+
chunks.push(chunk);
188+
}
189+
const data = Buffer.concat(chunks);
190+
fileSize = data.length;
191+
192+
readChunk = async (size: number, offset: number): Promise<Buffer> => {
193+
return data.slice(offset, offset + size);
194+
};
195+
} else {
196+
throw new Error('Tipo de entrada não suportado');
197+
}
198+
199+
const result = await mediainfo.analyzeData(() => fileSize, readChunk);
200+
const jsonResult = JSON.parse(result);
201+
202+
const generalTrack = jsonResult.media.track.find((t: any) => t['@type'] === 'General');
203+
const duration = generalTrack.Duration;
204+
205+
return Math.round(parseFloat(duration));
206+
}
207+
147208
export class BaileysStartupService extends ChannelStartupService {
148209
constructor(
149210
public readonly configService: ConfigService,
@@ -1101,6 +1162,7 @@ export class BaileysStartupService extends ChannelStartupService {
11011162
received?.message?.stickerMessage ||
11021163
received?.message?.documentMessage ||
11031164
received?.message?.documentWithCaptionMessage ||
1165+
received?.message?.ptvMessage ||
11041166
received?.message?.audioMessage;
11051167

11061168
if (this.localSettings.readMessages && received.key.id !== 'status@broadcast') {
@@ -2097,6 +2159,7 @@ export class BaileysStartupService extends ChannelStartupService {
20972159
messageSent?.message?.ptvMessage ||
20982160
messageSent?.message?.documentMessage ||
20992161
messageSent?.message?.documentWithCaptionMessage ||
2162+
messageSent?.message?.ptvMessage ||
21002163
messageSent?.message?.audioMessage;
21012164

21022165
if (this.configService.get<Chatwoot>('CHATWOOT').ENABLED && this.localChatwoot?.enabled && !isIntegration) {
@@ -2500,6 +2563,37 @@ export class BaileysStartupService extends ChannelStartupService {
25002563

25012564
if (mediaMessage.mediatype === 'ptv') {
25022565
prepareMedia[mediaType] = prepareMedia[type + 'Message'];
2566+
mimetype = 'video/mp4';
2567+
2568+
if (!prepareMedia[mediaType]) {
2569+
throw new Error('Failed to prepare video message');
2570+
}
2571+
2572+
try {
2573+
let mediaInput;
2574+
if (isURL(mediaMessage.media)) {
2575+
mediaInput = mediaMessage.media;
2576+
} else {
2577+
const mediaBuffer = Buffer.from(mediaMessage.media, 'base64');
2578+
if (!mediaBuffer || mediaBuffer.length === 0) {
2579+
throw new Error('Invalid media buffer');
2580+
}
2581+
mediaInput = mediaBuffer;
2582+
}
2583+
2584+
const duration = await getVideoDuration(mediaInput);
2585+
if (!duration || duration <= 0) {
2586+
throw new Error('Invalid media duration');
2587+
}
2588+
2589+
this.logger.verbose(`Video duration: ${duration} seconds`);
2590+
prepareMedia[mediaType].seconds = duration;
2591+
2592+
} catch (error) {
2593+
this.logger.error('Error getting video duration:');
2594+
this.logger.error(error);
2595+
throw new Error(`Failed to get video duration: ${error.message}`);
2596+
}
25032597
}
25042598

25052599
prepareMedia[mediaType].caption = mediaMessage?.caption;

src/api/types/wa.types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ export declare namespace wa {
131131
export type StatusMessage = 'ERROR' | 'PENDING' | 'SERVER_ACK' | 'DELIVERY_ACK' | 'READ' | 'DELETED' | 'PLAYED';
132132
}
133133

134-
export const TypeMediaMessage = ['imageMessage', 'documentMessage', 'audioMessage', 'videoMessage', 'stickerMessage'];
134+
export const TypeMediaMessage = ['imageMessage', 'documentMessage', 'audioMessage', 'videoMessage', 'stickerMessage', 'ptvMessage'];
135135

136136
export const MessageSubtype = [
137137
'ephemeralMessage',

0 commit comments

Comments
 (0)