mirror of
https://github.com/mudabbir-ahmad/Media-Aggregation-and-Sorting-System.git
synced 2026-10-07 19:40:20 +00:00
feat: update NAS configuration and enhance UI components for better user experience
This commit is contained in:
1 parent
8e6fa5270b
commit
6167418074
23 files changed
+2147
-702
No files matched your search
@@ -0,0 +1,342 @@
|
||||
const readline = require('readline');
|
||||
const os = require('os');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const config = require('./config');
|
||||
const passwordManager = require('./password_manager');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
});
|
||||
|
||||
function ask(question) {
|
||||
return new Promise(resolve => rl.question(question, resolve));
|
||||
}
|
||||
|
||||
function clearScreen() {
|
||||
process.stdout.write(process.platform === 'win32' ? '\x1Bc' : '\033[2J\033[H');
|
||||
}
|
||||
|
||||
let detectedPlatform = null;
|
||||
|
||||
function printBanner() {
|
||||
const user = os.userInfo().username;
|
||||
const photosPath = config.getPhotosPath() || 'NOT SET';
|
||||
const shortPath = photosPath.length > 25 ? '...' + photosPath.slice(-22) : photosPath;
|
||||
|
||||
console.log('');
|
||||
console.log('╔══════════════════════════════════════════════╗');
|
||||
console.log('║ NAS Photo Server - CLI Client ║');
|
||||
console.log('╠══════════════════════════════════════════════╣');
|
||||
console.log(`║ User: ${user.padEnd(32)}║`);
|
||||
|
||||
if (passwordManager.hasStoredPassword()) {
|
||||
console.log('║ Password: [STORED - Press P to view] ║');
|
||||
} else {
|
||||
console.log('║ Password: [NOT SET] ║');
|
||||
}
|
||||
|
||||
console.log(`║ Platform: ${(detectedPlatform || 'Unknown').padEnd(32)}║`);
|
||||
console.log(`║ Photos: ${shortPath.padEnd(32)}║`);
|
||||
console.log(`║ Port: ${String(config.DEFAULT_PORT).padEnd(32)}║`);
|
||||
console.log('╚══════════════════════════════════════════════╝');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
async function detectOrAskPlatform() {
|
||||
const plat = process.platform;
|
||||
if (plat === 'win32') {
|
||||
detectedPlatform = 'Windows';
|
||||
console.log('[*] Detected platform: Windows');
|
||||
return 'windows';
|
||||
} else if (plat === 'linux') {
|
||||
detectedPlatform = 'Linux (Ubuntu)';
|
||||
console.log('[*] Detected platform: Linux (assuming Ubuntu)');
|
||||
return 'linux';
|
||||
} else {
|
||||
console.log('');
|
||||
console.log('What operating system are you running?');
|
||||
console.log(' [1] Windows');
|
||||
console.log(' [2] Linux (Ubuntu)');
|
||||
const choice = await ask('Select (1/2): ');
|
||||
if (choice.trim() === '1') {
|
||||
detectedPlatform = 'Windows';
|
||||
return 'windows';
|
||||
} else {
|
||||
detectedPlatform = 'Linux (Ubuntu)';
|
||||
return 'linux';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkDependencies() {
|
||||
console.log('[*] Checking dependencies...');
|
||||
try {
|
||||
execSync('node --version', { stdio: 'ignore' });
|
||||
console.log(' [OK] Node.js found');
|
||||
} catch {
|
||||
console.log(' [!!] Node.js not found. Please install Node.js.');
|
||||
return false;
|
||||
}
|
||||
|
||||
const nodeModules = path.join(__dirname, 'node_modules');
|
||||
if (!fs.existsSync(nodeModules)) {
|
||||
console.log('[*] Installing dependencies...');
|
||||
try {
|
||||
execSync('npm install', { cwd: __dirname, stdio: 'inherit' });
|
||||
console.log(' [OK] Dependencies installed');
|
||||
} catch {
|
||||
console.log(' [!!] Failed to install dependencies. Run "npm install" manually in ServerFiles/');
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
console.log(' [OK] Dependencies already installed');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async function setupPhotosPath(platform) {
|
||||
const current = config.getPhotosPath();
|
||||
if (current) {
|
||||
console.log(`[*] Current photos path: ${current}`);
|
||||
const change = await ask('Change photos path? (Y/N): ');
|
||||
if (change.trim().toUpperCase() !== 'Y') return;
|
||||
}
|
||||
|
||||
let defaultPath;
|
||||
if (platform === 'windows') {
|
||||
defaultPath = path.join(os.homedir(), 'NASPhotos');
|
||||
} else {
|
||||
defaultPath = path.join(os.homedir(), 'nas-photos');
|
||||
}
|
||||
|
||||
console.log(`Default path: ${defaultPath}`);
|
||||
const inputPath = await ask('Enter photos storage path (or press Enter for default): ');
|
||||
const finalPath = inputPath.trim() || defaultPath;
|
||||
|
||||
if (!fs.existsSync(finalPath)) {
|
||||
console.log(`[*] Creating directory: ${finalPath}`);
|
||||
fs.mkdirSync(finalPath, { recursive: true });
|
||||
}
|
||||
|
||||
config.setPhotosPath(finalPath);
|
||||
console.log(`[OK] Photos path set to: ${finalPath}`);
|
||||
}
|
||||
|
||||
async function handlePassword() {
|
||||
console.log('');
|
||||
console.log('╔══════════════════════════════════════════════╗');
|
||||
console.log('║ Password Management ║');
|
||||
console.log('╠══════════════════════════════════════════════╣');
|
||||
|
||||
if (passwordManager.hasStoredPassword()) {
|
||||
console.log('║ A password is currently stored. ║');
|
||||
console.log('║ [V] View password ║');
|
||||
console.log('║ [C] Change password ║');
|
||||
console.log('║ [D] Delete password ║');
|
||||
console.log('║ [B] Back ║');
|
||||
console.log('╚══════════════════════════════════════════════╝');
|
||||
|
||||
const choice = await ask('Select option: ');
|
||||
switch (choice.trim().toUpperCase()) {
|
||||
case 'V': {
|
||||
const pw = passwordManager.retrievePassword();
|
||||
if (pw) {
|
||||
console.log('');
|
||||
console.log(` User: ${os.userInfo().username}`);
|
||||
console.log(` Password: ${pw}`);
|
||||
console.log('');
|
||||
} else {
|
||||
console.log('[!!] Could not decrypt password. It may have been created on another machine.');
|
||||
}
|
||||
await ask('Press Enter to continue...');
|
||||
break;
|
||||
}
|
||||
case 'C': {
|
||||
const newPw = await ask('Enter new password: ');
|
||||
if (newPw.trim().length > 0) {
|
||||
passwordManager.storePassword(newPw.trim());
|
||||
console.log('[OK] Password updated.');
|
||||
console.log(` New password: ${newPw.trim()}`);
|
||||
} else {
|
||||
console.log('[!] Empty password not saved.');
|
||||
}
|
||||
await ask('Press Enter to continue...');
|
||||
break;
|
||||
}
|
||||
case 'D': {
|
||||
const confirm = await ask('Are you sure? (Y/N): ');
|
||||
if (confirm.trim().toUpperCase() === 'Y') {
|
||||
passwordManager.deletePassword();
|
||||
console.log('[OK] Password deleted.');
|
||||
}
|
||||
await ask('Press Enter to continue...');
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
console.log('║ No password is stored. ║');
|
||||
console.log('╚══════════════════════════════════════════════╝');
|
||||
const store = await ask('Do you want to store a password? (Y/N): ');
|
||||
if (store.trim().toUpperCase() === 'Y') {
|
||||
const pw = await ask('Enter password: ');
|
||||
if (pw.trim().length > 0) {
|
||||
passwordManager.storePassword(pw.trim());
|
||||
console.log(`[OK] Password stored successfully.`);
|
||||
console.log(` Your password: ${pw.trim()}`);
|
||||
} else {
|
||||
console.log('[!] Empty password not saved.');
|
||||
}
|
||||
await ask('Press Enter to continue...');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showConnectionInfo() {
|
||||
const interfaces = os.networkInterfaces();
|
||||
const addresses = [];
|
||||
|
||||
for (const [name, nets] of Object.entries(interfaces)) {
|
||||
for (const net of nets) {
|
||||
if (net.family === 'IPv4' && !net.internal) {
|
||||
addresses.push({ name, address: net.address });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('');
|
||||
console.log('╔══════════════════════════════════════════════╗');
|
||||
console.log('║ Connection Information ║');
|
||||
console.log('╠══════════════════════════════════════════════╣');
|
||||
console.log(`║ User: ${os.userInfo().username.padEnd(35)}║`);
|
||||
|
||||
if (passwordManager.hasStoredPassword()) {
|
||||
console.log('║ Pass: [STORED] ║');
|
||||
} else {
|
||||
console.log('║ Pass: [NOT SET] ║');
|
||||
}
|
||||
|
||||
console.log(`║ Port: ${String(config.DEFAULT_PORT).padEnd(35)}║`);
|
||||
console.log('║ ║');
|
||||
|
||||
if (addresses.length > 0) {
|
||||
console.log('║ Network Addresses: ║');
|
||||
for (const addr of addresses) {
|
||||
const line = ` ${addr.name}: http://${addr.address}:${config.DEFAULT_PORT}`;
|
||||
console.log(`║${line.padEnd(46)}║`);
|
||||
}
|
||||
} else {
|
||||
console.log('║ No network interfaces found ║');
|
||||
}
|
||||
|
||||
console.log('╚══════════════════════════════════════════════╝');
|
||||
}
|
||||
|
||||
async function startServerInteractive() {
|
||||
const photosPath = config.getPhotosPath();
|
||||
if (!photosPath) {
|
||||
console.log('[!!] Photos path not set. Please configure it first.');
|
||||
await ask('Press Enter to continue...');
|
||||
return false;
|
||||
}
|
||||
|
||||
const portInput = await ask(`Enter port (default ${config.DEFAULT_PORT}): `);
|
||||
const port = parseInt(portInput.trim()) || config.DEFAULT_PORT;
|
||||
|
||||
console.log(`[*] Starting NAS server on port ${port}...`);
|
||||
console.log(`[*] Photos path: ${photosPath}`);
|
||||
console.log('[*] Press Ctrl+C to stop the server.');
|
||||
console.log('');
|
||||
|
||||
const { startServer } = require('./server');
|
||||
startServer(port);
|
||||
return true; // Server takes over the process
|
||||
}
|
||||
|
||||
async function mainMenu(platform) {
|
||||
while (true) {
|
||||
clearScreen();
|
||||
printBanner();
|
||||
console.log(' [1] Start NAS Server');
|
||||
console.log(' [2] Configure Photos Path');
|
||||
console.log(' [3] Password Management (P)');
|
||||
console.log(' [4] Show Connection Info');
|
||||
console.log(' [5] Exit');
|
||||
console.log('');
|
||||
|
||||
const choice = await ask('Select option: ');
|
||||
|
||||
switch (choice.trim().toUpperCase()) {
|
||||
case '1': {
|
||||
const started = await startServerInteractive();
|
||||
if (started) return; // Server is now running
|
||||
break;
|
||||
}
|
||||
case '2':
|
||||
await setupPhotosPath(platform);
|
||||
break;
|
||||
case '3':
|
||||
case 'P':
|
||||
await handlePassword();
|
||||
break;
|
||||
case '4':
|
||||
showConnectionInfo();
|
||||
await ask('\nPress Enter to continue...');
|
||||
break;
|
||||
case '5':
|
||||
console.log('Goodbye!');
|
||||
rl.close();
|
||||
process.exit(0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
clearScreen();
|
||||
console.log('Welcome to NAS Photo Server Setup');
|
||||
console.log('');
|
||||
|
||||
const platform = await detectOrAskPlatform();
|
||||
console.log('');
|
||||
|
||||
if (!checkDependencies()) {
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
}
|
||||
console.log('');
|
||||
|
||||
// First-time setup: photos path
|
||||
if (!config.getPhotosPath()) {
|
||||
console.log('[!] No photos path configured. Let\'s set one up.');
|
||||
await setupPhotosPath(platform);
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Ask about password on first run
|
||||
if (!passwordManager.hasStoredPassword()) {
|
||||
const storePw = await ask('Do you want to store a password? (Y/N): ');
|
||||
if (storePw.trim().toUpperCase() === 'Y') {
|
||||
const pw = await ask('Enter password: ');
|
||||
if (pw.trim().length > 0) {
|
||||
passwordManager.storePassword(pw.trim());
|
||||
console.log(`[OK] Password stored. Your password: ${pw.trim()}`);
|
||||
}
|
||||
}
|
||||
console.log('');
|
||||
}
|
||||
|
||||
await mainMenu(platform);
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('Fatal error:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user