├── lib ├── Gotartech ├── index.js ├── emix-utils.js ├── database.js ├── video-utils.js ├── fetchGif.js ├── sticker-utils.js ├── functions.js ├── antidel.js ├── groupevents.js ├── functions2.js └── msg.js ├── sessions └── temp ├── data ├── Gotartech ├── reports.json ├── version.json ├── index.js ├── updateDB.js ├── sticker-converter.js ├── antidel.js ├── converter.js └── store.js ├── heroku.yml ├── Dockerfile ├── koyeb.yaml ├── command.js ├── SECURITY.md ├── package.json ├── config.js ├── app.json └── README.md /lib/Gotartech: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /sessions/temp: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /data/Gotartech: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | worker: DockerFile 4 | run: 5 | worker: npm install -g pm2 && npm start 6 | -------------------------------------------------------------------------------- /data/reports.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "user": "50912345678", 4 | "message": "Play command is not working", 5 | "timestamp": "2025-05-18T14:30:00Z" 6 | } 7 | ] 8 | -------------------------------------------------------------------------------- /data/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "changelog": "📌 Fixed YouTube Downloader -: .play and .song \n 📌 Added Update command, plugin count, and command count, plugin newsletter.\n🛠 Improved system info.\n🚀 Enhanced update detection." 4 | } 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:lts-buster 2 | RUN git clone https://github.com/gotartech/GOTAR-XMD/root/gotartech 3 | WORKDIR /root/gotartech 4 | RUN npm install && npm install -g pm2 || yarn install --network-concurrency 1 5 | COPY . . 6 | EXPOSE 9090 7 | CMD ["npm", "start"] 8 | -------------------------------------------------------------------------------- /koyeb.yaml: -------------------------------------------------------------------------------- 1 | name: gotar-xmd 2 | services: 3 | - name: gotar-xmd-service 4 | type: web 5 | ports: 6 | - 5000 7 | routes: 8 | - path: "/" 9 | build: 10 | type: docker 11 | dockerfile: ./Dockerfile 12 | regions: 13 | - fra 14 | - sin 15 | 16 | -------------------------------------------------------------------------------- /command.js: -------------------------------------------------------------------------------- 1 | var commands = []; 2 | 3 | function cmd(info, func) { 4 | var data = info; 5 | data.function = func; 6 | if (!data.dontAddCommandList) data.dontAddCommandList = false; 7 | if (!info.desc) info.desc = ''; 8 | if (!data.fromMe) data.fromMe = false; 9 | if (!info.category) data.category = 'misc'; 10 | if(!info.filename) data.filename = "Not Provided"; 11 | commands.push(data); 12 | return data; 13 | } 14 | module.exports = { 15 | cmd, 16 | AddCommand:cmd, 17 | Function:cmd, 18 | Module:cmd, 19 | commands, 20 | }; 21 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | const { DeletedText, 2 | DeletedMedia, 3 | AntiDelete, } = require('./antidel'); 4 | //const { AntiViewOnce } = require('./antivv'); 5 | const { 6 | DATABASE 7 | } = require('./database'); 8 | const { getBuffer, getGroupAdmins, getRandom, h2k, isUrl, Json, runtime, sleep, fetchJson } = require('./functions'); 9 | const {sms, downloadMediaMessage} = require('./msg'); 10 | //const {shannzCdn} = require('./shannzCdn'); 11 | 12 | module.exports = { 13 | DeletedText, 14 | DeletedMedia, 15 | AntiDelete, 16 | //AntiViewOnce, 17 | getBuffer, 18 | getGroupAdmins, 19 | getRandom, 20 | h2k, 21 | isUrl, 22 | Json, 23 | runtime, 24 | sleep, 25 | fetchJson, 26 | DATABASE, 27 | sms, 28 | downloadMediaMessage, 29 | // shannzCdn, 30 | }; -------------------------------------------------------------------------------- /data/index.js: -------------------------------------------------------------------------------- 1 | const { AntiDelDB, 2 | initializeAntiDeleteSettings, 3 | setAnti, 4 | getAnti, 5 | getAllAntiDeleteSettings, } = require('./antidel'); 6 | const { 7 | saveContact, 8 | loadMessage, 9 | getName, 10 | getChatSummary, 11 | saveGroupMetadata, 12 | getGroupMetadata, 13 | saveMessageCount, 14 | getInactiveGroupMembers, 15 | getGroupMembersMessageCount, 16 | saveMessage, 17 | } = require('./store'); 18 | 19 | 20 | module.exports = { 21 | AntiDelDB, 22 | initializeAntiDeleteSettings, 23 | setAnti, 24 | getAnti, 25 | getAllAntiDeleteSettings, 26 | saveContact, 27 | loadMessage, 28 | getName, 29 | getChatSummary, 30 | saveGroupMetadata, 31 | getGroupMetadata, 32 | saveMessageCount, 33 | getInactiveGroupMembers, 34 | getGroupMembersMessageCount, 35 | saveMessage, 36 | }; 37 | -------------------------------------------------------------------------------- /lib/emix-utils.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | 3 | /** 4 | * Fetch Emoji Mix image from API. 5 | * @param {string} emoji1 - First emoji. 6 | * @param {string} emoji2 - Second emoji. 7 | * @returns {Promise} - The image URL. 8 | */ 9 | async function fetchEmix(emoji1, emoji2) { 10 | try { 11 | if (!emoji1 || !emoji2) { 12 | throw new Error("Invalid emoji input. Please provide two emojis."); 13 | } 14 | 15 | const apiUrl = `https://levanter.onrender.com/emix?q=${encodeURIComponent(emoji1)},${encodeURIComponent(emoji2)}`; 16 | const response = await axios.get(apiUrl); 17 | 18 | if (response.data && response.data.result) { 19 | return response.data.result; // Return the image URL 20 | } else { 21 | throw new Error("No valid image found."); 22 | } 23 | } catch (error) { 24 | console.error("Error fetching emoji mix:", error.message); 25 | throw new Error("Failed to fetch emoji mix."); 26 | } 27 | } 28 | 29 | module.exports = { fetchEmix }; 30 | -------------------------------------------------------------------------------- /data/updateDB.js: -------------------------------------------------------------------------------- 1 | const { DATABASE } = require('../lib/database'); 2 | const { DataTypes } = require('sequelize'); 3 | 4 | const UpdateDB = DATABASE.define('UpdateInfo', { 5 | id: { 6 | type: DataTypes.INTEGER, 7 | primaryKey: true, 8 | autoIncrement: false, 9 | defaultValue: 1, 10 | }, 11 | commitHash: { 12 | type: DataTypes.STRING, 13 | allowNull: false, 14 | }, 15 | }, { 16 | tableName: 'update_info', 17 | timestamps: false, 18 | hooks: { 19 | beforeCreate: (record) => { record.id = 1; }, 20 | beforeBulkCreate: (records) => { 21 | records.forEach(record => { record.id = 1; }); 22 | }, 23 | }, 24 | }); 25 | 26 | async function initializeUpdateDB() { 27 | await UpdateDB.sync(); 28 | const [record, created] = await UpdateDB.findOrCreate({ 29 | where: { id: 1 }, 30 | defaults: { commitHash: 'unknown' }, 31 | }); 32 | return record; 33 | } 34 | 35 | async function setCommitHash(hash) { 36 | await initializeUpdateDB(); 37 | const record = await UpdateDB.findByPk(1); 38 | record.commitHash = hash; 39 | await record.save(); 40 | } 41 | 42 | async function getCommitHash() { 43 | await initializeUpdateDB(); 44 | const record = await UpdateDB.findByPk(1); 45 | return record ? record.commitHash : 'unknown'; 46 | } 47 | 48 | module.exports = { 49 | UpdateDB, 50 | setCommitHash, 51 | getCommitHash, 52 | }; 53 | -------------------------------------------------------------------------------- /lib/database.js: -------------------------------------------------------------------------------- 1 | const Sequelize = require('sequelize'); 2 | 3 | class DatabaseManager { 4 | static instance = null; 5 | 6 | static getInstance() { 7 | if (!DatabaseManager.instance) { 8 | const DATABASE_URL = process.env.DATABASE_URL || './database.db'; 9 | 10 | DatabaseManager.instance = 11 | DATABASE_URL === './database.db' 12 | ? new Sequelize({ 13 | dialect: 'sqlite', 14 | storage: DATABASE_URL, 15 | logging: false, 16 | }) 17 | : new Sequelize(DATABASE_URL, { 18 | dialect: 'postgres', 19 | ssl: true, 20 | protocol: 'postgres', 21 | dialectOptions: { 22 | native: true, 23 | ssl: { require: true, rejectUnauthorized: false }, 24 | }, 25 | logging: false, 26 | }); 27 | } 28 | return DatabaseManager.instance; 29 | } 30 | } 31 | 32 | const DATABASE = DatabaseManager.getInstance(); 33 | 34 | DATABASE.sync() 35 | .then(() => { 36 | console.log('Database synchronized successfully.'); 37 | }) 38 | .catch((error) => { 39 | console.error('Error synchronizing the database:', error); 40 | }); 41 | 42 | module.exports = { DATABASE }; 43 | 44 | //powered by Gotar-Tech 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GOTAR-XMD", 3 | "version": "1.0.0", 4 | "description": "A WhatsApp Bot Created By GotarTech", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "pm2 start index.js --deep-monitoring --attach --name GOTAR-XMD", 8 | "stop": "pm2 stop GOTAR-XMD", 9 | "restart": "pm2 restart GOTAR-XMD" 10 | }, 11 | "dependencies": { 12 | "@whiskeysockets/baileys": "6.7.9", 13 | "@adiwajshing/keyed-db": "^0.2.4", 14 | "@dark-yasiya/yt-dl.js": "1.0.5", 15 | "@ffmpeg-installer/ffmpeg": "^1.1.0", 16 | "@vitalets/google-translate-api": "^9.2.0", 17 | "@dark-yasiya/scrap":"1.0.1", 18 | "pino": "^7.0.5", 19 | "pm2": "^6.0.5", 20 | "util": "^0.12.4", 21 | "express": "latest", 22 | "moment-timezone": "^0.5.45", 23 | "axios": "^1.2.5", 24 | "crypto-digest-sync": "^1.0.0", 25 | "crypto-js": "latest", 26 | "file_size_url": "1.0.4", 27 | "fs-extra": "^11.1.0", 28 | "fs": "^0.0.1-security", 29 | "ffmpeg": "^0.0.4", 30 | "file-type": "^16.5.3", 31 | "fluent-ffmpeg": "^2.1.2", 32 | "form-data": "^4.0.0", 33 | "google-tts-api": "^2.0.2", 34 | "path": "^0.12.7", 35 | "node-fetch": "^2.6.1", 36 | "btch-downloader": "^2.2.9", 37 | "megajs": "^1.1.0", 38 | "pdfkit": "^0.14.0", 39 | "wa_set_pkg": "1.0.5", 40 | "wa-sticker-formatter": "^4.4.4", 41 | "path": "^0.12.7", 42 | "vm": "^0.1.0", 43 | "adm-zip": "^0.5.16", 44 | "cheerio": "^1.0.0-rc.12", 45 | "ruhend-scraper" : "8.0.3", 46 | "qrcode-terminal": "^0.12.0", 47 | "yt-search":"2.11.1", 48 | "sequelize": "^6.37.5", 49 | "sqlite3": "^5.1.7", 50 | "vm": "^0.1.0", 51 | "api-dylux":"1.8.5", 52 | "@mrnima/tiktok-downloader":"1.0.0", 53 | "@mrnima/facebook-downloader":"1.0.0", 54 | "mrnima-moviedl":"1.0.0" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/video-utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { tmpdir } = require('os'); 4 | const Crypto = require('crypto'); 5 | const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; 6 | const ffmpeg = require('fluent-ffmpeg'); 7 | 8 | // Set ffmpeg path 9 | ffmpeg.setFfmpegPath(ffmpegPath); 10 | 11 | /** 12 | * Converts a video or GIF buffer to a WebP sticker format. 13 | * @param {Buffer} videoBuffer - The video or GIF buffer to convert. 14 | * @returns {Promise} - The converted WebP sticker buffer. 15 | */ 16 | async function videoToWebp(videoBuffer) { 17 | const outputPath = path.join( 18 | tmpdir(), 19 | Crypto.randomBytes(6).readUIntLE(0, 6).toString(36) + '.webp' 20 | ); 21 | const inputPath = path.join( 22 | tmpdir(), 23 | Crypto.randomBytes(6).readUIntLE(0, 6).toString(36) + '.mp4' 24 | ); 25 | 26 | // Save the video buffer to a file 27 | fs.writeFileSync(inputPath, videoBuffer); 28 | 29 | await new Promise((resolve, reject) => { 30 | ffmpeg(inputPath) 31 | .on('error', reject) 32 | .on('end', () => resolve(true)) 33 | .addOutputOptions([ 34 | '-vcodec', 'libwebp', 35 | '-vf', "scale='min(320,iw)':min'(320,ih)':force_original_aspect_ratio=decrease,fps=15,pad=320:320:-1:-1:color=white@0.0,split [a][b];[a] palettegen=reserve_transparent=on:transparency_color=ffffff [p];[b][p] paletteuse", 36 | '-loop', '0', // Loop forever 37 | '-ss', '00:00:00', // Start time (optional) 38 | '-t', '00:00:05', // Duration (optional) 39 | '-preset', 'default', 40 | '-an', // No audio 41 | '-vsync', '0' 42 | ]) 43 | .toFormat('webp') 44 | .save(outputPath); 45 | }); 46 | 47 | const webpBuffer = fs.readFileSync(outputPath); 48 | fs.unlinkSync(outputPath); 49 | fs.unlinkSync(inputPath); 50 | 51 | return webpBuffer; 52 | } 53 | 54 | module.exports = { 55 | videoToWebp 56 | }; 57 | -------------------------------------------------------------------------------- /data/sticker-converter.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const { execSync } = require('child_process'); 4 | const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; 5 | const ffmpeg = require('fluent-ffmpeg'); 6 | 7 | // Set ffmpeg path 8 | ffmpeg.setFfmpegPath(ffmpegPath); 9 | 10 | class StickerConverter { 11 | constructor() { 12 | this.tempDir = path.join(__dirname, '../temp'); 13 | this.ensureTempDir(); 14 | } 15 | 16 | ensureTempDir() { 17 | if (!fs.existsSync(this.tempDir)) { 18 | fs.mkdirSync(this.tempDir, { recursive: true }); 19 | } 20 | } 21 | 22 | async convertStickerToImage(stickerBuffer) { 23 | const tempPath = path.join(this.tempDir, `sticker_${Date.now()}.webp`); 24 | const outputPath = path.join(this.tempDir, `image_${Date.now()}.png`); 25 | 26 | try { 27 | // Save sticker to temp file 28 | await fs.promises.writeFile(tempPath, stickerBuffer); 29 | 30 | // Convert using fluent-ffmpeg (same as your video sticker converter) 31 | await new Promise((resolve, reject) => { 32 | ffmpeg(tempPath) 33 | .on('error', reject) 34 | .on('end', resolve) 35 | .output(outputPath) 36 | .run(); 37 | }); 38 | 39 | // Read and return converted image 40 | return await fs.promises.readFile(outputPath); 41 | } catch (error) { 42 | console.error('Conversion error:', error); 43 | throw new Error('Failed to convert sticker to image'); 44 | } finally { 45 | // Cleanup temp files 46 | await Promise.all([ 47 | fs.promises.unlink(tempPath).catch(() => {}), 48 | fs.promises.unlink(outputPath).catch(() => {}) 49 | ]); 50 | } 51 | } 52 | } 53 | 54 | module.exports = new StickerConverter(); 55 | -------------------------------------------------------------------------------- /lib/fetchGif.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const { tmpdir } = require('os'); 5 | const Crypto = require('crypto'); 6 | const ffmpeg = require('fluent-ffmpeg'); 7 | const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; 8 | 9 | ffmpeg.setFfmpegPath(ffmpegPath); 10 | 11 | /** 12 | * Fetch a GIF from a given API URL. 13 | * @param {string} url - The API endpoint to fetch the GIF. 14 | * @returns {Promise} - The GIF buffer. 15 | */ 16 | async function fetchGif(url) { 17 | try { 18 | const response = await axios.get(url, { responseType: 'arraybuffer' }); 19 | return response.data; 20 | } catch (error) { 21 | console.error("❌ Error fetching GIF:", error); 22 | throw new Error("Could not fetch GIF."); 23 | } 24 | } 25 | 26 | /** 27 | * Converts a GIF buffer to a video buffer. 28 | * @param {Buffer} gifBuffer - The GIF buffer. 29 | * @returns {Promise} - The MP4 video buffer. 30 | */ 31 | async function gifToVideo(gifBuffer) { 32 | const filename = Crypto.randomBytes(6).toString('hex'); 33 | const gifPath = path.join(tmpdir(), `${filename}.gif`); 34 | const mp4Path = path.join(tmpdir(), `${filename}.mp4`); 35 | 36 | fs.writeFileSync(gifPath, gifBuffer); 37 | 38 | await new Promise((resolve, reject) => { 39 | ffmpeg(gifPath) 40 | .outputOptions([ 41 | "-movflags faststart", 42 | "-pix_fmt yuv420p", 43 | "-vf scale=trunc(iw/2)*2:trunc(ih/2)*2" 44 | ]) 45 | .on("error", (err) => { 46 | console.error("❌ ffmpeg conversion error:", err); 47 | reject(new Error("Could not process GIF to video.")); 48 | }) 49 | .on("end", resolve) 50 | .save(mp4Path); 51 | }); 52 | 53 | const videoBuffer = fs.readFileSync(mp4Path); 54 | fs.unlinkSync(gifPath); 55 | fs.unlinkSync(mp4Path); 56 | 57 | return videoBuffer; 58 | } 59 | 60 | module.exports = { fetchGif, gifToVideo }; 61 | 62 | -------------------------------------------------------------------------------- /data/antidel.js: -------------------------------------------------------------------------------- 1 | const { DATABASE } = require('../lib/database'); 2 | const { DataTypes } = require('sequelize'); 3 | 4 | const AntiDelDB = DATABASE.define('AntiDelete', { 5 | id: { 6 | type: DataTypes.INTEGER, 7 | primaryKey: true, 8 | autoIncrement: false, 9 | defaultValue: 1, 10 | }, 11 | gc_status: { 12 | type: DataTypes.BOOLEAN, 13 | defaultValue: false, 14 | }, 15 | dm_status: { 16 | type: DataTypes.BOOLEAN, 17 | defaultValue: false, 18 | }, 19 | }, { 20 | tableName: 'antidelete', 21 | timestamps: false, 22 | hooks: { 23 | beforeCreate: record => { record.id = 1; }, 24 | beforeBulkCreate: records => { records.forEach(record => { record.id = 1; }); }, 25 | }, 26 | }); 27 | 28 | let isInitialized = false; 29 | 30 | async function initializeAntiDeleteSettings() { 31 | if (isInitialized) return; 32 | try { 33 | await AntiDelDB.sync(); 34 | await AntiDelDB.findOrCreate({ 35 | where: { id: 1 }, 36 | defaults: { gc_status: false, dm_status: false }, 37 | }); 38 | isInitialized = true; 39 | } catch (error) { 40 | console.error('Error initializing anti-delete settings:', error); 41 | } 42 | } 43 | 44 | async function setAnti(type, status) { 45 | try { 46 | await initializeAntiDeleteSettings(); 47 | const record = await AntiDelDB.findByPk(1); 48 | if (type === 'gc') record.gc_status = status; 49 | else if (type === 'dm') record.dm_status = status; 50 | await record.save(); 51 | return true; 52 | } catch (error) { 53 | console.error('Error setting anti-delete status:', error); 54 | return false; 55 | } 56 | } 57 | 58 | async function getAnti(type) { 59 | try { 60 | await initializeAntiDeleteSettings(); 61 | const record = await AntiDelDB.findByPk(1); 62 | return type === 'gc' ? record.gc_status : record.dm_status; 63 | } catch (error) { 64 | console.error('Error getting anti-delete status:', error); 65 | return false; 66 | } 67 | } 68 | 69 | async function getAllAntiDeleteSettings() { 70 | try { 71 | await initializeAntiDeleteSettings(); 72 | const record = await AntiDelDB.findByPk(1); 73 | return [{ gc_status: record.gc_status, dm_status: record.dm_status }]; 74 | } catch (error) { 75 | console.error('Error retrieving all anti-delete settings:', error); 76 | return []; 77 | } 78 | } 79 | 80 | module.exports = { 81 | AntiDelDB, 82 | initializeAntiDeleteSettings, 83 | setAnti, 84 | getAnti, 85 | getAllAntiDeleteSettings, 86 | }; 87 | -------------------------------------------------------------------------------- /lib/sticker-utils.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const { tmpdir } = require('os'); 5 | const Crypto = require('crypto'); 6 | const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; 7 | const ffmpeg = require('fluent-ffmpeg'); 8 | 9 | ffmpeg.setFfmpegPath(ffmpegPath); 10 | 11 | /** 12 | * Fetch an image from a given URL. 13 | * @param {string} url - The image URL. 14 | * @returns {Promise} - The image buffer. 15 | */ 16 | async function fetchImage(url) { 17 | try { 18 | const response = await axios.get(url, { responseType: 'arraybuffer' }); 19 | return response.data; 20 | } catch (error) { 21 | console.error("Error fetching image:", error); 22 | throw new Error("Could not fetch image."); 23 | } 24 | } 25 | 26 | /** 27 | * Fetch a GIF from a given API URL. 28 | * @param {string} url - API endpoint to fetch GIF. 29 | * @returns {Promise} - The GIF buffer. 30 | */ 31 | async function fetchGif(url) { 32 | try { 33 | const response = await axios.get(url, { responseType: 'arraybuffer' }); 34 | return response.data; 35 | } catch (error) { 36 | console.error("Error fetching GIF:", error); 37 | throw new Error("Could not fetch GIF."); 38 | } 39 | } 40 | 41 | /** 42 | * Converts a GIF buffer to WebP sticker format. 43 | * @param {Buffer} gifBuffer - The GIF buffer. 44 | * @returns {Promise} - The WebP sticker buffer. 45 | */ 46 | async function gifToSticker(gifBuffer) { 47 | const outputPath = path.join(tmpdir(), Crypto.randomBytes(6).toString('hex') + ".webp"); 48 | const inputPath = path.join(tmpdir(), Crypto.randomBytes(6).toString('hex') + ".gif"); 49 | 50 | fs.writeFileSync(inputPath, gifBuffer); 51 | 52 | await new Promise((resolve, reject) => { 53 | ffmpeg(inputPath) 54 | .on("error", reject) 55 | .on("end", () => resolve(true)) 56 | .addOutputOptions([ 57 | "-vcodec", "libwebp", 58 | "-vf", "scale='min(320,iw)':min'(320,ih)':force_original_aspect_ratio=decrease,fps=15,pad=320:320:-1:-1:color=white@0.0,split [a][b];[a] palettegen=reserve_transparent=on:transparency_color=ffffff [p];[b][p] paletteuse", 59 | "-loop", "0", 60 | "-preset", "default", 61 | "-an", 62 | "-vsync", "0" 63 | ]) 64 | .toFormat("webp") 65 | .save(outputPath); 66 | }); 67 | 68 | const webpBuffer = fs.readFileSync(outputPath); 69 | fs.unlinkSync(outputPath); 70 | fs.unlinkSync(inputPath); 71 | 72 | return webpBuffer; 73 | } 74 | 75 | module.exports = { fetchImage, fetchGif, gifToSticker }; 76 | 77 | -------------------------------------------------------------------------------- /lib/functions.js: -------------------------------------------------------------------------------- 1 | const axios = require('axios') 2 | 3 | const getBuffer = async(url, options) => { 4 | try { 5 | options ? options : {} 6 | var res = await axios({ 7 | method: 'get', 8 | url, 9 | headers: { 10 | 'DNT': 1, 11 | 'Upgrade-Insecure-Request': 1 12 | }, 13 | ...options, 14 | responseType: 'arraybuffer' 15 | }) 16 | return res.data 17 | } catch (e) { 18 | console.log(e) 19 | } 20 | } 21 | 22 | const getGroupAdmins = (participants) => { 23 | var admins = [] 24 | for (let i of participants) { 25 | i.admin !== null ? admins.push(i.id) : '' 26 | } 27 | return admins 28 | } 29 | 30 | const getRandom = (ext) => { 31 | return `${Math.floor(Math.random() * 10000)}${ext}` 32 | } 33 | 34 | const h2k = (eco) => { 35 | var lyrik = ['', 'K', 'M', 'B', 'T', 'P', 'E'] 36 | var ma = Math.log10(Math.abs(eco)) / 3 | 0 37 | if (ma == 0) return eco 38 | var ppo = lyrik[ma] 39 | var scale = Math.pow(10, ma * 3) 40 | var scaled = eco / scale 41 | var formatt = scaled.toFixed(1) 42 | if (/\.0$/.test(formatt)) 43 | formatt = formatt.substr(0, formatt.length - 2) 44 | return formatt + ppo 45 | } 46 | 47 | const isUrl = (url) => { 48 | return url.match( 49 | new RegExp( 50 | /https?:\/\/(www\.)?[-a-zA-Z0-9@:%.+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%+.~#?&/=]*)/, 51 | 'gi' 52 | ) 53 | ) 54 | } 55 | 56 | const Json = (string) => { 57 | return JSON.stringify(string, null, 2) 58 | } 59 | 60 | const runtime = (seconds) => { 61 | seconds = Number(seconds) 62 | var d = Math.floor(seconds / (3600 * 24)) 63 | var h = Math.floor(seconds % (3600 * 24) / 3600) 64 | var m = Math.floor(seconds % 3600 / 60) 65 | var s = Math.floor(seconds % 60) 66 | var dDisplay = d > 0 ? d + (d == 1 ? ' day, ' : ' days, ') : '' 67 | var hDisplay = h > 0 ? h + (h == 1 ? ' hour, ' : ' hours, ') : '' 68 | var mDisplay = m > 0 ? m + (m == 1 ? ' minute, ' : ' minutes, ') : '' 69 | var sDisplay = s > 0 ? s + (s == 1 ? ' second' : ' seconds') : '' 70 | return dDisplay + hDisplay + mDisplay + sDisplay; 71 | } 72 | 73 | const sleep = async(ms) => { 74 | return new Promise(resolve => setTimeout(resolve, ms)) 75 | } 76 | 77 | const fetchJson = async (url, options) => { 78 | try { 79 | options ? options : {} 80 | const res = await axios({ 81 | method: 'GET', 82 | url: url, 83 | headers: { 84 | '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' 85 | }, 86 | ...options 87 | }) 88 | return res.data 89 | } catch (err) { 90 | return err 91 | } 92 | } 93 | 94 | module.exports = { getBuffer, getGroupAdmins, getRandom, h2k, isUrl, Json, runtime, sleep , fetchJson} 95 | -------------------------------------------------------------------------------- /data/converter.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; 4 | const { spawn } = require('child_process'); 5 | 6 | class AudioConverter { 7 | constructor() { 8 | this.tempDir = path.join(__dirname, '../temp'); 9 | this.ensureTempDir(); 10 | } 11 | 12 | ensureTempDir() { 13 | if (!fs.existsSync(this.tempDir)) { 14 | fs.mkdirSync(this.tempDir, { recursive: true }); 15 | } 16 | } 17 | 18 | async cleanFile(file) { 19 | if (file && fs.existsSync(file)) { 20 | await fs.promises.unlink(file).catch(() => {}); 21 | } 22 | } 23 | 24 | async convert(buffer, args, ext, ext2) { 25 | const inputPath = path.join(this.tempDir, `${Date.now()}.${ext}`); 26 | const outputPath = path.join(this.tempDir, `${Date.now()}.${ext2}`); 27 | 28 | try { 29 | await fs.promises.writeFile(inputPath, buffer); 30 | 31 | return new Promise((resolve, reject) => { 32 | const ffmpeg = spawn(ffmpegPath, [ 33 | '-y', 34 | '-i', inputPath, 35 | ...args, 36 | outputPath 37 | ], { timeout: 30000 }); 38 | 39 | let errorOutput = ''; 40 | ffmpeg.stderr.on('data', (data) => errorOutput += data.toString()); 41 | 42 | ffmpeg.on('close', async (code) => { 43 | await this.cleanFile(inputPath); 44 | 45 | if (code !== 0) { 46 | await this.cleanFile(outputPath); 47 | return reject(new Error(`Conversion failed with code ${code}`)); 48 | } 49 | 50 | try { 51 | const result = await fs.promises.readFile(outputPath); 52 | await this.cleanFile(outputPath); 53 | resolve(result); 54 | } catch (readError) { 55 | reject(readError); 56 | } 57 | }); 58 | 59 | ffmpeg.on('error', (err) => { 60 | reject(err); 61 | }); 62 | }); 63 | } catch (err) { 64 | await this.cleanFile(inputPath); 65 | await this.cleanFile(outputPath); 66 | throw err; 67 | } 68 | } 69 | 70 | toAudio(buffer, ext) { 71 | return this.convert(buffer, [ 72 | '-vn', 73 | '-ac', '2', 74 | '-b:a', '128k', 75 | '-ar', '44100', 76 | '-f', 'mp3' 77 | ], ext, 'mp3'); 78 | } 79 | 80 | toPTT(buffer, ext) { 81 | return this.convert(buffer, [ 82 | '-vn', 83 | '-c:a', 'libopus', 84 | '-b:a', '128k', 85 | '-vbr', 'on', 86 | '-compression_level', '10' 87 | ], ext, 'opus'); 88 | } 89 | } 90 | 91 | module.exports = new AudioConverter(); 92 | -------------------------------------------------------------------------------- /lib/antidel.js: -------------------------------------------------------------------------------- 1 | const { isJidGroup } = require('@whiskeysockets/baileys'); 2 | const { loadMessage, getAnti } = require('../data'); 3 | const config = require('../config'); 4 | 5 | const DeletedText = async (conn, mek, jid, deleteInfo, isGroup, update) => { 6 | const messageContent = mek.message?.conversation || mek.message?.extendedTextMessage?.text || 'Unknown content'; 7 | deleteInfo += `\n\n*Content:* ${messageContent}`; 8 | 9 | await conn.sendMessage( 10 | jid, 11 | { 12 | text: deleteInfo, 13 | contextInfo: { 14 | mentionedJid: isGroup ? [update.key.participant, mek.key.participant] : [update.key.remoteJid], 15 | }, 16 | }, 17 | { quoted: mek }, 18 | ); 19 | }; 20 | 21 | const DeletedMedia = async (conn, mek, jid, deleteInfo) => { 22 | const antideletedmek = structuredClone(mek.message); 23 | const messageType = Object.keys(antideletedmek)[0]; 24 | if (antideletedmek[messageType]) { 25 | antideletedmek[messageType].contextInfo = { 26 | stanzaId: mek.key.id, 27 | participant: mek.sender, 28 | quotedMessage: mek.message, 29 | }; 30 | } 31 | if (messageType === 'imageMessage' || messageType === 'videoMessage') { 32 | antideletedmek[messageType].caption = deleteInfo; 33 | } else if (messageType === 'audioMessage' || messageType === 'documentMessage') { 34 | await conn.sendMessage(jid, { text: `*🚨 Delete Detected!*\n\n${deleteInfo}` }, { quoted: mek }); 35 | } 36 | await conn.relayMessage(jid, antideletedmek, {}); 37 | }; 38 | 39 | const AntiDelete = async (conn, updates) => { 40 | for (const update of updates) { 41 | if (update.update.message === null) { 42 | const store = await loadMessage(update.key.id); 43 | 44 | if (store && store.message) { 45 | const mek = store.message; 46 | const isGroup = isJidGroup(store.jid); 47 | const antiDeleteType = isGroup ? 'gc' : 'dm'; 48 | const antiDeleteStatus = await getAnti(antiDeleteType); 49 | if (!antiDeleteStatus) continue; 50 | 51 | const deleteTime = new Date().toLocaleTimeString('en-GB', { 52 | hour: '2-digit', 53 | minute: '2-digit', 54 | second: '2-digit', 55 | }); 56 | 57 | let deleteInfo, jid; 58 | if (isGroup) { 59 | const groupMetadata = await conn.groupMetadata(store.jid); 60 | const groupName = groupMetadata.subject; 61 | const sender = mek.key.participant?.split('@')[0]; 62 | const deleter = update.key.participant?.split('@')[0]; 63 | 64 | deleteInfo = `*AntiDelete Detected*\n\n*Time:* ${deleteTime}\n*Group:* ${groupName}\n*Deleted by:* @${deleter}\n*Sender:* @${sender}`; 65 | jid = config.ANTI_DEL_PATH === "log" ? conn.user.id : store.jid; 66 | } else { 67 | const senderNumber = mek.key.remoteJid?.split('@')[0]; 68 | const deleterNumber = update.key.remoteJid?.split('@')[0]; 69 | 70 | 71 | deleteInfo = `*-- AntiDelete Detected --*\n\n*Time:* ${deleteTime}\n*Deleted by:* @${deleterNumber}\n*Sender:* @${senderNumber}`; 72 | jid = config.ANTI_DEL_PATH === "log" ? conn.user.id : update.key.remoteJid; 73 | } 74 | 75 | if (mek.message?.conversation || mek.message?.extendedTextMessage) { 76 | await DeletedText(conn, mek, jid, deleteInfo, isGroup, update); 77 | } else { 78 | await DeletedMedia(conn, mek, jid, deleteInfo); 79 | } 80 | } 81 | } 82 | } 83 | }; 84 | 85 | module.exports = { 86 | DeletedText, 87 | DeletedMedia, 88 | AntiDelete, 89 | }; 90 | 91 | // by jawadtechx 92 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | if (fs.existsSync('config.env')) require('dotenv').config({ path: './config.env' }); 3 | 4 | function convertToBool(text, fault = 'true') { 5 | return text === fault ? true : false; 6 | } 7 | module.exports = { 8 | SESSION_ID: process.env.SESSION_ID || "pur your session id here ", 9 | // add your Session Id 10 | AUTO_STATUS_SEEN: process.env.AUTO_STATUS_SEEN || "true", 11 | // make true or false status auto seen 12 | AUTO_STATUS_REPLY: process.env.AUTO_STATUS_REPLY || "false", 13 | // make true if you want auto reply on status 14 | AUTO_STATUS_REACT: process.env.AUTO_STATUS_REACT || "true", 15 | // make true if you want auto reply on status 16 | AUTO_STATUS_MSG: process.env.AUTO_STATUS_MSG || "*SEEN YOUR STATUS BY GOTAR-XMD 🤍*", 17 | // set the auto reply massage on status reply 18 | WELCOME: process.env.WELCOME || "true", 19 | // true if want welcome and goodbye msg in groups 20 | ADMIN_EVENTS: process.env.ADMIN_EVENTS || "false", 21 | // make true to know who dismiss or promoted a member in group 22 | ANTI_LINK: process.env.ANTI_LINK || "true", 23 | // make anti link true,false for groups 24 | MENTION_REPLY: process.env.MENTION_REPLY || "false", 25 | // make true if want auto voice reply if someone menetion you 26 | MENU_IMAGE_URL: process.env.MENU_IMAGE_URL || "https://files.catbox.moe/q0t3l2.jpg", 27 | // add custom menu and mention reply image url 28 | PREFIX: process.env.PREFIX || ".", 29 | // add your prifix for bot 30 | BOT_NAME: process.env.BOT_NAME || "𝐆𝐎𝐓𝐀𝐑 𝐗𝐌𝐃", 31 | // add bot namw here for menu 32 | STICKER_NAME: process.env.STICKER_NAME || "𝐆𝐎𝐓𝐀𝐑 𝐗𝐌𝐃", 33 | // type sticker pack name 34 | CUSTOM_REACT: process.env.CUSTOM_REACT || "false", 35 | // make this true for custum emoji react 36 | CUSTOM_REACT_EMOJIS: process.env.CUSTOM_REACT_EMOJIS || "💝,💖,💗,❤️‍🩹,❤️,🧡,💛,💚,💙,💜,🤎,🖤,🤍", 37 | // chose custom react emojis by yourself 38 | DELETE_LINKS: process.env.DELETE_LINKS || "false", 39 | // automatic delete links witho remove member 40 | OWNER_NUMBER: process.env.OWNER_NUMBER || "18494967948", 41 | // add your bot owner number 42 | OWNER_NAME: process.env.OWNER_NAME || "𝐆𝐎𝐓𝐀𝐑", 43 | // add bot owner name 44 | DESCRIPTION: process.env.DESCRIPTION || "*© ᴘᴏᴡᴇʀᴇᴅ ʙʏ ᴍᴇɢᴀʟᴏᴅᴏɴ ᴍᴅ*", 45 | // add bot owner name 46 | ALIVE_IMG: process.env.ALIVE_IMG || "https://files.catbox.moe/q0t3l2.jpg", 47 | // add img for alive msg 48 | LIVE_MSG: process.env.LIVE_MSG || "> Zinda Hun Yar *𝐆𝐎𝐓𝐀𝐑 𝐗𝐌𝐃*⚡", 49 | // add alive msg here 50 | READ_MESSAGE: process.env.READ_MESSAGE || "false", 51 | // Turn true or false for automatic read msgs 52 | AUTO_REACT: process.env.AUTO_REACT || "false", 53 | // make this true or false for auto react on all msgs 54 | ANTI_BAD: process.env.ANTI_BAD || "false", 55 | // false or true for anti bad words 56 | MODE: process.env.MODE || "public", 57 | // make bot public-private-inbox-group 58 | ANTI_LINK_KICK: process.env.ANTI_LINK_KICK || "false", 59 | // make anti link true,false for groups 60 | AUTO_VOICE: process.env.AUTO_VOICE || "false", 61 | // make true for send automatic voices 62 | AUTO_STICKER: process.env.AUTO_STICKER || "false", 63 | // make true for automatic stickers 64 | AUTO_REPLY: process.env.AUTO_REPLY || "false", 65 | // make true or false automatic text reply 66 | ALWAYS_ONLINE: process.env.ALWAYS_ONLINE || "false", 67 | // maks true for always online 68 | PUBLIC_MODE: process.env.PUBLIC_MODE || "true", 69 | // make false if want private mod 70 | AUTO_TYPING: process.env.AUTO_TYPING || "false", 71 | // true for automatic show typing 72 | READ_CMD: process.env.READ_CMD || "false", 73 | // true if want mark commands as read 74 | DEV: process.env.DEV || "18494967948", 75 | //replace with your whatsapp number 76 | ANTI_VV: process.env.ANTI_VV || "true", 77 | // true for anti once view 78 | ANTI_DEL_PATH: process.env.ANTI_DEL_PATH || "same", 79 | // change it to 'same' if you want to resend deleted message in same chat 80 | AUTO_RECORDING: process.env.AUTO_RECORDING || "true" 81 | // make it true for auto recoding 82 | }; 83 | -------------------------------------------------------------------------------- /lib/groupevents.js: -------------------------------------------------------------------------------- 1 | //Give Me Credit If Using This File Give Me Credit On Your Channel ✅ 2 | // Credits DybyTech 3 | 4 | const { isJidGroup } = require('@whiskeysockets/baileys'); 5 | const config = require('../config'); 6 | 7 | const getContextInfo = (m) => { 8 | return { 9 | mentionedJid: [m.sender], 10 | forwardingScore: 999, 11 | isForwarded: true, 12 | forwardedNewsletterMessageInfo: { 13 | newsletterJid: '120363401658098220@newsletter', 14 | newsletterName: '𝗚𝗢𝗧𝗔𝗥-𝗫𝗠𝗗', 15 | serverMessageId: 143, 16 | }, 17 | }; 18 | }; 19 | 20 | const ppUrls = [ 21 | 'https://i.ibb.co/KhYC4FY/1221bc0bdd2354b42b293317ff2adbcf-icon.png', 22 | 'https://i.ibb.co/KhYC4FY/1221bc0bdd2354b42b293317ff2adbcf-icon.png', 23 | 'https://i.ibb.co/KhYC4FY/1221bc0bdd2354b42b293317ff2adbcf-icon.png', 24 | ]; 25 | 26 | const GroupEvents = async (conn, update) => { 27 | try { 28 | const isGroup = isJidGroup(update.id); 29 | if (!isGroup) return; 30 | 31 | const metadata = await conn.groupMetadata(update.id); 32 | const participants = update.participants; 33 | const desc = metadata.desc || "No Description"; 34 | const groupMembersCount = metadata.participants.length; 35 | 36 | let ppUrl; 37 | try { 38 | ppUrl = await conn.profilePictureUrl(update.id, 'image'); 39 | } catch { 40 | ppUrl = ppUrls[Math.floor(Math.random() * ppUrls.length)]; 41 | } 42 | 43 | for (const num of participants) { 44 | const userName = num.split("@")[0]; 45 | const timestamp = new Date().toLocaleString(); 46 | 47 | if (update.action === "add" && config.WELCOME === "true") { 48 | const WelcomeText = `Hey @${userName} 👋\n` + 49 | `Welcome to *${metadata.subject}*.\n` + 50 | `You are member number ${groupMembersCount} in this group. 🙏\n` + 51 | `Time joined: *${timestamp}*\n` + 52 | `Please read the group description to avoid being removed:\n` + 53 | `${desc}\n` + 54 | `> *ᴘᴏᴡᴇʀᴇᴅ ʙʏ ɢᴏᴛᴀʀ ᴛᴇᴄʜ*.`; 55 | 56 | await conn.sendMessage(update.id, { 57 | image: { url: ppUrl }, 58 | caption: WelcomeText, 59 | mentions: [num], 60 | contextInfo: getContextInfo({ sender: num }), 61 | }); 62 | 63 | } else if (update.action === "remove" && config.WELCOME === "true") { 64 | const GoodbyeText = `Goodbye @${userName}. 😔\n` + 65 | `Another member has left the group.\n` + 66 | `Time left: *${timestamp}*\n` + 67 | `The group now has ${groupMembersCount} members. 😭` 68 | `> ᴘᴏᴡᴇʀᴇᴅ ʙʏ ɢᴏᴛᴀʀ ᴛᴇᴄʜ`; 69 | 70 | await conn.sendMessage(update.id, { 71 | image: { url: ppUrl }, 72 | caption: GoodbyeText, 73 | mentions: [num], 74 | contextInfo: getContextInfo({ sender: num }), 75 | }); 76 | 77 | } else if (update.action === "demote" && config.ADMIN_EVENTS === "true") { 78 | const demoter = update.author.split("@")[0]; 79 | await conn.sendMessage(update.id, { 80 | text: `*Admin Event*\n\n` + 81 | `@${demoter} has demoted @${userName} from admin. 👀\n` + 82 | `Time: ${timestamp}\n` + 83 | `*Group:* ${metadata.subject}`, 84 | mentions: [update.author, num], 85 | contextInfo: getContextInfo({ sender: update.author }), 86 | }); 87 | 88 | } else if (update.action === "promote" && config.ADMIN_EVENTS === "true") { 89 | const promoter = update.author.split("@")[0]; 90 | await conn.sendMessage(update.id, { 91 | text: `*Admin Event*\n\n` + 92 | `@${promoter} has promoted @${userName} to admin. 🎉\n` + 93 | `Time: ${timestamp}\n` + 94 | `*Group:* ${metadata.subject}`, 95 | mentions: [update.author, num], 96 | contextInfo: getContextInfo({ sender: update.author }), 97 | }); 98 | } 99 | } 100 | } catch (err) { 101 | console.error('Group event error:', err); 102 | } 103 | }; 104 | 105 | module.exports = GroupEvents; 106 | -------------------------------------------------------------------------------- /lib/functions2.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const axios = require('axios'); 3 | const path = './config.env'; 4 | const FormData = require("form-data"); 5 | 6 | async function empiretourl(path) { 7 | if (!fs.existsSync(path)) { 8 | throw new Error(`File not found: ${path}`); 9 | } 10 | 11 | const form = new FormData(); 12 | const fileStream = fs.createReadStream(path); 13 | form.append("file", fileStream); 14 | const originalFileName = path.split("/").pop(); 15 | form.append("originalFileName", originalFileName); 16 | 17 | try { 18 | const response = await axios.post("https://cdn.empiretech.biz.id/api/upload.php", form, { 19 | headers: { 20 | ...form.getHeaders(), 21 | }, 22 | maxContentLength: Infinity, 23 | maxBodyLength: Infinity, 24 | }); 25 | return response.data; 26 | } catch (error) { 27 | if (error.response) { 28 | throw new Error(`API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`); 29 | } else if (error.request) { 30 | throw new Error("No response received from the server."); 31 | } else { 32 | throw new Error(`Request Error: ${error.message}`); 33 | } 34 | } 35 | } 36 | 37 | // Fetch a buffer from a URL 38 | const getBuffer = async (url, options) => { 39 | try { 40 | options = options || {}; 41 | const res = await axios({ 42 | method: 'get', 43 | url, 44 | headers: { 45 | 'DNT': 1, 46 | 'Upgrade-Insecure-Request': 1 47 | }, 48 | ...options, 49 | responseType: 'arraybuffer' 50 | }); 51 | return res.data; 52 | } catch (e) { 53 | console.error(e); 54 | return null; 55 | } 56 | }; 57 | 58 | // Get admin participants from a group 59 | const getGroupAdmins = (participants) => { 60 | const admins = []; 61 | for (let participant of participants) { 62 | if (participant.admin !== null) admins.push(participant.id); 63 | } 64 | return admins; 65 | }; 66 | 67 | // Generate a random string with an extension 68 | const getRandom = (ext) => { 69 | return `${Math.floor(Math.random() * 10000)}${ext}`; 70 | }; 71 | 72 | // Format large numbers with suffixes (e.g., K, M, B) 73 | const h2k = (eco) => { 74 | const lyrik = ['', 'K', 'M', 'B', 'T', 'P', 'E']; 75 | const ma = Math.floor(Math.log10(Math.abs(eco)) / 3); 76 | if (ma === 0) return eco.toString(); 77 | const scale = Math.pow(10, ma * 3); 78 | const scaled = eco / scale; 79 | const formatted = scaled.toFixed(1).replace(/\.0$/, ''); 80 | return formatted + lyrik[ma]; 81 | }; 82 | 83 | // Check if a string is a URL 84 | const isUrl = (url) => { 85 | return url.match( 86 | /https?:\/\/(www\.)?[-a-zA-Z0-9@:%.+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%+.~#?&/=]*)/ 87 | ); 88 | }; 89 | 90 | // Convert a JavaScript object or array to a JSON string 91 | const Json = (string) => { 92 | return JSON.stringify(string, null, 2); 93 | }; 94 | 95 | // Function to calculate and format uptime 96 | const runtime = (seconds) => { 97 | seconds = Math.floor(seconds); 98 | const d = Math.floor(seconds / (24 * 60 * 60)); 99 | seconds %= 24 * 60 * 60; 100 | const h = Math.floor(seconds / (60 * 60)); 101 | seconds %= 60 * 60; 102 | const m = Math.floor(seconds / 60); 103 | const s = Math.floor(seconds % 60); 104 | 105 | if (d > 0) return `${d}d ${h}h ${m}m ${s}s`; 106 | if (h > 0) return `${h}h ${m}m ${s}s`; 107 | if (m > 0) return `${m}m ${s}s`; 108 | return `${s}s`; 109 | }; 110 | // Delay execution for a specified time 111 | const sleep = async (ms) => { 112 | return new Promise((resolve) => setTimeout(resolve, ms)); 113 | }; 114 | 115 | // Fetch JSON from a URL 116 | const fetchJson = async (url, options) => { 117 | try { 118 | options = options || {}; 119 | const res = await axios({ 120 | method: 'GET', 121 | url: url, 122 | headers: { 123 | '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' 124 | }, 125 | ...options 126 | }); 127 | return res.data; 128 | } catch (err) { 129 | console.error(err); 130 | return null; 131 | } 132 | }; 133 | // Save config settings 134 | const saveConfig = (key, value) => { 135 | let configData = fs.existsSync(path) ? fs.readFileSync(path, 'utf8').split('\n') : []; 136 | let found = false; 137 | 138 | configData = configData.map(line => { 139 | if (line.startsWith(`${key}=`)) { 140 | found = true; 141 | return `${key}=${value}`; 142 | } 143 | return line; 144 | }); 145 | 146 | if (!found) configData.push(`${key}=${value}`); 147 | 148 | fs.writeFileSync(path, configData.join('\n'), 'utf8'); 149 | 150 | // Reload updated environment variables 151 | require('dotenv').config({ path }); 152 | }; 153 | 154 | module.exports = { 155 | getBuffer, 156 | getGroupAdmins, 157 | getRandom, 158 | h2k, 159 | isUrl, 160 | Json, 161 | runtime, 162 | sleep, 163 | fetchJson, 164 | saveConfig, 165 | empiretourl 166 | }; 167 | 168 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "GOTAR-XMD", 3 | "description": "Javascript WhatsApp bot made ɢᴏᴛᴀʀ ᴛᴇᴄʜ", 4 | "logo": "https://files.catbox.moe/82b8gr.jpg", 5 | "keywords": ["GOTAR-XMD"], 6 | "success_url": "/", 7 | 8 | "stack": "container", 9 | "env": { 10 | "SESSION_ID": { 11 | "description": "Put the session-id here.", 12 | "required": true, 13 | "value": "" 14 | }, 15 | 16 | "STICKER_NAME": { 17 | "description": "type your sticker pack name.", 18 | "required": false, 19 | "value": "𝐆𝐎𝐓𝐀𝐑 𝐗𝐌𝐃" 20 | }, 21 | 22 | "PREFIX": { 23 | "description": "paste your bot prefix note! Don't apply null prefix.", 24 | "required": false, 25 | "value": "." 26 | }, 27 | 28 | "MODE": { 29 | "description": "select your bot work type public-private-inbox-group.", 30 | "required": false, 31 | "value": "public" 32 | 33 | }, 34 | 35 | 36 | "ALWAYS_ONLINE": { 37 | "description": "Make it true if want always online.", 38 | "required": false, 39 | "value": "false" 40 | }, 41 | 42 | "AUTO_VOICE": { 43 | "description": "Make it true if want automatic voice reply .", 44 | "required": false, 45 | "value": "false" 46 | }, 47 | 48 | "AUTO_REPLY": { 49 | "description": "Make it true if you want automatic reply.", 50 | "required": false, 51 | "value": "false" 52 | }, 53 | 54 | "AUTO_STICKER": { 55 | "description": "Make it true if you want automatic sticker.", 56 | "required": false, 57 | "value": "false" 58 | }, 59 | 60 | 61 | "AUTO_STATUS_SEEN": { 62 | "description": "Make it true for automatic status seen.", 63 | "required": true, 64 | "value": "true" 65 | }, 66 | 67 | "AUTO_STATUS_REACT": { 68 | "description": "make it true for automatic status reaction or like.", 69 | "required": true, 70 | "value": "true" 71 | }, 72 | 73 | "AUTO_STATUS_REPLY": { 74 | "description": "Make it true for auto reply msg on status seen.", 75 | "required": true, 76 | "value": "false" 77 | }, 78 | 79 | "AUTO_STATUS_MSG": { 80 | "description": "Type custom message on status reply", 81 | "required": true, 82 | "value": "*SEEN YOUR STATUS BY 𝐆𝐎𝐓𝐀𝐑 𝐗𝐌𝐃 🖤*" 83 | 84 | }, 85 | 86 | "OWNER_NAME": { 87 | "description": "Type Bot Owner Name.", 88 | "required": false, 89 | "value": "YOUR NAME" 90 | }, 91 | 92 | "OWNER_NUMBER": { 93 | "description": "put the owner number for bot.", 94 | "required": false, 95 | "value": "509xxxxxx" 96 | 97 | }, 98 | 99 | "BOT_NAME": { 100 | "description": "Type here the bot name.", 101 | "required": false, 102 | "value": "𝐆𝐎𝐓𝐀𝐑 𝐗𝐌𝐃" 103 | 104 | }, 105 | 106 | "ANTI_LINK": { 107 | "description": "Make it true if you want bot auto remove group link.", 108 | "required": true, 109 | "value": "true" 110 | 111 | }, 112 | 113 | "ANTI_LINK_KICK": { 114 | "description": "Make it true if you want bot auto remove group link.", 115 | "required": true, 116 | "value": "false" 117 | 118 | }, 119 | 120 | "ANTI_BAD": { 121 | "description": "Make it true if you want bot auto delete bad words.", 122 | "required": false, 123 | "value": "false" 124 | }, 125 | 126 | "MENTION_REPLY": { 127 | "description": "make it true if want mention reply if someone menetion you.", 128 | "required": false, 129 | "value": "false" 130 | }, 131 | 132 | "MENU_IMAGE_URL": { 133 | "description": "add url for mention reply and menu if want.", 134 | "required": false, 135 | "value": "https://files.catbox.moe/82b8gr.jpg" 136 | }, 137 | 138 | "DESCRIPTION": { 139 | "description": "add caption for menu and other", 140 | "required": false, 141 | "value": "> *ᴘᴏᴡᴇʀᴇᴅ ʙʏ ɢᴏᴛᴀʀ ᴛᴇᴄʜ*" 142 | }, 143 | 144 | "DELETE_LINKS": { 145 | "description": "remove links from group automatically without removing member", 146 | "required": false, 147 | "value": "false" 148 | }, 149 | 150 | "AUTO_RECORDING": { 151 | "description": "Make it true if you want auto recoding.", 152 | "required": false, 153 | "value": "false" 154 | }, 155 | 156 | "AUTO_TYPING": { 157 | "description": "Make it true if you want auto typing.", 158 | "required": false, 159 | "value": "false" 160 | }, 161 | 162 | "AUTO_REACT": { 163 | "description": "Make it true if you want react on every message.", 164 | "required": false, 165 | "value": "false" 166 | }, 167 | 168 | "CUSTOM_REACT": { 169 | "description": "Make it true if you want custom reactions.", 170 | "required": false, 171 | "value": "false" 172 | 173 | }, 174 | 175 | "CUSTOM_REACT_EMOJIS": { 176 | "description": "put here custom react react emojis.", 177 | "required": false, 178 | "value": "💝,💖,💗,❤️‍🩹,❤️,🧡,💛,💚,💙,💜,🤎,🖤,🤍" 179 | }, 180 | 181 | "ANTI_DEL_PATH": { 182 | "description": "change it to -same- if you want to resend deleted message in same chat", 183 | "required": false, 184 | "value": "log" 185 | }, 186 | 187 | "ADMIN_EVENTS": { 188 | "description": "make it true if want know who promote or demote a member .", 189 | "required": false, 190 | "value": "false" 191 | }, 192 | 193 | "WELCOME": { 194 | "description": "make it true if want goodbye and welcome message in groups.", 195 | "required": false, 196 | "value": "true" 197 | }, 198 | 199 | "READ_MESSAGE": { 200 | "description": "Make it true if you want bot read your all sms just now.", 201 | "required": false, 202 | "value": "false" 203 | } 204 | 205 | }, 206 | 207 | "buildpacks": [ 208 | { 209 | "url": "https://github.com/heroku/heroku-buildpack-nodejs.git" 210 | } 211 | ], 212 | "stack": "heroku-24" 213 | } 214 | 215 | -------------------------------------------------------------------------------- /data/store.js: -------------------------------------------------------------------------------- 1 | const { isJidBroadcast, isJidGroup, isJidNewsletter } = require('@whiskeysockets/baileys'); 2 | const fs = require('fs/promises') 3 | const path = require('path') 4 | const { DataTypes } = require('sequelize'); 5 | const { DATABASE } = require('../lib/database'); 6 | const storeDir = path.join(process.cwd(), 'store'); 7 | 8 | const readJSON = async (file) => { 9 | try { 10 | const filePath = path.join(storeDir, file); 11 | const data = await fs.readFile(filePath, 'utf8'); 12 | return JSON.parse(data); 13 | } catch { 14 | return []; 15 | } 16 | }; 17 | 18 | const writeJSON = async (file, data) => { 19 | const filePath = path.join(storeDir, file); 20 | await fs.mkdir(storeDir, { recursive: true }); 21 | await fs.writeFile(filePath, JSON.stringify(data, null, 2)); 22 | }; 23 | 24 | const saveContact = async (jid, name) => { 25 | if (!jid || !name || isJidGroup(jid) || isJidBroadcast(jid) || isJidNewsletter(jid)) return; 26 | const contacts = await readJSON('contact.json'); 27 | const index = contacts.findIndex((contact) => contact.jid === jid); 28 | if (index > -1) { 29 | contacts[index].name = name; 30 | } else { 31 | contacts.push({ jid, name }); 32 | } 33 | await writeJSON('contact.json', contacts); 34 | }; 35 | 36 | const getContacts = async () => { 37 | try { 38 | const contacts = await readJSON('contact.json'); 39 | return contacts; 40 | } catch (error) { 41 | return []; 42 | } 43 | }; 44 | 45 | const saveMessage = async (message) => { 46 | const jid = message.key.remoteJid; 47 | const id = message.key.id; 48 | if (!id || !jid || !message) return; 49 | await saveContact(message.sender, message.pushName); 50 | const messages = await readJSON('message.json'); 51 | const index = messages.findIndex((msg) => msg.id === id && msg.jid === jid); 52 | const timestamp = message.messageTimestamp ? message.messageTimestamp * 1000 : Date.now(); 53 | if (index > -1) { 54 | messages[index].message = message; 55 | messages[index].timestamp = timestamp; 56 | } else { 57 | messages.push({ id, jid, message, timestamp }); 58 | } 59 | await writeJSON('message.json', messages); 60 | }; 61 | 62 | const loadMessage = async (id) => { 63 | if (!id) return null; 64 | const messages = await readJSON('message.json'); 65 | return messages.find((msg) => msg.id === id) || null; 66 | }; 67 | 68 | const getName = async (jid) => { 69 | const contacts = await readJSON('contact.json'); 70 | const contact = contacts.find((contact) => contact.jid === jid); 71 | return contact ? contact.name : jid.split('@')[0].replace(/_/g, ' '); 72 | }; 73 | 74 | const saveGroupMetadata = async (jid, client) => { 75 | if (!isJidGroup(jid)) return; 76 | const groupMetadata = await client.groupMetadata(jid); 77 | const metadata = { 78 | jid: groupMetadata.id, 79 | subject: groupMetadata.subject, 80 | subjectOwner: groupMetadata.subjectOwner, 81 | subjectTime: groupMetadata.subjectTime 82 | ? new Date(groupMetadata.subjectTime * 1000).toISOString() 83 | : null, 84 | size: groupMetadata.size, 85 | creation: groupMetadata.creation ? new Date(groupMetadata.creation * 1000).toISOString() : null, 86 | owner: groupMetadata.owner, 87 | desc: groupMetadata.desc, 88 | descId: groupMetadata.descId, 89 | linkedParent: groupMetadata.linkedParent, 90 | restrict: groupMetadata.restrict, 91 | announce: groupMetadata.announce, 92 | isCommunity: groupMetadata.isCommunity, 93 | isCommunityAnnounce: groupMetadata.isCommunityAnnounce, 94 | joinApprovalMode: groupMetadata.joinApprovalMode, 95 | memberAddMode: groupMetadata.memberAddMode, 96 | ephemeralDuration: groupMetadata.ephemeralDuration, 97 | }; 98 | 99 | const metadataList = await readJSON('metadata.json'); 100 | const index = metadataList.findIndex((meta) => meta.jid === jid); 101 | if (index > -1) { 102 | metadataList[index] = metadata; 103 | } else { 104 | metadataList.push(metadata); 105 | } 106 | await writeJSON('metadata.json', metadataList); 107 | 108 | const participants = groupMetadata.participants.map((participant) => ({ 109 | jid, 110 | participantId: participant.id, 111 | admin: participant.admin, 112 | })); 113 | await writeJSON(`${jid}_participants.json`, participants); 114 | }; 115 | 116 | const getGroupMetadata = async (jid) => { 117 | if (!isJidGroup(jid)) return null; 118 | const metadataList = await readJSON('metadata.json'); 119 | const metadata = metadataList.find((meta) => meta.jid === jid); 120 | if (!metadata) return null; 121 | 122 | const participants = await readJSON(`${jid}_participants.json`); 123 | return { ...metadata, participants }; 124 | }; 125 | const saveMessageCount = async (message) => { 126 | if (!message) return; 127 | const jid = message.key.remoteJid; 128 | const sender = message.key.participant || message.sender; 129 | if (!jid || !sender || !isJidGroup(jid)) return; 130 | 131 | const messageCounts = await readJSON('message_count.json'); 132 | const index = messageCounts.findIndex((record) => record.jid === jid && record.sender === sender); 133 | 134 | if (index > -1) { 135 | messageCounts[index].count += 1; 136 | } else { 137 | messageCounts.push({ jid, sender, count: 1 }); 138 | } 139 | 140 | await writeJSON('message_count.json', messageCounts); 141 | }; 142 | 143 | const getInactiveGroupMembers = async (jid) => { 144 | if (!isJidGroup(jid)) return []; 145 | const groupMetadata = await getGroupMetadata(jid); 146 | if (!groupMetadata) return []; 147 | 148 | const messageCounts = await readJSON('message_count.json'); 149 | const inactiveMembers = groupMetadata.participants.filter((participant) => { 150 | const record = messageCounts.find((msg) => msg.jid === jid && msg.sender === participant.id); 151 | return !record || record.count === 0; 152 | }); 153 | 154 | return inactiveMembers.map((member) => member.id); 155 | }; 156 | 157 | const getGroupMembersMessageCount = async (jid) => { 158 | if (!isJidGroup(jid)) return []; 159 | const messageCounts = await readJSON('message_count.json'); 160 | const groupCounts = messageCounts 161 | .filter((record) => record.jid === jid && record.count > 0) 162 | .sort((a, b) => b.count - a.count); 163 | 164 | return Promise.all( 165 | groupCounts.map(async (record) => ({ 166 | sender: record.sender, 167 | name: await getName(record.sender), 168 | messageCount: record.count, 169 | })) 170 | ); 171 | }; 172 | 173 | const getChatSummary = async () => { 174 | const messages = await readJSON('message.json'); 175 | const distinctJids = [...new Set(messages.map((msg) => msg.jid))]; 176 | 177 | const summaries = await Promise.all( 178 | distinctJids.map(async (jid) => { 179 | const chatMessages = messages.filter((msg) => msg.jid === jid); 180 | const messageCount = chatMessages.length; 181 | const lastMessage = chatMessages.sort( 182 | (a, b) => new Date(b.timestamp) - new Date(a.timestamp) 183 | )[0]; 184 | const chatName = isJidGroup(jid) ? jid : await getName(jid); 185 | 186 | return { 187 | jid, 188 | name: chatName, 189 | messageCount, 190 | lastMessageTimestamp: lastMessage ? lastMessage.timestamp : null, 191 | }; 192 | }) 193 | ); 194 | 195 | return summaries.sort( 196 | (a, b) => new Date(b.lastMessageTimestamp) - new Date(a.lastMessageTimestamp) 197 | ); 198 | }; 199 | 200 | const saveMessageV1 = saveMessage; 201 | const saveMessageV2 = (message) => { 202 | return Promise.all([saveMessageV1(message), saveMessageCount(message)]); 203 | }; 204 | 205 | module.exports = { 206 | saveContact, 207 | loadMessage, 208 | getName, 209 | getChatSummary, 210 | saveGroupMetadata, 211 | getGroupMetadata, 212 | saveMessageCount, 213 | getInactiveGroupMembers, 214 | getGroupMembersMessageCount, 215 | saveMessage: saveMessageV2, 216 | }; 217 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ``` 3 | DONT FORGET TO FORK 🍴 & STAR 🌟 REPO😇 4 | ``` 5 | --- 6 | 7 | > **CURRENT BOT VERSION ➜ `1.0.0 ⚡`** 8 | --- 9 | 10 | 11 | 12 | 13 | 14 |

15 | 16 | 17 | 18 | 19 |    20 |

21 | 22 |

23 | 24 | Typing SVG 25 | 26 |

27 | 28 | --- 29 | 30 | 31 | 32 | 33 | 34 | *** 35 | 36 | 37 | 38 | 39 | ### 1. 𐃁FORK THIS REPOSITORY𐃁 40 | 41 | `FORK 🍴 AND STAR ⭐ IF YOU LIKE THIS BOT` 42 | 43 | 44 | 45 | ### 2. 𐃁GET SESSION ID𐃁 46 | 47 | `IF YOU DON'T HAVE YOUR SESSION_ID SO U CAN GET IT CLICK ON SESSION_ID BUTTON AND PASTE YOUR NUMBER With COUNTRY CODE EXAMPLE:1855xxxxxx THEN YOU CAN GET YOUR SESSION_ID ✠` 48 | 49 | 50 | > **1. PAIR CODE SESSION ID** 51 | 52 | 53 | Pairing Code 54 | 55 |
56 | 57 | > **2. PAIR CODE SESSION ID** 58 | 59 | 60 | Pairing Code 61 | 62 |
63 | 64 | 65 | 66 | --- 67 | 68 | ###

𐃁GOTAR-XMD DEPLOYMENT OPTIONS𐃁

69 | 70 | --- 71 | 72 | ###

1. HEROKU

73 |

74 | 75 | 76 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://dashboard.heroku.com/new?template=https://github.com/gotartech/GOTAR-XMD) 77 | 78 | 79 | ###

3. KOYEB

80 |

81 | 82 |

83 | Heroku 84 | 85 | 86 | ###

2. TALKDROVE FREE

87 |

88 | 89 |

90 | Heroku 91 | 92 | 93 | ###

4. RAILWAY

94 |

95 | 96 |

97 | Heroku 98 | 99 | 100 | ###

5. RENDER

101 |

102 | 103 |

104 | Heroku 105 | 106 | 107 | ###

6. HUGGING FACE

108 |

109 | 110 |

111 | Netlify 112 | 113 |

114 | 115 | EASIEST METHOD 2 116 |

117 | 118 | 119 | ##

HOW TO DEPLOY ON HUGGING FACE

120 |
121 | *❄️ Deploy GOTAR-XMD On Hugging Face For Free !* 122 | 123 | `Specs :` 124 | - v2 CPU 125 | - 16GB RAM 126 | 127 | > `Steps to deploy` 128 | 129 | `Step 1` 130 | 1. Go to hugginface.co/join and create an account and verify your email too. 131 | 132 | `Step 2` 133 | 1. Go to https://huggingface.co/spaces/gotar/GOTAR-XMD 134 | 135 | 2. Tap on *three dots* _(as shown in image)_ 136 | 137 | 3. Tap on *duplicate space* _(as shown in image)_ 138 | 139 | `Step 3` 140 | 1. Fill your details, e.g., Session ID, Bot Name, owner number etc... 141 | 142 | 2. Tap on *duplicate space shown below* 143 | 144 | ```After that wait 10 seconds & your have deployed it successfuly for free 24/7``` 145 | 146 | > CREDITS 🎐 147 | 148 | *ᴘᴏᴡᴇʀᴇᴅ ʙʏ ᴅʏʙʏ ᴛᴇᴄʜ*
149 | 150 |
151 | 152 | 153 | 154 | 155 | ###

7. REPLIT

156 |

157 | 158 |

159 | Replit 160 | 161 | 162 | 163 | ## WORKFLOWS 164 | 165 | ``` 166 | name: Node.js CI 167 | 168 | on: 169 | push: 170 | branches: 171 | - main 172 | pull_request: 173 | branches: 174 | - main 175 | schedule: 176 | - cron: '0 */6 * * *' 177 | 178 | jobs: 179 | build: 180 | 181 | runs-on: ubuntu-latest 182 | 183 | strategy: 184 | matrix: 185 | node-version: [20.x] 186 | 187 | steps: 188 | - name: Checkout repository 189 | uses: actions/checkout@v3 190 | 191 | - name: Set up Node.js 192 | uses: actions/setup-node@v3 193 | with: 194 | node-version: ${{ matrix.node-version }} 195 | 196 | - name: Install dependencies 197 | run: npm install 198 | 199 | - name: Install FFmpeg 200 | run: sudo apt-get install -y ffmpeg 201 | 202 | - name: Start application with timeout 203 | run: | 204 | timeout 21590s npm start # Limite l'exécution à 5h 59m 50s 205 | 206 | - name: Save state (Optional) 207 | run: | 208 | ./save_state.sh 209 | ``` 210 | 211 | 212 | 213 | ## 👑 PROJECT OWNER 214 | HII DEARS FRIENDS IF YOU WANT ANY HELP SO YOU CAN CONTACT↘︎ WITH ME WIA WHATSAPP ITS ME GOTAR TECH࿐➺ 215 | 216 |

217 | Replit 218 | 219 | 220 | 221 | ## 🪀 WHATSAPP CHANNEL 222 | STAY CONNECTED WITH THE LATEST UPDATES AND COMMUNITY BY JOINING OUR OFFICIAL WHATSAPP GROUP AND CHANNEL. YOU CAN ALSO CONTACT THE OWNER DIRECTLY. 223 | 224 | [![WhatsApp Channel](https://img.shields.io/badge/JOIN-WHATSAAP%20CHANNEL-25D366?style=for-the-badge&logo=whatsapp)](https://whatsapp.com/channel/0029VbAOpMmAInPoTescPr0y) 225 | 226 | ## 🪀 WHATSAPP GROUP 227 | JOINING OUR OFFICIAL WHATSAPP GROUP AND CHANNEL. YOU CAN ALSO CONTACT THE OWNER DIRECTLY. 228 | 229 | [![WhatsApp Group](https://img.shields.io/badge/JOIN-WHATSAAP%20GROUP-25D366?style=for-the-badge&logo=whatsapp)](https://chat.whatsapp.com/KSEIThE3vIS3fVQZTyDia2) 230 | 231 | 232 | 233 | 234 | *** 235 | 236 | ##

⚠️ REMINDER

237 |

238 | 239 | - **DISCLAIMER:** THIS BOT IS NOT AFFILIATED WITH `WhatsApp Inc.`. USE IT AT YOUR OWN RISK. 240 | - MISUSING THE BOT MAY RESULT IN YOUR `WhatsApp` ACCOUNT BEING BANNED. NOTE THAT YOU CAN ONLY UNBAN YOUR ACCOUNT ONCE. 241 | - I AM NOT RESPONSIBLE FOR ANY BANS OR MISUSE OF THE BOT. PLEASE KEEP THIS WARNING IN MIND BEFORE PROCEEDING. 242 | 243 | --- 244 | 245 |

ℹ️ NOTICE

246 |

247 | NOT FOR SALE - IF ANY PLUGIN'S CODE IS OBFUSCATED, YOU DO NOT HAVE PERMISSION TO EDIT IT IN ANY FORM. PLEASE REMEMBER TO GIVE CREDIT IF YOU ARE USING OR RE-UPLOADING MY PLUGINS/FILES. WISHING YOU A WONDERFUL DAY AHEAD!

248 | 249 | --- 250 | 251 |
252 |

⚠️ DISCLAIMER ⚠️ 253 |

254 | 255 | --- 256 | 257 |

DON'T COPY WITHOUT PERMISSION 258 |

259 | 260 |
261 | 262 | ``` 263 | THANK YOU DybyTech, & YOU SUPPORTERS 264 | ``` 265 | ----- 266 | 267 | 268 | ------ 269 | -------------------------------------------------------------------------------- /lib/msg.js: -------------------------------------------------------------------------------- 1 | const { proto, downloadContentFromMessage, getContentType } = require('@whiskeysockets/baileys') 2 | const fs = require('fs') 3 | 4 | const downloadMediaMessage = async(m, filename) => { 5 | if (m.type === 'viewOnceMessage') { 6 | m.type = m.msg.type 7 | } 8 | if (m.type === 'imageMessage') { 9 | var nameJpg = filename ? filename + '.jpg' : 'undefined.jpg' 10 | const stream = await downloadContentFromMessage(m.msg, 'image') 11 | let buffer = Buffer.from([]) 12 | for await (const chunk of stream) { 13 | buffer = Buffer.concat([buffer, chunk]) 14 | } 15 | fs.writeFileSync(nameJpg, buffer) 16 | return fs.readFileSync(nameJpg) 17 | } else if (m.type === 'videoMessage') { 18 | var nameMp4 = filename ? filename + '.mp4' : 'undefined.mp4' 19 | const stream = await downloadContentFromMessage(m.msg, 'video') 20 | let buffer = Buffer.from([]) 21 | for await (const chunk of stream) { 22 | buffer = Buffer.concat([buffer, chunk]) 23 | } 24 | fs.writeFileSync(nameMp4, buffer) 25 | return fs.readFileSync(nameMp4) 26 | } else if (m.type === 'audioMessage') { 27 | var nameMp3 = filename ? filename + '.mp3' : 'undefined.mp3' 28 | const stream = await downloadContentFromMessage(m.msg, 'audio') 29 | let buffer = Buffer.from([]) 30 | for await (const chunk of stream) { 31 | buffer = Buffer.concat([buffer, chunk]) 32 | } 33 | fs.writeFileSync(nameMp3, buffer) 34 | return fs.readFileSync(nameMp3) 35 | } else if (m.type === 'stickerMessage') { 36 | var nameWebp = filename ? filename + '.webp' : 'undefined.webp' 37 | const stream = await downloadContentFromMessage(m.msg, 'sticker') 38 | let buffer = Buffer.from([]) 39 | for await (const chunk of stream) { 40 | buffer = Buffer.concat([buffer, chunk]) 41 | } 42 | fs.writeFileSync(nameWebp, buffer) 43 | return fs.readFileSync(nameWebp) 44 | } else if (m.type === 'documentMessage') { 45 | var ext = m.msg.fileName.split('.')[1].toLowerCase().replace('jpeg', 'jpg').replace('png', 'jpg').replace('m4a', 'mp3') 46 | var nameDoc = filename ? filename + '.' + ext : 'undefined.' + ext 47 | const stream = await downloadContentFromMessage(m.msg, 'document') 48 | let buffer = Buffer.from([]) 49 | for await (const chunk of stream) { 50 | buffer = Buffer.concat([buffer, chunk]) 51 | } 52 | fs.writeFileSync(nameDoc, buffer) 53 | return fs.readFileSync(nameDoc) 54 | } 55 | } 56 | 57 | const sms = (conn, m, store) => { 58 | if (!m) return m 59 | let M = proto.WebMessageInfo 60 | if (m.key) { 61 | m.id = m.key.id 62 | m.isBot = m.id.startsWith('BAES') && m.id.length === 16 63 | m.isBaileys = m.id.startsWith('BAE5') && m.id.length === 16 64 | m.chat = m.key.remoteJid 65 | m.fromMe = m.key.fromMe 66 | m.isGroup = m.chat.endsWith('@g.us') 67 | m.sender = m.fromMe ? conn.user.id.split(':')[0]+'@s.whatsapp.net' : m.isGroup ? m.key.participant : m.key.remoteJid 68 | //m.sender = conn.decodeJid(m.fromMe && conn.user.id || m.participant || m.key.participant || m.chat || '') 69 | //if (m.isGroup) m.participant = conn.decodeJid(m.key.participant) || '' 70 | } 71 | if (m.message) { 72 | m.mtype = getContentType(m.message) 73 | m.msg = (m.mtype == 'viewOnceMessage' ? m.message[m.mtype].message[getContentType(m.message[m.mtype].message)] : m.message[m.mtype]) 74 | try { 75 | m.body = (m.mtype === 'conversation') ? m.message.conversation : 76 | (m.mtype == 'imageMessage' && m.message.imageMessage.caption != undefined) ? m.message.imageMessage.caption : 77 | (m.mtype == 'videoMessage' && m.message.videoMessage.caption != undefined) ? m.message.videoMessage.caption : 78 | (m.mtype == 'extendedTextMessage' && m.message.extendedTextMessage.text != undefined) ? m.message.extendedTextMessage.text : 79 | (m.mtype == 'buttonsResponseMessage') ? m.message.buttonsResponseMessage.selectedButtonId : 80 | (m.mtype == 'listResponseMessage') ? m.message.listResponseMessage.singleSelectReply.selectedRowId : 81 | (m.mtype == 'templateButtonReplyMessage') ? m.message.templateButtonReplyMessage.selectedId : 82 | (m.mtype === 'messageContextInfo') ? (m.message.buttonsResponseMessage?.selectedButtonId || m.message.listResponseMessage?.singleSelectReply.selectedRowId || m.text) : ''; 83 | } catch { 84 | m.body = false 85 | } 86 | let quoted = (m.quoted = m.msg.contextInfo ? m.msg.contextInfo.quotedMessage : null); 87 | m.mentionedJid = m.msg.contextInfo ? m.msg.contextInfo.mentionedJid : [] 88 | 89 | if (m.quoted) { 90 | let type = getContentType(quoted) 91 | m.quoted = m.quoted[type] 92 | if (['productMessage'].includes(type)) { 93 | type = getContentType(m.quoted) 94 | m.quoted = m.quoted[type] 95 | } 96 | if (typeof m.quoted === 'string') m.quoted = { text: m.quoted } 97 | 98 | 99 | if(quoted.viewOnceMessageV2) 100 | { 101 | console.log("entered ==================================== ") 102 | //console.log ("m Is : ",m,"\nm Quoted is :",m.quoted ,"\n Quoted is : ",quoted,"\nviewOnce : ", quoted.viewOnceMessageV2.message) 103 | 104 | } else 105 | { 106 | 107 | 108 | m.quoted.mtype = type 109 | m.quoted.id = m.msg.contextInfo.stanzaId 110 | m.quoted.chat = m.msg.contextInfo.remoteJid || m.chat 111 | m.quoted.isBot = m.quoted.id ? m.quoted.id.startsWith('BAES') && m.quoted.id.length === 16 : false 112 | m.quoted.isBaileys = m.quoted.id ? m.quoted.id.startsWith('BAE5') && m.quoted.id.length === 16 : false 113 | m.quoted.sender = conn.decodeJid(m.msg.contextInfo.participant) 114 | m.quoted.fromMe = m.quoted.sender === (conn.user && conn.user.id) 115 | m.quoted.text = m.quoted.text || m.quoted.caption || m.quoted.conversation || m.quoted.contentText || m.quoted.selectedDisplayText || m.quoted.title || '' 116 | m.quoted.mentionedJid = m.msg.contextInfo ? m.msg.contextInfo.mentionedJid : [] 117 | m.getQuotedObj = m.getQuotedMessage = async () => { 118 | if (!m.quoted.id) return false 119 | let q = await store.loadMessage(m.chat, m.quoted.id, conn) 120 | return exports.sms(conn, q, store) 121 | } 122 | let vM = m.quoted.fakeObj = M.fromObject({ 123 | key: { 124 | remoteJid: m.quoted.chat, 125 | fromMe: m.quoted.fromMe, 126 | id: m.quoted.id 127 | }, 128 | message: quoted, 129 | ...(m.isGroup ? { participant: m.quoted.sender } : {}) 130 | }) 131 | /** 132 | * 133 | * @returns 134 | */ 135 | let { chat, fromMe, id } = m.quoted; 136 | const key = { 137 | remoteJid: m.chat, 138 | fromMe: false, 139 | id: m.quoted.id, 140 | participant: m.quoted.sender 141 | } 142 | m.quoted.delete = async() => await conn.sendMessage(m.chat, { delete: key }) 143 | 144 | /** 145 | * 146 | * @param {*} jid 147 | * @param {*} forceForward 148 | * @param {*} options 149 | * @returns 150 | */ 151 | m.forwardMessage = (jid, forceForward = true, options = {}) => conn.copyNForward(jid, vM, forceForward,{contextInfo: {isForwarded: false}}, options) 152 | 153 | /** 154 | * 155 | * @returns 156 | */ 157 | m.quoted.download = () => conn.downloadMediaMessage(m.quoted) 158 | } 159 | } 160 | } 161 | if (m.msg.url) m.download = () => conn.downloadMediaMessage(m.msg) 162 | m.text = m.msg.text || m.msg.caption || m.message.conversation || m.msg.contentText || m.msg.selectedDisplayText || m.msg.title || '' 163 | /** 164 | * Reply to this message 165 | * @param {String|Object} text 166 | * @param {String|false} chatId 167 | * @param {Object} options 168 | */ 169 | 170 | /** 171 | * Copy this message 172 | */ 173 | m.copy = () => exports.sms(conn, M.fromObject(M.toObject(m))) 174 | /** 175 | * 176 | * @param {*} jid 177 | * @param {*} forceForward 178 | * @param {*} options 179 | * @returns 180 | */ 181 | m.copyNForward = (jid = m.chat, forceForward = false, options = {}) => conn.copyNForward(jid, m, forceForward, options) 182 | m.sticker = (stik, id = m.chat, option = { mentions: [m.sender] }) => conn.sendMessage(id, { sticker: stik, contextInfo: { mentionedJid: option.mentions } }, { quoted: m }) 183 | m.replyimg = (img, teks, id = m.chat, option = { mentions: [m.sender] }) => conn.sendMessage(id, { image: img, caption: teks, contextInfo: { mentionedJid: option.mentions } }, { quoted: m }) 184 | m.imgurl = (img, teks, id = m.chat, option = { mentions: [m.sender] }) => conn.sendMessage(id, { image: {url: img }, caption: teks, contextInfo: { mentionedJid: option.mentions } }, { quoted: m }) 185 | m.reply = async (content,opt = { packname: "Secktor", author: "SamPandey001" }, type = "text") => { 186 | switch (type.toLowerCase()) { 187 | case "text":{ 188 | return await conn.sendMessage( m.chat, { text: content }, { quoted:m }); 189 | } 190 | break; 191 | case "image": { 192 | if (Buffer.isBuffer(content)) { 193 | return await conn.sendMessage(m.chat, { image: content, ...opt }, { ...opt } ); 194 | } else if (isUrl(content)) { 195 | return conn.sendMessage( m.chat, { image: { url: content }, ...opt },{ ...opt } ); 196 | } 197 | } 198 | break; 199 | case "video": { 200 | if (Buffer.isBuffer(content)) { 201 | return await conn.sendMessage(m.chat, { video: content, ...opt }, { ...opt } ); 202 | } else if (isUrl(content)) { 203 | return await conn.sendMessage( m.chat, { video: { url: content }, ...opt }, { ...opt } ); 204 | } 205 | } 206 | case "audio": { 207 | if (Buffer.isBuffer(content)) { 208 | return await conn.sendMessage( m.chat, { audio: content, ...opt }, { ...opt } ); 209 | } else if (isUrl(content)) { 210 | return await conn.sendMessage( m.chat, { audio: { url: content }, ...opt }, { ...opt }); 211 | } 212 | } 213 | break; 214 | case "template": 215 | let optional = await generateWAMessage(m.chat, content, opt); 216 | let message = { viewOnceMessage: { message: { ...optional.message,}, },}; 217 | await conn.relayMessage(m.chat, message, { messageId: optional.key.id,}); 218 | break; 219 | case "sticker":{ 220 | let { data, mime } = await conn.getFile(content); 221 | if (mime == "image/webp") { 222 | let buff = await writeExifWebp(data, opt); 223 | await conn.sendMessage(m.chat, { sticker: { url: buff }, ...opt }, opt ); 224 | } else { 225 | mime = await mime.split("/")[0]; 226 | if (mime === "video") { 227 | await conn.sendImageAsSticker(m.chat, content, opt); 228 | } else if (mime === "image") { 229 | await conn.sendImageAsSticker(m.chat, content, opt); 230 | } 231 | } 232 | } 233 | break; 234 | } 235 | } 236 | m.senddoc = (doc,type, id = m.chat, option = { mentions: [m.sender], filename: Config.ownername, mimetype: type, 237 | externalAdRepl: { 238 | title: Config.ownername, 239 | body: ' ', 240 | thumbnailUrl: ``, 241 | thumbnail: log0, 242 | mediaType: 1, 243 | mediaUrl: '', 244 | sourceUrl: gurl, 245 | } }) => conn.sendMessage(id, { document: doc, mimetype: option.mimetype, fileName: option.filename, contextInfo: { 246 | externalAdReply: option.externalAdRepl, 247 | mentionedJid: option.mentions } }, { quoted: m }) 248 | 249 | m.sendcontact = (name, info, number) => { 250 | var vcard = 'BEGIN:VCARD\n' + 'VERSION:3.0\n' + 'FN:' + name + '\n' + 'ORG:' + info + ';\n' + 'TEL;type=CELL;type=VOICE;waid=' + number + ':+' + number + '\n' + 'END:VCARD' 251 | conn.sendMessage(m.chat, { contacts: { displayName: name, contacts: [{ vcard }] } }, { quoted: m }) 252 | } 253 | m.react = (emoji) => conn.sendMessage(m.chat, { react: { text: emoji, key: m.key } }) 254 | 255 | return m 256 | } 257 | 258 | module.exports = { sms, downloadMediaMessage } --------------------------------------------------------------------------------