descargas-play.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. //import { youtubedl, youtubedlv2 } from '@bochilteam/scraper'
  2. import fetch from 'node-fetch';
  3. import yts from 'yt-search';
  4. import ytdl from 'ytdl-core';
  5. import axios from 'axios';
  6. import { savetube } from '../lib/yt-savetube.js'
  7. import { ogmp3 } from '../lib/youtubedl.js';
  8. import { createRequire } from 'module';
  9. const require = createRequire(import.meta.url);
  10. const { ytmp3, ytmp4 } = require("@hiudyy/ytdl");
  11. const LimitAud = 725 * 1024 * 1024; // 725MB
  12. const LimitVid = 425 * 1024 * 1024; // 425MB
  13. const youtubeRegexID = /(?:youtu\.be\/|youtube\.com\/(?:watch\?v=|embed\/))([a-zA-Z0-9_-]{11})/;
  14. const handler = async (m, { conn, command, args, text, usedPrefix }) => {
  15. if (!text) return m.reply(`**˚₊· ͟͟͞͞➳❥ Y T ¸.☆.¸ P L A Y*\n*Ingrese el nombre de la canción*\n\n*Ejemplo:*\n${usedPrefix + command} emilia 420`);
  16. const tipoDescarga = command === 'play' || command === 'musica' ? 'audio' : command === 'play2' ? 'video' : command === 'play3' ? 'audio (documento)' : command === 'play4' ? 'video (documento)' : '';
  17. let videoIdToFind = text.match(youtubeRegexID) || null;
  18. const yt_play = await search(args.join(' '));
  19. let ytplay2 = await yts(videoIdToFind === null ? text : 'https://youtu.be/' + videoIdToFind[1]);
  20. if (videoIdToFind) {
  21. const videoId = videoIdToFind[1];
  22. ytplay2 = ytplay2.all.find(item => item.videoId === videoId) || ytplay2.videos.find(item => item.videoId === videoId)}
  23. ytplay2 = ytplay2.all?.[0] || ytplay2.videos?.[0] || ytplay2;
  24. await conn.sendMessage(m.chat, { text: `${yt_play[0].title}
  25. > [ YOUTUBE - PLAY ]
  26. *ੈ✰‧₊˚ /Duración ${secondString(yt_play[0].duration.seconds)}
  27. *ੈ✰‧₊˚ Aguarde un momento en lo que envío su ${tipoDescarga}*`,
  28. contextInfo:{
  29. forwardedNewsletterMessageInfo: {
  30. newsletterJid: '120363371008200788@newsletter',
  31. serverMessageId: '',
  32. newsletterName: 'The Kantu Bot ⚡' },
  33. forwardingScore: 9999999,
  34. isForwarded: true,
  35. mentionedJid: null,
  36. externalAdReply: {
  37. showAdAttribution: true,
  38. renderLargerThumbnail: true,
  39. title: yt_play[0].title,
  40. body: wm,
  41. containsAutoReply: true,
  42. mediaType: 1,
  43. thumbnailUrl: yt_play[0].thumbnail,
  44. sourceUrl: [nna, nna2, nnaa].getRandom()
  45. }}}, { quoted: m })
  46. /*conn.sendFile(m.chat, yt_play[0].thumbnail, 'error.jpg', `${yt_play[0].title}
  47. *⇄ㅤ ◁ ㅤ ❚❚ㅤ ▷ㅤ ↻*
  48. *⏰ Duración:* ${secondString(yt_play[0].duration.seconds)}
  49. *👉🏻Aguarde un momento en lo que envío su audio*`, m, null, fake);*/
  50. const [input, qualityInput = command === 'play' || command === 'musica' || command === 'play3' ? '320' : '720'] = text.split(' ');
  51. const audioQualities = ['64', '96', '128', '192', '256', '320'];
  52. const videoQualities = ['240', '360', '480', '720', '1080'];
  53. const isAudioCommand = command === 'play' || command === 'musica' || command === 'play3';
  54. const selectedQuality = (isAudioCommand ? audioQualities : videoQualities).includes(qualityInput) ? qualityInput : (isAudioCommand ? '320' : '720');
  55. const isAudio = command.toLowerCase().includes('mp3') || command.toLowerCase().includes('audio')
  56. const format = isAudio ? 'mp3' : '720'
  57. const audioApis = [
  58. { url: () => savetube.download(yt_play[0].url, format), extract: (data) => ({ data: data.result.download, isDirect: false }) },
  59. { url: () => ogmp3.download(yt_play[0].url, selectedQuality, 'audio'), extract: (data) => ({ data: data.result.download, isDirect: false }) },
  60. { url: () => ytmp3(yt_play[0].url), extract: (data) => ({ data, isDirect: true }) },
  61. { url: () => fetch(`https://api.dorratz.com/v3/ytdl?url=${yt_play[0].url}`).then(res => res.json()), extract: (data) => {
  62. const mp3 = data.medias.find(media => media.quality === "160kbps" && media.extension === "mp3");
  63. return { data: mp3.url, isDirect: false }}},
  64. { url: () => fetch(`${APIs.neoxr.url}/youtube?url=${yt_play[0].url}&type=audio&quality=128kbps&apikey=${APIs.neoxr.key}`).then(res => res.json()), extract: (data) => ({ data: data.data.url, isDirect: false }) },
  65. { url: () => fetch(`https://api.fgmods.xyz/api/downloader/ytmp4?url=${yt_play[0].url}&apikey=${APIs.fgmods.url}`).then(res => res.json()), extract: (data) => ({ data: data.result.dl_url, isDirect: false }) },
  66. { url: () => fetch(`https://api.siputzx.my.id/api/d/ytmp4?url=${yt_play[0].url}`).then(res => res.json()), extract: (data) => ({ data: data.dl, isDirect: false }) },
  67. { url: () => fetch(`${apis}/download/ytmp3?url=${yt_play[0].url}`).then(res => res.json()), extract: (data) => ({ data: data.status ? data.data.download.url : null, isDirect: false }) },
  68. { url: () => fetch(`https://api.zenkey.my.id/api/download/ytmp3?apikey=zenkey&url=${yt_play[0].url}`).then(res => res.json()), extract: (data) => ({ data: data.result.download.url, isDirect: false }) },
  69. { url: () => fetch(`https://exonity.tech/api/dl/playmp3?query=${yt_play[0].title}`).then(res => res.json()), extract: (data) => ({ data: data.result.download, isDirect: false })
  70. }];
  71. const videoApis = [
  72. { url: () => savetube.download(yt_play[0].url, '720'), extract: (data) => ({ data: data.result.download, isDirect: false }) },
  73. { url: () => ogmp3.download(yt_play[0].url, selectedQuality, 'video'), extract: (data) => ({ data: data.result.download, isDirect: false }) },
  74. { url: () => ytmp4(yt_play[0].url), extract: (data) => ({ data, isDirect: true }) },
  75. { url: () => fetch(`https://api.siputzx.my.id/api/d/ytmp4?url=${yt_play[0].url}`).then(res => res.json()), extract: (data) => ({ data: data.dl, isDirect: false }) },
  76. { url: () => fetch(`${APIs.neoxr.url}/youtube?url=${yt_play[0].url}&type=video&quality=720p&apikey=${APIs.neoxr.key}`).then(res => res.json()), extract: (data) => ({ data: data.data.url, isDirect: false }) },
  77. { url: () => fetch(`https://api.fgmods.xyz/api/downloader/ytmp4?url=${yt_play[0].url}&apikey=${APIs.fgmods.key}`).then(res => res.json()), extract: (data) => ({ data: data.result.dl_url, isDirect: false }) },
  78. { url: () => fetch(`${apis}/download/ytmp4?url=${encodeURIComponent(yt_play[0].url)}`).then(res => res.json()), extract: (data) => ({ data: data.status ? data.data.download.url : null, isDirect: false }) },
  79. { url: () => fetch(`https://exonity.tech/api/dl/playmp4?query=${encodeURIComponent(yt_play[0].title)}`).then(res => res.json()), extract: (data) => ({ data: data.result.download, isDirect: false })
  80. }];
  81. const download = async (apis) => {
  82. let mediaData = null;
  83. let isDirect = false;
  84. for (const api of apis) {
  85. try {
  86. const data = await api.url();
  87. const { data: extractedData, isDirect: direct } = api.extract(data);
  88. if (extractedData) {
  89. const size = await getFileSize(extractedData);
  90. if (size >= 1024) {
  91. mediaData = extractedData;
  92. isDirect = direct;
  93. break;
  94. }}} catch (e) {
  95. console.log(`Error con API: ${e}`);
  96. continue;
  97. }}
  98. return { mediaData, isDirect };
  99. };
  100. if (command === 'play' || command === 'musica') {
  101. const { mediaData, isDirect } = await download(audioApis);
  102. if (mediaData) {
  103. const fileSize = await getFileSize(mediaData);
  104. if (fileSize > LimitAud) {
  105. await conn.sendMessage(m.chat, { document: isDirect ? mediaData : { url: mediaData }, mimetype: 'audio/mpeg', fileName: `${yt_play[0].title}.mp3` }, { quoted: m });
  106. } else {
  107. await conn.sendMessage(m.chat, { audio: isDirect ? mediaData : { url: mediaData }, mimetype: 'audio/mpeg' }, { quoted: m });
  108. }} else {
  109. await m.react('❌');
  110. }}
  111. if (command === 'play2' || command === 'video') {
  112. const { mediaData, isDirect } = await download(videoApis);
  113. if (mediaData) {
  114. const fileSize = await getFileSize(mediaData);
  115. const messageOptions = { fileName: `${yt_play[0].title}.mp4`, caption: `🔰 Aquí está tu video \n🔥 Título: ${yt_play[0].title}`, mimetype: 'video/mp4' };
  116. if (fileSize > LimitVid) {
  117. await conn.sendMessage(m.chat, { document: isDirect ? mediaData : { url: mediaData }, ...messageOptions }, { quoted: m });
  118. } else {
  119. await conn.sendMessage(m.chat, { video: isDirect ? mediaData : { url: mediaData }, thumbnail: yt_play[0].thumbnail, ...messageOptions }, { quoted: m });
  120. }} else {
  121. await m.react('❌');
  122. }}
  123. if (command === 'play3' || command === 'playdoc') {
  124. const { mediaData, isDirect } = await download(audioApis);
  125. if (mediaData) {
  126. await conn.sendMessage(m.chat, { document: isDirect ? mediaData : { url: mediaData }, mimetype: 'audio/mpeg', fileName: `${yt_play[0].title}.mp3`}, { quoted: m });
  127. } else {
  128. await m.react('❌');
  129. }}
  130. if (command === 'play4' || command === 'playdoc2') {
  131. const { mediaData, isDirect } = await download(videoApis);
  132. if (mediaData) {
  133. await conn.sendMessage(m.chat, { document: isDirect ? mediaData : { url: mediaData }, fileName: `${yt_play[0].title}.mp4`, caption: `🔰Título: ${yt_play[0].title}`, thumbnail: yt_play[0].thumbnail, mimetype: 'video/mp4'}, { quoted: m })
  134. } else {
  135. await m.react('❌');
  136. }}};
  137. handler.help = ['play', 'play2', 'play3', 'play4', 'playdoc'];
  138. handler.tags = ['downloader'];
  139. handler.command = ['play', 'play2', 'play3', 'play4', 'audio', 'video', 'playdoc', 'playdoc2', 'musica'];
  140. handler.register = true;
  141. export default handler;
  142. async function search(query, options = {}) {
  143. const search = await yts.search({query, hl: 'es', gl: 'ES', ...options});
  144. return search.videos;
  145. }
  146. function MilesNumber(number) {
  147. const exp = /(\d)(?=(\d{3})+(?!\d))/g;
  148. const rep = '$1.';
  149. const arr = number.toString().split('.');
  150. arr[0] = arr[0].replace(exp, rep);
  151. return arr[1] ? arr.join('.') : arr[0];
  152. }
  153. function secondString(seconds) {
  154. seconds = Number(seconds);
  155. const d = Math.floor(seconds / (3600 * 24));
  156. const h = Math.floor((seconds % (3600 * 24)) / 3600);
  157. const m = Math.floor((seconds % 3600) / 60);
  158. const s = Math.floor(seconds % 60);
  159. const dDisplay = d > 0 ? d + (d == 1 ? ' día, ' : ' días, ') : '';
  160. const hDisplay = h > 0 ? h + (h == 1 ? ' hora, ' : ' horas, ') : '';
  161. const mDisplay = m > 0 ? m + (m == 1 ? ' minuto, ' : ' minutos, ') : '';
  162. const sDisplay = s > 0 ? s + (s == 1 ? ' segundo' : ' segundos') : '';
  163. return dDisplay + hDisplay + mDisplay + sDisplay;
  164. }
  165. const getBuffer = async (url) => {
  166. try {
  167. const response = await fetch(url);
  168. const buffer = await response.arrayBuffer();
  169. return Buffer.from(buffer);
  170. } catch (error) {
  171. console.error("Error al obtener el buffer", error);
  172. throw new Error("Error al obtener el buffer");
  173. }
  174. }
  175. async function getFileSize(url) {
  176. try {
  177. const response = await fetch(url, { method: 'HEAD' });
  178. return parseInt(response.headers.get('content-length') || 0);
  179. } catch {
  180. return 0; // Si falla, asumimos 0
  181. }
  182. }
  183. async function fetchY2mate(url) {
  184. const baseUrl = 'https://www.y2mate.com/mates/en60';
  185. const videoInfo = await fetch(`${baseUrl}/analyze/ajax`, {
  186. method: 'POST',
  187. headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  188. body: new URLSearchParams({ url, q_auto: 0 })
  189. }).then(res => res.json());
  190. const id = videoInfo.result.id;
  191. const downloadInfo = await fetch(`${baseUrl}/convert`, {
  192. method: 'POST',
  193. headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  194. body: new URLSearchParams({ type: 'youtube', _id: id, v_id: url, token: '', ftype: 'mp4', fquality: '360p' })
  195. }).then(res => res.json());
  196. return downloadInfo.result.url;
  197. }
  198. async function fetchInvidious(url) {
  199. const apiUrl = `https://invidious.io/api/v1/get_video_info`;
  200. const response = await fetch(`${apiUrl}?url=${encodeURIComponent(url)}`);
  201. const data = await response.json();
  202. if (data && data.video) {
  203. const videoInfo = data.video;
  204. return videoInfo;
  205. } else {
  206. throw new Error("No se pudo obtener información del video desde Invidious");
  207. }
  208. }
  209. async function fetch9Convert(url) {
  210. const apiUrl = `https://9convert.com/en429/api`;
  211. const response = await fetch(`${apiUrl}?url=${encodeURIComponent(url)}`);
  212. const data = await response.json();
  213. if (data.status === 'ok') {
  214. return data.result.mp3;
  215. } else {
  216. throw new Error("No se pudo obtener la descarga desde 9Convert");
  217. }
  218. }