diff --git a/plugins/_cmdWithMedia.js b/plugins/_cmdWithMedia.js index b29d09c059..10c8372bc7 100644 --- a/plugins/_cmdWithMedia.js +++ b/plugins/_cmdWithMedia.js @@ -1,9 +1,13 @@ -const { proto, generateWAMessage, areJidsSameUser } = (await import("baileys")).default; +const { + proto, + generateWAMessage, + areJidsSameUser, +} = (await import('baileys')).default; export async function all(m, chatUpdate) { - if (m?.isBaileys) return; - if (!m?.message) return; - if (!m?.msg?.fileSha256) return; + if (m.isBaileys) return; + if (!m.message) return; + if (!m.msg.fileSha256) return; if (!(Buffer.from(m.msg.fileSha256).toString('base64') in global.db.data.sticker)) return; const hash = global.db.data.sticker[Buffer.from(m.msg.fileSha256).toString('base64')]; @@ -12,8 +16,8 @@ export async function all(m, chatUpdate) { userJid: this.user.id, quoted: m.quoted && m.quoted.fakeObj, }); - messages.key.fromMe = areJidsSameUser(m.sender, this.user.id); - messages.key.id = m.key.id; + messages.key.fromMe = m.isBaileys || (m.sender === m.conn?.user?.jid) + messages.key.id = m.key.id; messages.pushName = m.pushName; if (m.isGroup) messages.participant = m.sender; const msg = { @@ -23,3 +27,4 @@ export async function all(m, chatUpdate) { }; this.ev.emit('messages.upsert', msg); } + diff --git a/plugins/downloader-play.js b/plugins/downloader-play.js index bf85501094..96333d8f75 100644 --- a/plugins/downloader-play.js +++ b/plugins/downloader-play.js @@ -1,345 +1,93 @@ +import fetch from 'node-fetch'; import axios from 'axios'; -import fs from 'fs'; -import path from 'path'; import yts from 'yt-search'; -import ffmpeg from 'fluent-ffmpeg'; -import ffmpegPath from '@ffmpeg-installer/ffmpeg'; -import crypto from 'crypto'; -ffmpeg.setFfmpegPath(ffmpegPath.path); - -let limit1 = 100; // Tamaño mínimo para enviar como documento (MB) - Videos -let limit2 = 400; // Tamaño máximo (MB) - Videos -let limit_a1 = 50; // Tamaño mínimo para enviar como documento (MB) - Audios -let limit_a2 = 400; // Tamaño máximo (MB) - Audios - -const requestQueue = []; -let isProcessing = false; - -const handler = async (m, { conn, command, args, text, usedPrefix }) => { - try { - if (!text) { - throw `🎵 **Descargas - Play**\n\nPor favor, proporciona el título de la canción o video de YouTube.\n\n💡 *Ejemplo:* _${usedPrefix + command} Good Feeling - Flo Rida_`; - } - - const yt_play = await search(args.join(' ')); - if (!yt_play || !yt_play[0]?.title) { - return m.reply('> ❌ Error: No se encontró el audio o video buscado.'); - } - - // Verifica duración máxima de 30 minutos - if (yt_play[0].duration.seconds > 1800) { - await conn.sendMessage(m.chat, { - text: '> ❌ No se puede procesar la solicitud porque la duración del video excede los 30 minutos.' - }, { quoted: m }); - return; - } - - // Notifica si hay solicitudes en cola - if (isProcessing) { - await conn.sendMessage(m.chat, { - text: '> ⏳ Tu solicitud está en cola. Será procesada en breve.' - }, { quoted: m }); - } else { - const texto1 = `🎵 Título: ${yt_play[0].title}\n📆 Publicado: ${yt_play[0].ago}\n⏱ Duración: ${secondString(yt_play[0].duration.seconds)}\n👤 Autor: ${yt_play[0].author.name}\n\n> ⏳ Enviando, por favor espera...`.trim(); - await conn.sendMessage(m.chat, { image: { url: yt_play[0].thumbnail }, caption: texto1 }, { quoted: m }); - } - - // Agrega la solicitud a la cola - requestQueue.push({ m, conn, command, yt_play, retryCount: 0 }); - processQueue(); - } catch (error) { - console.error('Handler Error:', error); - if (typeof error === 'string') { - m.reply(error); - } else { - m.reply('> ❌ Ocurrió un error al procesar tu solicitud. \n> Por favor, inténtalo de nuevo más tarde.'); - } - } -}; - -async function processQueue() { - if (isProcessing) return; - isProcessing = true; - - while (requestQueue.length > 0) { - const { m, conn, command, yt_play, retryCount } = requestQueue.shift(); - - // Identifica si el comando es para audio o video - if (['play', 'play3', 'playdoc'].includes(command)) { - await handleAudio(m, conn, command, yt_play, retryCount); - } - if (['play2', 'play4', 'playdoc2'].includes(command)) { - await handleVideo(m, conn, command, yt_play, retryCount); - } - } - - isProcessing = false; -} - -async function handleAudio(m, conn, command, yt_play, retryCount) { - try { - // --------------------------------------------------------- - // Realizamos POST a la API local con "downloadMode: audio" - // --------------------------------------------------------- - const postData = { - url: yt_play[0].url, - youtubeVideoCodec: 'h264', - videoQuality: '1080', - downloadMode: 'audio' - }; - - // Realiza el POST para obtener la URL de descarga - const tunnelResponse = await axios.post('http://181.131.14.192:9000/', postData, { - headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } - }); - - // Extrae la URL para descargar el archivo de audio - const { url: audioFileUrl } = tunnelResponse.data; - - // Descarga el archivo de audio desde la URL obtenida - const downloadResp = await axios.get(audioFileUrl, { - responseType: 'arraybuffer', - timeout: 30000 - }); - const buff_aud = downloadResp.data; - - // Calcula el tamaño en MB - const size = (buff_aud.byteLength / (1024 * 1024)).toFixed(2); - - if (size >= limit_a2) { - await conn.sendMessage(m.chat, { - text: `🎶 El audio es demasiado grande para enviarlo. Por favor, descárgalo desde: _${yt_play[0].url}_` - }, { quoted: m }); - return; - } - - // Decide entre enviarlo como documento o audio - if (size >= limit_a1 && size <= limit_a2) { - await conn.sendMessage(m.chat, { - document: buff_aud, - mimetype: 'audio/mpeg', - fileName: `${sanitizeFileName(yt_play[0].title)}.mp3` - }, { quoted: m }); - } else { - if (['playdoc', 'play3'].includes(command)) { - await conn.sendMessage(m.chat, { - document: buff_aud, - mimetype: 'audio/mpeg', - fileName: `${sanitizeFileName(yt_play[0].title)}.mp3` - }, { quoted: m }); - } else { - await conn.sendMessage(m.chat, { - audio: buff_aud, - mimetype: 'audio/mpeg', - fileName: `${sanitizeFileName(yt_play[0].title)}.mp3` - }, { quoted: m }); - } - } - } catch (error) { - handleAxiosError(error, conn, m, { command, yt_play, retryCount }); - } -} - -async function handleVideo(m, conn, command, yt_play, retryCount) { - let success = false; - let buff_vid; - - // --------------------------------------------------------- - // Realizamos POST a la API local para obtener video - // --------------------------------------------------------- - const postData = { - url: yt_play[0].url, - youtubeVideoCodec: 'h264', - videoQuality: '1080' - }; - - while (!success) { - try { - const tunnelResponse = await axios.post('http://181.131.14.192:9000/', postData, { - headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' } - }); - - // Extrae la URL donde se encuentra el video - const { url: videoFileUrl } = tunnelResponse.data; - - // Descarga el archivo de video desde la URL obtenida - const downloadResp = await axios.get(videoFileUrl, { - responseType: 'arraybuffer', - timeout: 30000 - }); - - buff_vid = downloadResp.data; - success = true; - } catch (error) { - // Manejo de errores y reintentos - if (error.code === 'ECONNABORTED') { - console.warn('Axios timeout. Reintentando...'); - await new Promise(resolve => setTimeout(resolve, 5000)); - } else if (error.response && [500, 502, 503].includes(error.response.status)) { - console.warn(`Error ${error.response.status}. Reintentando...`); - await conn.sendMessage(m.chat, { - text: 'El servidor está ocupado. Tu petición está en cola. Por favor espera...' - }, { quoted: m }); - await new Promise(resolve => setTimeout(resolve, 5000)); - } else { - console.error('Error fetching video:', error); - await conn.sendMessage(m.chat, { - text: '> ❌ Ocurrió un error al procesar tu solicitud. \n> Por favor, inténtalo de nuevo más tarde.' - }, { quoted: m }); - return; - } - } - } - - // Procesa y envía el buffer del video - try { - const size2 = (buff_vid.byteLength / (1024 * 1024)).toFixed(2); - - // Verifica límite de tamaño - if (size2 >= limit2) { - await conn.sendMessage(m.chat, { - text: `🎥 El vídeo es demasiado grande para enviarlo. Por favor, descárgalo desde: _${yt_play[0].url}_` - }, { quoted: m }); - return; +let handler = async (m, { conn, text, usedPrefix, command }) => { +const datas = global; +const idioma = datas.db.data.users[m.sender].language || global.defaultLenguaje; +const _translate = JSON.parse(fs.readFileSync(`./src/languages/${idioma}.json`)); +const tradutor = _translate.plugins.descargas_play; + + let additionalText = ''; + if (['play', 'play1doc'].includes(command)) { + additionalText = 'audio'; + } else if (['play2', 'play2doc'].includes(command)) { + additionalText = 'vídeo'; + } + + if (command === 'play') { + if (!text) throw `${tradutor.texto1[0]} _${usedPrefix + command} ${tradutor.texto1[1]}`; + try { + const apisearch = await axios.get(`https://api-rin-tohsaka.vercel.app/search/ytsearch?text=${encodeURIComponent(text)}`) + const responsev1 = apisearch.data.data[0]; + + const body = `${tradutor.texto2[0]} ${responsev1.title}\n${tradutor.texto2[1]} ${responsev1.uploaded}\n${tradutor.texto2[2]} ${responsev1.duration}\n${tradutor.texto2[3]} ${responsev1.views}\n${tradutor.texto2[4]} ${responsev1.author.name}\n${tradutor.texto2[5]} ${responsev1.identifier}\n${tradutor.texto2[6]} ${responsev1.type}\n${tradutor.texto2[7]} ${responsev1.url}\n${tradutor.texto2[8]} ${responsev1.author.url}\n\n> ${tradutor.texto2[9]} ${additionalText}, ${tradutor.texto2[10]}`.trim(); + conn.sendMessage(m.chat, { image: { url: responsev1.thumbnail }, caption: body }, { quoted: m }); + + const apidownload = await axios.get(`https://api-rin-tohsaka.vercel.app/download/ytmp3?url=${responsev1.url}`) + const responsev2 = await apidownload.data.data.download; + + await conn.sendMessage(m.chat, { audio: { url: responsev2 }, mimetype: 'audio/mpeg' }, { quoted: m }); + } catch (e) { + conn.reply(m.chat, `「 ✰ 」OCURRIO UN FALLO AL PROCESAR SU SOLICITUD\n\n> ${e}`, m); + } } - // Almacena el video temporalmente para posible recompresión - const uniqueId = crypto.randomBytes(6).toString('hex'); - const tempDir = path.join(process.cwd(), 'temp'); - - if (!fs.existsSync(tempDir)) { - fs.mkdirSync(tempDir); + if (command === 'play2') { + if (!text) throw `${tradutor.texto1[0]} _${usedPrefix + command} ${tradutor.texto1[1]}`; + try { + const apisearch = await axios.get(`https://api-rin-tohsaka.vercel.app/search/ytsearch?text=${encodeURIComponent(text)}`) + const responsev1 = apisearch.data.data[0]; + + const body = `${tradutor.texto2[0]} ${responsev1.title}\n${tradutor.texto2[1]} ${responsev1.uploaded}\n${tradutor.texto2[2]} ${responsev1.duration}\n${tradutor.texto2[3]} ${responsev1.views}\n${tradutor.texto2[4]} ${responsev1.author.name}\n${tradutor.texto2[5]} ${responsev1.identifier}\n${tradutor.texto2[6]} ${responsev1.type}\n${tradutor.texto2[7]} ${responsev1.url}\n${tradutor.texto2[8]} ${responsev1.author.url}\n\n> ${tradutor.texto2[9]} ${additionalText}, ${tradutor.texto2[10]}`.trim(); + conn.sendMessage(m.chat, { image: { url: responsev1.thumbnail }, caption: body }, { quoted: m }); + + const apidownload = await axios.get(`https://api-rin-tohsaka.vercel.app/download/ytmp4?url=${responsev1.url}`) + const responsev2 = await apidownload.data.data.download; + + await conn.sendMessage(m.chat, { video: { url: responsev2 }, mimetype: 'video/mp4' }, { quoted: m }); + } catch (e) { + conn.reply(m.chat, `「 ✰ 」OCURRIO UN FALLO AL PROCESAR SU SOLICITUD\n\n> ${e}`, m); + } } - - const originalFileName = `${sanitizeFileName(yt_play[0].title)}_${uniqueId}.mp4`; - const originalFilePath = path.join(tempDir, originalFileName); - fs.writeFileSync(originalFilePath, buff_vid); - - // Se realizará una pasada por ffmpeg si deseas reempaquetar - const processedFileName = `${sanitizeFileName(yt_play[0].title)}_processed_${uniqueId}.mp4`; - const processedFilePath = path.join(tempDir, processedFileName); - - await new Promise((resolve, reject) => { - ffmpeg(originalFilePath) - .videoCodec('libx264') - .format('mp4') - .outputOptions('-movflags frag_keyframe+empty_moov') - .save(processedFilePath) - .on('end', resolve) - .on('error', reject); - }); - - const fileBuffer = fs.readFileSync(processedFilePath); - - // Envía como documento o como video según tamaño y comando - if (size2 >= limit1 && size2 <= limit2) { - await conn.sendMessage(m.chat, { - document: fileBuffer, - mimetype: 'video/mp4', - fileName: processedFileName, - caption: `🎥 Aquí está el video` - }, { quoted: m }); - } else { - if (['playdoc2', 'play4'].includes(command)) { - await conn.sendMessage(m.chat, { - document: fileBuffer, - mimetype: 'video/mp4', - fileName: processedFileName, - caption: `🎥 Aquí está el video` - }, { quoted: m }); - } else { - await conn.sendMessage(m.chat, { - video: fileBuffer, - mimetype: 'video/mp4', - fileName: processedFileName, - caption: `🎥 Aquí está el video` - }, { quoted: m }); - } + + if (command === 'play1doc') { + if (!text) throw `${tradutor.texto1[0]} _${usedPrefix + command} ${tradutor.texto1[1]}`; + try { + const apisearch = await axios.get(`https://api-rin-tohsaka.vercel.app/search/ytsearch?text=${encodeURIComponent(text)}`) + const responsev1 = apisearch.data.data[0]; + + const body = `${tradutor.texto2[0]} ${responsev1.title}\n${tradutor.texto2[1]} ${responsev1.uploaded}\n${tradutor.texto2[2]} ${responsev1.duration}\n${tradutor.texto2[3]} ${responsev1.views}\n${tradutor.texto2[4]} ${responsev1.author.name}\n${tradutor.texto2[5]} ${responsev1.identifier}\n${tradutor.texto2[6]} ${responsev1.type}\n${tradutor.texto2[7]} ${responsev1.url}\n${tradutor.texto2[8]} ${responsev1.author.url}\n\n> ${tradutor.texto2[9]} ${additionalText}, ${tradutor.texto2[10]}`.trim(); + conn.sendMessage(m.chat, { image: { url: responsev1.thumbnail }, caption: body }, { quoted: m }); + + const apidownload = await axios.get(`https://api-rin-tohsaka.vercel.app/download/ytmp3?url=${responsev1.url}`) + const responsev2 = await apidownload.data.data.download; + + await conn.sendMessage(m.chat, { document: { url: responsev2 }, mimetype: 'audio/mpeg', fileName: `${responsev1.title}.mp3` }, { quoted: m }); + } catch (e) { + conn.reply(m.chat, `「 ✰ 」OCURRIO UN FALLO AL PROCESAR SU SOLICITUD\n\n> ${e}`, m); + } } - // Limpia archivos temporales - fs.unlinkSync(originalFilePath); - fs.unlinkSync(processedFilePath); - } catch (error) { - console.error('Error processing video:', error); - const tempDir = path.join(process.cwd(), 'temp'); - if (fs.existsSync(tempDir)) { - fs.readdirSync(tempDir).forEach(file => { - if (file.includes(crypto.randomBytes(6).toString('hex'))) { - fs.unlinkSync(path.join(tempDir, file)); + if (command === 'play2doc') { + if (!text) throw `${tradutor.texto1[0]} _${usedPrefix + command} ${tradutor.texto1[1]}`; + try { + const apisearch = await axios.get(`https://api-rin-tohsaka.vercel.app/search/ytsearch?text=${encodeURIComponent(text)}`) + const responsev1 = apisearch.data.data[0]; + + const body = `${tradutor.texto2[0]} ${responsev1.title}\n${tradutor.texto2[1]} ${responsev1.uploaded}\n${tradutor.texto2[2]} ${responsev1.duration}\n${tradutor.texto2[3]} ${responsev1.views}\n${tradutor.texto2[4]} ${responsev1.author.name}\n${tradutor.texto2[5]} ${responsev1.identifier}\n${tradutor.texto2[6]} ${responsev1.type}\n${tradutor.texto2[7]} ${responsev1.url}\n${tradutor.texto2[8]} ${responsev1.author.url}\n\n> ${tradutor.texto2[9]} ${additionalText}, ${tradutor.texto2[10]}`.trim(); + conn.sendMessage(m.chat, { image: { url: responsev1.thumbnail }, caption: body }, { quoted: m }); + + const apidownload = await axios.get(`https://api-rin-tohsaka.vercel.app/download/ytmp4?url=${responsev1.url}`) + const responsev2 = await apidownload.data.data.download; + + await conn.sendMessage(m.chat, { document: { url: responsev2 }, mimetype: 'video/mp4', fileName: `${responsev1.title}.mp4` }, { quoted: m }); + } catch (e) { + conn.reply(m.chat, `「 ✰ 」OCURRIO UN FALLO AL PROCESAR SU SOLICITUD\n\n> ${e}`, m); } - }); } +}; - if (retryCount < 3) { - console.warn('Retrying video processing...'); - requestQueue.push({ m, conn, command, yt_play, retryCount: retryCount + 1 }); - processQueue(); - } else { - await conn.sendMessage(m.chat, { - text: '> ❌ Ocurrió un error al procesar tu solicitud. \n> Por favor, inténtalo de nuevo más tarde.' - }, { quoted: m }); - } - } -} +handler.command = ['play', 'play2', 'play1doc', 'play2doc']; -// Comandos que activan este handler -handler.command = /^(play|play2|play3|play4|playdoc|playdoc2)$/i; export default handler; - -// Search con yt-search -async function search(query, options = {}) { - try { - const search = await yts.search({ query, hl: 'es', gl: 'ES', ...options }); - return search.videos; - } catch (error) { - console.error('Search Error:', error); - return null; - } -} - -// Convertir segundos en string legible -function secondString(seconds) { - seconds = Number(seconds); - const d = Math.floor(seconds / (3600 * 24)); - const h = Math.floor((seconds % (3600 * 24)) / 3600); - const m = Math.floor((seconds % 3600) / 60); - const s = Math.floor(seconds % 60); - const dDisplay = d > 0 ? d + 'd ' : ''; - const hDisplay = h > 0 ? h + 'h ' : ''; - const mDisplay = m > 0 ? m + 'm ' : ''; - const sDisplay = s > 0 ? s + 's' : ''; - return dDisplay + hDisplay + mDisplay + sDisplay; -} - -// Manejo de errores en Axios -async function handleAxiosError(error, conn, m, { command, yt_play, retryCount }) { - if (error.code === 'ECONNABORTED') { - console.warn('Axios timeout. Enviando mensaje de timeout.'); - await conn.sendMessage(m.chat, { - text: '❌ La solicitud ha excedido el tiempo de espera. Por favor, inténtalo de nuevo.' - }, { quoted: m }); - } else if (error.response && [500, 502, 503].includes(error.response.status)) { - console.warn(`Error ${error.response.status}. Enviando mensaje de servidor ocupado.`); - await conn.sendMessage(m.chat, { - text: '> ⚠️ El servidor está ocupado. \n> Si no se envia en unos instantes, inténtalo de nuevo más tarde.' - }, { quoted: m }); - } else { - console.error('Axios Error:', error); - await conn.sendMessage(m.chat, { - text: '> ❌ Ocurrió un error al procesar tu solicitud. \n> Por favor, inténtalo de nuevo más tarde.' - }, { quoted: m }); - } - - if (retryCount < 3) { - console.warn('Reintentando la solicitud...'); - requestQueue.push({ m, conn, command, yt_play, retryCount: retryCount + 1 }); - processQueue(); - } -} - -// Sanitiza nombres de archivo -function sanitizeFileName(name) { - return name.replace(/[^a-z0-9_\-\.]/gi, '_'); -} diff --git a/plugins/owner-exec.js b/plugins/owner-exec.js index b79e8d500b..38124f324b 100644 --- a/plugins/owner-exec.js +++ b/plugins/owner-exec.js @@ -1,3 +1,4 @@ +/* import syntaxerror from 'syntax-error'; import {format} from 'util'; import {fileURLToPath} from 'url'; @@ -46,3 +47,4 @@ class CustomArray extends Array { function pickRandom(list) { return list[Math.floor(Math.random() * list.length)]; } +*_