Init sqlite take 2

This commit is contained in:
advplyr 2023-07-04 18:14:44 -05:00
parent d86a3b3dc2
commit cf7fd315b6
88 changed files with 7017 additions and 692 deletions

View file

@ -4,6 +4,7 @@ const { createNewSortInstance } = require('../libs/fastSort')
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
const { reqSupportsWebp } = require('../utils/index')
@ -21,7 +22,7 @@ class AuthorController {
// Used on author landing page to include library items and items grouped in series
if (include.includes('items')) {
authorJson.libraryItems = this.db.libraryItems.filter(li => {
authorJson.libraryItems = Database.libraryItems.filter(li => {
if (libraryId && li.libraryId !== libraryId) return false
if (!req.user.checkCanAccessLibraryItem(li)) return false // filter out library items user cannot access
return li.media.metadata.hasAuthor && li.media.metadata.hasAuthor(req.author.id)
@ -97,23 +98,29 @@ class AuthorController {
const authorNameUpdate = payload.name !== undefined && payload.name !== req.author.name
// Check if author name matches another author and merge the authors
const existingAuthor = authorNameUpdate ? this.db.authors.find(au => au.id !== req.author.id && payload.name === au.name) : false
const existingAuthor = authorNameUpdate ? Database.authors.find(au => au.id !== req.author.id && payload.name === au.name) : false
if (existingAuthor) {
const itemsWithAuthor = this.db.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasAuthor(req.author.id))
const bookAuthorsToCreate = []
const itemsWithAuthor = Database.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasAuthor(req.author.id))
itemsWithAuthor.forEach(libraryItem => { // Replace old author with merging author for each book
libraryItem.media.metadata.replaceAuthor(req.author, existingAuthor)
bookAuthorsToCreate.push({
bookId: libraryItem.media.id,
authorId: existingAuthor.id
})
})
if (itemsWithAuthor.length) {
await this.db.updateLibraryItems(itemsWithAuthor)
await Database.removeBulkBookAuthors(req.author.id) // Remove all old BookAuthor
await Database.createBulkBookAuthors(bookAuthorsToCreate) // Create all new BookAuthor
SocketAuthority.emitter('items_updated', itemsWithAuthor.map(li => li.toJSONExpanded()))
}
// Remove old author
await this.db.removeEntity('author', req.author.id)
await Database.removeAuthor(req.author.id)
SocketAuthority.emitter('author_removed', req.author.toJSON())
// Send updated num books for merged author
const numBooks = this.db.libraryItems.filter(li => {
const numBooks = Database.libraryItems.filter(li => {
return li.media.metadata.hasAuthor && li.media.metadata.hasAuthor(existingAuthor.id)
}).length
SocketAuthority.emitter('author_updated', existingAuthor.toJSONExpanded(numBooks))
@ -131,18 +138,17 @@ class AuthorController {
req.author.updatedAt = Date.now()
if (authorNameUpdate) { // Update author name on all books
const itemsWithAuthor = this.db.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasAuthor(req.author.id))
const itemsWithAuthor = Database.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasAuthor(req.author.id))
itemsWithAuthor.forEach(libraryItem => {
libraryItem.media.metadata.updateAuthor(req.author)
})
if (itemsWithAuthor.length) {
await this.db.updateLibraryItems(itemsWithAuthor)
SocketAuthority.emitter('items_updated', itemsWithAuthor.map(li => li.toJSONExpanded()))
}
}
await this.db.updateEntity('author', req.author)
const numBooks = this.db.libraryItems.filter(li => {
await Database.updateAuthor(req.author)
const numBooks = Database.libraryItems.filter(li => {
return li.media.metadata.hasAuthor && li.media.metadata.hasAuthor(req.author.id)
}).length
SocketAuthority.emitter('author_updated', req.author.toJSONExpanded(numBooks))
@ -159,7 +165,7 @@ class AuthorController {
var q = (req.query.q || '').toLowerCase()
if (!q) return res.json([])
var limit = (req.query.limit && !isNaN(req.query.limit)) ? Number(req.query.limit) : 25
var authors = this.db.authors.filter(au => au.name.toLowerCase().includes(q))
var authors = Database.authors.filter(au => au.name.toLowerCase().includes(q))
authors = authors.slice(0, limit)
res.json({
results: authors
@ -204,8 +210,8 @@ class AuthorController {
if (hasUpdates) {
req.author.updatedAt = Date.now()
await this.db.updateEntity('author', req.author)
const numBooks = this.db.libraryItems.filter(li => {
await Database.updateAuthor(req.author)
const numBooks = Database.libraryItems.filter(li => {
return li.media.metadata.hasAuthor && li.media.metadata.hasAuthor(req.author.id)
}).length
SocketAuthority.emitter('author_updated', req.author.toJSONExpanded(numBooks))
@ -238,7 +244,7 @@ class AuthorController {
}
middleware(req, res, next) {
var author = this.db.authors.find(au => au.id === req.params.id)
var author = Database.authors.find(au => au.id === req.params.id)
if (!author) return res.sendStatus(404)
if (req.method == 'DELETE' && !req.user.canDelete) {

View file

@ -1,5 +1,6 @@
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
const Collection = require('../objects/Collection')
@ -13,22 +14,22 @@ class CollectionController {
if (!success) {
return res.status(500).send('Invalid collection data')
}
var jsonExpanded = newCollection.toJSONExpanded(this.db.libraryItems)
await this.db.insertEntity('collection', newCollection)
var jsonExpanded = newCollection.toJSONExpanded(Database.libraryItems)
await Database.createCollection(newCollection)
SocketAuthority.emitter('collection_added', jsonExpanded)
res.json(jsonExpanded)
}
findAll(req, res) {
res.json({
collections: this.db.collections.map(c => c.toJSONExpanded(this.db.libraryItems))
collections: Database.collections.map(c => c.toJSONExpanded(Database.libraryItems))
})
}
findOne(req, res) {
const includeEntities = (req.query.include || '').split(',')
const collectionExpanded = req.collection.toJSONExpanded(this.db.libraryItems)
const collectionExpanded = req.collection.toJSONExpanded(Database.libraryItems)
if (includeEntities.includes('rssfeed')) {
const feedData = this.rssFeedManager.findFeedForEntityId(collectionExpanded.id)
@ -41,9 +42,9 @@ class CollectionController {
async update(req, res) {
const collection = req.collection
const wasUpdated = collection.update(req.body)
const jsonExpanded = collection.toJSONExpanded(this.db.libraryItems)
const jsonExpanded = collection.toJSONExpanded(Database.libraryItems)
if (wasUpdated) {
await this.db.updateEntity('collection', collection)
await Database.updateCollection(collection)
SocketAuthority.emitter('collection_updated', jsonExpanded)
}
res.json(jsonExpanded)
@ -51,19 +52,19 @@ class CollectionController {
async delete(req, res) {
const collection = req.collection
const jsonExpanded = collection.toJSONExpanded(this.db.libraryItems)
const jsonExpanded = collection.toJSONExpanded(Database.libraryItems)
// Close rss feed - remove from db and emit socket event
await this.rssFeedManager.closeFeedForEntityId(collection.id)
await this.db.removeEntity('collection', collection.id)
await Database.removeCollection(collection.id)
SocketAuthority.emitter('collection_removed', jsonExpanded)
res.sendStatus(200)
}
async addBook(req, res) {
const collection = req.collection
const libraryItem = this.db.libraryItems.find(li => li.id === req.body.id)
const libraryItem = Database.libraryItems.find(li => li.id === req.body.id)
if (!libraryItem) {
return res.status(500).send('Book not found')
}
@ -74,8 +75,14 @@ class CollectionController {
return res.status(500).send('Book already in collection')
}
collection.addBook(req.body.id)
const jsonExpanded = collection.toJSONExpanded(this.db.libraryItems)
await this.db.updateEntity('collection', collection)
const jsonExpanded = collection.toJSONExpanded(Database.libraryItems)
const collectionBook = {
collectionId: collection.id,
bookId: libraryItem.media.id,
order: collection.books.length
}
await Database.createCollectionBook(collectionBook)
SocketAuthority.emitter('collection_updated', jsonExpanded)
res.json(jsonExpanded)
}
@ -83,13 +90,18 @@ class CollectionController {
// DELETE: api/collections/:id/book/:bookId
async removeBook(req, res) {
const collection = req.collection
const libraryItem = Database.libraryItems.find(li => li.id === req.params.bookId)
if (!libraryItem) {
return res.sendStatus(404)
}
if (collection.books.includes(req.params.bookId)) {
collection.removeBook(req.params.bookId)
var jsonExpanded = collection.toJSONExpanded(this.db.libraryItems)
await this.db.updateEntity('collection', collection)
const jsonExpanded = collection.toJSONExpanded(Database.libraryItems)
SocketAuthority.emitter('collection_updated', jsonExpanded)
await Database.updateCollection(collection)
}
res.json(collection.toJSONExpanded(this.db.libraryItems))
res.json(collection.toJSONExpanded(Database.libraryItems))
}
// POST: api/collections/:id/batch/add
@ -98,19 +110,30 @@ class CollectionController {
if (!req.body.books || !req.body.books.length) {
return res.status(500).send('Invalid request body')
}
var bookIdsToAdd = req.body.books
var hasUpdated = false
for (let i = 0; i < bookIdsToAdd.length; i++) {
if (!collection.books.includes(bookIdsToAdd[i])) {
collection.addBook(bookIdsToAdd[i])
const bookIdsToAdd = req.body.books
const collectionBooksToAdd = []
let hasUpdated = false
let order = collection.books.length
for (const libraryItemId of bookIdsToAdd) {
const libraryItem = Database.libraryItems.find(li => li.id === libraryItemId)
if (!libraryItem) continue
if (!collection.books.includes(libraryItemId)) {
collection.addBook(libraryItemId)
collectionBooksToAdd.push({
collectionId: collection.id,
bookId: libraryItem.media.id,
order: order++
})
hasUpdated = true
}
}
if (hasUpdated) {
await this.db.updateEntity('collection', collection)
SocketAuthority.emitter('collection_updated', collection.toJSONExpanded(this.db.libraryItems))
await Database.createBulkCollectionBooks(collectionBooksToAdd)
SocketAuthority.emitter('collection_updated', collection.toJSONExpanded(Database.libraryItems))
}
res.json(collection.toJSONExpanded(this.db.libraryItems))
res.json(collection.toJSONExpanded(Database.libraryItems))
}
// POST: api/collections/:id/batch/remove
@ -120,23 +143,26 @@ class CollectionController {
return res.status(500).send('Invalid request body')
}
var bookIdsToRemove = req.body.books
var hasUpdated = false
for (let i = 0; i < bookIdsToRemove.length; i++) {
if (collection.books.includes(bookIdsToRemove[i])) {
collection.removeBook(bookIdsToRemove[i])
let hasUpdated = false
for (const libraryItemId of bookIdsToRemove) {
const libraryItem = Database.libraryItems.find(li => li.id === libraryItemId)
if (!libraryItem) continue
if (collection.books.includes(libraryItemId)) {
collection.removeBook(libraryItemId)
hasUpdated = true
}
}
if (hasUpdated) {
await this.db.updateEntity('collection', collection)
SocketAuthority.emitter('collection_updated', collection.toJSONExpanded(this.db.libraryItems))
await Database.updateCollection(collection)
SocketAuthority.emitter('collection_updated', collection.toJSONExpanded(Database.libraryItems))
}
res.json(collection.toJSONExpanded(this.db.libraryItems))
res.json(collection.toJSONExpanded(Database.libraryItems))
}
middleware(req, res, next) {
if (req.params.id) {
const collection = this.db.collections.find(c => c.id === req.params.id)
const collection = Database.collections.find(c => c.id === req.params.id)
if (!collection) {
return res.status(404).send('Collection not found')
}

View file

@ -1,22 +1,23 @@
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
class EmailController {
constructor() { }
getSettings(req, res) {
res.json({
settings: this.db.emailSettings
settings: Database.emailSettings
})
}
async updateSettings(req, res) {
const updated = this.db.emailSettings.update(req.body)
const updated = Database.emailSettings.update(req.body)
if (updated) {
await this.db.updateEntity('settings', this.db.emailSettings)
await Database.updateSetting(Database.emailSettings)
}
res.json({
settings: this.db.emailSettings
settings: Database.emailSettings
})
}
@ -36,24 +37,24 @@ class EmailController {
}
}
const updated = this.db.emailSettings.update({
const updated = Database.emailSettings.update({
ereaderDevices
})
if (updated) {
await this.db.updateEntity('settings', this.db.emailSettings)
await Database.updateSetting(Database.emailSettings)
SocketAuthority.adminEmitter('ereader-devices-updated', {
ereaderDevices: this.db.emailSettings.ereaderDevices
ereaderDevices: Database.emailSettings.ereaderDevices
})
}
res.json({
ereaderDevices: this.db.emailSettings.ereaderDevices
ereaderDevices: Database.emailSettings.ereaderDevices
})
}
async sendEBookToDevice(req, res) {
Logger.debug(`[EmailController] Send ebook to device request for libraryItemId=${req.body.libraryItemId}, deviceName=${req.body.deviceName}`)
const libraryItem = this.db.getLibraryItem(req.body.libraryItemId)
const libraryItem = Database.getLibraryItem(req.body.libraryItemId)
if (!libraryItem) {
return res.status(404).send('Library item not found')
}
@ -67,7 +68,7 @@ class EmailController {
return res.status(404).send('EBook file not found')
}
const device = this.db.emailSettings.getEReaderDevice(req.body.deviceName)
const device = Database.emailSettings.getEReaderDevice(req.body.deviceName)
if (!device) {
return res.status(404).send('E-reader device not found')
}

View file

@ -1,5 +1,6 @@
const Path = require('path')
const Logger = require('../Logger')
const Database = require('../Database')
const fs = require('../libs/fsExtra')
class FileSystemController {
@ -16,7 +17,7 @@ class FileSystemController {
})
// Do not include existing mapped library paths in response
this.db.libraries.forEach(lib => {
Database.libraries.forEach(lib => {
lib.folders.forEach((folder) => {
let dir = folder.fullPath
if (dir.includes(global.appRoot)) dir = dir.replace(global.appRoot, '')

View file

@ -9,6 +9,9 @@ const { sort, createNewSortInstance } = require('../libs/fastSort')
const naturalSort = createNewSortInstance({
comparer: new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare
})
const Database = require('../Database')
class LibraryController {
constructor() { }
@ -40,13 +43,13 @@ class LibraryController {
}
const library = new Library()
newLibraryPayload.displayOrder = this.db.libraries.length + 1
newLibraryPayload.displayOrder = Database.libraries.length + 1
library.setData(newLibraryPayload)
await this.db.insertEntity('library', library)
await Database.createLibrary(library)
// Only emit to users with access to library
const userFilter = (user) => {
return user.checkCanAccessLibrary && user.checkCanAccessLibrary(library.id)
return user.checkCanAccessLibrary?.(library.id)
}
SocketAuthority.emitter('library_added', library.toJSON(), userFilter)
@ -58,14 +61,15 @@ class LibraryController {
findAll(req, res) {
const librariesAccessible = req.user.librariesAccessible || []
if (librariesAccessible && librariesAccessible.length) {
if (librariesAccessible.length) {
return res.json({
libraries: this.db.libraries.filter(lib => librariesAccessible.includes(lib.id)).map(lib => lib.toJSON())
libraries: Database.libraries.filter(lib => librariesAccessible.includes(lib.id)).map(lib => lib.toJSON())
})
}
res.json({
libraries: this.db.libraries.map(lib => lib.toJSON())
libraries: Database.libraries.map(lib => lib.toJSON())
// libraries: Database.libraries.map(lib => lib.toJSON())
})
}
@ -75,7 +79,7 @@ class LibraryController {
return res.json({
filterdata: libraryHelpers.getDistinctFilterDataNew(req.libraryItems),
issues: req.libraryItems.filter(li => li.hasIssues).length,
numUserPlaylists: this.db.playlists.filter(p => p.userId === req.user.id && p.libraryId === req.library.id).length,
numUserPlaylists: Database.playlists.filter(p => p.userId === req.user.id && p.libraryId === req.library.id).length,
library: req.library
})
}
@ -128,14 +132,14 @@ class LibraryController {
this.cronManager.updateLibraryScanCron(library)
// Remove libraryItems no longer in library
const itemsToRemove = this.db.libraryItems.filter(li => li.libraryId === library.id && !library.checkFullPathInLibrary(li.path))
const itemsToRemove = Database.libraryItems.filter(li => li.libraryId === library.id && !library.checkFullPathInLibrary(li.path))
if (itemsToRemove.length) {
Logger.info(`[Scanner] Updating library, removing ${itemsToRemove.length} items`)
for (let i = 0; i < itemsToRemove.length; i++) {
await this.handleDeleteLibraryItem(itemsToRemove[i])
}
}
await this.db.updateEntity('library', library)
await Database.updateLibrary(library)
// Only emit to users with access to library
const userFilter = (user) => {
@ -153,21 +157,21 @@ class LibraryController {
this.watcher.removeLibrary(library)
// Remove collections for library
const collections = this.db.collections.filter(c => c.libraryId === library.id)
const collections = Database.collections.filter(c => c.libraryId === library.id)
for (const collection of collections) {
Logger.info(`[Server] deleting collection "${collection.name}" for library "${library.name}"`)
await this.db.removeEntity('collection', collection.id)
await Database.removeCollection(collection.id)
}
// Remove items in this library
const libraryItems = this.db.libraryItems.filter(li => li.libraryId === library.id)
const libraryItems = Database.libraryItems.filter(li => li.libraryId === library.id)
Logger.info(`[Server] deleting library "${library.name}" with ${libraryItems.length} items"`)
for (let i = 0; i < libraryItems.length; i++) {
await this.handleDeleteLibraryItem(libraryItems[i])
}
const libraryJson = library.toJSON()
await this.db.removeEntity('library', library.id)
await Database.removeLibrary(library.id)
SocketAuthority.emitter('library_removed', libraryJson)
return res.json(libraryJson)
}
@ -209,7 +213,7 @@ class LibraryController {
// If also filtering by series, will not collapse the filtered series as this would lead
// to series having a collapsed series that is just that series.
if (payload.collapseseries) {
let collapsedItems = libraryHelpers.collapseBookSeries(libraryItems, this.db.series, filterSeries, req.library.settings.hideSingleBookSeries)
let collapsedItems = libraryHelpers.collapseBookSeries(libraryItems, Database.series, filterSeries, req.library.settings.hideSingleBookSeries)
if (!(collapsedItems.length == 1 && collapsedItems[0].collapsedSeries)) {
libraryItems = collapsedItems
@ -237,7 +241,7 @@ class LibraryController {
// If no series sequence then fallback to sorting by title (or collapsed series name for sub-series)
sortArray.push({
asc: (li) => {
if (this.db.serverSettings.sortingIgnorePrefix) {
if (Database.serverSettings.sortingIgnorePrefix) {
return li.collapsedSeries?.nameIgnorePrefix || li.media.metadata.titleIgnorePrefix
} else {
return li.collapsedSeries?.name || li.media.metadata.title
@ -255,7 +259,7 @@ class LibraryController {
// Handle server setting sortingIgnorePrefix
const sortByTitle = sortKey === 'media.metadata.title'
if (sortByTitle && this.db.serverSettings.sortingIgnorePrefix) {
if (sortByTitle && Database.serverSettings.sortingIgnorePrefix) {
// BookMetadata.js has titleIgnorePrefix getter
sortKey += 'IgnorePrefix'
}
@ -267,7 +271,7 @@ class LibraryController {
sortArray.push({
asc: (li) => {
if (li.collapsedSeries) {
return this.db.serverSettings.sortingIgnorePrefix ?
return Database.serverSettings.sortingIgnorePrefix ?
li.collapsedSeries.nameIgnorePrefix :
li.collapsedSeries.name
} else {
@ -284,7 +288,7 @@ class LibraryController {
if (mediaIsBook && sortBySequence) {
return li.media.metadata.getSeries(filterSeries).sequence
} else if (mediaIsBook && sortByTitle && li.collapsedSeries) {
return this.db.serverSettings.sortingIgnorePrefix ?
return Database.serverSettings.sortingIgnorePrefix ?
li.collapsedSeries.nameIgnorePrefix :
li.collapsedSeries.name
} else {
@ -405,7 +409,7 @@ class LibraryController {
include: include.join(',')
}
let series = libraryHelpers.getSeriesFromBooks(libraryItems, this.db.series, null, payload.filterBy, req.user, payload.minified, req.library.settings.hideSingleBookSeries)
let series = libraryHelpers.getSeriesFromBooks(libraryItems, Database.series, null, payload.filterBy, req.user, payload.minified, req.library.settings.hideSingleBookSeries)
const direction = payload.sortDesc ? 'desc' : 'asc'
series = naturalSort(series).by([
@ -422,7 +426,7 @@ class LibraryController {
} else if (payload.sortBy === 'lastBookAdded') {
return Math.max(...(se.books).map(x => x.addedAt), 0)
} else { // sort by name
return this.db.serverSettings.sortingIgnorePrefix ? se.nameIgnorePrefixSort : se.name
return Database.serverSettings.sortingIgnorePrefix ? se.nameIgnorePrefixSort : se.name
}
}
}
@ -466,7 +470,7 @@ class LibraryController {
include: include.join(',')
}
let collections = this.db.collections.filter(c => c.libraryId === req.library.id).map(c => {
let collections = Database.collections.filter(c => c.libraryId === req.library.id).map(c => {
const expanded = c.toJSONExpanded(libraryItems, payload.minified)
// If all books restricted to user in this collection then hide this collection
@ -493,7 +497,7 @@ class LibraryController {
// api/libraries/:id/playlists
async getUserPlaylistsForLibrary(req, res) {
let playlistsForUser = this.db.playlists.filter(p => p.userId === req.user.id && p.libraryId === req.library.id).map(p => p.toJSONExpanded(this.db.libraryItems))
let playlistsForUser = Database.playlists.filter(p => p.userId === req.user.id && p.libraryId === req.library.id).map(p => p.toJSONExpanded(Database.libraryItems))
const payload = {
results: [],
@ -517,7 +521,7 @@ class LibraryController {
return res.status(400).send('Invalid library media type')
}
let libraryItems = this.db.libraryItems.filter(li => li.libraryId === req.library.id)
let libraryItems = Database.libraryItems.filter(li => li.libraryId === req.library.id)
let albums = libraryHelpers.groupMusicLibraryItemsIntoAlbums(libraryItems)
albums = naturalSort(albums).asc(a => a.title) // Alphabetical by album title
@ -561,26 +565,26 @@ class LibraryController {
var orderdata = req.body
var hasUpdates = false
for (let i = 0; i < orderdata.length; i++) {
var library = this.db.libraries.find(lib => lib.id === orderdata[i].id)
var library = Database.libraries.find(lib => lib.id === orderdata[i].id)
if (!library) {
Logger.error(`[LibraryController] Invalid library not found in reorder ${orderdata[i].id}`)
return res.sendStatus(500)
}
if (library.update({ displayOrder: orderdata[i].newOrder })) {
hasUpdates = true
await this.db.updateEntity('library', library)
await Database.updateLibrary(library)
}
}
if (hasUpdates) {
this.db.libraries.sort((a, b) => a.displayOrder - b.displayOrder)
Database.libraries.sort((a, b) => a.displayOrder - b.displayOrder)
Logger.debug(`[LibraryController] Updated library display orders`)
} else {
Logger.debug(`[LibraryController] Library orders were up to date`)
}
res.json({
libraries: this.db.libraries.map(lib => lib.toJSON())
libraries: Database.libraries.map(lib => lib.toJSON())
})
}
@ -610,7 +614,7 @@ class LibraryController {
if (queryResult.series?.length) {
queryResult.series.forEach((se) => {
if (!seriesMatches[se.id]) {
const _series = this.db.series.find(_se => _se.id === se.id)
const _series = Database.series.find(_se => _se.id === se.id)
if (_series) seriesMatches[se.id] = { series: _series.toJSON(), books: [li.toJSON()] }
} else {
seriesMatches[se.id].books.push(li.toJSON())
@ -620,7 +624,7 @@ class LibraryController {
if (queryResult.authors?.length) {
queryResult.authors.forEach((au) => {
if (!authorMatches[au.id]) {
const _author = this.db.authors.find(_au => _au.id === au.id)
const _author = Database.authors.find(_au => _au.id === au.id)
if (_author) {
authorMatches[au.id] = _author.toJSON()
authorMatches[au.id].numBooks = 1
@ -687,7 +691,7 @@ class LibraryController {
if (li.media.metadata.authors && li.media.metadata.authors.length) {
li.media.metadata.authors.forEach((au) => {
if (!authors[au.id]) {
const _author = this.db.authors.find(_au => _au.id === au.id)
const _author = Database.authors.find(_au => _au.id === au.id)
if (_author) {
authors[au.id] = _author.toJSON()
authors[au.id].numBooks = 1
@ -749,7 +753,7 @@ class LibraryController {
}
if (itemsUpdated.length) {
await this.db.updateLibraryItems(itemsUpdated)
await Database.updateBulkBooks(itemsUpdated.map(i => i.media))
SocketAuthority.emitter('items_updated', itemsUpdated.map(li => li.toJSONExpanded()))
}
@ -774,7 +778,7 @@ class LibraryController {
}
if (itemsUpdated.length) {
await this.db.updateLibraryItems(itemsUpdated)
await Database.updateBulkBooks(itemsUpdated.map(i => i.media))
SocketAuthority.emitter('items_updated', itemsUpdated.map(li => li.toJSONExpanded()))
}
@ -858,12 +862,12 @@ class LibraryController {
return res.sendStatus(404)
}
const library = this.db.libraries.find(lib => lib.id === req.params.id)
const library = Database.libraries.find(lib => lib.id === req.params.id)
if (!library) {
return res.status(404).send('Library not found')
}
req.library = library
req.libraryItems = this.db.libraryItems.filter(li => {
req.libraryItems = Database.libraryItems.filter(li => {
return li.libraryId === library.id && req.user.checkCanAccessLibraryItem(li)
})
next()

View file

@ -2,9 +2,10 @@ const Path = require('path')
const fs = require('../libs/fsExtra')
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
const zipHelpers = require('../utils/zipHelpers')
const { reqSupportsWebp, isNullOrNaN } = require('../utils/index')
const { reqSupportsWebp } = require('../utils/index')
const { ScanResult } = require('../utils/constants')
const { getAudioMimeTypeFromExtname } = require('../utils/fileUtils')
@ -31,7 +32,7 @@ class LibraryItemController {
if (item.mediaType == 'book') {
if (includeEntities.includes('authors')) {
item.media.metadata.authors = item.media.metadata.authors.map(au => {
var author = this.db.authors.find(_au => _au.id === au.id)
var author = Database.authors.find(_au => _au.id === au.id)
if (!author) return null
return {
...author
@ -61,7 +62,7 @@ class LibraryItemController {
const hasUpdates = libraryItem.update(req.body)
if (hasUpdates) {
Logger.debug(`[LibraryItemController] Updated now saving`)
await this.db.updateLibraryItem(libraryItem)
await Database.updateLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
}
res.json(libraryItem.toJSON())
@ -139,7 +140,7 @@ class LibraryItemController {
}
Logger.debug(`[LibraryItemController] Updated library item media ${libraryItem.media.metadata.title}`)
await this.db.updateLibraryItem(libraryItem)
await Database.updateLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
}
res.json({
@ -174,7 +175,7 @@ class LibraryItemController {
return res.status(500).send('Unknown error occurred')
}
await this.db.updateLibraryItem(libraryItem)
await Database.updateLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
res.json({
success: true,
@ -194,7 +195,7 @@ class LibraryItemController {
return res.status(500).send(validationResult.error)
}
if (validationResult.updated) {
await this.db.updateLibraryItem(libraryItem)
await Database.updateLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
}
res.json({
@ -210,7 +211,7 @@ class LibraryItemController {
if (libraryItem.media.coverPath) {
libraryItem.updateMediaCover('')
await this.cacheManager.purgeCoverCache(libraryItem.id)
await this.db.updateLibraryItem(libraryItem)
await Database.updateLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
}
@ -282,7 +283,7 @@ class LibraryItemController {
return res.sendStatus(500)
}
libraryItem.media.updateAudioTracks(orderedFileData)
await this.db.updateLibraryItem(libraryItem)
await Database.updateLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
res.json(libraryItem.toJSON())
}
@ -309,7 +310,7 @@ class LibraryItemController {
return res.sendStatus(500)
}
const itemsToDelete = this.db.libraryItems.filter(li => libraryItemIds.includes(li.id))
const itemsToDelete = Database.libraryItems.filter(li => libraryItemIds.includes(li.id))
if (!itemsToDelete.length) {
return res.sendStatus(404)
}
@ -338,7 +339,7 @@ class LibraryItemController {
for (let i = 0; i < updatePayloads.length; i++) {
var mediaPayload = updatePayloads[i].mediaPayload
var libraryItem = this.db.libraryItems.find(_li => _li.id === updatePayloads[i].id)
var libraryItem = Database.libraryItems.find(_li => _li.id === updatePayloads[i].id)
if (!libraryItem) return null
await this.createAuthorsAndSeriesForItemUpdate(mediaPayload)
@ -346,7 +347,7 @@ class LibraryItemController {
var hasUpdates = libraryItem.media.update(mediaPayload)
if (hasUpdates) {
Logger.debug(`[LibraryItemController] Updated library item media ${libraryItem.media.metadata.title}`)
await this.db.updateLibraryItem(libraryItem)
await Database.updateLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
itemsUpdated++
}
@ -366,7 +367,7 @@ class LibraryItemController {
}
const libraryItems = []
libraryItemIds.forEach((lid) => {
const li = this.db.libraryItems.find(_li => _li.id === lid)
const li = Database.libraryItems.find(_li => _li.id === lid)
if (li) libraryItems.push(li.toJSONExpanded())
})
res.json({
@ -389,7 +390,7 @@ class LibraryItemController {
return res.sendStatus(400)
}
const libraryItems = req.body.libraryItemIds.map(lid => this.db.getLibraryItem(lid)).filter(li => li)
const libraryItems = req.body.libraryItemIds.map(lid => Database.getLibraryItem(lid)).filter(li => li)
if (!libraryItems?.length) {
return res.sendStatus(400)
}
@ -424,7 +425,7 @@ class LibraryItemController {
return res.sendStatus(400)
}
const libraryItems = req.body.libraryItemIds.map(lid => this.db.getLibraryItem(lid)).filter(li => li)
const libraryItems = req.body.libraryItemIds.map(lid => Database.getLibraryItem(lid)).filter(li => li)
if (!libraryItems?.length) {
return res.sendStatus(400)
}
@ -441,15 +442,17 @@ class LibraryItemController {
}
// DELETE: api/items/all
// TODO: Remove
async deleteAll(req, res) {
if (!req.user.isAdminOrUp) {
Logger.warn('User other than admin attempted to delete all library items', req.user)
return res.sendStatus(403)
}
Logger.info('Removing all Library Items')
var success = await this.db.recreateLibraryItemsDb()
if (success) res.sendStatus(200)
else res.sendStatus(500)
return res.sendStatus(404)
// if (!req.user.isAdminOrUp) {
// Logger.warn('User other than admin attempted to delete all library items', req.user)
// return res.sendStatus(403)
// }
// Logger.info('Removing all Library Items')
// var success = await this.db.recreateLibraryItemsDb()
// if (success) res.sendStatus(200)
// else res.sendStatus(500)
}
// POST: api/items/:id/scan (admin)
@ -504,7 +507,7 @@ class LibraryItemController {
const chapters = req.body.chapters || []
const wasUpdated = req.libraryItem.media.updateChapters(chapters)
if (wasUpdated) {
await this.db.updateLibraryItem(req.libraryItem)
await Database.updateLibraryItem(req.libraryItem)
SocketAuthority.emitter('item_updated', req.libraryItem.toJSONExpanded())
}
@ -586,7 +589,7 @@ class LibraryItemController {
}
}
req.libraryItem.updatedAt = Date.now()
await this.db.updateLibraryItem(req.libraryItem)
await Database.updateLibraryItem(req.libraryItem)
SocketAuthority.emitter('item_updated', req.libraryItem.toJSONExpanded())
res.sendStatus(200)
}
@ -682,13 +685,13 @@ class LibraryItemController {
}
req.libraryItem.updatedAt = Date.now()
await this.db.updateLibraryItem(req.libraryItem)
await Database.updateLibraryItem(req.libraryItem)
SocketAuthority.emitter('item_updated', req.libraryItem.toJSONExpanded())
res.sendStatus(200)
}
middleware(req, res, next) {
req.libraryItem = this.db.libraryItems.find(li => li.id === req.params.id)
req.libraryItem = Database.libraryItems.find(li => li.id === req.params.id)
if (!req.libraryItem?.media) return res.sendStatus(404)
// Check user can access this library item

View file

@ -1,7 +1,8 @@
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
const { sort } = require('../libs/fastSort')
const { isObject, toNumber } = require('../utils/index')
const { toNumber } = require('../utils/index')
class MeController {
constructor() { }
@ -33,7 +34,7 @@ class MeController {
// GET: api/me/listening-stats
async getListeningStats(req, res) {
var listeningStats = await this.getUserListeningStatsHelpers(req.user.id)
const listeningStats = await this.getUserListeningStatsHelpers(req.user.id)
res.json(listeningStats)
}
@ -51,21 +52,21 @@ class MeController {
if (!req.user.removeMediaProgress(req.params.id)) {
return res.sendStatus(200)
}
await this.db.updateEntity('user', req.user)
await Database.removeMediaProgress(req.params.id)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
res.sendStatus(200)
}
// PATCH: api/me/progress/:id
async createUpdateMediaProgress(req, res) {
var libraryItem = this.db.libraryItems.find(ab => ab.id === req.params.id)
const libraryItem = Database.libraryItems.find(ab => ab.id === req.params.id)
if (!libraryItem) {
return res.status(404).send('Item not found')
}
var wasUpdated = req.user.createUpdateMediaProgress(libraryItem, req.body)
if (wasUpdated) {
await this.db.updateEntity('user', req.user)
if (req.user.createUpdateMediaProgress(libraryItem, req.body)) {
const mediaProgress = req.user.getMediaProgress(libraryItem.id)
if (mediaProgress) await Database.upsertMediaProgress(mediaProgress)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
}
res.sendStatus(200)
@ -73,8 +74,8 @@ class MeController {
// PATCH: api/me/progress/:id/:episodeId
async createUpdateEpisodeMediaProgress(req, res) {
var episodeId = req.params.episodeId
var libraryItem = this.db.libraryItems.find(ab => ab.id === req.params.id)
const episodeId = req.params.episodeId
const libraryItem = Database.libraryItems.find(ab => ab.id === req.params.id)
if (!libraryItem) {
return res.status(404).send('Item not found')
}
@ -83,9 +84,9 @@ class MeController {
return res.status(404).send('Episode not found')
}
var wasUpdated = req.user.createUpdateMediaProgress(libraryItem, req.body, episodeId)
if (wasUpdated) {
await this.db.updateEntity('user', req.user)
if (req.user.createUpdateMediaProgress(libraryItem, req.body, episodeId)) {
const mediaProgress = req.user.getMediaProgress(libraryItem.id, episodeId)
if (mediaProgress) await Database.upsertMediaProgress(mediaProgress)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
}
res.sendStatus(200)
@ -93,24 +94,26 @@ class MeController {
// PATCH: api/me/progress/batch/update
async batchUpdateMediaProgress(req, res) {
var itemProgressPayloads = req.body
if (!itemProgressPayloads || !itemProgressPayloads.length) {
const itemProgressPayloads = req.body
if (!itemProgressPayloads?.length) {
return res.status(400).send('Missing request payload')
}
var shouldUpdate = false
itemProgressPayloads.forEach((itemProgress) => {
var libraryItem = this.db.libraryItems.find(li => li.id === itemProgress.libraryItemId) // Make sure this library item exists
let shouldUpdate = false
for (const itemProgress of itemProgressPayloads) {
const libraryItem = Database.libraryItems.find(li => li.id === itemProgress.libraryItemId) // Make sure this library item exists
if (libraryItem) {
var wasUpdated = req.user.createUpdateMediaProgress(libraryItem, itemProgress, itemProgress.episodeId)
if (wasUpdated) shouldUpdate = true
if (req.user.createUpdateMediaProgress(libraryItem, itemProgress, itemProgress.episodeId)) {
const mediaProgress = req.user.getMediaProgress(libraryItem.id, itemProgress.episodeId)
if (mediaProgress) await Database.upsertMediaProgress(mediaProgress)
shouldUpdate = true
}
} else {
Logger.error(`[MeController] batchUpdateMediaProgress: Library Item does not exist ${itemProgress.id}`)
}
})
}
if (shouldUpdate) {
await this.db.updateEntity('user', req.user)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
}
@ -119,18 +122,18 @@ class MeController {
// POST: api/me/item/:id/bookmark
async createBookmark(req, res) {
var libraryItem = this.db.libraryItems.find(li => li.id === req.params.id)
var libraryItem = Database.libraryItems.find(li => li.id === req.params.id)
if (!libraryItem) return res.sendStatus(404)
const { time, title } = req.body
var bookmark = req.user.createBookmark(libraryItem.id, time, title)
await this.db.updateEntity('user', req.user)
await Database.updateUser(req.user)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
res.json(bookmark)
}
// PATCH: api/me/item/:id/bookmark
async updateBookmark(req, res) {
var libraryItem = this.db.libraryItems.find(li => li.id === req.params.id)
var libraryItem = Database.libraryItems.find(li => li.id === req.params.id)
if (!libraryItem) return res.sendStatus(404)
const { time, title } = req.body
if (!req.user.findBookmark(libraryItem.id, time)) {
@ -139,14 +142,14 @@ class MeController {
}
var bookmark = req.user.updateBookmark(libraryItem.id, time, title)
if (!bookmark) return res.sendStatus(500)
await this.db.updateEntity('user', req.user)
await Database.updateUser(req.user)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
res.json(bookmark)
}
// DELETE: api/me/item/:id/bookmark/:time
async removeBookmark(req, res) {
var libraryItem = this.db.libraryItems.find(li => li.id === req.params.id)
var libraryItem = Database.libraryItems.find(li => li.id === req.params.id)
if (!libraryItem) return res.sendStatus(404)
var time = Number(req.params.time)
if (isNaN(time)) return res.sendStatus(500)
@ -156,7 +159,7 @@ class MeController {
return res.sendStatus(404)
}
req.user.removeBookmark(libraryItem.id, time)
await this.db.updateEntity('user', req.user)
await Database.updateUser(req.user)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
res.sendStatus(200)
}
@ -178,16 +181,16 @@ class MeController {
return res.sendStatus(500)
}
const updatedLocalMediaProgress = []
var numServerProgressUpdates = 0
let numServerProgressUpdates = 0
const updatedServerMediaProgress = []
const localMediaProgress = req.body.localMediaProgress || []
localMediaProgress.forEach(localProgress => {
for (const localProgress of localMediaProgress) {
if (!localProgress.libraryItemId) {
Logger.error(`[MeController] syncLocalMediaProgress invalid local media progress object`, localProgress)
return
}
var libraryItem = this.db.getLibraryItem(localProgress.libraryItemId)
const libraryItem = Database.getLibraryItem(localProgress.libraryItemId)
if (!libraryItem) {
Logger.error(`[MeController] syncLocalMediaProgress invalid local media progress object no library item`, localProgress)
return
@ -199,12 +202,14 @@ class MeController {
Logger.debug(`[MeController] syncLocalMediaProgress local progress is new - creating ${localProgress.id}`)
req.user.createUpdateMediaProgress(libraryItem, localProgress, localProgress.episodeId)
mediaProgress = req.user.getMediaProgress(localProgress.libraryItemId, localProgress.episodeId)
if (mediaProgress) await Database.upsertMediaProgress(mediaProgress)
updatedServerMediaProgress.push(mediaProgress)
numServerProgressUpdates++
} else if (mediaProgress.lastUpdate < localProgress.lastUpdate) {
Logger.debug(`[MeController] syncLocalMediaProgress local progress is more recent - updating ${mediaProgress.id}`)
req.user.createUpdateMediaProgress(libraryItem, localProgress, localProgress.episodeId)
mediaProgress = req.user.getMediaProgress(localProgress.libraryItemId, localProgress.episodeId)
if (mediaProgress) await Database.upsertMediaProgress(mediaProgress)
updatedServerMediaProgress.push(mediaProgress)
numServerProgressUpdates++
} else if (mediaProgress.lastUpdate > localProgress.lastUpdate) {
@ -222,11 +227,10 @@ class MeController {
} else {
Logger.debug(`[MeController] syncLocalMediaProgress server and local are in sync - ${mediaProgress.id}`)
}
})
}
Logger.debug(`[MeController] syncLocalMediaProgress server updates = ${numServerProgressUpdates}, local updates = ${updatedLocalMediaProgress.length}`)
if (numServerProgressUpdates > 0) {
await this.db.updateEntity('user', req.user)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
}
@ -244,7 +248,7 @@ class MeController {
let itemsInProgress = []
for (const mediaProgress of req.user.mediaProgress) {
if (!mediaProgress.isFinished && (mediaProgress.progress > 0 || mediaProgress.ebookProgress > 0)) {
const libraryItem = this.db.getLibraryItem(mediaProgress.libraryItemId)
const libraryItem = Database.getLibraryItem(mediaProgress.libraryItemId)
if (libraryItem) {
if (mediaProgress.episodeId && libraryItem.mediaType === 'podcast') {
const episode = libraryItem.media.episodes.find(ep => ep.id === mediaProgress.episodeId)
@ -274,7 +278,7 @@ class MeController {
// GET: api/me/series/:id/remove-from-continue-listening
async removeSeriesFromContinueListening(req, res) {
const series = this.db.series.find(se => se.id === req.params.id)
const series = Database.series.find(se => se.id === req.params.id)
if (!series) {
Logger.error(`[MeController] removeSeriesFromContinueListening: Series ${req.params.id} not found`)
return res.sendStatus(404)
@ -282,7 +286,7 @@ class MeController {
const hasUpdated = req.user.addSeriesToHideFromContinueListening(req.params.id)
if (hasUpdated) {
await this.db.updateEntity('user', req.user)
await Database.updateUser(req.user)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
}
res.json(req.user.toJSONForBrowser())
@ -290,7 +294,7 @@ class MeController {
// GET: api/me/series/:id/readd-to-continue-listening
async readdSeriesFromContinueListening(req, res) {
const series = this.db.series.find(se => se.id === req.params.id)
const series = Database.series.find(se => se.id === req.params.id)
if (!series) {
Logger.error(`[MeController] readdSeriesFromContinueListening: Series ${req.params.id} not found`)
return res.sendStatus(404)
@ -298,7 +302,7 @@ class MeController {
const hasUpdated = req.user.removeSeriesFromHideFromContinueListening(req.params.id)
if (hasUpdated) {
await this.db.updateEntity('user', req.user)
await Database.updateUser(req.user)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
}
res.json(req.user.toJSONForBrowser())
@ -308,7 +312,7 @@ class MeController {
async removeItemFromContinueListening(req, res) {
const hasUpdated = req.user.removeProgressFromContinueListening(req.params.id)
if (hasUpdated) {
await this.db.updateEntity('user', req.user)
await Database.updateUser(req.user)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', req.user.toJSONForBrowser())
}
res.json(req.user.toJSONForBrowser())

View file

@ -2,6 +2,7 @@ const Path = require('path')
const fs = require('../libs/fsExtra')
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
const filePerms = require('../utils/filePerms')
const patternValidation = require('../libs/nodeCron/pattern-validation')
@ -30,7 +31,7 @@ class MiscController {
var libraryId = req.body.library
var folderId = req.body.folder
var library = this.db.libraries.find(lib => lib.id === libraryId)
var library = Database.libraries.find(lib => lib.id === libraryId)
if (!library) {
return res.status(404).send(`Library not found with id ${libraryId}`)
}
@ -116,18 +117,18 @@ class MiscController {
return res.status(500).send('Invalid settings update object')
}
var madeUpdates = this.db.serverSettings.update(settingsUpdate)
var madeUpdates = Database.serverSettings.update(settingsUpdate)
if (madeUpdates) {
// If backup schedule is updated - update backup manager
if (settingsUpdate.backupSchedule !== undefined) {
this.backupManager.updateCronSchedule()
}
await this.db.updateServerSettings()
await Database.updateServerSettings()
}
return res.json({
success: true,
serverSettings: this.db.serverSettings.toJSONForBrowser()
serverSettings: Database.serverSettings.toJSONForBrowser()
})
}
@ -147,7 +148,7 @@ class MiscController {
return res.sendStatus(404)
}
const tags = []
this.db.libraryItems.forEach((li) => {
Database.libraryItems.forEach((li) => {
if (li.media.tags && li.media.tags.length) {
li.media.tags.forEach((tag) => {
if (!tags.includes(tag)) tags.push(tag)
@ -176,7 +177,7 @@ class MiscController {
let tagMerged = false
let numItemsUpdated = 0
for (const li of this.db.libraryItems) {
for (const li of Database.libraryItems) {
if (!li.media.tags || !li.media.tags.length) continue
if (li.media.tags.includes(newTag)) tagMerged = true // new tag is an existing tag so this is a merge
@ -187,7 +188,7 @@ class MiscController {
li.media.tags.push(newTag) // Add new tag
}
Logger.debug(`[MiscController] Rename tag "${tag}" to "${newTag}" for item "${li.media.metadata.title}"`)
await this.db.updateLibraryItem(li)
await Database.updateLibraryItem(li)
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
numItemsUpdated++
}
@ -209,13 +210,13 @@ class MiscController {
const tag = Buffer.from(decodeURIComponent(req.params.tag), 'base64').toString()
let numItemsUpdated = 0
for (const li of this.db.libraryItems) {
for (const li of Database.libraryItems) {
if (!li.media.tags || !li.media.tags.length) continue
if (li.media.tags.includes(tag)) {
li.media.tags = li.media.tags.filter(t => t !== tag)
Logger.debug(`[MiscController] Remove tag "${tag}" from item "${li.media.metadata.title}"`)
await this.db.updateLibraryItem(li)
await Database.updateLibraryItem(li)
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
numItemsUpdated++
}
@ -233,7 +234,7 @@ class MiscController {
return res.sendStatus(404)
}
const genres = []
this.db.libraryItems.forEach((li) => {
Database.libraryItems.forEach((li) => {
if (li.media.metadata.genres && li.media.metadata.genres.length) {
li.media.metadata.genres.forEach((genre) => {
if (!genres.includes(genre)) genres.push(genre)
@ -262,7 +263,7 @@ class MiscController {
let genreMerged = false
let numItemsUpdated = 0
for (const li of this.db.libraryItems) {
for (const li of Database.libraryItems) {
if (!li.media.metadata.genres || !li.media.metadata.genres.length) continue
if (li.media.metadata.genres.includes(newGenre)) genreMerged = true // new genre is an existing genre so this is a merge
@ -273,7 +274,7 @@ class MiscController {
li.media.metadata.genres.push(newGenre) // Add new genre
}
Logger.debug(`[MiscController] Rename genre "${genre}" to "${newGenre}" for item "${li.media.metadata.title}"`)
await this.db.updateLibraryItem(li)
await Database.updateLibraryItem(li)
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
numItemsUpdated++
}
@ -295,13 +296,13 @@ class MiscController {
const genre = Buffer.from(decodeURIComponent(req.params.genre), 'base64').toString()
let numItemsUpdated = 0
for (const li of this.db.libraryItems) {
for (const li of Database.libraryItems) {
if (!li.media.metadata.genres || !li.media.metadata.genres.length) continue
if (li.media.metadata.genres.includes(genre)) {
li.media.metadata.genres = li.media.metadata.genres.filter(t => t !== genre)
Logger.debug(`[MiscController] Remove genre "${genre}" from item "${li.media.metadata.title}"`)
await this.db.updateLibraryItem(li)
await Database.updateLibraryItem(li)
SocketAuthority.emitter('item_updated', li.toJSONExpanded())
numItemsUpdated++
}

View file

@ -1,4 +1,5 @@
const Logger = require('../Logger')
const Database = require('../Database')
const { version } = require('../../package.json')
class NotificationController {
@ -7,14 +8,14 @@ class NotificationController {
get(req, res) {
res.json({
data: this.notificationManager.getData(),
settings: this.db.notificationSettings
settings: Database.notificationSettings
})
}
async update(req, res) {
const updated = this.db.notificationSettings.update(req.body)
const updated = Database.notificationSettings.update(req.body)
if (updated) {
await this.db.updateEntity('settings', this.db.notificationSettings)
await Database.updateSetting(Database.notificationSettings)
}
res.sendStatus(200)
}
@ -29,31 +30,31 @@ class NotificationController {
}
async createNotification(req, res) {
const success = this.db.notificationSettings.createNotification(req.body)
const success = Database.notificationSettings.createNotification(req.body)
if (success) {
await this.db.updateEntity('settings', this.db.notificationSettings)
await Database.updateSetting(Database.notificationSettings)
}
res.json(this.db.notificationSettings)
res.json(Database.notificationSettings)
}
async deleteNotification(req, res) {
if (this.db.notificationSettings.removeNotification(req.notification.id)) {
await this.db.updateEntity('settings', this.db.notificationSettings)
if (Database.notificationSettings.removeNotification(req.notification.id)) {
await Database.updateSetting(Database.notificationSettings)
}
res.json(this.db.notificationSettings)
res.json(Database.notificationSettings)
}
async updateNotification(req, res) {
const success = this.db.notificationSettings.updateNotification(req.body)
const success = Database.notificationSettings.updateNotification(req.body)
if (success) {
await this.db.updateEntity('settings', this.db.notificationSettings)
await Database.updateSetting(Database.notificationSettings)
}
res.json(this.db.notificationSettings)
res.json(Database.notificationSettings)
}
async sendNotificationTest(req, res) {
if (!this.db.notificationSettings.isUseable) return res.status(500).send('Apprise is not configured')
if (!Database.notificationSettings.isUseable) return res.status(500).send('Apprise is not configured')
const success = await this.notificationManager.sendTestNotification(req.notification)
if (success) res.sendStatus(200)
@ -66,7 +67,7 @@ class NotificationController {
}
if (req.params.id) {
const notification = this.db.notificationSettings.getNotification(req.params.id)
const notification = Database.notificationSettings.getNotification(req.params.id)
if (!notification) {
return res.sendStatus(404)
}

View file

@ -1,5 +1,6 @@
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
const Playlist = require('../objects/Playlist')
@ -14,8 +15,8 @@ class PlaylistController {
if (!success) {
return res.status(400).send('Invalid playlist request data')
}
const jsonExpanded = newPlaylist.toJSONExpanded(this.db.libraryItems)
await this.db.insertEntity('playlist', newPlaylist)
const jsonExpanded = newPlaylist.toJSONExpanded(Database.libraryItems)
await Database.createPlaylist(newPlaylist)
SocketAuthority.clientEmitter(newPlaylist.userId, 'playlist_added', jsonExpanded)
res.json(jsonExpanded)
}
@ -23,22 +24,22 @@ class PlaylistController {
// GET: api/playlists
findAllForUser(req, res) {
res.json({
playlists: this.db.playlists.filter(p => p.userId === req.user.id).map(p => p.toJSONExpanded(this.db.libraryItems))
playlists: Database.playlists.filter(p => p.userId === req.user.id).map(p => p.toJSONExpanded(Database.libraryItems))
})
}
// GET: api/playlists/:id
findOne(req, res) {
res.json(req.playlist.toJSONExpanded(this.db.libraryItems))
res.json(req.playlist.toJSONExpanded(Database.libraryItems))
}
// PATCH: api/playlists/:id
async update(req, res) {
const playlist = req.playlist
let wasUpdated = playlist.update(req.body)
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
const jsonExpanded = playlist.toJSONExpanded(Database.libraryItems)
if (wasUpdated) {
await this.db.updateEntity('playlist', playlist)
await Database.updatePlaylist(playlist)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_updated', jsonExpanded)
}
res.json(jsonExpanded)
@ -47,8 +48,8 @@ class PlaylistController {
// DELETE: api/playlists/:id
async delete(req, res) {
const playlist = req.playlist
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
await this.db.removeEntity('playlist', playlist.id)
const jsonExpanded = playlist.toJSONExpanded(Database.libraryItems)
await Database.removePlaylist(playlist.id)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_removed', jsonExpanded)
res.sendStatus(200)
}
@ -62,7 +63,7 @@ class PlaylistController {
return res.status(400).send('Request body has no libraryItemId')
}
const libraryItem = this.db.libraryItems.find(li => li.id === itemToAdd.libraryItemId)
const libraryItem = Database.libraryItems.find(li => li.id === itemToAdd.libraryItemId)
if (!libraryItem) {
return res.status(400).send('Library item not found')
}
@ -80,8 +81,16 @@ class PlaylistController {
}
playlist.addItem(itemToAdd.libraryItemId, itemToAdd.episodeId)
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
await this.db.updateEntity('playlist', playlist)
const playlistMediaItem = {
playlistId: playlist.id,
mediaItemId: itemToAdd.episodeId || libraryItem.media.id,
mediaItemType: itemToAdd.episodeId ? 'podcastEpisode' : 'book',
order: playlist.items.length
}
const jsonExpanded = playlist.toJSONExpanded(Database.libraryItems)
await Database.createPlaylistMediaItem(playlistMediaItem)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_updated', jsonExpanded)
res.json(jsonExpanded)
}
@ -99,15 +108,15 @@ class PlaylistController {
playlist.removeItem(itemToRemove.libraryItemId, itemToRemove.episodeId)
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
const jsonExpanded = playlist.toJSONExpanded(Database.libraryItems)
// Playlist is removed when there are no items
if (!playlist.items.length) {
Logger.info(`[PlaylistController] Playlist "${playlist.name}" has no more items - removing it`)
await this.db.removeEntity('playlist', playlist.id)
await Database.removePlaylist(playlist.id)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_removed', jsonExpanded)
} else {
await this.db.updateEntity('playlist', playlist)
await Database.updatePlaylist(playlist)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_updated', jsonExpanded)
}
@ -122,20 +131,34 @@ class PlaylistController {
}
const itemsToAdd = req.body.items
let hasUpdated = false
let order = playlist.items.length
const playlistMediaItems = []
for (const item of itemsToAdd) {
if (!item.libraryItemId) {
return res.status(400).send('Item does not have libraryItemId')
}
const libraryItem = Database.getLibraryItem(item.libraryItemId)
if (!libraryItem) {
return res.status(400).send('Item not found with id ' + item.libraryItemId)
}
if (!playlist.containsItem(item)) {
playlistMediaItems.push({
playlistId: playlist.id,
mediaItemId: item.episodeId || libraryItem.media.id, // podcastEpisodeId or bookId
mediaItemType: item.episodeId ? 'podcastEpisode' : 'book',
order: order++
})
playlist.addItem(item.libraryItemId, item.episodeId)
hasUpdated = true
}
}
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
const jsonExpanded = playlist.toJSONExpanded(Database.libraryItems)
if (hasUpdated) {
await this.db.updateEntity('playlist', playlist)
await Database.createBulkPlaylistMediaItems(playlistMediaItems)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_updated', jsonExpanded)
}
res.json(jsonExpanded)
@ -153,21 +176,22 @@ class PlaylistController {
if (!item.libraryItemId) {
return res.status(400).send('Item does not have libraryItemId')
}
if (playlist.containsItem(item)) {
playlist.removeItem(item.libraryItemId, item.episodeId)
hasUpdated = true
}
}
const jsonExpanded = playlist.toJSONExpanded(this.db.libraryItems)
const jsonExpanded = playlist.toJSONExpanded(Database.libraryItems)
if (hasUpdated) {
// Playlist is removed when there are no items
if (!playlist.items.length) {
Logger.info(`[PlaylistController] Playlist "${playlist.name}" has no more items - removing it`)
await this.db.removeEntity('playlist', playlist.id)
await Database.removePlaylist(playlist.id)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_removed', jsonExpanded)
} else {
await this.db.updateEntity('playlist', playlist)
await Database.updatePlaylist(playlist)
SocketAuthority.clientEmitter(playlist.userId, 'playlist_updated', jsonExpanded)
}
}
@ -176,12 +200,12 @@ class PlaylistController {
// POST: api/playlists/collection/:collectionId
async createFromCollection(req, res) {
let collection = this.db.collections.find(c => c.id === req.params.collectionId)
let collection = Database.collections.find(c => c.id === req.params.collectionId)
if (!collection) {
return res.status(404).send('Collection not found')
}
// Expand collection to get library items
collection = collection.toJSONExpanded(this.db.libraryItems)
collection = collection.toJSONExpanded(Database.libraryItems)
// Filter out library items not accessible to user
const libraryItems = collection.books.filter(item => req.user.checkCanAccessLibraryItem(item))
@ -201,15 +225,15 @@ class PlaylistController {
}
newPlaylist.setData(newPlaylistData)
const jsonExpanded = newPlaylist.toJSONExpanded(this.db.libraryItems)
await this.db.insertEntity('playlist', newPlaylist)
const jsonExpanded = newPlaylist.toJSONExpanded(Database.libraryItems)
await Database.createPlaylist(newPlaylist)
SocketAuthority.clientEmitter(newPlaylist.userId, 'playlist_added', jsonExpanded)
res.json(jsonExpanded)
}
middleware(req, res, next) {
if (req.params.id) {
const playlist = this.db.playlists.find(p => p.id === req.params.id)
const playlist = Database.playlists.find(p => p.id === req.params.id)
if (!playlist) {
return res.status(404).send('Playlist not found')
}

View file

@ -1,5 +1,6 @@
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
const fs = require('../libs/fsExtra')
@ -18,7 +19,7 @@ class PodcastController {
}
const payload = req.body
const library = this.db.libraries.find(lib => lib.id === payload.libraryId)
const library = Database.libraries.find(lib => lib.id === payload.libraryId)
if (!library) {
Logger.error(`[PodcastController] Create: Library not found "${payload.libraryId}"`)
return res.status(404).send('Library not found')
@ -33,7 +34,7 @@ class PodcastController {
const podcastPath = filePathToPOSIX(payload.path)
// Check if a library item with this podcast folder exists already
const existingLibraryItem = this.db.libraryItems.find(li => li.path === podcastPath && li.libraryId === library.id)
const existingLibraryItem = Database.libraryItems.find(li => li.path === podcastPath && li.libraryId === library.id)
if (existingLibraryItem) {
Logger.error(`[PodcastController] Podcast already exists with name "${existingLibraryItem.media.metadata.title}" at path "${podcastPath}"`)
return res.status(400).send('Podcast already exists')
@ -80,7 +81,7 @@ class PodcastController {
}
}
await this.db.insertLibraryItem(libraryItem)
await Database.createLibraryItem(libraryItem)
SocketAuthority.emitter('item_added', libraryItem.toJSONExpanded())
res.json(libraryItem.toJSONExpanded())
@ -199,7 +200,7 @@ class PodcastController {
const overrideDetails = req.query.override === '1'
const episodesUpdated = await this.scanner.quickMatchPodcastEpisodes(req.libraryItem, { overrideDetails })
if (episodesUpdated) {
await this.db.updateLibraryItem(req.libraryItem)
await Database.updateLibraryItem(req.libraryItem)
SocketAuthority.emitter('item_updated', req.libraryItem.toJSONExpanded())
}
@ -216,9 +217,8 @@ class PodcastController {
return res.status(404).send('Episode not found')
}
var wasUpdated = libraryItem.media.updateEpisode(episodeId, req.body)
if (wasUpdated) {
await this.db.updateLibraryItem(libraryItem)
if (libraryItem.media.updateEpisode(episodeId, req.body)) {
await Database.updateLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
}
@ -267,13 +267,13 @@ class PodcastController {
libraryItem.removeLibraryFile(episodeRemoved.audioFile.ino)
}
await this.db.updateLibraryItem(libraryItem)
await Database.updateLibraryItem(libraryItem)
SocketAuthority.emitter('item_updated', libraryItem.toJSONExpanded())
res.json(libraryItem.toJSON())
}
middleware(req, res, next) {
const item = this.db.libraryItems.find(li => li.id === req.params.id)
const item = Database.libraryItems.find(li => li.id === req.params.id)
if (!item || !item.media) return res.sendStatus(404)
if (!item.isPodcast) {

View file

@ -1,5 +1,5 @@
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
class RSSFeedController {
constructor() { }
@ -8,7 +8,7 @@ class RSSFeedController {
async openRSSFeedForItem(req, res) {
const options = req.body || {}
const item = this.db.libraryItems.find(li => li.id === req.params.itemId)
const item = Database.libraryItems.find(li => li.id === req.params.itemId)
if (!item) return res.sendStatus(404)
// Check user can access this library item
@ -45,7 +45,7 @@ class RSSFeedController {
async openRSSFeedForCollection(req, res) {
const options = req.body || {}
const collection = this.db.collections.find(li => li.id === req.params.collectionId)
const collection = Database.collections.find(li => li.id === req.params.collectionId)
if (!collection) return res.sendStatus(404)
// Check request body options exist
@ -60,7 +60,7 @@ class RSSFeedController {
return res.status(400).send('Slug already in use')
}
const collectionExpanded = collection.toJSONExpanded(this.db.libraryItems)
const collectionExpanded = collection.toJSONExpanded(Database.libraryItems)
const collectionItemsWithTracks = collectionExpanded.books.filter(li => li.media.tracks.length)
// Check collection has audio tracks
@ -79,7 +79,7 @@ class RSSFeedController {
async openRSSFeedForSeries(req, res) {
const options = req.body || {}
const series = this.db.series.find(se => se.id === req.params.seriesId)
const series = Database.series.find(se => se.id === req.params.seriesId)
if (!series) return res.sendStatus(404)
// Check request body options exist
@ -96,7 +96,7 @@ class RSSFeedController {
const seriesJson = series.toJSON()
// Get books in series that have audio tracks
seriesJson.books = this.db.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasSeries(series.id) && li.media.tracks.length)
seriesJson.books = Database.libraryItems.filter(li => li.mediaType === 'book' && li.media.metadata.hasSeries(series.id) && li.media.tracks.length)
// Check series has audio tracks
if (!seriesJson.books.length) {

View file

@ -1,5 +1,6 @@
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
class SeriesController {
constructor() { }
@ -35,7 +36,7 @@ class SeriesController {
var q = (req.query.q || '').toLowerCase()
if (!q) return res.json([])
var limit = (req.query.limit && !isNaN(req.query.limit)) ? Number(req.query.limit) : 25
var series = this.db.series.filter(se => se.name.toLowerCase().includes(q))
var series = Database.series.filter(se => se.name.toLowerCase().includes(q))
series = series.slice(0, limit)
res.json({
results: series
@ -45,17 +46,17 @@ class SeriesController {
async update(req, res) {
const hasUpdated = req.series.update(req.body)
if (hasUpdated) {
await this.db.updateEntity('series', req.series)
await Database.updateSeries(req.series)
SocketAuthority.emitter('series_updated', req.series.toJSON())
}
res.json(req.series.toJSON())
}
middleware(req, res, next) {
const series = this.db.series.find(se => se.id === req.params.id)
const series = Database.series.find(se => se.id === req.params.id)
if (!series) return res.sendStatus(404)
const libraryItemsInSeries = this.db.libraryItems.filter(li => li.media.metadata.hasSeries?.(series.id))
const libraryItemsInSeries = Database.libraryItems.filter(li => li.media.metadata.hasSeries?.(series.id))
if (libraryItemsInSeries.some(li => !req.user.checkCanAccessLibrary(li.libraryId))) {
Logger.warn(`[SeriesController] User attempted to access series "${series.id}" without access to the library`, req.user)
return res.sendStatus(403)

View file

@ -1,4 +1,5 @@
const Logger = require('../Logger')
const Database = require('../Database')
const { toNumber } = require('../utils/index')
class SessionController {
@ -49,7 +50,7 @@ class SessionController {
}
const openSessions = this.playbackSessionManager.sessions.map(se => {
const user = this.db.users.find(u => u.id === se.userId) || null
const user = Database.users.find(u => u.id === se.userId) || null
return {
...se.toJSON(),
user: user ? { id: user.id, username: user.username } : null
@ -62,7 +63,7 @@ class SessionController {
}
getOpenSession(req, res) {
var libraryItem = this.db.getLibraryItem(req.session.libraryItemId)
var libraryItem = Database.getLibraryItem(req.session.libraryItemId)
var sessionForClient = req.session.toJSONForClient(libraryItem)
res.json(sessionForClient)
}
@ -87,7 +88,7 @@ class SessionController {
await this.playbackSessionManager.removeSession(req.session.id)
}
await this.db.removeEntity('session', req.session.id)
await Database.removePlaybackSession(req.session.id)
res.sendStatus(200)
}
@ -115,7 +116,7 @@ class SessionController {
}
async middleware(req, res, next) {
const playbackSession = await this.db.getPlaybackSession(req.params.id)
const playbackSession = await Database.getPlaybackSession(req.params.id)
if (!playbackSession) {
Logger.error(`[SessionController] Unable to find playback session with id=${req.params.id}`)
return res.sendStatus(404)

View file

@ -1,4 +1,5 @@
const Logger = require('../Logger')
const Database = require('../Database')
class ToolsController {
constructor() { }
@ -65,7 +66,7 @@ class ToolsController {
const libraryItems = []
for (const libraryItemId of libraryItemIds) {
const libraryItem = this.db.getLibraryItem(libraryItemId)
const libraryItem = Database.getLibraryItem(libraryItemId)
if (!libraryItem) {
Logger.error(`[ToolsController] Batch embed metadata library item (${libraryItemId}) not found`)
return res.sendStatus(404)
@ -105,7 +106,7 @@ class ToolsController {
}
if (req.params.id) {
const item = this.db.libraryItems.find(li => li.id === req.params.id)
const item = Database.libraryItems.find(li => li.id === req.params.id)
if (!item || !item.media) return res.sendStatus(404)
// Check user can access this library item

View file

@ -1,9 +1,11 @@
const uuidv4 = require("uuid").v4
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const Database = require('../Database')
const User = require('../objects/user/User')
const { getId, toNumber } = require('../utils/index')
const { toNumber } = require('../utils/index')
class UserController {
constructor() { }
@ -15,11 +17,11 @@ class UserController {
const includes = (req.query.include || '').split(',').map(i => i.trim())
// Minimal toJSONForBrowser does not include mediaProgress and bookmarks
const users = this.db.users.map(u => u.toJSONForBrowser(hideRootToken, true))
const users = Database.users.map(u => u.toJSONForBrowser(hideRootToken, true))
if (includes.includes('latestSession')) {
for (const user of users) {
const userSessions = await this.db.selectUserSessions(user.id)
const userSessions = await Database.getPlaybackSessions({ userId: user.id })
user.latestSession = userSessions.sort((a, b) => b.updatedAt - a.updatedAt).shift() || null
}
}
@ -35,7 +37,7 @@ class UserController {
return res.sendStatus(403)
}
const user = this.db.users.find(u => u.id === req.params.id)
const user = Database.users.find(u => u.id === req.params.id)
if (!user) {
return res.sendStatus(404)
}
@ -47,18 +49,19 @@ class UserController {
var account = req.body
var username = account.username
var usernameExists = this.db.users.find(u => u.username.toLowerCase() === username.toLowerCase())
var usernameExists = Database.users.find(u => u.username.toLowerCase() === username.toLowerCase())
if (usernameExists) {
return res.status(500).send('Username already taken')
}
account.id = getId('usr')
account.id = uuidv4()
account.pash = await this.auth.hashPass(account.password)
delete account.password
account.token = await this.auth.generateAccessToken({ userId: account.id, username })
account.createdAt = Date.now()
var newUser = new User(account)
var success = await this.db.insertEntity('user', newUser)
const newUser = new User(account)
const success = await Database.createUser(newUser)
if (success) {
SocketAuthority.adminEmitter('user_added', newUser.toJSONForBrowser())
res.json({
@ -81,7 +84,7 @@ class UserController {
var shouldUpdateToken = false
if (account.username !== undefined && account.username !== user.username) {
var usernameExists = this.db.users.find(u => u.username.toLowerCase() === account.username.toLowerCase())
var usernameExists = Database.users.find(u => u.username.toLowerCase() === account.username.toLowerCase())
if (usernameExists) {
return res.status(500).send('Username already taken')
}
@ -94,13 +97,12 @@ class UserController {
delete account.password
}
var hasUpdated = user.update(account)
if (hasUpdated) {
if (user.update(account)) {
if (shouldUpdateToken) {
user.token = await this.auth.generateAccessToken({ userId: user.id, username: user.username })
Logger.info(`[UserController] User ${user.username} was generated a new api token`)
}
await this.db.updateEntity('user', user)
await Database.updateUser(user)
SocketAuthority.clientEmitter(req.user.id, 'user_updated', user.toJSONForBrowser())
}
@ -124,13 +126,13 @@ class UserController {
// Todo: check if user is logged in and cancel streams
// Remove user playlists
const userPlaylists = this.db.playlists.filter(p => p.userId === user.id)
const userPlaylists = Database.playlists.filter(p => p.userId === user.id)
for (const playlist of userPlaylists) {
await this.db.removeEntity('playlist', playlist.id)
await Database.removePlaylist(playlist.id)
}
const userJson = user.toJSONForBrowser()
await this.db.removeEntity('user', user.id)
await Database.removeUser(user.id)
SocketAuthority.adminEmitter('user_removed', userJson)
res.json({
success: true
@ -165,37 +167,39 @@ class UserController {
}
// POST: api/users/:id/purge-media-progress
// TODO: Remove
async purgeMediaProgress(req, res) {
const user = req.reqUser
return res.sendStatus(404)
// const user = req.reqUser
if (user.type === 'root' && !req.user.isRoot) {
Logger.error(`[UserController] Admin user attempted to purge media progress of root user`, req.user.username)
return res.sendStatus(403)
}
// if (user.type === 'root' && !req.user.isRoot) {
// Logger.error(`[UserController] Admin user attempted to purge media progress of root user`, req.user.username)
// return res.sendStatus(403)
// }
var progressPurged = 0
user.mediaProgress = user.mediaProgress.filter(mp => {
const libraryItem = this.db.libraryItems.find(li => li.id === mp.libraryItemId)
if (!libraryItem) {
progressPurged++
return false
} else if (mp.episodeId) {
const episode = libraryItem.mediaType === 'podcast' ? libraryItem.media.getEpisode(mp.episodeId) : null
if (!episode) { // Episode not found
progressPurged++
return false
}
}
return true
})
// var progressPurged = 0
// user.mediaProgress = user.mediaProgress.filter(mp => {
// const libraryItem = Database.libraryItems.find(li => li.id === mp.libraryItemId)
// if (!libraryItem) {
// progressPurged++
// return false
// } else if (mp.episodeId) {
// const episode = libraryItem.mediaType === 'podcast' ? libraryItem.media.getEpisode(mp.episodeId) : null
// if (!episode) { // Episode not found
// progressPurged++
// return false
// }
// }
// return true
// })
if (progressPurged) {
Logger.info(`[UserController] Purged ${progressPurged} media progress for user ${user.username}`)
await this.db.updateEntity('user', user)
SocketAuthority.adminEmitter('user_updated', user.toJSONForBrowser())
}
// if (progressPurged) {
// Logger.info(`[UserController] Purged ${progressPurged} media progress for user ${user.username}`)
// await this.db.updateEntity('user', user)
// SocketAuthority.adminEmitter('user_updated', user.toJSONForBrowser())
// }
res.json(this.userJsonWithItemProgressDetails(user, !req.user.isRoot))
// res.json(this.userJsonWithItemProgressDetails(user, !req.user.isRoot))
}
// POST: api/users/online (admin)
@ -218,7 +222,7 @@ class UserController {
}
if (req.params.id) {
req.reqUser = this.db.users.find(u => u.id === req.params.id)
req.reqUser = Database.users.find(u => u.id === req.params.id)
if (!req.reqUser) {
return res.sendStatus(404)
}