mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2024-11-07 16:44:16 +01:00
Updates to use new Library model
This commit is contained in:
parent
8774e6be71
commit
38edcdca4b
@ -384,11 +384,6 @@ class Database {
|
||||
return Promise.all(oldBooks.map((oldBook) => this.models.book.saveFromOld(oldBook)))
|
||||
}
|
||||
|
||||
updateLibrary(oldLibrary) {
|
||||
if (!this.sequelize) return false
|
||||
return this.models.library.updateFromOld(oldLibrary)
|
||||
}
|
||||
|
||||
removeLibrary(libraryId) {
|
||||
if (!this.sequelize) return false
|
||||
return this.models.library.removeById(libraryId)
|
||||
|
@ -142,7 +142,7 @@ class Server {
|
||||
await this.backupManager.init()
|
||||
await this.rssFeedManager.init()
|
||||
|
||||
const libraries = await Database.libraryModel.getAllOldLibraries()
|
||||
const libraries = await Database.libraryModel.getAllWithFolders()
|
||||
await this.cronManager.init(libraries)
|
||||
this.apiCacheManager.init()
|
||||
|
||||
|
@ -45,6 +45,10 @@ class FolderWatcher extends EventEmitter {
|
||||
return this.pendingFileUpdates.map((f) => f.path)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('./models/Library')} library
|
||||
*/
|
||||
buildLibraryWatcher(library) {
|
||||
if (this.libraryWatchers.find((w) => w.id === library.id)) {
|
||||
Logger.warn('[Watcher] Already watching library', library.name)
|
||||
@ -52,7 +56,7 @@ class FolderWatcher extends EventEmitter {
|
||||
}
|
||||
Logger.info(`[Watcher] Initializing watcher for "${library.name}".`)
|
||||
|
||||
const folderPaths = library.folderPaths
|
||||
const folderPaths = library.libraryFolders.map((f) => f.path)
|
||||
folderPaths.forEach((fp) => {
|
||||
Logger.debug(`[Watcher] Init watcher for library folder path "${fp}"`)
|
||||
})
|
||||
@ -90,12 +94,16 @@ class FolderWatcher extends EventEmitter {
|
||||
this.libraryWatchers.push({
|
||||
id: library.id,
|
||||
name: library.name,
|
||||
folders: library.folders,
|
||||
paths: library.folderPaths,
|
||||
libraryFolders: library.libraryFolders,
|
||||
paths: folderPaths,
|
||||
watcher
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('./models/Library')[]} libraries
|
||||
*/
|
||||
initWatcher(libraries) {
|
||||
libraries.forEach((lib) => {
|
||||
if (!lib.settings.disableWatcher) {
|
||||
@ -104,12 +112,17 @@ class FolderWatcher extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('./models/Library')} library
|
||||
*/
|
||||
addLibrary(library) {
|
||||
if (this.disabled || library.settings.disableWatcher) return
|
||||
this.buildLibraryWatcher(library)
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Update to new library model
|
||||
*
|
||||
* @param {import('./objects/Library')} library
|
||||
*/
|
||||
@ -129,8 +142,9 @@ class FolderWatcher extends EventEmitter {
|
||||
libwatcher.name = library.name
|
||||
|
||||
// If any folder paths were added or removed then re-init watcher
|
||||
const pathsToAdd = library.folderPaths.filter((path) => !libwatcher.paths.includes(path))
|
||||
const pathsRemoved = libwatcher.paths.filter((path) => !library.folderPaths.includes(path))
|
||||
const folderPaths = library.libraryFolders.map((f) => f.path)
|
||||
const pathsToAdd = folderPaths.filter((path) => !libwatcher.paths.includes(path))
|
||||
const pathsRemoved = libwatcher.paths.filter((path) => !folderPaths.includes(path))
|
||||
if (pathsToAdd.length || pathsRemoved.length) {
|
||||
Logger.info(`[Watcher] Re-Initializing watcher for "${library.name}".`)
|
||||
|
||||
@ -145,6 +159,10 @@ class FolderWatcher extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import('./models/Library')} library
|
||||
*/
|
||||
removeLibrary(library) {
|
||||
if (this.disabled) return
|
||||
var libwatcher = this.libraryWatchers.find((lib) => lib.id === library.id)
|
||||
@ -255,15 +273,15 @@ class FolderWatcher extends EventEmitter {
|
||||
}
|
||||
|
||||
// Get file folder
|
||||
const folder = libwatcher.folders.find((fold) => isSameOrSubPath(fold.fullPath, path))
|
||||
const folder = libwatcher.libraryFolders.find((fold) => isSameOrSubPath(fold.path, path))
|
||||
if (!folder) {
|
||||
Logger.error(`[Watcher] New file folder not found in library "${libwatcher.name}" with path "${path}"`)
|
||||
return
|
||||
}
|
||||
|
||||
const folderFullPath = filePathToPOSIX(folder.fullPath)
|
||||
const folderPath = filePathToPOSIX(folder.path)
|
||||
|
||||
const relPath = path.replace(folderFullPath, '')
|
||||
const relPath = path.replace(folderPath, '')
|
||||
|
||||
if (Path.extname(relPath).toLowerCase() === '.part') {
|
||||
Logger.debug(`[Watcher] Ignoring .part file "${relPath}"`)
|
||||
|
@ -4,7 +4,6 @@ const Path = require('path')
|
||||
const fs = require('../libs/fsExtra')
|
||||
const Logger = require('../Logger')
|
||||
const SocketAuthority = require('../SocketAuthority')
|
||||
const Library = require('../objects/Library')
|
||||
const libraryHelpers = require('../utils/libraryHelpers')
|
||||
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')
|
||||
const libraryItemFilters = require('../utils/queries/libraryItemFilters')
|
||||
@ -158,7 +157,7 @@ class LibraryController {
|
||||
SocketAuthority.emitter('library_added', oldLibrary.toJSON(), userFilter)
|
||||
|
||||
// Add library watcher
|
||||
this.watcher.addLibrary(oldLibrary)
|
||||
this.watcher.addLibrary(library)
|
||||
|
||||
res.json(oldLibrary)
|
||||
}
|
||||
@ -190,15 +189,16 @@ class LibraryController {
|
||||
const filterdata = await libraryFilters.getFilterData(req.library.mediaType, req.library.id)
|
||||
const customMetadataProviders = await Database.customMetadataProviderModel.getForClientByMediaType(req.library.mediaType)
|
||||
|
||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
||||
return res.json({
|
||||
filterdata,
|
||||
issues: filterdata.numIssues,
|
||||
numUserPlaylists: await Database.playlistModel.getNumPlaylistsForUserAndLibrary(req.user.id, req.library.id),
|
||||
customMetadataProviders,
|
||||
library: req.library
|
||||
library: oldLibrary
|
||||
})
|
||||
}
|
||||
res.json(req.library)
|
||||
res.json(oldLibrary)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -220,7 +220,7 @@ class LibraryController {
|
||||
*/
|
||||
async update(req, res) {
|
||||
/** @type {import('../objects/Library')} */
|
||||
const library = req.library
|
||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
||||
|
||||
// Validate that the custom provider exists if given any
|
||||
if (req.body.provider?.startsWith('custom-')) {
|
||||
@ -259,7 +259,7 @@ class LibraryController {
|
||||
}
|
||||
|
||||
// Handle removing folders
|
||||
for (const folder of library.folders) {
|
||||
for (const folder of oldLibrary.folders) {
|
||||
if (!req.body.folders.some((f) => f.id === folder.id)) {
|
||||
// Remove library items in folder
|
||||
const libraryItemsInFolder = await Database.libraryItemModel.findAll({
|
||||
@ -278,10 +278,10 @@ class LibraryController {
|
||||
}
|
||||
]
|
||||
})
|
||||
Logger.info(`[LibraryController] Removed folder "${folder.fullPath}" from library "${library.name}" with ${libraryItemsInFolder.length} library items`)
|
||||
Logger.info(`[LibraryController] Removed folder "${folder.fullPath}" from library "${oldLibrary.name}" with ${libraryItemsInFolder.length} library items`)
|
||||
for (const libraryItem of libraryItemsInFolder) {
|
||||
let mediaItemIds = []
|
||||
if (library.isPodcast) {
|
||||
if (oldLibrary.isPodcast) {
|
||||
mediaItemIds = libraryItem.media.podcastEpisodes.map((pe) => pe.id)
|
||||
} else {
|
||||
mediaItemIds.push(libraryItem.mediaId)
|
||||
@ -293,26 +293,27 @@ class LibraryController {
|
||||
}
|
||||
}
|
||||
|
||||
const hasUpdates = library.update(req.body)
|
||||
const hasUpdates = oldLibrary.update(req.body)
|
||||
// TODO: Should check if this is an update to folder paths or name only
|
||||
if (hasUpdates) {
|
||||
// Update watcher
|
||||
this.watcher.updateLibrary(library)
|
||||
|
||||
// Update auto scan cron
|
||||
this.cronManager.updateLibraryScanCron(library)
|
||||
this.cronManager.updateLibraryScanCron(oldLibrary)
|
||||
|
||||
await Database.updateLibrary(library)
|
||||
const updatedLibrary = await Database.libraryModel.updateFromOld(oldLibrary)
|
||||
updatedLibrary.libraryFolders = await updatedLibrary.getLibraryFolders()
|
||||
|
||||
// Update watcher
|
||||
this.watcher.updateLibrary(updatedLibrary)
|
||||
|
||||
// Only emit to users with access to library
|
||||
const userFilter = (user) => {
|
||||
return user.checkCanAccessLibrary?.(library.id)
|
||||
return user.checkCanAccessLibrary?.(oldLibrary.id)
|
||||
}
|
||||
SocketAuthority.emitter('library_updated', library.toJSON(), userFilter)
|
||||
SocketAuthority.emitter('library_updated', oldLibrary.toJSON(), userFilter)
|
||||
|
||||
await Database.resetLibraryIssuesFilterData(library.id)
|
||||
await Database.resetLibraryIssuesFilterData(oldLibrary.id)
|
||||
}
|
||||
return res.json(library.toJSON())
|
||||
return res.json(oldLibrary.toJSON())
|
||||
}
|
||||
|
||||
/**
|
||||
@ -323,10 +324,10 @@ class LibraryController {
|
||||
* @param {Response} res
|
||||
*/
|
||||
async delete(req, res) {
|
||||
const library = req.library
|
||||
const library = Database.libraryModel.getOldLibrary(req.library)
|
||||
|
||||
// Remove library watcher
|
||||
this.watcher.removeLibrary(library)
|
||||
this.watcher.removeLibrary(req.library)
|
||||
|
||||
// Remove collections for library
|
||||
const numCollectionsRemoved = await Database.collectionModel.removeAllForLibrary(library.id)
|
||||
@ -386,6 +387,8 @@ class LibraryController {
|
||||
* @param {Response} res
|
||||
*/
|
||||
async getLibraryItems(req, res) {
|
||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
||||
|
||||
const include = (req.query.include || '')
|
||||
.split(',')
|
||||
.map((v) => v.trim().toLowerCase())
|
||||
@ -411,9 +414,9 @@ class LibraryController {
|
||||
const filterByValue = filterByGroup ? libraryFilters.decode(payload.filterBy.replace(`${filterByGroup}.`, '')) : null
|
||||
if (filterByGroup === 'series' && filterByValue !== 'no-series' && payload.collapseseries) {
|
||||
const seriesId = libraryFilters.decode(payload.filterBy.split('.')[1])
|
||||
payload.results = await libraryHelpers.handleCollapseSubseries(payload, seriesId, req.user, req.library)
|
||||
payload.results = await libraryHelpers.handleCollapseSubseries(payload, seriesId, req.user, oldLibrary)
|
||||
} else {
|
||||
const { libraryItems, count } = await Database.libraryItemModel.getByFilterAndSort(req.library, req.user, payload)
|
||||
const { libraryItems, count } = await Database.libraryItemModel.getByFilterAndSort(oldLibrary, req.user, payload)
|
||||
payload.results = libraryItems
|
||||
payload.total = count
|
||||
}
|
||||
@ -461,7 +464,7 @@ class LibraryController {
|
||||
Logger.info(`[LibraryController] Removing ${libraryItemsWithIssues.length} items with issues`)
|
||||
for (const libraryItem of libraryItemsWithIssues) {
|
||||
let mediaItemIds = []
|
||||
if (req.library.isPodcast) {
|
||||
if (req.library.mediaType === 'podcast') {
|
||||
mediaItemIds = libraryItem.media.podcastEpisodes.map((pe) => pe.id)
|
||||
} else {
|
||||
mediaItemIds.push(libraryItem.mediaId)
|
||||
@ -486,6 +489,8 @@ class LibraryController {
|
||||
* @param {Response} res
|
||||
*/
|
||||
async getAllSeriesForLibrary(req, res) {
|
||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
||||
|
||||
const include = (req.query.include || '')
|
||||
.split(',')
|
||||
.map((v) => v.trim().toLowerCase())
|
||||
@ -504,7 +509,7 @@ class LibraryController {
|
||||
}
|
||||
|
||||
const offset = payload.page * payload.limit
|
||||
const { series, count } = await seriesFilters.getFilteredSeries(req.library, req.user, payload.filterBy, payload.sortBy, payload.sortDesc, include, payload.limit, offset)
|
||||
const { series, count } = await seriesFilters.getFilteredSeries(oldLibrary, req.user, payload.filterBy, payload.sortBy, payload.sortDesc, include, payload.limit, offset)
|
||||
|
||||
payload.total = count
|
||||
payload.results = series
|
||||
@ -635,12 +640,13 @@ class LibraryController {
|
||||
* @param {Response} res
|
||||
*/
|
||||
async getUserPersonalizedShelves(req, res) {
|
||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
||||
const limitPerShelf = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) || 10 : 10
|
||||
const include = (req.query.include || '')
|
||||
.split(',')
|
||||
.map((v) => v.trim().toLowerCase())
|
||||
.filter((v) => !!v)
|
||||
const shelves = await Database.libraryItemModel.getPersonalizedShelves(req.library, req.user, include, limitPerShelf)
|
||||
const shelves = await Database.libraryItemModel.getPersonalizedShelves(oldLibrary, req.user, include, limitPerShelf)
|
||||
res.json(shelves)
|
||||
}
|
||||
|
||||
@ -668,7 +674,7 @@ class LibraryController {
|
||||
}
|
||||
if (library.update({ displayOrder: orderdata[i].newOrder })) {
|
||||
hasUpdates = true
|
||||
await Database.updateLibrary(library)
|
||||
await Database.libraryModel.updateFromOld(library)
|
||||
}
|
||||
}
|
||||
|
||||
@ -696,10 +702,11 @@ class LibraryController {
|
||||
if (!req.query.q || typeof req.query.q !== 'string') {
|
||||
return res.status(400).send('Invalid request. Query param "q" must be a string')
|
||||
}
|
||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
||||
const limit = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 12
|
||||
const query = asciiOnlyToLowerCase(req.query.q.trim())
|
||||
|
||||
const matches = await libraryItemFilters.search(req.user, req.library, query, limit)
|
||||
const matches = await libraryItemFilters.search(req.user, oldLibrary, query, limit)
|
||||
res.json(matches)
|
||||
}
|
||||
|
||||
@ -715,7 +722,7 @@ class LibraryController {
|
||||
largestItems: await libraryItemFilters.getLargestItems(req.library.id, 10)
|
||||
}
|
||||
|
||||
if (req.library.isBook) {
|
||||
if (req.library.mediaType === 'book') {
|
||||
const authors = await authorFilters.getAuthorsWithCount(req.library.id, 10)
|
||||
const genres = await libraryItemsBookFilters.getGenresWithCount(req.library.id)
|
||||
const bookStats = await libraryItemsBookFilters.getBookLibraryStats(req.library.id)
|
||||
@ -938,7 +945,8 @@ class LibraryController {
|
||||
Logger.error(`[LibraryController] Non-root user "${req.user.username}" attempted to match library items`)
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
Scanner.matchLibraryItems(req.library)
|
||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
||||
Scanner.matchLibraryItems(oldLibrary)
|
||||
res.sendStatus(200)
|
||||
}
|
||||
|
||||
@ -956,9 +964,9 @@ class LibraryController {
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
res.sendStatus(200)
|
||||
|
||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
||||
const forceRescan = req.query.force === '1'
|
||||
await LibraryScanner.scan(req.library, forceRescan)
|
||||
await LibraryScanner.scan(oldLibrary, forceRescan)
|
||||
|
||||
await Database.resetLibraryIssuesFilterData(req.library.id)
|
||||
Logger.info('[LibraryController] Scan complete')
|
||||
@ -972,10 +980,10 @@ class LibraryController {
|
||||
* @param {Response} res
|
||||
*/
|
||||
async getRecentEpisodes(req, res) {
|
||||
if (!req.library.isPodcast) {
|
||||
if (req.library.mediaType !== 'podcast') {
|
||||
return res.sendStatus(404)
|
||||
}
|
||||
|
||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
||||
const payload = {
|
||||
episodes: [],
|
||||
limit: req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 0,
|
||||
@ -983,7 +991,7 @@ class LibraryController {
|
||||
}
|
||||
|
||||
const offset = payload.page * payload.limit
|
||||
payload.episodes = await libraryItemsPodcastFilters.getRecentEpisodes(req.user, req.library, payload.limit, offset)
|
||||
payload.episodes = await libraryItemsPodcastFilters.getRecentEpisodes(req.user, oldLibrary, payload.limit, offset)
|
||||
res.json(payload)
|
||||
}
|
||||
|
||||
@ -1076,7 +1084,8 @@ class LibraryController {
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
|
||||
const library = await Database.libraryModel.getOldById(req.params.id)
|
||||
// const library = await Database.libraryModel.getOldById(req.params.id)
|
||||
const library = await Database.libraryModel.findByIdWithFolders(req.params.id)
|
||||
if (!library) {
|
||||
return res.status(404).send('Library not found')
|
||||
}
|
||||
|
@ -21,7 +21,8 @@ class CronManager {
|
||||
|
||||
/**
|
||||
* Initialize library scan crons & podcast download crons
|
||||
* @param {import('../objects/Library')[]} libraries
|
||||
*
|
||||
* @param {import('../models/Library')[]} libraries
|
||||
*/
|
||||
async init(libraries) {
|
||||
this.initOpenSessionCleanupCron()
|
||||
@ -46,7 +47,7 @@ class CronManager {
|
||||
|
||||
/**
|
||||
* Initialize library scan crons
|
||||
* @param {import('../objects/Library')[]} libraries
|
||||
* @param {import('../models/Library')[]} libraries
|
||||
*/
|
||||
initLibraryScanCrons(libraries) {
|
||||
for (const library of libraries) {
|
||||
@ -59,17 +60,17 @@ class CronManager {
|
||||
/**
|
||||
* Start cron schedule for library
|
||||
*
|
||||
* @param {import('../objects/Library')} _library
|
||||
* @param {import('../models/Library')} _library
|
||||
*/
|
||||
startCronForLibrary(_library) {
|
||||
Logger.debug(`[CronManager] Init library scan cron for ${_library.name} on schedule ${_library.settings.autoScanCronExpression}`)
|
||||
const libScanCron = cron.schedule(_library.settings.autoScanCronExpression, async () => {
|
||||
const library = await Database.libraryModel.getOldById(_library.id)
|
||||
if (!library) {
|
||||
const oldLibrary = await Database.libraryModel.getOldById(_library.id)
|
||||
if (!oldLibrary) {
|
||||
Logger.error(`[CronManager] Library not found for scan cron ${_library.id}`)
|
||||
} else {
|
||||
Logger.debug(`[CronManager] Library scan cron executing for ${library.name}`)
|
||||
LibraryScanner.scan(library)
|
||||
Logger.debug(`[CronManager] Library scan cron executing for ${oldLibrary.name}`)
|
||||
LibraryScanner.scan(oldLibrary)
|
||||
}
|
||||
})
|
||||
this.libraryScanCrons.push({
|
||||
@ -79,11 +80,21 @@ class CronManager {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Update to new library model
|
||||
*
|
||||
* @param {*} library
|
||||
*/
|
||||
removeCronForLibrary(library) {
|
||||
Logger.debug(`[CronManager] Removing library scan cron for ${library.name}`)
|
||||
this.libraryScanCrons = this.libraryScanCrons.filter((lsc) => lsc.libraryId !== library.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Update to new library model
|
||||
*
|
||||
* @param {*} library
|
||||
*/
|
||||
updateLibraryScanCron(library) {
|
||||
const expression = library.settings.autoScanCronExpression
|
||||
const existingCron = this.libraryScanCrons.find((lsc) => lsc.libraryId === library.id)
|
||||
|
@ -43,6 +43,8 @@ class Library extends Model {
|
||||
this.createdAt
|
||||
/** @type {Date} */
|
||||
this.updatedAt
|
||||
/** @type {import('./LibraryFolder')[]|undefined} */
|
||||
this.libraryFolders
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,6 +76,28 @@ class Library extends Model {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {Promise<Library[]>}
|
||||
*/
|
||||
static getAllWithFolders() {
|
||||
return this.findAll({
|
||||
include: this.sequelize.models.libraryFolder,
|
||||
order: [['displayOrder', 'ASC']]
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} libraryId
|
||||
* @returns {Promise<Library>}
|
||||
*/
|
||||
static findByIdWithFolders(libraryId) {
|
||||
return this.findByPk(libraryId, {
|
||||
include: this.sequelize.models.libraryFolder
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all old libraries
|
||||
* @returns {Promise<oldLibrary[]>}
|
||||
@ -121,7 +145,7 @@ class Library extends Model {
|
||||
/**
|
||||
* Update library and library folders
|
||||
* @param {object} oldLibrary
|
||||
* @returns
|
||||
* @returns {Promise<Library|null>}
|
||||
*/
|
||||
static async updateFromOld(oldLibrary) {
|
||||
const existingLibrary = await this.findByPk(oldLibrary.id, {
|
||||
|
Loading…
Reference in New Issue
Block a user