Last active
January 3, 2025 08:03
-
-
Save weskerty/9fc58cac7b028cbec0d817ee199580a3 to your computer and use it in GitHub Desktop.
7zip Compress/Dess
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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