remove embedded plugins - now managed via manyplug

This commit is contained in:
synt-xerror
2026-04-21 11:18:19 -03:00
parent 3c767bb14b
commit 18821dd951
9 changed files with 0 additions and 758 deletions

View File

@@ -1,9 +0,0 @@
import { forcaAtiva } from "../forca/index.js";
export default async function ({ msg }) {
if (msg.body.trim().toLowerCase() !== "a") return;
if (msg.args.length > 1) return;
if (forcaAtiva) return;
await msg.reply("B!");
}

View File

@@ -1,79 +0,0 @@
/**
* plugins/adivinhacao/index.js
*
* Estado dos jogos fica aqui dentro — isolado no plugin.
* Múltiplos grupos jogam simultaneamente sem conflito.
*/
const RANGE = { min: 1, max: 100 };
const jogosAtivos = new Map();
import { CMD_PREFIX } from "../../config.js"
const sorteio = () =>
Math.floor(Math.random() * (RANGE.max - RANGE.min + 1)) + RANGE.min;
export default async function ({ msg, api }) {
const chatId = api.chat.id;
// ── Comando adivinhação ──────────────────────────────────
if (msg.is(CMD_PREFIX + "adivinhação")) {
const sub = msg.args[1];
if (!sub) {
await api.send(
"🎮 *Jogo de adivinhação:*\n\n" +
`\`${CMD_PREFIX}adivinhação começar\` — inicia o jogo\n` +
`\`${CMD_PREFIX}adivinhação parar\` — encerra o jogo`
);
return;
}
if (sub === "começar") {
jogosAtivos.set(chatId, sorteio());
await api.send(
"🎮 *Jogo iniciado!*\n\n" +
"Estou pensando em um número de 1 a 100.\n" +
"Tente adivinhar! 🤔"
);
api.log.info(CMD_PREFIX + "adivinhação — jogo iniciado");
return;
}
if (sub === "parar") {
jogosAtivos.delete(chatId);
await api.send("🛑 Jogo encerrado.");
api.log.info(CMD_PREFIX + "adivinhação — jogo parado");
return;
}
await api.send(
`❌ Subcomando *${sub}* não existe.\n\n` +
`Use ${CMD_PREFIX} + \`adivinhação começar\` ou ${CMD_PREFIX} + \`adivinhação parar\`.`
);
return;
}
// ── Tentativas durante o jogo ─────────────────────────────
const numero = jogosAtivos.get(chatId);
if (numero === undefined) return;
const tentativa = msg.body.trim();
if (!/^\d+$/.test(tentativa)) return;
const num = parseInt(tentativa, 10);
if (num < RANGE.min || num > RANGE.max) {
await msg.reply(`⚠️ Digite um número entre ${RANGE.min} e ${RANGE.max}.`);
return;
}
if (num === numero) {
await msg.reply(
`🎉 *Acertou!* O número era ${numero}!\n\n` +
`Use ${CMD_PREFIX} + \`adivinhação começar\` para jogar de novo.`
);
jogosAtivos.delete(chatId);
} else {
await api.send(num > numero ? "📉 Tente um número *menor*!" : "📈 Tente um número *maior*!");
}
}

View File

@@ -1,123 +0,0 @@
/**
* plugins/audio/index.js
*
* Baixa vídeo via yt-dlp, converte para mp3 via ffmpeg e envia no chat.
* Todo o processo (download + conversão + envio + limpeza) fica aqui.
*/
import { spawn } from "child_process";
import { execFile } from "child_process";
import { promisify } from "util";
import fs from "fs";
import path from "path";
import os from "os";
import { enqueue } from "../../download/queue.js";
import { emptyFolder } from "../../utils/file.js";
import { CMD_PREFIX } from "../../config.js";
const logStream = fs.createWriteStream("logs/audio-error.log", { flags: "a" });
const execFileAsync = promisify(execFile);
const DOWNLOADS_DIR = path.resolve("downloads");
const YT_DLP = os.platform() === "win32" ? ".\\bin\\yt-dlp.exe" : "./bin/yt-dlp";
const FFMPEG = os.platform() === "win32" ? ".\\bin\\ffmpeg.exe" : "./bin/ffmpeg";
const ARGS_BASE = [
"--extractor-args", "youtube:player_client=android",
"--print", "after_move:filepath",
"--cookies", "cookies.txt",
"--add-header", "User-Agent:Mozilla/5.0",
"--add-header", "Referer:https://www.youtube.com/",
"--retries", "4",
"--fragment-retries", "5",
"--socket-timeout", "15",
"--sleep-interval", "1",
"--max-sleep-interval", "4",
"--no-playlist",
"-f", "bv+ba/best",
];
function downloadRaw(url, id) {
return new Promise((resolve, reject) => {
fs.mkdirSync(DOWNLOADS_DIR, { recursive: true });
const output = path.join(DOWNLOADS_DIR, `${id}.%(ext)s`);
const proc = spawn(YT_DLP, [...ARGS_BASE, "--output", output, url]);
let stdout = "";
proc.on("error", err => reject(new Error(
err.code === "EACCES"
? "Sem permissão para executar o yt-dlp. Rode: chmod +x ./bin/yt-dlp"
: err.code === "ENOENT"
? "yt-dlp não encontrado em ./bin/yt-dlp"
: `Erro ao iniciar o yt-dlp: ${err.message}`
)));
proc.stdout.on("data", d => { stdout += d.toString(); });
proc.stderr.on("data", d => logStream.write(d));
proc.on("close", code => {
if (code !== 0) return reject(new Error(
"Não foi possível baixar o áudio. Verifique se o link é válido e tente novamente."
));
const filePath = stdout.trim().split("\n").filter(Boolean).at(-1);
if (!filePath || !fs.existsSync(filePath)) return reject(new Error(
"Download concluído mas arquivo não encontrado. Tente novamente."
));
resolve(filePath);
});
});
}
async function convertToMp3(videoPath, id) {
const mp3Path = path.join(DOWNLOADS_DIR, `${id}.mp3`);
await execFileAsync(FFMPEG, [
"-i", videoPath,
"-vn", // sem vídeo
"-ar", "44100", // sample rate
"-ac", "2", // stereo
"-b:a", "192k", // bitrate
"-y", // sobrescreve se existir
mp3Path,
]);
fs.unlinkSync(videoPath); // remove o vídeo intermediário
return mp3Path;
}
export default async function ({ msg, api }) {
if (!msg.is(CMD_PREFIX + "audio")) return;
const url = msg.args[1];
if (!url) {
await msg.reply(`❌ Você precisa informar um link.\n\nExemplo: \`${CMD_PREFIX}audio https://youtube.com/...\``);
return;
}
await msg.reply("⏳ Baixando o áudio, aguarde...");
const id = `audio-${Date.now()}`;
enqueue(
async () => {
const videoPath = await downloadRaw(url, id);
const mp3Path = await convertToMp3(videoPath, id);
await api.sendAudio(mp3Path);
fs.unlinkSync(mp3Path);
emptyFolder(DOWNLOADS_DIR);
api.log.info(`${CMD_PREFIX}audio concluído → ${url}`);
},
async () => {
await msg.reply(
"❌ Não consegui baixar o áudio.\n\n" +
"Verifique se o link é válido e tente novamente.\n" +
"Se o problema persistir, o conteúdo pode estar indisponível ou protegido."
);
}
);
}

View File

@@ -1,247 +0,0 @@
/**
* plugins/figurinha/index.js
*
* Modos de uso:
* comando + mídia anexa → cria 1 sticker direto
* comando + respondendo mídia → cria 1 sticker direto
* comando + mídia anexa + respondendo mídia → cria 2 stickers direto
* comando (sem mídia nenhuma) → abre sessão
* comando criar (com sessão aberta) → processa as mídias da sessão
*/
import fs from "fs";
import path from "path";
import os from "os";
import { execFile } from "child_process";
import { promisify } from "util";
import { createSticker } from "wa-sticker-formatter";
import { emptyFolder } from "../../utils/file.js";
import { CMD_PREFIX } from "../../config.js";
const execFileAsync = promisify(execFile);
// ── Constantes ────────────────────────────────────────────────
const DOWNLOADS_DIR = path.resolve("downloads");
const FFMPEG = os.platform() === "win32" ? ".\\bin\\ffmpeg.exe" : "./bin/ffmpeg";
const MAX_STICKER_SIZE = 900 * 1024;
const SESSION_TIMEOUT = 2 * 60 * 1000;
const MAX_MEDIA = 30;
const HELP =
"📌 *Como criar figurinhas:*\n\n" +
`1⃣ Envie \`${CMD_PREFIX}figurinha\` junto com uma mídia, ou respondendo uma mídia\n` +
" — o sticker é criado na hora\n\n" +
"2⃣ Ou use o modo sessão para várias mídias de uma vez:\n" +
`\`${CMD_PREFIX}figurinha\` sem mídia para iniciar\n` +
" — envie as imagens, GIFs ou vídeos\n" +
`\`${CMD_PREFIX}figurinha criar\` para gerar todas\n\n` +
"⏳ A sessão expira em 2 minutos se nenhuma mídia for enviada.";
// ── Estado interno ────────────────────────────────────────────
// { chatId → { author, medias[], timeout } }
const sessions = new Map();
// ── Conversão ─────────────────────────────────────────────────
function ensureDir() {
fs.mkdirSync(DOWNLOADS_DIR, { recursive: true });
}
function cleanup(...files) {
for (const f of files) {
try { if (f && fs.existsSync(f)) fs.unlinkSync(f); } catch { }
}
}
async function convertToGif(input, output, fps = 12) {
const filter = [
`fps=${Math.min(fps, 12)},scale=512:512:flags=lanczos,split[s0][s1]`,
`[s0]palettegen=max_colors=256:reserve_transparent=1[p]`,
`[s1][p]paletteuse=dither=bayer`,
].join(";");
await execFileAsync(FFMPEG, ["-i", input, "-filter_complex", filter, "-loop", "0", "-y", output]);
}
async function resizeImage(input, output) {
await execFileAsync(FFMPEG, ["-i", input, "-vf", "scale=512:512:flags=lanczos", "-y", output]);
}
async function buildSticker(inputPath, isAnimated) {
for (const quality of [80, 60, 40, 20]) {
const buf = await createSticker(fs.readFileSync(inputPath), {
pack: "Criada por ManyBot\n",
author: "\ngithub.com/synt-xerror/manybot",
type: isAnimated ? "FULL" : "STATIC",
categories: ["🤖"],
quality,
});
if (buf.length <= MAX_STICKER_SIZE) return buf;
}
throw new Error("Não foi possível reduzir o sticker para menos de 900 KB.");
}
/**
* Converte um objeto { mimetype, data } em sticker e envia.
* Retorna true se ok, false se falhou.
*/
async function processarUmaMedia(media, isGif, api, msg) {
ensureDir();
const ext = media.mimetype.split("/")[1];
const isVideo = media.mimetype.startsWith("video/");
const isAnimated = isVideo || isGif;
const id = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
const inputPath = path.join(DOWNLOADS_DIR, `${id}.${ext}`);
const gifPath = path.join(DOWNLOADS_DIR, `${id}.gif`);
const resizedPath = path.join(DOWNLOADS_DIR, `${id}-scaled.${ext}`);
try {
fs.writeFileSync(inputPath, Buffer.from(media.data, "base64"));
let stickerInput;
if (isAnimated) {
await convertToGif(inputPath, gifPath, isVideo ? 12 : 24);
stickerInput = gifPath;
} else {
await resizeImage(inputPath, resizedPath);
stickerInput = resizedPath;
}
const buf = await buildSticker(stickerInput, isAnimated);
await api.sendSticker(buf);
return true;
} catch (err) {
api.log.error(`Erro ao gerar sticker: ${err.message}`);
await msg.reply(
"⚠️ Não consegui criar uma das figurinhas.\n" +
"Tente reenviar essa mídia ou use outro formato (JPG, PNG, GIF, MP4)."
);
return false;
} finally {
cleanup(inputPath, gifPath, resizedPath);
}
}
/**
* Verifica se uma mídia é suportada para sticker.
*/
function isSupported(media, isGif) {
return (
media.mimetype?.startsWith("image/") ||
media.mimetype?.startsWith("video/") ||
isGif
);
}
// ── Plugin ────────────────────────────────────────────────────
export default async function ({ msg, api }) {
const chatId = api.chat.id;
if (!msg.is(CMD_PREFIX + "figurinha")) {
// ── Coleta de mídia durante sessão ──────────────────────
const session = sessions.get(chatId);
if (!session) return;
if (!msg.hasMedia) return;
if (msg.sender !== session.author) return;
const media = await msg.downloadMedia();
if (!media) return;
const gif = media.mimetype === "image/gif" ||
(media.mimetype === "video/mp4" && msg.isGif);
if (isSupported(media, gif) && session.medias.length < MAX_MEDIA) {
session.medias.push({ media, isGif: gif });
}
return;
}
// ── figurinha criar ──────────────────────────────────────
const sub = msg.args[1];
if (sub === "criar") {
const session = sessions.get(chatId);
if (!session) {
await msg.reply(`❌ *Nenhuma sessão ativa.*\n\n${HELP}`);
return;
}
if (!session.medias.length) {
await msg.reply(`📭 *Você ainda não enviou nenhuma mídia!*\n\n${HELP}`);
return;
}
clearTimeout(session.timeout);
await msg.reply("⏳ Gerando suas figurinhas, aguarde um momento...");
for (const { media, isGif } of session.medias) {
await processarUmaMedia(media, isGif, api, msg);
}
await msg.reply("✅ *Figurinhas criadas com sucesso!*\nSalve as que quiser no seu WhatsApp. 😄");
sessions.delete(chatId);
emptyFolder(DOWNLOADS_DIR);
return;
}
// ── figurinha com mídia direta ───────────────────────────
const mediasParaCriar = [];
// Mídia anexa à própria mensagem
if (msg.hasMedia) {
const media = await msg.downloadMedia();
if (media) {
const gif = media.mimetype === "image/gif" ||
(media.mimetype === "video/mp4" && msg.isGif);
if (isSupported(media, gif)) mediasParaCriar.push({ media, isGif: gif });
}
}
// Mídia da mensagem citada
if (msg.hasReply) {
const quoted = await msg.getReply();
if (quoted?.hasMedia) {
const media = await quoted.downloadMedia();
if (media) {
const gif = media.mimetype === "image/gif" ||
(media.mimetype === "video/mp4" && quoted.isGif);
if (isSupported(media, gif)) mediasParaCriar.push({ media, isGif: gif });
}
}
}
// Tem mídia para criar direto
if (mediasParaCriar.length > 0) {
await msg.reply("⏳ Gerando figurinha, aguarde...");
for (const { media, isGif } of mediasParaCriar) {
await processarUmaMedia(media, isGif, api, msg);
}
emptyFolder(DOWNLOADS_DIR);
return;
}
// ── figurinha sem mídia → abre sessão ───────────────────
if (sessions.has(chatId)) {
await msg.reply(
"⚠️ Já existe uma sessão aberta.\n\n" +
`Envie as mídias e depois use \`${CMD_PREFIX}figurinha criar\`.\n` +
"Ou aguarde 2 minutos para a sessão expirar."
);
return;
}
const timeout = setTimeout(async () => {
sessions.delete(chatId);
try {
await msg.reply(
"⏰ *Sessão expirada!*\n\n" +
"Você demorou mais de 2 minutos para enviar as mídias.\n" +
`Digite \`${CMD_PREFIX}figurinha\` para começar de novo.`
);
} catch { }
}, SESSION_TIMEOUT);
sessions.set(chatId, { author: msg.sender, medias: [], timeout });
await msg.reply(`✅ Sessão iniciada por *${msg.senderName}*!\n\n${HELP}`);
}

View File

@@ -1,159 +0,0 @@
/**
* plugins/forca/index.js
*
* Estado dos jogos de forca fica aqui dentro — isolado no plugin.
* Múltiplos grupos jogam simultaneamente sem conflito.
*/
import { CMD_PREFIX } from "../../config.js";
// Estados dos jogos
const jogosAtivos = new Map(); // chatId -> { palavra, tema, vidas, progresso }
const participantesAtivos = new Map(); // chatId -> Set de usuários que reagiram
export let forcaAtiva = false;
// Palavras de exemplo
const PALAVRAS = [
{ palavra: "python", tema: "Linguagem de programação" },
{ palavra: "javascript", tema: "Linguagem de programação" },
{ palavra: "java", tema: "Linguagem de programação" },
{ palavra: "cachorro", tema: "Animal" },
{ palavra: "gato", tema: "Animal" },
{ palavra: "elefante", tema: "Animal" },
{ palavra: "girafa", tema: "Animal" },
{ palavra: "guitarra", tema: "Instrumento musical" },
{ palavra: "piano", tema: "Instrumento musical" },
{ palavra: "bateria", tema: "Instrumento musical" },
{ palavra: "violino", tema: "Instrumento musical" },
{ palavra: "futebol", tema: "Esporte" },
{ palavra: "basquete", tema: "Esporte" },
{ palavra: "natação", tema: "Esporte" },
{ palavra: "tênis", tema: "Esporte" },
{ palavra: "brasil", tema: "País" },
{ palavra: "japão", tema: "País" },
{ palavra: "canadá", tema: "País" },
{ palavra: "frança", tema: "País" },
{ palavra: "marte", tema: "Planeta" },
{ palavra: "vênus", tema: "Planeta" },
{ palavra: "júpiter", tema: "Planeta" },
{ palavra: "saturno", tema: "Planeta" },
{ palavra: "minecraft", tema: "Jogo" },
{ palavra: "fortnite", tema: "Jogo" },
{ palavra: "roblox", tema: "Jogo" },
{ palavra: "amongus", tema: "Jogo" },
{ palavra: "rosa", tema: "Flor" },
{ palavra: "girassol", tema: "Flor" },
{ palavra: "tulipa", tema: "Flor" },
{ palavra: "orquídea", tema: "Flor" },
{ palavra: "tesoura", tema: "Objeto" },
{ palavra: "caderno", tema: "Objeto" },
{ palavra: "computador", tema: "Objeto" },
{ palavra: "telefone", tema: "Objeto" },
{ palavra: "lua", tema: "Corpo celeste" },
{ palavra: "sol", tema: "Corpo celeste" },
{ palavra: "estrela", tema: "Corpo celeste" },
{ palavra: "cometa", tema: "Corpo celeste" },
{ palavra: "oceano", tema: "Natureza" },
{ palavra: "montanha", tema: "Natureza" },
];
// Função para gerar a palavra com underscores
const gerarProgresso = palavra =>
palavra.replace(/[a-zA-Z]/g, "_");
export default async function ({ msg, api }) {
const chatId = api.chat.id;
const sub = msg.args[1];
// ── Comando principal do jogo
if (msg.is(CMD_PREFIX + "forca")) {
if (!sub) {
await api.send(
`🎮 *Jogo da Forca*\n\n` +
`\`${CMD_PREFIX}forca começar\` — inicia o jogo\n` +
`\`${CMD_PREFIX}forca parar\` — encerra o jogo`
);
return;
}
if (sub === "começar") {
forcaAtiva = true;
// Pega uma palavra aleatória
const sorteio = PALAVRAS[Math.floor(Math.random() * PALAVRAS.length)];
// Inicializa o jogo
jogosAtivos.set(chatId, {
palavra: sorteio.palavra.toLowerCase(),
tema: sorteio.tema,
vidas: 6,
progresso: gerarProgresso(sorteio.palavra)
});
participantesAtivos.set(chatId, new Set()); // reset participantes
await api.send(
`🎮 *Jogo da Forca iniciado!*\n\n` +
`Tema: *${sorteio.tema}*\n` +
`Palavra: \`${gerarProgresso(sorteio.palavra)}\`\n` +
`Vidas: 6\n\n` +
`Digite uma letra para adivinhar!`
);
return;
}
if (sub === "parar") {
jogosAtivos.delete(chatId);
participantesAtivos.delete(chatId);
await api.send("🛑 Jogo da Forca encerrado.");
return;
}
await api.send(
`❌ Subcomando *${sub}* não existe.\n` +
`Use ${CMD_PREFIX} + \`forca começar\` ou ${CMD_PREFIX} + \`forca parar\`.`
);
return;
}
// ── Tentativas durante o jogo
const jogo = jogosAtivos.get(chatId);
if (!jogo) return; // Nenhum jogo ativo
const tentativa = msg.body.trim().toLowerCase();
if (!/^[a-z]$/.test(tentativa)) return; // apenas letras simples
// Se a letra está na palavra
let acerto = false;
let novoProgresso = jogo.progresso.split("");
for (let i = 0; i < jogo.palavra.length; i++) {
if (jogo.palavra[i] === tentativa) {
novoProgresso[i] = tentativa;
acerto = true;
}
}
jogo.progresso = novoProgresso.join("");
if (!acerto) jogo.vidas--;
// Feedback para o grupo
if (jogo.progresso === jogo.palavra) {
await msg.reply(`🎉 Parabéns! Palavra completa: \`${jogo.palavra}\``);
jogosAtivos.delete(chatId);
participantesAtivos.delete(chatId);
return;
}
if (jogo.vidas <= 0) {
await msg.reply(`💀 Fim de jogo! Palavra era: \`${jogo.palavra}\``);
jogosAtivos.delete(chatId);
participantesAtivos.delete(chatId);
return;
}
await msg.reply(
`Palavra: \`${jogo.progresso}\`\n` +
`Vidas: ${jogo.vidas}\n` +
(acerto ? "✅ Acertou a letra!" : "❌ Errou a letra!")
);
}

View File

@@ -1,14 +0,0 @@
import { CMD_PREFIX } from "../../config.js"
export default async function ({ msg, api }) {
if (!msg.is(CMD_PREFIX + "many")) return;
await api.send(
`🤖 *ManyBot — Comandos disponíveis:*\n\n` +
`🎬 \`${CMD_PREFIX}video <link>\` — baixa um vídeo\n` +
`🎵 \`${CMD_PREFIX}audio <link>\` — baixa um áudio\n` +
`🖼️ \`${CMD_PREFIX}figurinha\` — cria figurinhas\n` +
`🎮 \`${CMD_PREFIX}adivinhação começar|parar\` — jogo de adivinhar número\n` +
`🎮 \`${CMD_PREFIX}forca começar|parar\` — jogo da forca\n`
);
}

View File

@@ -1,8 +0,0 @@
import { CMD_PREFIX } from "../../config.js";
const gatilhos = ["obrigado", "valeu", "brigado"];
export default async function ({ msg }) {
if (!gatilhos.some(g => msg.is(CMD_PREFIX + g))) return;
await msg.reply("😊 Por nada!");
}

View File

@@ -1,98 +0,0 @@
/**
* plugins/video/index.js
*
* Baixa vídeo via yt-dlp e envia no chat.
* Todo o processo (download + envio + limpeza) fica aqui.
*/
import { spawn } from "child_process";
import fs from "fs";
import path from "path";
import os from "os";
import { enqueue } from "../../download/queue.js";
import { emptyFolder } from "../../utils/file.js";
import { CMD_PREFIX } from "../../config.js";
const logStream = fs.createWriteStream("logs/video-error.log", { flags: "a" });
const DOWNLOADS_DIR = path.resolve("downloads");
const YT_DLP = os.platform() === "win32" ? ".\\bin\\yt-dlp.exe" : "./bin/yt-dlp";
const ARGS_BASE = [
"--extractor-args", "youtube:player_client=android",
"--print", "after_move:filepath",
"--cookies", "cookies.txt",
"--add-header", "User-Agent:Mozilla/5.0",
"--add-header", "Referer:https://www.youtube.com/",
"--retries", "4",
"--fragment-retries", "5",
"--socket-timeout", "15",
"--sleep-interval", "1",
"--max-sleep-interval", "4",
"--no-playlist",
"-f", "bv+ba/best",
];
function downloadVideo(url, id) {
return new Promise((resolve, reject) => {
fs.mkdirSync(DOWNLOADS_DIR, { recursive: true });
const output = path.join(DOWNLOADS_DIR, `${id}.%(ext)s`);
const proc = spawn(YT_DLP, [...ARGS_BASE, "--output", output, url]);
let stdout = "";
proc.on("error", err => reject(new Error(
err.code === "EACCES"
? "Sem permissão para executar o yt-dlp. Rode: chmod +x ./bin/yt-dlp"
: err.code === "ENOENT"
? "yt-dlp não encontrado em ./bin/yt-dlp"
: `Erro ao iniciar o yt-dlp: ${err.message}`
)));
proc.stdout.on("data", d => { stdout += d.toString(); });
proc.stderr.on("data", d => logStream.write(d));
proc.on("close", code => {
if (code !== 0) return reject(new Error(
"Não foi possível baixar o vídeo. Verifique se o link é válido e tente novamente."
));
const filePath = stdout.trim().split("\n").filter(Boolean).at(-1);
if (!filePath || !fs.existsSync(filePath)) return reject(new Error(
"Download concluído mas arquivo não encontrado. Tente novamente."
));
resolve(filePath);
});
});
}
export default async function ({ msg, api }) {
if (!msg.is(CMD_PREFIX + "video")) return;
const url = msg.args[1];
if (!url) {
await msg.reply(`❌ Você precisa informar um link.\n\nExemplo: \`${CMD_PREFIX}video https://youtube.com/...\``);
return;
}
await msg.reply("⏳ Baixando o vídeo, aguarde...");
enqueue(
async () => {
const filePath = await downloadVideo(url, `video-${Date.now()}`);
await api.sendVideo(filePath);
fs.unlinkSync(filePath);
emptyFolder(DOWNLOADS_DIR);
api.log.info(`${CMD_PREFIX}video concluído → ${url}`);
},
async () => {
await msg.reply(
"❌ Não consegui baixar o vídeo.\n\n" +
"Verifique se o link é válido e tente novamente.\n" +
"Se o problema persistir, o conteúdo pode estar indisponível ou protegido."
);
}
);
}

View File

@@ -1,21 +0,0 @@
/**
* Ideia:
*
* Quando esse plugin for chamado, vai salvar o id de quem mandou no banco de dados.
* Quando esse id mandar mensagem de novo, o plugin vai "se lembrar" dessa pessoa e contar xp com:
*
* - Número de mensagens a cada 30s > conta 1 ponto cada mensagem sendo de texto ou de audio. Durante o intervalo de 30s ele não conta nada.
* - Tipo da mensagem:
* - Texto/Audio: multiplicar por 1
* - Vídeo/Foto: multiplcar por 2
*
* - Aculma karma dependendo da mensagem. Se suas mensagens conterem palavrões frequentes ou muito spam (ex. 5 mensagens/s), seu karma diminui:
* - Karma negativo (abaixo de 0): divide pontos de xp por 2
* - Karma baixo (10-20): multplica pontos por 1
* - Karma médio (30-40): multiplica pontos por 2
* - Karma alto (50-80): multiplca pontos por 3
*
* No final de cada mês, esse plugin organiza uma lista com o ranking dos top 10 com maiores XP do mês e manda em ID (chat).
*
* Esse plugin é a base para fazer um sistema de economia daqui um tempo.
*/