Last active
March 25, 2026 18:02
-
-
Save weskerty/8c0c3f5801d2042869c79b57066c4ef9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const fs = require('fs').promises; | |
| const path = require('path'); | |
| const { promisify } = require('util'); | |
| const { exec: execCallback } = require('child_process'); | |
| const { bot } = require('../lib'); | |
| const exec = promisify(execCallback); | |
| const fmtTime = (s) => { | |
| if (!s || isNaN(s)) return "0"; | |
| return `${Math.floor(s/60)}:${Math.floor(s%60).toString().padStart(2,'0')}`; | |
| }; | |
| class MessageUtils { | |
| static getVideoDetails(q) { | |
| try { | |
| const m = q.message?.message || q; | |
| if (m?.videoMessage) return { isVideo: true, mimetype: m.videoMessage.mimetype || 'video/mp4', fileLength: m.videoMessage.fileLength ? parseInt(m.videoMessage.fileLength) : null }; | |
| if (m?.documentMessage) { const mt = m.documentMessage.mimetype || ''; return { isVideo: mt.startsWith('video/'), mimetype: m.documentMessage.mimetype, fileLength: m.documentMessage.fileLength ? parseInt(m.documentMessage.fileLength) : null }; } | |
| return { isVideo: false }; | |
| } catch { return { isVideo: false }; } | |
| } | |
| } | |
| const SEG = 89; | |
| bot( | |
| { pattern: 'split ?(.*)', fromMe: true, desc: 'Split video Status', type: 'whatsapp' }, | |
| async (message, match, ctx) => { | |
| const reply = async (text, err = false) => message.send(`${err ? '❌' : '✅'} ${text}`, { quoted: message.data }); | |
| try { | |
| const q = message.reply_message; | |
| if (!q) return reply('Cita un video', true); | |
| const vd = MessageUtils.getVideoDetails(q); | |
| if (!vd.isVideo) return reply('El archivo citado no es video', true); | |
| try { await exec('ffmpeg -version'); } catch { return reply('FFmpeg no instalado', true); } | |
| const sid = `split_${Date.now()}`; | |
| const tmpDir = `/tmp/${sid}`; | |
| await fs.mkdir(tmpDir, { recursive: true }); | |
| try { | |
| const buf = await q.downloadMediaMessage(); | |
| if (!buf) return reply('No se pudo descargar el video', true); | |
| const inPath = path.join(tmpDir, 'in.mp4'); | |
| await fs.writeFile(inPath, buf); | |
| const durRes = await exec(`ffprobe -v quiet -show_entries format=duration -of csv=p=0 "${inPath}"`); | |
| const duration = parseFloat(durRes.stdout.trim()); | |
| const outPattern = path.join(tmpDir, 'seg_%03d.mp4'); | |
| await exec([ | |
| 'ffmpeg', '-i', `"${inPath}"`, | |
| '-c', 'copy', | |
| '-map', '0', | |
| '-segment_time', SEG.toString(), | |
| '-f', 'segment', | |
| '-reset_timestamps', '1', | |
| '-avoid_negative_ts', 'make_zero', | |
| `"${outPattern}"` | |
| ].join(' ')); | |
| const files = (await fs.readdir(tmpDir)) | |
| .filter(f => f.startsWith('seg_') && f.endsWith('.mp4')) | |
| .sort() | |
| .map(f => path.join(tmpDir, f)); | |
| if (!files.length) return reply('No se generaron segmentos', true); | |
| for (let i = 0; i < files.length; i++) { | |
| const segBuf = await fs.readFile(files[i]); | |
| const t0 = i * SEG; | |
| const t1 = Math.min((i+1) * SEG, duration || (i+1)*SEG); | |
| await message.send(segBuf, { | |
| fileName: `parte_${String(i+1).padStart(2,'0')}_de_${files.length}.mp4`, | |
| mimetype: 'video/mp4', | |
| quoted: message.data, | |
| caption: `Parte ${i+1}/${files.length} | ${fmtTime(t0)} - ${fmtTime(t1)}` | |
| }, 'video'); | |
| if (i < files.length - 1) await new Promise(r => setTimeout(r, 1000)); | |
| } | |
| } finally { | |
| await fs.rm(tmpDir, { recursive: true, force: true }).catch(() => {}); | |
| } | |
| } catch (e) { | |
| await reply(`Error: ${e.message}`, true); | |
| } | |
| } | |
| ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment