empty / commands /Structure.js
github-actions[bot]
Automated sync from GitHub
e65d066
Raw History Blame Contribute Delete
19.5 kB
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import os from 'os';
import { t, translate, translateAIResponse, getUserLang } from '../france/translator.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export const commands = [
{
name: 'structure',
aliases: ['tree'],
description: 'Analyze the complete structure, files, and folders of the bot',
category: 'Owner',
ownerOnly: true,
execute: async ({ sock, from, text, msg, config }) => {
const botName = config.BOT_NAME || 'Flash-MD';
const args = text.trim().split(/\s+/);
const option = args[0]?.toLowerCase() || '';
if (option === 'help') {
const helpTitle = await t(from, 'structure', 'helpTitle');
const cmdDefault = await t(from, 'structure', 'cmdDefault');
const cmdTree = await t(from, 'structure', 'cmdTree');
const cmdDetails = await t(from, 'structure', 'cmdDetails');
const cmdSize = await t(from, 'structure', 'cmdSize');
const cmdFiles = await t(from, 'structure', 'cmdFiles');
const cmdTreeAlias = await t(from, 'structure', 'cmdTreeAlias');
const poweredMsg = await t(from, 'structure', 'powered');
return sock.sendMessage(from, {
text: `${helpTitle}\n\n` +
`${cmdDefault}\n` +
`${cmdTree}\n` +
`${cmdDetails}\n` +
`${cmdSize}\n` +
`${cmdFiles}\n` +
`${cmdTreeAlias}\n\n` +
`${poweredMsg} ${botName}`
}, { quoted: msg });
}
const analyzingMsg = await t(from, 'structure', 'analyzing');
const processingMsg = await sock.sendMessage(from, { text: analyzingMsg }, { quoted: msg });
try {
const rootDir = process.cwd();
const excludeDirs = ['node_modules', '.git', 'temp', 'tmp', 'logs', 'sessions', 'backups', 'uploads', 'cache', 'sessions', 'venv', 'env', '__pycache__'];
const excludeFiles = ['.env', '*.log', '*.zip', 'session.json', 'creds.json', 'package-lock.json', 'yarn.lock'];
const structure = {
totalFiles: 0,
totalFolders: 0,
totalSize: 0,
byExtension: {},
byFolder: {},
files: [],
tree: ''
};
const generateTree = (dir, prefix = '', isLast = true) => {
if (!fs.existsSync(dir)) return '';
const items = fs.readdirSync(dir).filter(item => {
const itemPath = path.join(dir, item);
const stat = fs.statSync(itemPath);
if (stat.isDirectory()) {
return !excludeDirs.includes(item) && !item.startsWith('.');
}
const ext = path.extname(item).toLowerCase();
const shouldExclude = excludeFiles.some(pattern => {
if (pattern.includes('*')) {
const regex = new RegExp(pattern.replace('*', '.*'));
return regex.test(item);
}
return item === pattern;
});
return !shouldExclude;
});
items.sort((a, b) => {
const aPath = path.join(dir, a);
const bPath = path.join(dir, b);
const aIsDir = fs.statSync(aPath).isDirectory();
const bIsDir = fs.statSync(bPath).isDirectory();
if (aIsDir && !bIsDir) return -1;
if (!aIsDir && bIsDir) return 1;
return a.localeCompare(b);
});
let treeString = '';
for (let i = 0; i < items.length; i++) {
const item = items[i];
const itemPath = path.join(dir, item);
const stat = fs.statSync(itemPath);
const isLastItem = i === items.length - 1;
const connector = isLastItem ? 'โ””โ”€โ”€ ' : 'โ”œโ”€โ”€ ';
const newPrefix = prefix + (isLastItem ? ' ' : 'โ”‚ ');
if (stat.isDirectory()) {
treeString += `${prefix}${connector}๐Ÿ“ ${item}/\n`;
treeString += generateTree(itemPath, newPrefix, isLastItem);
} else {
const size = (stat.size / 1024).toFixed(1);
treeString += `${prefix}${connector}๐Ÿ“„ ${item} (${size} KB)\n`;
}
}
return treeString;
};
const scanDirectory = (dir, folderName = '') => {
if (!fs.existsSync(dir)) return { files: 0, size: 0 };
const items = fs.readdirSync(dir);
let folderFiles = 0;
let folderSize = 0;
for (const item of items) {
const itemPath = path.join(dir, item);
const stat = fs.statSync(itemPath);
if (stat.isDirectory()) {
if (!excludeDirs.includes(item) && !item.startsWith('.')) {
structure.totalFolders++;
const subResult = scanDirectory(itemPath, path.join(folderName, item));
folderFiles += subResult.files;
folderSize += subResult.size;
}
} else {
const ext = path.extname(item).toLowerCase() || 'no extension';
const shouldExclude = excludeFiles.some(pattern => {
if (pattern.includes('*')) {
const regex = new RegExp(pattern.replace('*', '.*'));
return regex.test(item);
}
return item === pattern;
});
if (!shouldExclude) {
structure.totalFiles++;
structure.totalSize += stat.size;
folderFiles++;
folderSize += stat.size;
structure.byExtension[ext] = (structure.byExtension[ext] || 0) + 1;
structure.files.push({
name: item,
path: path.join(folderName, item),
size: stat.size,
ext: ext,
modified: stat.mtime
});
}
}
}
if (folderName && (folderFiles > 0 || folderSize > 0)) {
structure.byFolder[folderName] = {
files: folderFiles,
size: folderSize
};
}
return { files: folderFiles, size: folderSize };
};
scanDirectory(rootDir);
if (option === 'tree' || text.trim() === 'tree') {
const treeOutput = generateTree(rootDir);
await sock.sendMessage(from, { delete: processingMsg.key });
const treeHeader = await t(from, 'structure', 'treeHeader');
const poweredMsg = await t(from, 'structure', 'powered');
let resultText = `${treeHeader}\n\n`;
resultText += `๐Ÿ“ ${path.basename(rootDir)}/\n`;
resultText += treeOutput || 'No files found\n';
resultText += `\n${poweredMsg} ${botName}`;
if (resultText.length > 3500) {
const parts = resultText.match(/[\s\S]{1,3500}/g) || [];
const continuedMsg = await t(from, 'structure', 'continued');
for (let i = 0; i < parts.length; i++) {
await sock.sendMessage(from, { text: parts[i] + (i < parts.length - 1 ? `\n\n${continuedMsg}` : '') }, { quoted: msg });
}
} else {
await sock.sendMessage(from, { text: resultText }, { quoted: msg });
}
return;
}
if (option === 'details') {
const sortedBySize = [...structure.files].sort((a, b) => b.size - a.size).slice(0, 20);
const detailsHeader = await t(from, 'structure', 'detailsHeader');
const totalFilesLabel = await t(from, 'structure', 'totalFiles');
const totalFoldersLabel = await t(from, 'structure', 'totalFolders');
const totalSizeLabel = await t(from, 'structure', 'totalSize');
const largestFilesLabel = await t(from, 'structure', 'largestFiles');
const poweredMsg = await t(from, 'structure', 'powered');
let resultText = `${detailsHeader}\n\n`;
resultText += `${totalFilesLabel} ${structure.totalFiles}\n`;
resultText += `${totalFoldersLabel} ${structure.totalFolders}\n`;
resultText += `${totalSizeLabel} ${(structure.totalSize / 1024 / 1024).toFixed(2)} MB\n\n`;
resultText += `${largestFilesLabel}\n`;
for (let i = 0; i < sortedBySize.length; i++) {
const file = sortedBySize[i];
const sizeKB = (file.size / 1024).toFixed(1);
resultText += `${i + 1}. ${file.path}\n`;
resultText += ` ๐Ÿ’พ ${sizeKB} KB | ๐Ÿ“ ${file.ext}\n`;
resultText += ` ๐Ÿ•’ ${file.modified.toLocaleDateString()}\n\n`;
}
resultText += `${poweredMsg} ${botName}`;
await sock.sendMessage(from, { delete: processingMsg.key });
if (resultText.length > 3500) {
const parts = resultText.match(/[\s\S]{1,3500}/g) || [];
const continuedMsg = await t(from, 'structure', 'continued');
for (let i = 0; i < parts.length; i++) {
await sock.sendMessage(from, { text: parts[i] + (i < parts.length - 1 ? `\n\n${continuedMsg}` : '') }, { quoted: msg });
}
} else {
await sock.sendMessage(from, { text: resultText }, { quoted: msg });
}
return;
}
if (option === 'size') {
const sortedFolders = Object.entries(structure.byFolder)
.sort((a, b) => b[1].size - a[1].size)
.slice(0, 20);
const sizeHeader = await t(from, 'structure', 'sizeHeader');
const totalSizeLabel = await t(from, 'structure', 'totalSize');
const totalFilesLabel = await t(from, 'structure', 'totalFiles');
const largestFoldersLabel = await t(from, 'structure', 'largestFolders');
const poweredMsg = await t(from, 'structure', 'powered');
let resultText = `${sizeHeader}\n\n`;
resultText += `${totalSizeLabel} ${(structure.totalSize / 1024 / 1024).toFixed(2)} MB\n`;
resultText += `${totalFilesLabel} ${structure.totalFiles}\n\n`;
resultText += `${largestFoldersLabel}\n`;
for (let i = 0; i < sortedFolders.length; i++) {
const [folder, data] = sortedFolders[i];
const sizeMB = (data.size / 1024 / 1024).toFixed(2);
const percent = ((data.size / structure.totalSize) * 100).toFixed(1);
resultText += `${i + 1}. ๐Ÿ“ ${folder || 'root'}\n`;
resultText += ` ๐Ÿ’พ ${sizeMB} MB (${percent}%)\n`;
resultText += ` ๐Ÿ“„ ${data.files} files\n\n`;
}
resultText += `${poweredMsg} ${botName}`;
await sock.sendMessage(from, { delete: processingMsg.key });
await sock.sendMessage(from, { text: resultText }, { quoted: msg });
return;
}
if (option === 'files') {
const extensions = Object.entries(structure.byExtension).sort((a, b) => b[1] - a[1]);
const filesHeader = await t(from, 'structure', 'filesHeader');
const totalFilesLabel = await t(from, 'structure', 'totalFiles');
const totalSizeLabel = await t(from, 'structure', 'totalSize');
const poweredMsg = await t(from, 'structure', 'powered');
let resultText = `${filesHeader}\n\n`;
for (const [ext, count] of extensions) {
const percent = ((count / structure.totalFiles) * 100).toFixed(1);
resultText += `๐Ÿ“ ${ext || 'no extension'}: ${count} files (${percent}%)\n`;
}
resultText += `\n${totalFilesLabel} ${structure.totalFiles} files\n`;
resultText += `${totalSizeLabel} ${(structure.totalSize / 1024 / 1024).toFixed(2)} MB\n`;
resultText += `\n${poweredMsg} ${botName}`;
await sock.sendMessage(from, { delete: processingMsg.key });
await sock.sendMessage(from, { text: resultText }, { quoted: msg });
return;
}
const extensions = Object.entries(structure.byExtension).sort((a, b) => b[1] - a[1]).slice(0, 10);
const largestFiles = [...structure.files].sort((a, b) => b.size - a.size).slice(0, 10);
const analysisHeader = await t(from, 'structure', 'analysisHeader');
const totalFoldersLabel = await t(from, 'structure', 'totalFolders');
const totalFilesLabel = await t(from, 'structure', 'totalFiles');
const totalSizeLabel = await t(from, 'structure', 'totalSize');
const platformLabel = await t(from, 'structure', 'platform');
const nodeLabel = await t(from, 'structure', 'node');
const topExtensionsLabel = await t(from, 'structure', 'topExtensions');
const largestFilesLabel = await t(from, 'structure', 'largestFiles');
const tipsLabel = await t(from, 'structure', 'tips');
const cmdDefault = await t(from, 'structure', 'cmdDefault');
const cmdTree = await t(from, 'structure', 'cmdTree');
const cmdDetails = await t(from, 'structure', 'cmdDetails');
const cmdSize = await t(from, 'structure', 'cmdSize');
const cmdFiles = await t(from, 'structure', 'cmdFiles');
const cmdTreeAlias = await t(from, 'structure', 'cmdTreeAlias');
const poweredMsg = await t(from, 'structure', 'powered');
let resultText = `${analysisHeader}\n\n`;
resultText += `โ•ญโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•ฎ\n`;
resultText += `โ”‚ ${totalFoldersLabel} ${structure.totalFolders}\n`;
resultText += `โ”‚ ${totalFilesLabel} ${structure.totalFiles}\n`;
resultText += `โ”‚ ${totalSizeLabel} ${(structure.totalSize / 1024 / 1024).toFixed(2)} MB\n`;
resultText += `โ”‚ ${platformLabel} ${os.platform()}\n`;
resultText += `โ”‚ ${nodeLabel} ${process.version}\n`;
resultText += `โ•ฐโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•ฏ\n\n`;
resultText += `${topExtensionsLabel}\n`;
for (const [ext, count] of extensions) {
resultText += ` ${ext || 'no ext'}: ${count} files\n`;
}
resultText += `\n`;
resultText += `${largestFilesLabel}\n`;
for (let i = 0; i < largestFiles.length; i++) {
const file = largestFiles[i];
const sizeKB = (file.size / 1024).toFixed(1);
resultText += ` ${i + 1}. ${file.path} (${sizeKB} KB)\n`;
}
resultText += `\n`;
resultText += `${tipsLabel}\n`;
resultText += ` โ€ข ${cmdDefault}\n`;
resultText += ` โ€ข ${cmdTree}\n`;
resultText += ` โ€ข ${cmdDetails}\n`;
resultText += ` โ€ข ${cmdSize}\n`;
resultText += ` โ€ข ${cmdFiles}\n`;
resultText += ` โ€ข ${cmdTreeAlias}\n`;
resultText += `\n${poweredMsg} ${botName}`;
await sock.sendMessage(from, { delete: processingMsg.key });
await sock.sendMessage(from, { text: resultText }, { quoted: msg });
} catch (error) {
console.error('Structure error:', error);
await sock.sendMessage(from, { delete: processingMsg.key });
const errorMsg = await t(from, 'structure', 'error');
const poweredMsg = await t(from, 'structure', 'powered');
await sock.sendMessage(from, {
text: `${errorMsg}\n\n${poweredMsg} ${botName}`
}, { quoted: msg });
}
}
}
];