@@ -141,9 +141,70 @@ import qrcodeTerminal from 'qrcode-terminal';
141141import sharp from 'sharp' ;
142142import { PassThrough } from 'stream' ;
143143import { v4 } from 'uuid' ;
144+ import { Readable } from 'stream' ;
144145
145146const 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+
147208export 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 ;
0 commit comments