|
|
const axios = require('axios') |
|
|
const { jidDecode, delay, generateWAMessageFromContent, proto } = require('baileys') |
|
|
const id3 = require('browser-id3-writer') |
|
|
const { fromBuffer } = require('file-type') |
|
|
const path = require('path') |
|
|
const FormData = require('form-data') |
|
|
const { spawn } = require('child_process') |
|
|
const { default: fetch } = require('node-fetch') |
|
|
let { JSDOM } = require('jsdom') |
|
|
const cheerio = require('cheerio') |
|
|
const { commands } = require('./plugins') |
|
|
const config = require('../config') |
|
|
const jsQR = require('jsqr') |
|
|
const fs = require('fs') |
|
|
const jimp = require('jimp') |
|
|
const { loadMessage } = require('./database/StoreDb') |
|
|
const { tmpdir } = require('os') |
|
|
const { exec } = require('child_process') |
|
|
const streamBuffers = require('stream-buffers') |
|
|
const { URLSearchParams } = require('url') |
|
|
async function editAudio(message, effect = 'bass', options = '') { |
|
|
if (!message.quoted) { |
|
|
return await message.send('*Reply to audio*') |
|
|
} |
|
|
|
|
|
let mediaType = message.quoted.mtype || message.mtype |
|
|
if (!/audio/.test(mediaType)) { |
|
|
return await message.send('*_Reply Audio_*', {}, '', options) |
|
|
} |
|
|
let filterCommand = '-af equalizer=f=54:width_type=o:width=2:g=20' |
|
|
|
|
|
switch (effect.toLowerCase()) { |
|
|
case 'bass': |
|
|
filterCommand = '-af equalizer=f=54:width_type=o:width=2:g=20' |
|
|
break |
|
|
case 'blown': |
|
|
filterCommand = '-af acrusher=.1:1:64:0:log' |
|
|
break |
|
|
case 'deep': |
|
|
filterCommand = '-af atempo=4/4,asetrate=44500*2/3' |
|
|
break |
|
|
case 'earrape': |
|
|
filterCommand = '-af volume=12' |
|
|
break |
|
|
case 'fast': |
|
|
filterCommand = '-filter:a "atempo=1.63,asetrate=44100"' |
|
|
break |
|
|
case 'fat': |
|
|
filterCommand = '-filter:a "atempo=1.6,asetrate=22100"' |
|
|
break |
|
|
case 'nightcore': |
|
|
filterCommand = '-filter:a atempo=1.06,asetrate=44100*1.25' |
|
|
break |
|
|
case 'reverse': |
|
|
filterCommand = '-filter_complex "areverse"' |
|
|
break |
|
|
case 'robot': |
|
|
filterCommand = "-filter_complex \"afftfilt=real='hypot(re,im)*sin(0)':imag='hypot(re,im)*cos(0)':win_size=512:overlap=0.75\"" |
|
|
break |
|
|
case 'slow': |
|
|
filterCommand = '-filter:a "atempo=0.7,asetrate=44100"' |
|
|
break |
|
|
case 'smooth': |
|
|
filterCommand = '-filter:v "minterpolate=\'mi_mode=mci:mc_mode=aobmc:vsbmc=1:fps=120\'"' |
|
|
break |
|
|
case 'tupai': |
|
|
filterCommand = '-filter:a "atempo=0.5,asetrate=65100"' |
|
|
break |
|
|
default: |
|
|
break |
|
|
} |
|
|
|
|
|
let audioFilePath = await message.client.downloadAndSaveMediaMessage(message.quoted) |
|
|
let outputFilePath = 'temp/' + (message.sender.slice(6) + effect) + '.mp3' |
|
|
|
|
|
exec(`ffmpeg -i ${audioFilePath} ${filterCommand} ${outputFilePath}`, async (error, stdout, stderr) => { |
|
|
try { |
|
|
fs.unlinkSync(audioFilePath) |
|
|
} catch {} |
|
|
|
|
|
if (error) { |
|
|
return message.error(error) |
|
|
} else { |
|
|
let editedAudio = fs.readFileSync(outputFilePath) |
|
|
try { |
|
|
fs.unlinkSync(outputFilePath) |
|
|
} catch {} |
|
|
|
|
|
let contextInfo = { |
|
|
...(await message.bot.contextInfo('Sir ' + message.senderName + ' 🤍', '⇆ㅤ ||◁ㅤ❚❚ㅤ▷||ㅤ ⇆')), |
|
|
} |
|
|
|
|
|
return message.bot.sendMessage( |
|
|
message.chat, |
|
|
{ |
|
|
audio: editedAudio, |
|
|
mimetype: 'audio/mpeg', |
|
|
ptt: /ptt|voice/.test(message.test || '') ? true : false, |
|
|
contextInfo: contextInfo, |
|
|
}, |
|
|
{ |
|
|
quoted: message, |
|
|
messageId: message.bot.messageId(), |
|
|
} |
|
|
) |
|
|
} |
|
|
}) |
|
|
} |
|
|
const captureScreenshot = (url, device = 'desktop') => { |
|
|
return new Promise((resolve, reject) => { |
|
|
const screenshotApiUrl = 'https://www.screenshotmachine.com/capture.php' |
|
|
const requestData = { |
|
|
url, |
|
|
device, |
|
|
cacheLimit: 0, |
|
|
} |
|
|
|
|
|
axios |
|
|
.post(screenshotApiUrl, new URLSearchParams(requestData), { |
|
|
headers: { |
|
|
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', |
|
|
}, |
|
|
}) |
|
|
.then((response) => { |
|
|
const cookies = response.headers['set-cookie'] |
|
|
if (response.data.status === 'success') { |
|
|
axios |
|
|
.get(`https://www.screenshotmachine.com/${response.data.link}`, { |
|
|
headers: { cookie: cookies.join('') }, |
|
|
responseType: 'arraybuffer', |
|
|
}) |
|
|
.then(({ data }) => { |
|
|
resolve({ status: 200, result: data }) |
|
|
}) |
|
|
} else { |
|
|
reject({ |
|
|
status: 404, |
|
|
statusText: 'Link Error', |
|
|
message: response.data, |
|
|
}) |
|
|
} |
|
|
}) |
|
|
.catch(reject) |
|
|
}) |
|
|
} |
|
|
async function m3u82Mp4(m3u8Url) { |
|
|
return new Promise((resolve, reject) => { |
|
|
const writableStreamBuffer = new streamBuffers.WritableStreamBuffer({ |
|
|
initialSize: 100 * 1024, |
|
|
incrementAmount: 10 * 1024, |
|
|
}) |
|
|
const tempOutputFile = 'output.mp4' |
|
|
const command = `"${ffmpegPath}" -i "${m3u8Url}" -c copy "${tempOutputFile}"` |
|
|
const ffmpegProcess = exec(command, (error, stdout, stderr) => { |
|
|
if (error) { |
|
|
console.error(`Error occurred: ${error.message}`) |
|
|
return reject(error) |
|
|
} |
|
|
|
|
|
|
|
|
fs.readFile(tempOutputFile, (err, data) => { |
|
|
if (err) { |
|
|
return reject(err) |
|
|
} |
|
|
writableStreamBuffer.write(data) |
|
|
writableStreamBuffer.end() |
|
|
fs.unlinkSync(tempOutputFile) |
|
|
resolve(writableStreamBuffer.getContents()) |
|
|
}) |
|
|
}) |
|
|
ffmpegProcess.stderr.on('data', (data) => { |
|
|
const progressLine = data.toString() |
|
|
const timeMatch = progressLine.match(/time=(\d{2}:\d{2}:\d{2}\.\d{2})/) |
|
|
if (timeMatch) { |
|
|
const elapsedTime = timeMatch[1] |
|
|
console.log(`Conversion progress: ${elapsedTime}`) |
|
|
} |
|
|
}) |
|
|
}) |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function buffToFile(buffer, filename) { |
|
|
if (!filename) filename = Date.now() |
|
|
let { ext } = await fromBuffer(buffer) |
|
|
let filePath = path.join(tmpdir(), `${filename}.${ext}`) |
|
|
await fs.promises.writeFile(filePath, buffer) |
|
|
return filePath |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const removeBg = async (imageBuffer) => { |
|
|
const formData = new FormData() |
|
|
const inputPath = await buffToFile(imageBuffer) |
|
|
formData.append('size', 'auto') |
|
|
formData.append('image_file', fs.createReadStream(inputPath), path.basename(inputPath)) |
|
|
try { |
|
|
const response = await axios({ |
|
|
method: 'post', |
|
|
url: 'https://api.remove.bg/v1.0/removebg', |
|
|
data: formData, |
|
|
responseType: 'arraybuffer', |
|
|
headers: { |
|
|
...formData.getHeaders(), |
|
|
'X-Api-Key': config.REMOVEBG, |
|
|
}, |
|
|
encoding: null, |
|
|
}) |
|
|
|
|
|
if (response.status !== 200) { |
|
|
console.error('Error:', response.status, response.statusText) |
|
|
return null |
|
|
} |
|
|
|
|
|
return response.data |
|
|
} catch (error) { |
|
|
console.error('Request failed:', error) |
|
|
return null |
|
|
} |
|
|
} |
|
|
|
|
|
async function validatAndSaveDeleted(client, msg) { |
|
|
if (msg.type === 'protocolMessage') { |
|
|
if (msg.message.protocolMessage.type === 'REVOKE') { |
|
|
await client.sendMessage(msg.key.remoteJid, { text: 'Message Deleted' }) |
|
|
let jid = config.DELETED_LOG_CHAT |
|
|
let message = await loadMessage(msg.message.protocolMessage.key.id) |
|
|
const m = generateWAMessageFromContent(jid, message.message, { |
|
|
userJid: client.user.id, |
|
|
}) |
|
|
await client.relayMessage(jid, m.message, { |
|
|
messageId: m.key.id, |
|
|
}) |
|
|
return m |
|
|
} |
|
|
} |
|
|
} |
|
|
async function textToImg(text) { |
|
|
try { |
|
|
const words = text.split(' ') |
|
|
const lines = [] |
|
|
let line = '' |
|
|
words.forEach((word) => { |
|
|
if (line.length + word.length < 30) { |
|
|
line += word + ' ' |
|
|
} else { |
|
|
lines.push(line) |
|
|
line = word + ' ' |
|
|
} |
|
|
}) |
|
|
lines.push(line) |
|
|
text = lines.join('\n') |
|
|
const font = await jimp.loadFont(jimp.FONT_SANS_64_WHITE) |
|
|
const textWidth = jimp.measureText(font, text.substring(0, 35)) |
|
|
const textHeight = jimp.measureTextHeight(font, text) |
|
|
const canvasWidth = textWidth |
|
|
const canvasHeight = textHeight + -(textHeight * 0.8) |
|
|
const image = new jimp(canvasWidth, canvasHeight, 0x075e54ff) |
|
|
const x = 5 |
|
|
const y = 5 |
|
|
image.print(font, x, y, text, textWidth, textHeight) |
|
|
image.shadow({ blur: 3, x: 6, y: 5, color: '#000000' }) |
|
|
const buffer = await image.getBufferAsync(jimp.MIME_PNG) |
|
|
return buffer |
|
|
} catch (err) { |
|
|
throw new Error(err) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function readQr(imageBuffer) { |
|
|
try { |
|
|
const image = await jimp.read(imageBuffer) |
|
|
const { data, width, height } = image.bitmap |
|
|
const code = jsQR(data, width, height) |
|
|
if (code) { |
|
|
return code.data |
|
|
} |
|
|
} catch (err) { |
|
|
throw new Error(`Error reading QR code: ${err.message}`) |
|
|
} |
|
|
return null |
|
|
} |
|
|
|
|
|
function createInteractiveMessage(data, options = {}) { |
|
|
const { jid, button, header, footer, body } = data |
|
|
let buttons = [] |
|
|
for (let i = 0; i < button.length; i++) { |
|
|
let btn = button[i] |
|
|
let Button = {} |
|
|
Button.buttonParamsJson = JSON.stringify(btn.params) |
|
|
switch (btn.type) { |
|
|
case 'copy': |
|
|
Button.name = 'cta_copy' |
|
|
break |
|
|
case 'url': |
|
|
Button.name = 'cta_url' |
|
|
break |
|
|
case 'location': |
|
|
Button.name = 'send_location' |
|
|
break |
|
|
case 'address': |
|
|
Button.name = 'address_message' |
|
|
break |
|
|
case 'call': |
|
|
Button.name = 'cta_call' |
|
|
break |
|
|
case 'reply': |
|
|
Button.name = 'quick_reply' |
|
|
break |
|
|
case 'list': |
|
|
Button.name = 'single_select' |
|
|
break |
|
|
default: |
|
|
Button.name = 'quick_reply' |
|
|
break |
|
|
} |
|
|
buttons.push(Button) |
|
|
} |
|
|
const mess = { |
|
|
viewOnceMessage: { |
|
|
message: { |
|
|
messageContextInfo: { |
|
|
deviceListMetadata: {}, |
|
|
deviceListMetadataVersion: 2, |
|
|
}, |
|
|
interactiveMessage: proto.Message.InteractiveMessage.create({ |
|
|
body: proto.Message.InteractiveMessage.Body.create({ ...body }), |
|
|
footer: proto.Message.InteractiveMessage.Footer.create({ ...footer }), |
|
|
header: proto.Message.InteractiveMessage.Header.create({ ...header }), |
|
|
nativeFlowMessage: proto.Message.InteractiveMessage.NativeFlowMessage.create({ |
|
|
buttons: buttons, |
|
|
}), |
|
|
}), |
|
|
}, |
|
|
}, |
|
|
} |
|
|
let optional = generateWAMessageFromContent(jid, mess, options) |
|
|
return optional |
|
|
} |
|
|
|
|
|
function ffmpeg(buffer, args = [], ext = '', ext2 = '') { |
|
|
return new Promise(async (resolve, reject) => { |
|
|
try { |
|
|
let tmp = path.join(tmpdir() + '/' + new Date() + '.' + ext) |
|
|
let out = tmp + '.' + ext2 |
|
|
await fs.promises.writeFile(tmp, buffer) |
|
|
const ffmpegProcess = spawn('ffmpeg', ['-y', '-i', tmp, ...args, out]) |
|
|
.on('error', reject) |
|
|
.on('close', async (code) => { |
|
|
try { |
|
|
await fs.promises.unlink(tmp) |
|
|
if (code !== 0) { |
|
|
reject(new Error(`FFmpeg process exited with code ${code}`)) |
|
|
return |
|
|
} |
|
|
const processedData = await fs.promises.readFile(out) |
|
|
await fs.promises.unlink(out) |
|
|
resolve(processedData) |
|
|
} catch (e) { |
|
|
reject(e) |
|
|
} |
|
|
}) |
|
|
} catch (e) { |
|
|
reject(e) |
|
|
} |
|
|
}) |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toAudio(buffer, ext) { |
|
|
return ffmpeg(buffer, ['-vn', '-ac', '2', '-b:a', '128k', '-ar', '44100', '-f', 'mp3'], ext, 'mp3') |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toPTT(buffer, ext) { |
|
|
return ffmpeg(buffer, ['-vn', '-c:a', 'libopus', '-b:a', '128k', '-vbr', 'on', '-compression_level', '10'], ext, 'opus') |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function toVideo(buffer, ext) { |
|
|
return ffmpeg(buffer, ['-c:v', 'libx264', '-c:a', 'aac', '-ab', '128k', '-ar', '44100', '-crf', '32', '-preset', 'slow'], ext, 'mp4') |
|
|
} |
|
|
|
|
|
async function getBuffer(url, options = {}) { |
|
|
try { |
|
|
const res = await axios({ |
|
|
method: 'get', |
|
|
url, |
|
|
headers: { |
|
|
DNT: 1, |
|
|
'Upgrade-Insecure-Request': 1, |
|
|
}, |
|
|
...options, |
|
|
responseType: 'arraybuffer', |
|
|
}) |
|
|
return res.data |
|
|
} catch (error) { |
|
|
throw new Error(`Error: ${error.message}`) |
|
|
} |
|
|
} |
|
|
const decodeJid = (jid) => { |
|
|
if (!jid) return jid |
|
|
if (/:\d+@/gi.test(jid)) { |
|
|
const decode = jidDecode(jid) || {} |
|
|
return decode.user && decode.server ? `${decode.user}@${decode.server}` : jid |
|
|
} else { |
|
|
return jid |
|
|
} |
|
|
} |
|
|
async function FiletypeFromUrl(url) { |
|
|
const buffer = await getBuffer(url) |
|
|
const out = await fromBuffer(buffer) |
|
|
let type |
|
|
if (out) { |
|
|
type = out.mime.split('/')[0] |
|
|
} |
|
|
return { type, buffer } |
|
|
} |
|
|
function extractUrlFromMessage(message) { |
|
|
const urlRegex = /(https?:\/\/[^\s]+)/gi |
|
|
const match = urlRegex.exec(message) |
|
|
return match ? match[0] : null |
|
|
} |
|
|
|
|
|
const removeCommand = async (name) => { |
|
|
return new Promise((resolve, reject) => { |
|
|
commands.map(async (command, index) => { |
|
|
if (command.pattern !== undefined && command.pattern.test(new RegExp(`${config.HANDLERS}( ?${name})`, 'is'))) { |
|
|
commands.splice(index, 1) |
|
|
return resolve(true) |
|
|
} |
|
|
}) |
|
|
resolve(false) |
|
|
}) |
|
|
} |
|
|
async function igdl(igurl) { |
|
|
const data = `q=${encodeURIComponent(igurl)}&t=media&lang=en` |
|
|
const config = { |
|
|
method: 'post', |
|
|
maxBodyLength: Infinity, |
|
|
url: 'https://v3.saveig.app/api/ajaxSearch', |
|
|
headers: { |
|
|
Accept: '/', |
|
|
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', |
|
|
}, |
|
|
data: data, |
|
|
} |
|
|
|
|
|
const response = await axios.request(config) |
|
|
const html = response.data.data |
|
|
|
|
|
const $ = cheerio.load(html, { decodeEntities: true }) |
|
|
const downloadItems = $('.download-items') |
|
|
const result = [] |
|
|
|
|
|
downloadItems.each((index, element) => { |
|
|
let url = $(element).find('.download-items__btn > a').attr('href') |
|
|
if (url.includes('file')) { |
|
|
let newUrl = new URL(url) |
|
|
let encodedUrl = newUrl.searchParams.get('file') |
|
|
let decodedUrl = Buffer.from(encodedUrl, 'base64').toString('utf-8') |
|
|
result.push(decodedUrl) |
|
|
} else { |
|
|
result.push(url) |
|
|
} |
|
|
}) |
|
|
|
|
|
return result |
|
|
} |
|
|
|
|
|
function aiImage(prompt) { |
|
|
return new Promise((resolve, reject) => { |
|
|
axios |
|
|
.post( |
|
|
'https://socket.xasena.me/generate-image', |
|
|
{ |
|
|
prompt: prompt, |
|
|
}, |
|
|
{ |
|
|
headers: { |
|
|
Accept: '*/*', |
|
|
'User-Agent': 'Thunder Client (https://www.thunderclient.com)', |
|
|
'Content-Type': 'application/json', |
|
|
}, |
|
|
responseType: 'arraybuffer', |
|
|
} |
|
|
) |
|
|
.then(function (response) { |
|
|
if (response.status === 400) { |
|
|
resolve(response.data) |
|
|
} else { |
|
|
resolve(Buffer.from(response.data, 'binary')) |
|
|
} |
|
|
}) |
|
|
.catch(function (error) { |
|
|
reject(error) |
|
|
}) |
|
|
}) |
|
|
} |
|
|
|
|
|
async function getJson(url, options) { |
|
|
try { |
|
|
options ? options : {} |
|
|
const res = await axios({ |
|
|
method: 'GET', |
|
|
url: url, |
|
|
headers: { |
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36', |
|
|
}, |
|
|
...options, |
|
|
}) |
|
|
return res.data |
|
|
} catch (err) { |
|
|
return err |
|
|
} |
|
|
} |
|
|
|
|
|
const API_KEY = 'e6d0cd0023b7ee562a97be33d3c5f524' |
|
|
const BASE_URL = 'https://api.musixmatch.com/ws/1.1/' |
|
|
|
|
|
async function getLyrics(song, artist) { |
|
|
try { |
|
|
const searchUrl = `${BASE_URL}track.search?q_track=${encodeURIComponent(song)}&q_artist=${encodeURIComponent(artist)}&f_has_lyrics=1&apikey=${API_KEY}` |
|
|
const searchData = await getJson(searchUrl) |
|
|
const trackList = searchData.message.body.track_list |
|
|
|
|
|
let trackId = null |
|
|
if (trackList.length > 0) { |
|
|
trackId = trackList[0].track.track_id |
|
|
} else { |
|
|
const allTracksUrl = `${BASE_URL}track.search?q_artist=${encodeURIComponent(artist)}&apikey=${API_KEY}` |
|
|
const allTracksData = await getJson(allTracksUrl) |
|
|
const allTracks = allTracksData.message.body.track_list |
|
|
if (allTracks.length > 0) { |
|
|
trackId = allTracks[0].track.track_id |
|
|
} |
|
|
} |
|
|
|
|
|
if (trackId) { |
|
|
const lyricsUrl = `${BASE_URL}track.lyrics.get?track_id=${trackId}&apikey=${API_KEY}` |
|
|
const lyricsData = await getJson(lyricsUrl) |
|
|
let lyrics = lyricsData.message.body.lyrics.lyrics_body |
|
|
const disclaimer = '********************** This Lyrics is NOT for Commercial use **********************' |
|
|
lyrics = lyrics.replace(disclaimer, '') |
|
|
return { |
|
|
artist_name: artist, |
|
|
song, |
|
|
lyrics: lyrics.replace(/\(\d+\)$/, ''), |
|
|
} |
|
|
} |
|
|
} catch (error) { |
|
|
console.error('Error:', error) |
|
|
throw error |
|
|
} |
|
|
|
|
|
return null |
|
|
} |
|
|
|
|
|
module.exports = { |
|
|
parseTimeToSeconds: (timeString) => { |
|
|
const [minutes, seconds] = timeString.split(':').map(Number) |
|
|
return minutes * 60 + seconds |
|
|
}, |
|
|
toAudio, |
|
|
toPTT, |
|
|
toVideo, |
|
|
ffmpeg, |
|
|
|
|
|
removeBg, |
|
|
FiletypeFromUrl, |
|
|
removeCommand, |
|
|
getBuffer, |
|
|
extractUrlFromMessage, |
|
|
decodeJid, |
|
|
isAdmin: async (jid, user, client) => { |
|
|
const groupMetadata = await client.groupMetadata(jid) |
|
|
const groupAdmins = groupMetadata.participants.filter((participant) => participant.admin !== null).map((participant) => participant.id) |
|
|
|
|
|
return groupAdmins.includes(decodeJid(user)) |
|
|
}, |
|
|
webp2mp4: async (source) => { |
|
|
let form = new FormData() |
|
|
let isUrl = typeof source === 'string' && /https?:\/\//.test(source) |
|
|
form.append('new-image-url', isUrl ? source : '') |
|
|
form.append('new-image', isUrl ? '' : source, 'image.webp') |
|
|
let res = await fetch('https://ezgif.com/webp-to-mp4', { |
|
|
method: 'POST', |
|
|
body: form, |
|
|
}) |
|
|
let html = await res.text() |
|
|
let { document } = new JSDOM(html).window |
|
|
let form2 = new FormData() |
|
|
let obj = {} |
|
|
for (let input of document.querySelectorAll('form input[name]')) { |
|
|
obj[input.name] = input.value |
|
|
form2.append(input.name, input.value) |
|
|
} |
|
|
let res2 = await fetch('https://ezgif.com/webp-to-mp4/' + obj.file, { |
|
|
method: 'POST', |
|
|
body: form2, |
|
|
}) |
|
|
let html2 = await res2.text() |
|
|
let { document: document2 } = new JSDOM(html2).window |
|
|
return new URL(document2.querySelector('div#output > p.outfile > video > source').src, res2.url).toString() |
|
|
}, |
|
|
validatAndSaveDeleted, |
|
|
webp2png: async (source) => { |
|
|
let form = new FormData() |
|
|
let isUrl = typeof source === 'string' && /https?:\/\//.test(source) |
|
|
form.append('new-image-url', isUrl ? source : '') |
|
|
form.append('new-image', isUrl ? '' : source, 'image.webp') |
|
|
let res = await fetch('https://s6.ezgif.com/webp-to-png', { |
|
|
method: 'POST', |
|
|
body: form, |
|
|
}) |
|
|
let html = await res.text() |
|
|
let { document } = new JSDOM(html).window |
|
|
let form2 = new FormData() |
|
|
let obj = {} |
|
|
for (let input of document.querySelectorAll('form input[name]')) { |
|
|
obj[input.name] = input.value |
|
|
form2.append(input.name, input.value) |
|
|
} |
|
|
let res2 = await fetch('https://ezgif.com/webp-to-png/' + obj.file, { |
|
|
method: 'POST', |
|
|
body: form2, |
|
|
}) |
|
|
let html2 = await res2.text() |
|
|
console.log(html2) |
|
|
let { document: document2 } = new JSDOM(html2).window |
|
|
return new URL(document2.querySelector('div#output > p.outfile > img').src, res2.url).toString() |
|
|
}, |
|
|
parseJid(text = '') { |
|
|
return [...text.matchAll(/@([0-9]{5,16}|0)/g)].map((v) => v[1] + '@s.whatsapp.net') |
|
|
}, |
|
|
parsedJid(text = '') { |
|
|
return [...text.matchAll(/([0-9]{5,16}|0)/g)].map((v) => v[1] + '@s.whatsapp.net') |
|
|
}, |
|
|
getLyrics, |
|
|
getJson, |
|
|
isIgUrl: (url) => { |
|
|
return /(?:(?:http|https):\/\/)?(?:www.)?(?:instagram.com|instagr.am|instagr.com)\/(\w+)/gim.test(url) |
|
|
}, |
|
|
isUrl: (isUrl = (url) => { |
|
|
return new RegExp(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)/, 'gi').test(url) |
|
|
}), |
|
|
getUrl: (getUrl = (url) => { |
|
|
return url.match(new RegExp(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&/=]*)/, 'gi')) |
|
|
}), |
|
|
qrcode: async (string) => { |
|
|
const { toBuffer } = require('qrcode') |
|
|
let buff = await toBuffer(string) |
|
|
return buff |
|
|
}, |
|
|
aiImage, |
|
|
secondsToDHMS: (seconds) => { |
|
|
seconds = Number(seconds) |
|
|
|
|
|
const days = Math.floor(seconds / (3600 * 24)) |
|
|
seconds %= 3600 * 24 |
|
|
|
|
|
const hours = Math.floor(seconds / 3600) |
|
|
seconds %= 3600 |
|
|
|
|
|
const minutes = Math.floor(seconds / 60) |
|
|
seconds %= 60 |
|
|
|
|
|
seconds = Math.floor(seconds) |
|
|
|
|
|
const parts = [] |
|
|
|
|
|
if (days) parts.push(`${days} Days`) |
|
|
if (hours) parts.push(`${hours} Hours`) |
|
|
if (minutes) parts.push(`${minutes} Minutes`) |
|
|
if (seconds) parts.push(`${seconds} Seconds`) |
|
|
return parts.join(' ') |
|
|
}, |
|
|
formatBytes: (bytes, decimals = 2) => { |
|
|
if (!+bytes) return '0 Bytes' |
|
|
|
|
|
const k = 1024 |
|
|
const dm = decimals < 0 ? 0 : decimals |
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] |
|
|
|
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k)) |
|
|
|
|
|
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}` |
|
|
}, |
|
|
sleep: delay, |
|
|
clockString: (duration) => { |
|
|
;(seconds = Math.floor((duration / 1000) % 60)), (minutes = Math.floor((duration / (1000 * 60)) % 60)), (hours = Math.floor((duration / (1000 * 60 * 60)) % 24)) |
|
|
|
|
|
hours = hours < 10 ? '0' + hours : hours |
|
|
minutes = minutes < 10 ? '0' + minutes : minutes |
|
|
seconds = seconds < 10 ? '0' + seconds : seconds |
|
|
|
|
|
return hours + ':' + minutes + ':' + seconds |
|
|
}, |
|
|
runtime: () => { |
|
|
const duration = process.uptime() |
|
|
const seconds = Math.floor(duration % 60) |
|
|
const minutes = Math.floor((duration / 60) % 60) |
|
|
const hours = Math.floor((duration / (60 * 60)) % 24) |
|
|
|
|
|
const formattedTime = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}` |
|
|
|
|
|
return formattedTime |
|
|
}, |
|
|
validateQuality: (quality) => { |
|
|
let valid = ['144p', '240p', '360p', '480p', '720p', '1080p'] |
|
|
return valid.includes(quality) |
|
|
}, |
|
|
AddMp3Meta: async (songbuffer, coverBuffer, options = { title: 'X-Asena Whatsapp bot', artist: ['Xasena'] }) => { |
|
|
if (!Buffer.isBuffer(songbuffer)) { |
|
|
songbuffer = await getBuffer(songbuffer) |
|
|
} |
|
|
if (!Buffer.isBuffer(coverBuffer)) { |
|
|
coverBuffer = await getBuffer(coverBuffer) |
|
|
} |
|
|
|
|
|
const writer = new id3(songbuffer) |
|
|
writer.setFrame('TIT2', options.title).setFrame('TPE1', ['X-Asena']).setFrame('APIC', { |
|
|
type: 3, |
|
|
data: coverBuffer, |
|
|
description: 'Xasena', |
|
|
}) |
|
|
|
|
|
writer.addTag() |
|
|
return Buffer.from(writer.arrayBuffer) |
|
|
}, |
|
|
Bitly: async (url) => { |
|
|
return new Promise((resolve, reject) => { |
|
|
const BitlyClient = require('bitly').BitlyClient |
|
|
const bitly = new BitlyClient('6e7f70590d87253af9359ed38ef81b1e26af70fd') |
|
|
bitly |
|
|
.shorten(url) |
|
|
.then((a) => { |
|
|
resolve(a) |
|
|
}) |
|
|
.catch((A) => reject(A)) |
|
|
return |
|
|
}) |
|
|
}, |
|
|
isNumber: function isNumber() { |
|
|
const int = parseInt(this) |
|
|
return typeof int === 'number' && !isNaN(int) |
|
|
}, |
|
|
getRandom: function getRandom() { |
|
|
if (Array.isArray(this) || this instanceof String) return this[Math.floor(Math.random() * this.length)] |
|
|
return Math.floor(Math.random() * this) |
|
|
}, |
|
|
createInteractiveMessage, |
|
|
igdl, |
|
|
textToImg, |
|
|
readQr, |
|
|
m3u82Mp4, |
|
|
captureScreenshot, |
|
|
editAudio, |
|
|
} |
|
|
|