Skip to content

Instantly share code, notes, and snippets.

@weskerty
Last active January 3, 2025 08:03
Show Gist options
  • Save weskerty/9fc58cac7b028cbec0d817ee199580a3 to your computer and use it in GitHub Desktop.
Save weskerty/9fc58cac7b028cbec0d817ee199580a3 to your computer and use it in GitHub Desktop.
7zip Compress/Dess
const fs = require('fs').promises;
const path = require('path');
const os = require('os');
const { promisify } = require('util');
const { exec: execCallback } = require('child_process');
const { bot } = require('../lib');
require('dotenv').config();
const exec = promisify(execCallback);
const FILE_TYPES = {
video: {
extensions: new Set(['mp4', 'mkv', 'avi', 'webm']),
mimetype: 'video/mp4',
},
image: {
extensions: new Set(['jpg', 'jpeg', 'png', 'gif', 'webp']),
mimetype: 'image/jpeg',
},
document: {
extensions: new Set(['pdf', 'epub', 'docx', 'txt', 'apk', 'apks']),
mimetypes: new Map([
['pdf', 'application/pdf'],
['epub', 'application/epub+zip'],
['docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
['txt', 'text/plain'],
['apk', 'application/vnd.android.package-archive'],
]),
defaultMimetype: 'application/octet-stream',
},
audio: {
extensions: new Set(['mp3', 'wav', 'ogg', 'flac']),
mimetype: 'audio/mpeg',
},
};
function getFileDetails(filePath) {
const ext = path.extname(filePath).slice(1).toLowerCase();
for (const [category, typeInfo] of Object.entries(FILE_TYPES)) {
if (typeInfo.extensions.has(ext)) {
return {
category,
mimetype: category === 'document'
? typeInfo.mimetypes.get(ext) || typeInfo.defaultMimetype
: typeInfo.mimetype,
};
}
}
return {
category: 'document',
mimetype: FILE_TYPES.document.defaultMimetype,
};
}
class SevenZipUtility {
constructor() {
this.config = {
tempDir: process.env.TEMP_DOWNLOAD_DIR || path.join(process.cwd(), 'tmp'),
maxFileSize: (parseInt(process.env.MAX_UPLOAD, 10) * 1048576) || 100000000, // 1.5 GB
maxQueueSize: parseInt(process.env.MAX_QUEUE_SIZE, 10) || 50,
compressTimeout: parseInt(process.env.COMPRESS_TIMEOUT, 10) || 300000 // 5 min
};
this.paths = {
compressDir: path.join(this.config.tempDir, 'compress_queue'),
binDir: path.join(process.cwd(), 'media', 'bin', '7ZIP'),
binaries: {
windows: {
x64: '7za.exe',
arm64: '7za.exe'
},
linux: {
x64: '7zzs',
arm64: '7zzs'
}
}
};
this.queue = new Map();
this.processing = false;
}
getBinaryPath() {
const platform = os.platform();
const arch = os.arch();
const platformMap = platform === 'win32' ? 'windows' : 'linux';
const binaryName = this.paths.binaries[platformMap]?.[arch];
if (!binaryName) {
throw new Error(`Unsupported platform: ${platform}-${arch}`);
}
return path.join(
this.paths.binDir,
platformMap.charAt(0).toUpperCase() + platformMap.slice(1),
arch,
binaryName
);
}
async ensureDirectories() {
await Promise.all([
fs.mkdir(this.config.tempDir, { recursive: true }),
fs.mkdir(this.paths.compressDir, { recursive: true }),
fs.mkdir(this.paths.binDir, { recursive: true })
]);
}
async downloadBinaries() {
const downloadUrl = 'https://raw.githubusercontent.com/weskerty/MysticTools/ca1be99212b6c77c5822ae9f72cbceaa9dec1551/Utilidades/Binarios/7ZIP/7ZIP.tar';
const tempTar = path.join(this.config.tempDir, '7ZIP.tar');
try {
const fetch = (await import('node-fetch')).default;
const response = await fetch(downloadUrl);
if (!response.ok) {
throw new Error(`Descarga Fallida: ${response.status}`);
}
const buffer = await response.buffer();
await fs.writeFile(tempTar, buffer);
await exec(`tar -xf "${tempTar}" -C "${path.dirname(this.paths.binDir)}"`);
if (os.platform() !== 'win32') {
await exec(`chmod +x "${this.getBinaryPath()}"`);
}
} finally {
await fs.unlink(tempTar).catch(() => {});
}
}
async ensure7Zip() {
try {
const binaryPath = this.getBinaryPath();
await fs.access(binaryPath);
return binaryPath;
} catch {
await this.ensureDirectories();
await this.downloadBinaries();
return this.getBinaryPath();
}
}
async addToQueue(message, filePath) {
if (!message.reply_message) {
throw new Error('❌ Quote a file to add to the compression queue');
}
if (!filePath || !filePath.trim()) {
throw new Error('❌ Specifies a path and name for the file');
}
const safePath = filePath.trim()
.split(/[/\\]/)
.map(part => part.replace(/[^a-zA-Z0-9._-]/g, '_'))
.join('/');
const mediaBuffer = await message.reply_message.downloadMediaMessage();
if (!mediaBuffer) {
throw new Error('❌ Error downloading the cited file');
}
if (mediaBuffer.length > this.config.maxFileSize) {
throw new Error(`❌ Exceeds maximum size ${this.config.maxFileSize / 1048576}MB`);
}
if (this.queue.size >= this.config.maxQueueSize) {
throw new Error(`❌ Full queue. Max ${this.config.maxQueueSize} Files`);
}
// crear directorio si no existe
const fullPath = path.join(this.paths.compressDir, safePath);
await fs.mkdir(path.dirname(fullPath), { recursive: true });
await fs.writeFile(fullPath, mediaBuffer);
this.queue.set(safePath, fullPath);
return safePath;
}
async processQueue(message) {
if (this.queue.size === 0) {
throw new Error('❌ There are no files in the compression queue');
}
if (this.processing) {
throw new Error('❌ There is already a compression process underway');
}
this.processing = true;
const binaryPath = await this.ensure7Zip();
const outputZip = path.join(this.config.tempDir, `compresion_${Date.now()}.zip`);
try {
await message.send('🔄 Compressing files...');
const command = `"${binaryPath}" a "${outputZip}" "${this.paths.compressDir}/*"`;
await Promise.race([
exec(command),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('❌ Tiempo Compresion Exed')), this.config.compressTimeout)
)
]);
const fileBuffer = await fs.readFile(outputZip);
await message.send(
fileBuffer,
{
fileName: path.basename(outputZip),
mimetype: 'application/zip',
caption: `✅ ${this.queue.size} compressed files`
},
'document'
);
} finally {
this.processing = false;
this.queue.clear();
await this.cleanup([outputZip, this.paths.compressDir]);
await fs.mkdir(this.paths.compressDir, { recursive: true });
}
}
async decompress(message) {
if (!message.reply_message) {
throw new Error('ℹ️ Quote a compressed file to extract\n`7zip add` path/name.ext to add\n`7zip up` to compress and upload');
}
const mediaBuffer = await message.reply_message.downloadMediaMessage();
if (!mediaBuffer) {
throw new Error('❌ Error Descargando');
}
const binaryPath = await this.ensure7Zip();
const fileName = message.reply_message.fileName || `archivo_${Date.now()}.zip`;
const tempPath = path.join(this.config.tempDir, fileName);
const outputDir = path.join(this.config.tempDir, `extract_${Date.now()}`);
try {
await fs.mkdir(outputDir, { recursive: true });
await fs.writeFile(tempPath, mediaBuffer);
await message.send('🔄 Extracting...');
await exec(`"${binaryPath}" x "${tempPath}" -o"${outputDir}" -y`);
const processDirectory = async (dir, baseDir = '') => {
const entries = await fs.readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
const relativePath = path.join(baseDir, entry.name).replace(/\\/g, '/');
if (entry.isFile()) {
const fileBuffer = await fs.readFile(fullPath);
const { category, mimetype } = getFileDetails(entry.name);
await message.send(
fileBuffer,
{
fileName: entry.name,
mimetype,
caption: `📁 ${relativePath}`
},
category
);
} else if (entry.isDirectory()) {
await processDirectory(fullPath, relativePath);
}
}
};
await processDirectory(outputDir);
await message.send('✅ Extraction Complete');
} finally {
await this.cleanup([tempPath, outputDir]);
}
}
async cleanup(paths) {
for (const path of paths) {
await fs.rm(path, { recursive: true, force: true }).catch(() => {});
}
}
}
const sevenZipUtility = new SevenZipUtility();
bot(
{
pattern: '7zip ?(.*)',
fromMe: true,
desc: 'Compress and decompress files using 7zip',
type: 'tools',
},
async (message, match) => {
const command = match.trim();
try {
if (command.startsWith('add ')) {
const filePath = command.slice(4).trim();
const safePath = await sevenZipUtility.addToQueue(message, filePath);
await message.send(`✅ Added *${safePath}*`);
} else if (command === 'up') {
await sevenZipUtility.processQueue(message);
} else {
await sevenZipUtility.decompress(message);
}
} catch (error) {
console.error('Error en 7zip:', error);
await message.send(error.message);
}
}
);
module.exports = { SevenZipUtility: sevenZipUtility };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment