Wizard stuff

This commit is contained in:
Paul Sori 2018-10-31 20:50:12 -04:00
parent b04d9408ad
commit ccee200657
8 changed files with 302 additions and 46 deletions

4
.gitignore vendored
View File

@ -3,6 +3,10 @@ node_modules/*
image-cache/*
!image-cache/default.png
!image-cache/README.md
save/*
!save/README.md
mstreamdb.lite
mstream.db
package-lock.json

View File

@ -2,17 +2,20 @@
Using a JSON config with mStream allows for more advanced configurations. This example contains all configurable params for reference purposes.
```
```json
{
"port": 3030,
"userinterface":"public",
"secret": "b6j7j5e6u5g36ubn536uyn536unm5m67u5365vby435y54ymn",
"database_plugin":{
"dbPath":"/path/to/loki.db",
"interval": 2,
"saveInterval": 500,
"scanOptions":{
"skipImg": true,
"pause": 50
"scanInterval": 1.5,
"pause": 50,
"saveInterval": 500,
"bootScanDelay": 15
},
"database_plugin":{
"dbPath":"/path/to/loki.db"
},
"albumArtDir": "/media/album-art",
"folders": {
@ -60,19 +63,34 @@ Folder that contains the frontend for mStream. Defaults to `public` if not set
Sets the secret key used for the login system. If this is not set, mStream will generate a random secret key on boot and previous login sessions will be voided
## Database
## Scan Options
* `dbPath`: path to save the database file to
* `interval`: The interval which controls how often file system will be scanned for changes (in hours)
* `skipImg`: (boolean) whether to skip scanning for album art. Speeds up the scan time
* `bootScanDelay`: delay between server boot and first file scan (in seconds)
* `scanInterval`: The interval which controls how often file system will be scanned for changes (in hours)
* `saveInterval`: interval which to refresh the DB on scan. Defaults to 250. Can be set to a higher number for large collections to avoid hogging the CPU thread
* `pause` (in milliseconds): During the scan, there is an optional pause that is aded between file parsing. This can prevent mStream from hogging system resources during the initial scan
```json
{
"scanOptions":{
"skipImg": true,
"scanInterval": 1.5,
"pause": 50,
"saveInterval": 500,
"bootScanDelay": 15
}
}
```
## Database
* `dbPath`: path to save the database file to
```json
"database_plugin":{
"dbPath":"/path/to/loki.db",
"interval": "1.5",
""pause": 50,
}
```

View File

@ -172,7 +172,7 @@ function editPort(port = 3000) {
}
}])
.then(answers => {
return answers.port;
return Number(answers.port);
});
}
@ -605,14 +605,18 @@ function addNewFolder() {
type: 'directory',
name: 'from',
message: 'Choose your music directory:',
basePath: '.'
basePath: require('os').homedir()
}]).then((answers) => {
return answers.from;
});
}
async function doTheThing(filepath) {
if (typeof filepath !== 'string') {
filepath = path.join(__dirname, '../../save/default.json');
}
filepath = path.resolve(filepath);
console.clear();
console.log();
console.log(colors.blue.bold('Welcome To The mStream Setup Wizard'));
@ -634,7 +638,16 @@ async function doTheThing(filepath) {
}
}
await initFile(filepath);
try {
await initFile(filepath);
} catch (err) {
console.log();
console.log(colors.red('Failed to save file'));
console.log(colors.yellow('Check that you have write access to this directory'));
console.log();
process.exit(0);
}
try {
var loadJson = JSON.parse(fs.readFileSync(filepath, 'utf8'));
} catch (error) {
@ -683,7 +696,7 @@ async function doTheThing(filepath) {
console.log(colors.blue.bold('Welcome To The mStream Setup Wizard'));
console.log(colors.magenta('User Configuration'));
console.log();
var addUser = false;
var shouldAdd = false;
if (!loadJson.users || typeof loadJson.users !== 'object') {
loadJson.users = {};
}
@ -691,11 +704,12 @@ async function doTheThing(filepath) {
console.log('There are currently no users');
console.log(colors.yellow('With no users, mStream will be publicly available and the login system will be disabled'));
console.log();
shouldAdd = true;
} else {
printUsers(loadJson.users);
}
addUser = await confirmThis("Would you like to add a user?");
while (addUser) {
while (await confirmThis("Would you like to add a user?", shouldAdd)) {
shouldAdd = false;
await addOneUser(loadJson);
console.clear();
console.log();
@ -703,7 +717,6 @@ async function doTheThing(filepath) {
console.log(colors.magenta('User Configuration'));
console.log();
printUsers(loadJson.users);
addUser = await confirmThis("Would you like to add a user?");
}
// Port
@ -741,6 +754,48 @@ async function doTheThing(filepath) {
// console.log('BLAH BLAH');
// console.log();
// Test write access in mStream directory
// If it works, suggest this one
// if not, suggest another one
// Scan Options
if (!loadJson.scanOptions) {
loadJson.scanOptions = {};
}
var editDb = { dbList: true };
while (editDb.dbList !== 'finished') {
console.clear();
console.log();
console.log(colors.blue.bold('Welcome To The mStream Setup Wizard'));
console.log(colors.magenta('File Scan Options'));
console.log();
switch (editDb.dbList) {
case 'dbpause':
loadJson.scanOptions.pause = await setScanPause();
break;
case 'interval':
loadJson.scanOptions.scanInterval = await setScanInterval();
break;
case 'bootpause':
loadJson.scanOptions.bootScanDelay = await setBootDelay();
break;
case 'saveinterval':
loadJson.scanOptions.saveInterval = await setSaveInterval();
break;
case 'skipimg':
const shouldSkip = await skipImg();
if (shouldSkip) {
loadJson.scanOptions.skipImg = true
}
break;
default:
console.log('How did you get here???');
}
editDb = await chooseDirOption();
}
// Save
fs.writeFileSync( filepath, JSON.stringify(loadJson, null, 2), 'utf8');
console.clear();
@ -755,6 +810,139 @@ async function doTheThing(filepath) {
// Print a Help Text explaining basic usage things
}
function chooseDirOption() {
return inquirer
.prompt([{
message: 'Choose your DB Option',
type: "list",
name: "dbList",
choices: [{ name: 'finished', value: 'finished' },
new inquirer.Separator(),
{ name: 'Pause Between Files', value: 'dbpause' },
{ name: 'Scan Interval', value: 'interval' },
{ name: 'Boot Scan Pause', value: 'bootpause' },
{ name: 'Skip Image Scan', value: 'skipimg' },
{ name: 'Save Interval', value: 'saveinterval' }
]
}])
.then(answers => {
return answers;
});
}
function skipImg() {
console.log(colors.yellow('Skipping images while scanning will reduce the scan time and lower the memory usage during scan'));
console.log();
return inquirer
.prompt([{
message: 'Would you like to skip Album Art images when scanning?',
type: "confirm",
name: "confirm",
default: false
}])
.then(answers => {
if(answers.confirm === true) {
return true;
}
return false;
});
}
function setSaveInterval() {
console.log(colors.yellow('Sets how often a DB update should happen during a file scan'));
console.log('Large libraries (4TB+) can see some performance gains during scan by increasing this');
console.log();
return inquirer
.prompt([{
message: "Save DB every __ files: ",
type: "input",
name: "interval",
default: 250,
validate: answer => {
if (!Number.isInteger(Number(answer)) || Number(answer) < 100) {
return 'Save Interval must be a an integer greater than 100!';
}
return true;
}
}])
.then(answers => {
return Number(answers.interval);
});
}
function setScanPause() {
console.log(colors.yellow('Sets a pause interval between each file that is scanned (in milliseconds)'));
console.log('Scanning large libraries can eat up disk and CPU resources on slower system');
console.log('Setting a pause between files will increase the scan time but reduce system resource usage');
console.log();
return inquirer
.prompt([{
message: "Set pause (milliseconds): ",
type: "input",
name: "pause",
default: 0,
validate: answer => {
if (!Number.isInteger(Number(answer)) || Number(answer) < 0) {
return 'Pause cannot be less than 0';
}
return true;
}
}])
.then(answers => {
return Number(answers.pause);
});
}
function setBootDelay() {
console.log(colors.yellow('Sets a delay between server boot and the initial file scan (in seconds)'));
console.log('Scanning large libraries can cause a spike in memory usage. And booting the server causes a spike in memory usage');
console.log('By adding a delay between boot and scan, you can reduce the max memory use');
console.log();
return inquirer
.prompt([{
message: "Set boot scan delay (seconds): ",
type: "input",
name: "delay",
default: 0,
validate: answer => {
if (!Number.isInteger(Number(answer)) || Number(answer) < 0) {
return 'Delay cannot be less than 0';
}
return true;
}
}])
.then(answers => {
return Number(answers.delay);
});
}
function setScanInterval() {
console.log(colors.yellow('Sets how often a scan should happen (in hours)'));
console.log('Scans happen every 24 hours by default');
console.log();
return inquirer
.prompt([{
message: "Scan every __ hours: ",
type: "input",
name: "interval",
default: 24,
validate: answer => {
if (!Number.isInteger(Number(answer)) || Number(answer) < 0) {
return 'Scan Interval cannot be less than 0';
}
return true;
}
}])
.then(answers => {
return Number(answers.interval);
});
}
function generateSecret() {
return new Promise((resolve, reject) => {
require('crypto').randomBytes(48, function (err, buffer) {

View File

@ -35,10 +35,11 @@ exports.setup = function (args) {
// DB
.option('-d, --database <path>', 'Specify Database Filepath', 'mstream.db')
.option('-E, --interval <interval>', 'Specify Database Scan Interval (In Hours)', /^\d+$/i, 24)
.option('-E, --scaninterval <scaninterval>', 'Specify Database Scan Interval (In Hours)', /^\d+$/i, 24)
.option('-D, --saveinterval <saveinterval>', 'Specify Database Save Interval', /^\d+$/i, 250)
.option('-S, --skipimg', 'While skip parsing album art if flagged')
.option('-P, --dbpause <dbpause>', 'Specify File Scan Pause Interval', /^\d+$/i, 0)
.option('-B, --bootdelay <bootdelay>', 'Specify Boot Scan Pause (In Seconds)', /^\d+$/i, 0)
.option('-P, --dbpause <dbpause>', 'Specify File Scan Pause Interval (in Milliseconds)', /^\d+$/i, 0)
// Logs
.option('-L, --logs <path>', 'Specify Database Filepath')
@ -56,9 +57,11 @@ exports.setup = function (args) {
.option("--makesecret", "Add an SSL Cert")
.option("--removeuser", "Delete User From Config")
.option("--removepath", "Remove Folder From Config")
.option("--wizard <file>", "Setup Wizard")
.option("--wizard [file]", "Setup Wizard")
.parse(args);
// TODO: If no params are supplied, try to use default.json
if (program.init) {
require('./config-inquirer').init(program.init).then((didWrite) => {
@ -194,15 +197,19 @@ exports.setup = function (args) {
program3['lastfm-password'] = program.lpass;
}
program3.scanOptions = {
scanInterval: Number(program.scaninterval),
saveInterval: Number(program.saveinterval),
pause: Number(program.dbpause),
bootScanDelay: Number(program.bootdelay)
}
// db plugins
program3.database_plugin = {
dbPath: program.database,
interval: Number(program.interval),
saveInterval: Number(program.saveinterval),
pause: Number(program.dbpause)
dbPath: program.database
}
if (program.skipimg) {
program3.database_plugin.skipImg = true;
program3.scanOptions.skipImg = true;
}
// port forwarding

View File

@ -17,27 +17,59 @@ exports.setup = function (loadJson) {
loadJson.database_plugin = {};
}
if (!loadJson.scanOptions) {
loadJson.scanOptions = {};
}
if (loadJson.database_plugin && loadJson.database_plugin.skipImg) {
console.log('The database plugin is being deprecated. Please move `skipImg` to the `scanOptions` object');
console.log('Or you can use `mstream --wizard` to automatically handle your config file');
loadJson.scanOptions.skipImg = loadJson.database_plugin.skipImg;
}
if (loadJson.database_plugin && loadJson.database_plugin.pause) {
console.log('The database plugin is being deprecated. Please move `skipImg` to the `pause` object');
console.log('Or you can use `mstream --wizard` to automatically handle your config file');
loadJson.scanOptions.pause = loadJson.database_plugin.pause;
}
if (loadJson.database_plugin && loadJson.database_plugin.saveInterval) {
console.log('The database plugin is being deprecated. Please move `saveInterval` to the `scanOptions` object');
console.log('Or you can use `mstream --wizard` to automatically handle your config file');
loadJson.scanOptions.saveInterval = loadJson.database_plugin.saveInterval;
}
if (loadJson.database_plugin && loadJson.database_plugin.interval) {
console.log('The database plugin is being deprecated. Please move `interval` to the `scanOptions` object under the name `scanInterval`');
console.log('Or you can use `mstream --wizard` to automatically handle your config file');
loadJson.scanOptions.scanInterval = loadJson.database_plugin.interval;
}
if (!loadJson.database_plugin.dbPath) {
loadJson.database_plugin.dbPath = 'mstream.db';
}
if (loadJson.database_plugin.interval === false) {
loadJson.database_plugin.interval = 0;
if (loadJson.scanOptions.scanInterval === false) {
loadJson.scanOptions.scanInterval = 0;
}
loadJson.database_plugin.interval = Number(loadJson.database_plugin.interval);
if (typeof loadJson.database_plugin.interval !== 'number' || isNaN(loadJson.database_plugin.interval) || loadJson.database_plugin.interval < 0) {
loadJson.database_plugin.interval = 24;
loadJson.scanOptions.scanInterval = Number(loadJson.scanOptions.scanInterval);
if (typeof loadJson.scanOptions.scanInterval !== 'number' || isNaN(loadJson.scanOptions.scanInterval) || loadJson.scanOptions.scanInterval < 0) {
loadJson.scanOptions.scanInterval = 24;
}
loadJson.database_plugin.saveInterval = Number(loadJson.database_plugin.saveInterval);
if (typeof loadJson.database_plugin.saveInterval !== 'number' || isNaN(loadJson.database_plugin.saveInterval) || loadJson.database_plugin.saveInterval < 0) {
loadJson.database_plugin.saveInterval = 250;
loadJson.scanOptions.saveInterval = Number(loadJson.scanOptions.saveInterval);
if (typeof loadJson.scanOptions.saveInterval !== 'number' || isNaN(loadJson.scanOptions.saveInterval) || loadJson.scanOptions.saveInterval < 0) {
loadJson.scanOptions.saveInterval = 250;
}
loadJson.database_plugin.pause = Number(loadJson.database_plugin.pause);
if (typeof loadJson.database_plugin.pause !== 'number' || isNaN(loadJson.database_plugin.pause) || loadJson.database_plugin.pause < 0) {
loadJson.database_plugin.pause = 0;
loadJson.scanOptions.pause = Number(loadJson.scanOptions.pause);
if (typeof loadJson.scanOptions.pause !== 'number' || isNaN(loadJson.scanOptions.pause) || loadJson.scanOptions.pause < 0) {
loadJson.scanOptions.pause = 0;
}
if(!loadJson.scanOptions) {
loadJson.scanOptions = {};
}
if (!loadJson.folders || typeof loadJson.folders !== 'object') {

View File

@ -151,7 +151,7 @@ function parseFile(thisSong) {
return metadata.parseFile(thisSong, opt).then(thisMetadata => {
return thisMetadata.common;
}).catch(err => {
console.error(`Warning: metadata parse error on${thisSong}: ${err.message}`);
console.error(`Warning: metadata parse error on ${thisSong}: ${err.message}`);
return {track: { no: null, of: null }, disk: { no: null, of: null }};
}).then(songInfo => {
songInfo.filesize = filestat.size;

View File

@ -15,9 +15,9 @@ function scanIt(directory, vpath, program, callback) {
vpath: vpath,
dbSettings: program.database_plugin,
albumArtDir: program.albumArtDir,
skipImg: program.database_plugin.skipImg ? true : false,
saveInterval: program.database_plugin.saveInterval ? program.database_plugin.saveInterval : 250,
pause: program.database_plugin.pause ? program.database_plugin.pause : false
skipImg: program.scanOptions.skipImg ? true : false,
saveInterval: program.scanOptions.saveInterval ? program.scanOptions.saveInterval : 250,
pause: program.scanOptions.pause ? program.scanOptions.pause : false
}
const forkedScan = child.fork(fe.join(__dirname, 'database-default-manager.js'), [JSON.stringify(jsonLoad)], { silent: true });
@ -94,9 +94,15 @@ exports.setup = function (mstream, program) {
}
exports.runAfterBoot = function (program) {
runScan(program);
if (program.database_plugin.interval) {
setInterval(() => runScan(program), program.database_plugin.interval * 60 * 60 * 1000);
var scanDelay = 0;
if (program.scanOptions.bootScanDelay && Number.isInteger(program.scanOptions.bootScanDelay) && program.scanOptions.bootScanDelay > 0) {
scanDelay = program.scanOptions.bootScanDelay
}
setTimeout(() => {
runScan(program);
if (program.scanOptions.scanInterval) {
setInterval(() => runScan(program), program.scanOptions.scanInterval * 60 * 60 * 1000);
}
}, scanDelay * 1000);
}

1
save/README.md Normal file
View File

@ -0,0 +1 @@
DB and Config files go here