@eido
אם מעניין אותך יש לי את הקוד הזה בnode.
שאני דבר ראשון מקבל את כל הנתיבים של הקבצים - שזה בקשות לא כבדות.
ואח"כ אני עובר על כל הקבצים עם מידע כמה אחוז כבר ירד (ושומר לקובץ ZIP את מה שנוצר)
// ============================================
// ייבוא מודולים
// ============================================
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const archiver = require('archiver');
const TOKEN = "XX"
const API_BASE_URL = 'https://www.call2all.co.il/ym/api/';
const ITEMS_PER_REQUEST = 500;
// ============================================
// פונקציות עזר
// ============================================
/**
* יצירת תיקייה אם לא קיימת
*/
function ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) {
fs.mkdirSync(dirPath, { recursive: true });
}
}
/**
* מחיקת תיקייה רקורסיבית
*/
function removeDir(dirPath) {
if (fs.existsSync(dirPath)) {
fs.rmSync(dirPath, { recursive: true, force: true });
}
}
/**
* קבלת פרטי המערכת
*/
async function getSystemInfo() {
try {
const response = await axios.get(`${API_BASE_URL}GetSession`, {
params: {
token: TOKEN
}
});
if (response.data.responseStatus !== 'OK') {
throw new Error(`Error getting system info: ${response.data.message}`);
}
return response.data;
} catch (error) {
console.error('❌ שגיאה בקבלת פרטי מערכת:', error.message);
throw error;
}
}
/**
* קבלת תוכן תיקייה מהשרת
*/
async function getDirectoryContent(dirPath, filesFrom = 0, filesLimit = ITEMS_PER_REQUEST) {
try {
const response = await axios.get(`${API_BASE_URL}GetIVR2Dir`, {
params: {
token: TOKEN,
path: dirPath,
filesFrom,
filesLimit
}
});
if (response.data.responseStatus !== 'OK') {
throw new Error(`Error getting directory: ${response.data.message}`);
}
return response.data;
} catch (error) {
console.error(`❌ שגיאה בקבלת תוכן תיקייה ${dirPath}:`, error.message);
throw error;
}
}
/**
* הורדת קובץ בודד
*/
async function downloadFile(filePath, localPath) {
try {
const response = await axios.get(`${API_BASE_URL}DownloadFile`, {
params: {
token: TOKEN,
path: filePath
},
responseType: 'arraybuffer'
});
ensureDir(path.dirname(localPath));
fs.writeFileSync(localPath, response.data);
return true;
} catch (error) {
console.error(`❌ שגיאה בהורדת קובץ ${filePath}:`, error.message);
return false;
}
}
/**
* איסוף כל הקבצים מתיקייה (עם טיפול בפגינציה) - ללא הורדה
*/
async function collectFilesFromDir(dirPath) {
let filesFrom = 0;
let allFiles = [];
let allIni = [];
let allHtml = [];
// איסוף כל הקבצים (עם פגינציה)
while (true) {
const dirContent = await getDirectoryContent(dirPath, filesFrom, ITEMS_PER_REQUEST);
const currentFiles = dirContent.files || [];
const currentIni = dirContent.ini || [];
const currentHtml = dirContent.html || [];
allFiles.push(...currentFiles);
allIni.push(...currentIni);
allHtml.push(...currentHtml);
// אם קיבלנו פחות מהלימיט, זה אומר שזה הסיבוב האחרון
if (currentFiles.length < ITEMS_PER_REQUEST) {
break;
}
filesFrom += ITEMS_PER_REQUEST;
}
return [
...allFiles,
...allIni,
...allHtml
];
}
/**
* סריקה רקורסיבית של כל התיקיות - רק איסוף נתיבים
*/
async function scanRecursively(dirPath, localDirPath, filesList = []) {
// איסוף הקבצים מהתיקייה הנוכחית
const files = await collectFilesFromDir(dirPath);
// הוספת הקבצים למערך עם הנתיב המקומי
for (const file of files) {
filesList.push({
remotePath: file.what,
localPath: path.join(localDirPath, file.name),
name: file.name,
size: file.size || 0
});
}
// קבלת רשימת התיקיות
const dirContent = await getDirectoryContent(dirPath, 0, ITEMS_PER_REQUEST);
const dirs = dirContent.dirs || [];
// עיבוד כל תיקייה באופן רקורסיבי
for (const dir of dirs) {
const subDirPath = dir.what;
const localSubDirPath = path.join(localDirPath, dir.name);
await scanRecursively(subDirPath, localSubDirPath, filesList);
}
return filesList;
}
/**
* הורדת כל הקבצים עם התקדמות
*/
async function downloadAllFiles(filesList, concurrency = 10) {
let completed = 0;
const total = filesList.length;
const startTime = Date.now();
console.log(`\n⬇️ מתחיל הורדת ${total} קבצים...\n`);
// חלוקה לבאצ'ים להורדה מקבילית מבוקרת
for (let i = 0; i < filesList.length; i += concurrency) {
const batch = filesList.slice(i, i + concurrency);
const downloadPromises = batch.map(async (file) => {
const success = await downloadFile(file.remotePath, file.localPath);
completed++;
const percentage = Math.floor((completed / total) * 100);
const elapsed = ((Date.now() - startTime) / 1000).toFixed(0);
const estimatedTotal = total > 0 ? ((elapsed / completed) * total).toFixed(0) : 0;
const remaining = estimatedTotal - elapsed;
// עדכון progress bar
const barLength = 30;
const filled = Math.floor((completed / total) * barLength);
const bar = '█'.repeat(filled) + '░'.repeat(barLength - filled);
process.stdout.write(`\r[${completed}/${total}] ${bar} ${percentage}% | ${elapsed}s / ~${estimatedTotal}s`);
return success;
});
await Promise.all(downloadPromises);
}
console.log('\n');
return completed;
}
/**
* יצירת קובץ ZIP
*/
async function createZip(sourceDir, outputPath) {
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(outputPath);
const archive = archiver('zip', {
zlib: { level: 9 } // דחיסה מקסימלית
});
output.on('close', () => {
console.log(`\n📦 קובץ ZIP נוצר: ${outputPath}`);
console.log(` גודל: ${(archive.pointer() / 1024 / 1024).toFixed(2)} MB`);
resolve();
});
archive.on('error', (err) => {
reject(err);
});
archive.pipe(output);
archive.directory(sourceDir, false);
archive.finalize();
});
}
/**
* פונקציה ראשית
*/
async function main() {
console.log('🚀 מתחיל תהליך גיבוי...\n');
// בדיקת טוקן
if (TOKEN === 'your-token-here') {
console.error('❌ שגיאה: לא הוגדר טוקן! הדבק את הטוקן שלך בתחילת הקובץ.');
process.exit(1);
}
const startTime = Date.now();
const startDate = new Date();
// יצירת פורמט תאריך מלא
const year = startDate.getFullYear();
const month = String(startDate.getMonth() + 1).padStart(2, '0');
const day = String(startDate.getDate()).padStart(2, '0');
const hours = String(startDate.getHours()).padStart(2, '0');
const minutes = String(startDate.getMinutes()).padStart(2, '0');
const seconds = String(startDate.getSeconds()).padStart(2, '0');
const dateTimeStr = `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;
try {
// קבלת פרטי מערכת
console.log('📋 מקבל פרטי מערכת...');
const systemInfo = await getSystemInfo();
const systemNumber = systemInfo.username || 'unknown';
console.log(` מערכת: ${systemNumber}`);
console.log(` שם: ${systemInfo.name || 'N/A'}\n`);
// יצירת תיקייה זמנית עם אותו שם כמו הקובץ
const backupName = `backup_${systemNumber}_${dateTimeStr}`;
const TEMP_DIR = path.join(__dirname, `temp_${backupName}`);
console.log('📁 יוצר תיקייה זמנית...');
ensureDir(TEMP_DIR);
// שלב 1: סריקה ואיסוף נתיבים
console.log('🔍 שלב 1: סורק תיקיות ואוסף רשימת קבצים...\n');
const allFiles = await scanRecursively('ivr2:/', TEMP_DIR);
const totalSize = allFiles.reduce((sum, file) => sum + (file.size || 0), 0);
const totalSizeMB = (totalSize / 1024 / 1024).toFixed(2);
console.log(`\n✅ סריקה הושלמה!`);
console.log(` 📊 נמצאו: ${allFiles.length} קבצים`);
console.log(` 💾 גודל כולל: ${totalSizeMB} MB\n`);
// שלב 2: הורדת קבצים
console.log('⬇️ שלב 2: מוריד קבצים...');
const successCount = await downloadAllFiles(allFiles, 10);
console.log(`✅ הורדה הושלמה: ${successCount}/${allFiles.length} קבצים\n`);
// יצירת קובץ ZIP
const zipPath = path.join(__dirname, `${backupName}.zip`);
console.log('\n📦 יוצר קובץ ZIP...');
await createZip(TEMP_DIR, zipPath);
// מחיקת תיקייה זמנית
console.log('🧹 מנקה תיקייה זמנית...');
removeDir(TEMP_DIR);
const duration = ((Date.now() - startTime) / 1000 / 60).toFixed(2);
console.log(`\n✅ הגיבוי הושלם בהצלחה!`);
console.log(`⏱️ זמן כולל: ${duration} דקות`);
console.log(`📁 קובץ הגיבוי: ${zipPath}`);
} catch (error) {
console.error('\n❌ שגיאה בתהליך הגיבוי:', error.message);
// ניקוי במקרה של שגיאה
if (TEMP_DIR) {
console.log('🧹 מנקה תיקייה זמנית...');
removeDir(TEMP_DIR);
}
process.exit(1);
}
}
// הרצת התוכנית
if (require.main === module) {
main();
}
שים לב שצריך להתקין את הספריות ולכתוב טוקן.