mirror of
https://github.com/IrosTheBeggar/mStream.git
synced 2025-10-27 07:31:02 +00:00
Wizard stuff
This commit is contained in:
parent
b04d9408ad
commit
ccee200657
4
.gitignore
vendored
4
.gitignore
vendored
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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') {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
1
save/README.md
Normal file
@ -0,0 +1 @@
|
||||
DB and Config files go here
|
||||
Loading…
Reference in New Issue
Block a user