2021-08-18 00:01:11 +02:00
|
|
|
const Path = require('path')
|
|
|
|
const njodb = require("njodb")
|
|
|
|
const jwt = require('jsonwebtoken')
|
|
|
|
const Logger = require('./Logger')
|
2021-09-04 21:17:26 +02:00
|
|
|
const Audiobook = require('./objects/Audiobook')
|
|
|
|
const User = require('./objects/User')
|
2021-10-05 05:11:42 +02:00
|
|
|
const Library = require('./objects/Library')
|
2021-09-05 02:58:39 +02:00
|
|
|
const ServerSettings = require('./objects/ServerSettings')
|
2021-08-18 00:01:11 +02:00
|
|
|
|
|
|
|
class Db {
|
2021-10-05 05:11:42 +02:00
|
|
|
constructor(ConfigPath, AudiobookPath) {
|
|
|
|
this.ConfigPath = ConfigPath
|
|
|
|
this.AudiobookPath = AudiobookPath
|
|
|
|
this.AudiobooksPath = Path.join(ConfigPath, 'audiobooks')
|
|
|
|
this.UsersPath = Path.join(ConfigPath, 'users')
|
|
|
|
this.LibrariesPath = Path.join(ConfigPath, 'libraries')
|
|
|
|
this.SettingsPath = Path.join(ConfigPath, 'settings')
|
2021-08-18 00:01:11 +02:00
|
|
|
|
|
|
|
this.audiobooksDb = new njodb.Database(this.AudiobooksPath)
|
|
|
|
this.usersDb = new njodb.Database(this.UsersPath)
|
2021-10-05 05:11:42 +02:00
|
|
|
this.librariesDb = new njodb.Database(this.LibrariesPath, { datastores: 2 })
|
2021-08-18 00:01:11 +02:00
|
|
|
this.settingsDb = new njodb.Database(this.SettingsPath, { datastores: 2 })
|
|
|
|
|
|
|
|
this.users = []
|
2021-10-05 05:11:42 +02:00
|
|
|
this.libraries = []
|
2021-08-18 00:01:11 +02:00
|
|
|
this.audiobooks = []
|
|
|
|
this.settings = []
|
2021-09-05 02:58:39 +02:00
|
|
|
|
|
|
|
this.serverSettings = null
|
2021-08-18 00:01:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
getEntityDb(entityName) {
|
|
|
|
if (entityName === 'user') return this.usersDb
|
|
|
|
else if (entityName === 'audiobook') return this.audiobooksDb
|
2021-10-05 05:11:42 +02:00
|
|
|
else if (entityName === 'library') return this.librariesDb
|
2021-08-18 00:01:11 +02:00
|
|
|
return this.settingsDb
|
|
|
|
}
|
|
|
|
|
|
|
|
getEntityArrayKey(entityName) {
|
|
|
|
if (entityName === 'user') return 'users'
|
|
|
|
else if (entityName === 'audiobook') return 'audiobooks'
|
2021-10-05 05:11:42 +02:00
|
|
|
else if (entityName === 'library') return 'libraries'
|
2021-08-18 00:01:11 +02:00
|
|
|
return 'settings'
|
|
|
|
}
|
|
|
|
|
|
|
|
getDefaultUser(token) {
|
|
|
|
return new User({
|
|
|
|
id: 'root',
|
|
|
|
type: 'root',
|
|
|
|
username: 'root',
|
|
|
|
pash: '',
|
|
|
|
stream: null,
|
|
|
|
token,
|
2021-08-27 14:01:47 +02:00
|
|
|
isActive: true,
|
2021-08-18 00:01:11 +02:00
|
|
|
createdAt: Date.now()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-10-05 05:11:42 +02:00
|
|
|
getDefaultLibrary() {
|
|
|
|
var defaultLibrary = new Library()
|
|
|
|
defaultLibrary.setData({
|
|
|
|
id: 'main',
|
|
|
|
name: 'Main',
|
|
|
|
folder: { // Generates default folder
|
|
|
|
id: 'audiobooks',
|
|
|
|
fullPath: this.AudiobookPath,
|
|
|
|
libraryId: 'main'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return defaultLibrary
|
|
|
|
}
|
|
|
|
|
2021-10-09 00:30:20 +02:00
|
|
|
reinit() {
|
|
|
|
this.audiobooksDb = new njodb.Database(this.AudiobooksPath)
|
|
|
|
this.usersDb = new njodb.Database(this.UsersPath)
|
|
|
|
this.librariesDb = new njodb.Database(this.LibrariesPath, { datastores: 2 })
|
|
|
|
this.settingsDb = new njodb.Database(this.SettingsPath, { datastores: 2 })
|
|
|
|
return this.init()
|
|
|
|
}
|
|
|
|
|
2021-08-18 00:01:11 +02:00
|
|
|
async init() {
|
|
|
|
await this.load()
|
|
|
|
|
|
|
|
// Insert Defaults
|
2021-10-16 14:49:12 +02:00
|
|
|
var rootUser = this.users.find(u => u.type === 'root')
|
|
|
|
if (!rootUser) {
|
2021-08-18 00:01:11 +02:00
|
|
|
var token = await jwt.sign({ userId: 'root' }, process.env.TOKEN_SECRET)
|
|
|
|
Logger.debug('Generated default token', token)
|
2021-10-16 14:49:12 +02:00
|
|
|
Logger.info('[Db] Root user created')
|
2021-10-05 05:11:42 +02:00
|
|
|
await this.insertEntity('user', this.getDefaultUser(token))
|
2021-10-16 14:49:12 +02:00
|
|
|
} else {
|
|
|
|
Logger.info(`[Db] Root user exists, pw: ${rootUser.hasPw}`)
|
2021-10-05 05:11:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.libraries.length) {
|
|
|
|
await this.insertEntity('library', this.getDefaultLibrary())
|
2021-08-18 00:01:11 +02:00
|
|
|
}
|
2021-09-05 02:58:39 +02:00
|
|
|
|
|
|
|
if (!this.serverSettings) {
|
|
|
|
this.serverSettings = new ServerSettings()
|
2021-10-05 05:11:42 +02:00
|
|
|
await this.insertEntity('settings', this.serverSettings)
|
2021-09-05 02:58:39 +02:00
|
|
|
}
|
2021-08-18 00:01:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async load() {
|
|
|
|
var p1 = this.audiobooksDb.select(() => true).then((results) => {
|
|
|
|
this.audiobooks = results.data.map(a => new Audiobook(a))
|
2021-10-05 05:11:42 +02:00
|
|
|
Logger.info(`[DB] ${this.audiobooks.length} Audiobooks Loaded`)
|
2021-08-18 00:01:11 +02:00
|
|
|
})
|
|
|
|
var p2 = this.usersDb.select(() => true).then((results) => {
|
|
|
|
this.users = results.data.map(u => new User(u))
|
2021-10-05 05:11:42 +02:00
|
|
|
Logger.info(`[DB] ${this.users.length} Users Loaded`)
|
|
|
|
})
|
|
|
|
var p3 = this.librariesDb.select(() => true).then((results) => {
|
|
|
|
this.libraries = results.data.map(l => new Library(l))
|
|
|
|
Logger.info(`[DB] ${this.libraries.length} Libraries Loaded`)
|
2021-08-18 00:01:11 +02:00
|
|
|
})
|
2021-10-05 05:11:42 +02:00
|
|
|
var p4 = this.settingsDb.select(() => true).then((results) => {
|
2021-09-05 02:58:39 +02:00
|
|
|
if (results.data && results.data.length) {
|
|
|
|
this.settings = results.data
|
|
|
|
var serverSettings = this.settings.find(s => s.id === 'server-settings')
|
|
|
|
if (serverSettings) {
|
|
|
|
this.serverSettings = new ServerSettings(serverSettings)
|
|
|
|
}
|
|
|
|
}
|
2021-08-18 00:01:11 +02:00
|
|
|
})
|
2021-10-05 05:11:42 +02:00
|
|
|
await Promise.all([p1, p2, p3, p4])
|
2021-09-05 02:58:39 +02:00
|
|
|
}
|
|
|
|
|
2021-08-18 00:01:11 +02:00
|
|
|
updateAudiobook(audiobook) {
|
|
|
|
return this.audiobooksDb.update((record) => record.id === audiobook.id, () => audiobook).then((results) => {
|
|
|
|
Logger.debug(`[DB] Audiobook updated ${results.updated}`)
|
2021-08-24 14:15:56 +02:00
|
|
|
return true
|
2021-08-18 00:01:11 +02:00
|
|
|
}).catch((error) => {
|
|
|
|
Logger.error(`[DB] Audiobook update failed ${error}`)
|
2021-08-24 14:15:56 +02:00
|
|
|
return false
|
2021-08-18 00:01:11 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
updateUserStream(userId, streamId) {
|
|
|
|
return this.usersDb.update((record) => record.id === userId, (user) => {
|
|
|
|
user.stream = streamId
|
|
|
|
return user
|
|
|
|
}).then((results) => {
|
|
|
|
Logger.debug(`[DB] Updated user ${results.updated}`)
|
|
|
|
this.users = this.users.map(u => {
|
|
|
|
if (u.id === userId) {
|
|
|
|
u.stream = streamId
|
|
|
|
}
|
|
|
|
return u
|
|
|
|
})
|
|
|
|
}).catch((error) => {
|
|
|
|
Logger.error(`[DB] Update user Failed ${error}`)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-10-05 05:11:42 +02:00
|
|
|
insertEntity(entityName, entity) {
|
|
|
|
var entityDb = this.getEntityDb(entityName)
|
|
|
|
return entityDb.insert([entity]).then((results) => {
|
|
|
|
Logger.debug(`[DB] Inserted ${results.inserted} ${entityName}`)
|
|
|
|
|
|
|
|
var arrayKey = this.getEntityArrayKey(entityName)
|
|
|
|
this[arrayKey].push(entity)
|
|
|
|
return true
|
|
|
|
}).catch((error) => {
|
|
|
|
Logger.error(`[DB] Failed to insert ${entityName}`, error)
|
|
|
|
return false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-08-18 00:01:11 +02:00
|
|
|
updateEntity(entityName, entity) {
|
|
|
|
var entityDb = this.getEntityDb(entityName)
|
|
|
|
return entityDb.update((record) => record.id === entity.id, () => entity).then((results) => {
|
|
|
|
Logger.debug(`[DB] Updated entity ${entityName}: ${results.updated}`)
|
|
|
|
var arrayKey = this.getEntityArrayKey(entityName)
|
|
|
|
this[arrayKey] = this[arrayKey].map(e => {
|
|
|
|
return e.id === entity.id ? entity : e
|
|
|
|
})
|
2021-08-22 17:46:04 +02:00
|
|
|
return true
|
2021-08-18 00:01:11 +02:00
|
|
|
}).catch((error) => {
|
|
|
|
Logger.error(`[DB] Update entity ${entityName} Failed: ${error}`)
|
2021-08-22 17:46:04 +02:00
|
|
|
return false
|
2021-08-18 00:01:11 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
removeEntity(entityName, entityId) {
|
|
|
|
var entityDb = this.getEntityDb(entityName)
|
|
|
|
return entityDb.delete((record) => record.id === entityId).then((results) => {
|
|
|
|
Logger.debug(`[DB] Deleted entity ${entityName}: ${results.deleted}`)
|
|
|
|
var arrayKey = this.getEntityArrayKey(entityName)
|
|
|
|
this[arrayKey] = this[arrayKey].filter(e => {
|
|
|
|
return e.id !== entityId
|
|
|
|
})
|
|
|
|
}).catch((error) => {
|
|
|
|
Logger.error(`[DB] Remove entity ${entityName} Failed: ${error}`)
|
|
|
|
})
|
|
|
|
}
|
2021-08-20 00:29:36 +02:00
|
|
|
|
2021-08-21 23:23:35 +02:00
|
|
|
recreateAudiobookDb() {
|
|
|
|
return this.audiobooksDb.drop().then((results) => {
|
|
|
|
Logger.info(`[DB] Dropped audiobook db`, results)
|
|
|
|
this.audiobooksDb = new njodb.Database(this.AudiobooksPath)
|
|
|
|
this.audiobooks = []
|
|
|
|
return true
|
|
|
|
}).catch((error) => {
|
|
|
|
Logger.error(`[DB] Failed to drop audiobook db`, error)
|
|
|
|
return false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-08-20 00:29:36 +02:00
|
|
|
getGenres() {
|
|
|
|
var allGenres = []
|
|
|
|
this.db.audiobooks.forEach((audiobook) => {
|
|
|
|
allGenres = allGenres.concat(audiobook.genres)
|
|
|
|
})
|
|
|
|
allGenres = [...new Set(allGenres)] // Removes duplicates
|
|
|
|
return allGenres
|
|
|
|
}
|
|
|
|
|
|
|
|
getTags() {
|
|
|
|
var allTags = []
|
|
|
|
this.db.audiobooks.forEach((audiobook) => {
|
|
|
|
allTags = allTags.concat(audiobook.tags)
|
|
|
|
})
|
|
|
|
allTags = [...new Set(allTags)] // Removes duplicates
|
|
|
|
return allTags
|
|
|
|
}
|
2021-08-18 00:01:11 +02:00
|
|
|
}
|
|
|
|
module.exports = Db
|