/* * Projekt: File Renamer CLI * Beschreibung: Ein rekursives CLI-Tool zum Umbenennen von Dateien mit Suffix. * Autor: M_Viper * Lizenz: MIT * GitHub: https://git.viper.ipv64.net/M_Viper/file-renamer-cli * Webseite: https://m-viper.de */ const fs = require('fs'); const path = require('path'); const os = require('os'); const readline = require('readline'); const configPath = path.join(os.homedir(), 'Documents', 'config.json'); // ================== Banner ================== function greenMessage(text) { console.log('\x1b[32m%s\x1b[0m', text); } function centerText(text, width) { const len = text.length; if (len >= width) return text; const leftPadding = Math.floor((width - len) / 2); return ' '.repeat(leftPadding) + text; } function showAsciiLogo() { const width = process.stdout.columns || 80; // Terminalbreite, fallback 80 const logoLines = [ '███████╗██╗██╗ ███████╗███╗ ██╗ █████╗ ███╗ ███╗███████╗ ██████╗██╗ ██╗', '██╔════╝██║██║ ██╔════╝████╗ ██║██╔══██╗████╗ ████║██╔════╝ ██╔════╝██║ ██║', '█████╗ ██║██║ █████╗ ██╔██╗ ██║███████║██╔████╔██║█████╗ ██║ ██║ ██║', '██╔══╝ ██║██║ ██╔══╝ ██║╚██╗██║██╔══██║██║╚██╔╝██║██╔══╝ ██║ ██║ ██║', '██║ ██║███████╗███████╗██║ ╚████║██║ ██║██║ ╚═╝ ██║███████╗ ╚██████╗███████╗██║', '╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚══════╝╚═╝', ]; console.log('\x1b[32m'); // grün starten for (const line of logoLines) { console.log(centerText(line, width)); } console.log('\x1b[0m'); // Farbe zurücksetzen console.log(''); } function showBanner() { console.clear(); showAsciiLogo(); const width = process.stdout.columns || 60; // Breite des Terminals, fallback 60 const bannerLines = [ 'Version 1.0', 'Script by', '@M_Viper', '__________________________', '', 'Git: https://git.viper.ipv64.net/M_Viper/file-renamer-cli', ]; // Obere Rahmenlinie greenMessage('╔' + '═'.repeat(width - 2) + '╗'); // Bannerzeilen mit Rahmen und Zentrierung for (const line of bannerLines) { const centered = centerText(line, width - 4); // 4 wegen Rahmen links und rechts + Leerzeichen greenMessage('║ ' + centered + ' ║'); } // Untere Rahmenlinie greenMessage('╚' + '═'.repeat(width - 2) + '╝'); greenMessage(''); } // ============================================ function saveConfig(config) { fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8'); } function loadConfig() { if (fs.existsSync(configPath)) { try { return JSON.parse(fs.readFileSync(configPath, 'utf-8')); } catch { return null; } } return null; } function askQuestion(query) { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return new Promise(resolve => rl.question(query, ans => { rl.close(); resolve(ans.trim()); })); } async function getConfig() { const existingConfig = loadConfig(); if (existingConfig?.folderPath && existingConfig?.suffix) { console.log(`Verwende gespeicherte Konfiguration:`); console.log(`Ordner: ${existingConfig.folderPath}`); console.log(`Suffix: ${existingConfig.suffix}`); return existingConfig; } console.log('Möchtest du den automatischen Ordner nutzen?'); console.log('1 = Ja (Desktop\\Filme)'); console.log('2 = Benutzerdefinierter Ordner'); const antwort = await askQuestion('Deine Wahl (1 oder 2): '); let folderPath; if (antwort === '1') { folderPath = path.join(os.homedir(), 'Desktop', 'Filme'); console.log(`Automatischer Ordner gewählt: ${folderPath}`); } else if (antwort === '2') { folderPath = await askQuestion('Bitte gib den vollständigen Pfad zum Ordner ein:\n'); } else { console.log('Ungültige Eingabe, bitte versuche es nochmal.'); return getConfig(); } const suffix = await askQuestion('Welcher Text soll am Ende der Dateinamen hinzugefügt werden? (z. B. @Name)\n'); const config = { folderPath, suffix }; saveConfig(config); return config; } function umbenennenSync(pfad, suffix) { console.log('Prüfe Ordner:', pfad); if (!fs.existsSync(pfad)) { console.log('Ordner existiert nicht, erstelle:', pfad); fs.mkdirSync(pfad, { recursive: true }); return; } const eintraege = fs.readdirSync(pfad, { withFileTypes: true }); if (eintraege.length === 0) { console.log('Ordner ist leer:', pfad); } for (const eintrag of eintraege) { const vollerPfad = path.join(pfad, eintrag.name); if (eintrag.isDirectory()) { if ( eintrag.name === 'System Volume Information' || eintrag.name.startsWith('$') || eintrag.name.startsWith('.') ) { console.log('Überspringe geschützten/verborgenen Ordner:', vollerPfad); continue; } console.log('Betrete Unterordner:', vollerPfad); umbenennenSync(vollerPfad, suffix); } else if (eintrag.isFile()) { const ext = path.extname(eintrag.name); const name = path.basename(eintrag.name, ext); if (name.endsWith(` ${suffix}`)) { console.log('Datei schon umbenannt, überspringe:', eintrag.name); continue; } const neuerName = `${name} ${suffix}${ext}`; const neuerPfad = path.join(pfad, neuerName); try { fs.renameSync(vollerPfad, neuerPfad); console.log(`Umbenannt: ${eintrag.name} → ${neuerName}`); } catch (e) { console.error(`Fehler bei ${eintrag.name}:`, e.message); if (e.code === 'EPERM' || e.code === 'EACCES') { console.error('Keine Zugriffsrechte oder Datei geschützt. Übersprungen.'); } } } else { console.log('Kein Datei- oder Ordner-Eintrag, überspringe:', eintrag.name); } } } async function main() { showBanner(); // Banner anzeigen const config = await getConfig(); umbenennenSync(config.folderPath, config.suffix); console.log('Fertig!'); } main();