mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-04-07 01:15:44 +02:00
Remove old library, folder and librarysettings model
This commit is contained in:
parent
fd827b2214
commit
c45c82306e
@ -19,7 +19,7 @@ class FolderWatcher extends EventEmitter {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
/** @type {{id:string, name:string, folders:import('./objects/Folder')[], paths:string[], watcher:Watcher[]}[]} */
|
/** @type {{id:string, name:string, libraryFolders:import('./models/Folder')[], paths:string[], watcher:Watcher[]}[]} */
|
||||||
this.libraryWatchers = []
|
this.libraryWatchers = []
|
||||||
/** @type {PendingFileUpdate[]} */
|
/** @type {PendingFileUpdate[]} */
|
||||||
this.pendingFileUpdates = []
|
this.pendingFileUpdates = []
|
||||||
|
@ -172,17 +172,17 @@ class LibraryController {
|
|||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
*/
|
*/
|
||||||
async findAll(req, res) {
|
async findAll(req, res) {
|
||||||
const libraries = await Database.libraryModel.getAllOldLibraries()
|
const libraries = await Database.libraryModel.getAllWithFolders()
|
||||||
|
|
||||||
const librariesAccessible = req.user.permissions?.librariesAccessible || []
|
const librariesAccessible = req.user.permissions?.librariesAccessible || []
|
||||||
if (librariesAccessible.length) {
|
if (librariesAccessible.length) {
|
||||||
return res.json({
|
return res.json({
|
||||||
libraries: libraries.filter((lib) => librariesAccessible.includes(lib.id)).map((lib) => lib.toJSON())
|
libraries: libraries.filter((lib) => librariesAccessible.includes(lib.id)).map((lib) => lib.toOldJSON())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
libraries: libraries.map((lib) => lib.toJSON())
|
libraries: libraries.map((lib) => lib.toOldJSON())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,16 +198,15 @@ class LibraryController {
|
|||||||
const filterdata = await libraryFilters.getFilterData(req.library.mediaType, req.library.id)
|
const filterdata = await libraryFilters.getFilterData(req.library.mediaType, req.library.id)
|
||||||
const customMetadataProviders = await Database.customMetadataProviderModel.getForClientByMediaType(req.library.mediaType)
|
const customMetadataProviders = await Database.customMetadataProviderModel.getForClientByMediaType(req.library.mediaType)
|
||||||
|
|
||||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
|
||||||
return res.json({
|
return res.json({
|
||||||
filterdata,
|
filterdata,
|
||||||
issues: filterdata.numIssues,
|
issues: filterdata.numIssues,
|
||||||
numUserPlaylists: await Database.playlistModel.getNumPlaylistsForUserAndLibrary(req.user.id, req.library.id),
|
numUserPlaylists: await Database.playlistModel.getNumPlaylistsForUserAndLibrary(req.user.id, req.library.id),
|
||||||
customMetadataProviders,
|
customMetadataProviders,
|
||||||
library: oldLibrary
|
library: req.library.toOldJSON()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
res.json(oldLibrary)
|
res.json(req.library.toOldJSON())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1051,9 +1050,7 @@ class LibraryController {
|
|||||||
Logger.error(`[LibraryController] Non-root user "${req.user.username}" attempted to match library items`)
|
Logger.error(`[LibraryController] Non-root user "${req.user.username}" attempted to match library items`)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
// TODO: Update to new library model
|
Scanner.matchLibraryItems(req.library)
|
||||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
|
||||||
Scanner.matchLibraryItems(oldLibrary)
|
|
||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1071,10 +1068,9 @@ class LibraryController {
|
|||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
}
|
}
|
||||||
res.sendStatus(200)
|
res.sendStatus(200)
|
||||||
// TODO: Update to new library model
|
|
||||||
const oldLibrary = Database.libraryModel.getOldLibrary(req.library)
|
|
||||||
const forceRescan = req.query.force === '1'
|
const forceRescan = req.query.force === '1'
|
||||||
await LibraryScanner.scan(oldLibrary, forceRescan)
|
await LibraryScanner.scan(req.library, forceRescan)
|
||||||
|
|
||||||
await Database.resetLibraryIssuesFilterData(req.library.id)
|
await Database.resetLibraryIssuesFilterData(req.library.id)
|
||||||
Logger.info('[LibraryController] Scan complete')
|
Logger.info('[LibraryController] Scan complete')
|
||||||
|
@ -65,12 +65,12 @@ class CronManager {
|
|||||||
startCronForLibrary(_library) {
|
startCronForLibrary(_library) {
|
||||||
Logger.debug(`[CronManager] Init library scan cron for ${_library.name} on schedule ${_library.settings.autoScanCronExpression}`)
|
Logger.debug(`[CronManager] Init library scan cron for ${_library.name} on schedule ${_library.settings.autoScanCronExpression}`)
|
||||||
const libScanCron = cron.schedule(_library.settings.autoScanCronExpression, async () => {
|
const libScanCron = cron.schedule(_library.settings.autoScanCronExpression, async () => {
|
||||||
const oldLibrary = await Database.libraryModel.getOldById(_library.id)
|
const library = await Database.libraryModel.findByIdWithFolders(_library.id)
|
||||||
if (!oldLibrary) {
|
if (!library) {
|
||||||
Logger.error(`[CronManager] Library not found for scan cron ${_library.id}`)
|
Logger.error(`[CronManager] Library not found for scan cron ${_library.id}`)
|
||||||
} else {
|
} else {
|
||||||
Logger.debug(`[CronManager] Library scan cron executing for ${oldLibrary.name}`)
|
Logger.debug(`[CronManager] Library scan cron executing for ${library.name}`)
|
||||||
LibraryScanner.scan(oldLibrary)
|
LibraryScanner.scan(library)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.libraryScanCrons.push({
|
this.libraryScanCrons.push({
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
const { DataTypes, Model } = require('sequelize')
|
const { DataTypes, Model } = require('sequelize')
|
||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
const oldLibrary = require('../objects/Library')
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef LibrarySettingsObject
|
* @typedef LibrarySettingsObject
|
||||||
@ -98,114 +97,6 @@ class Library extends Model {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get all old libraries
|
|
||||||
* @returns {Promise<oldLibrary[]>}
|
|
||||||
*/
|
|
||||||
static async getAllOldLibraries() {
|
|
||||||
const libraries = await this.findAll({
|
|
||||||
include: this.sequelize.models.libraryFolder,
|
|
||||||
order: [['displayOrder', 'ASC']]
|
|
||||||
})
|
|
||||||
return libraries.map((lib) => this.getOldLibrary(lib))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert expanded Library to oldLibrary
|
|
||||||
* @param {Library} libraryExpanded
|
|
||||||
* @returns {oldLibrary}
|
|
||||||
*/
|
|
||||||
static getOldLibrary(libraryExpanded) {
|
|
||||||
const folders = libraryExpanded.libraryFolders.map((folder) => {
|
|
||||||
return {
|
|
||||||
id: folder.id,
|
|
||||||
fullPath: folder.path,
|
|
||||||
libraryId: folder.libraryId,
|
|
||||||
addedAt: folder.createdAt.valueOf()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return new oldLibrary({
|
|
||||||
id: libraryExpanded.id,
|
|
||||||
oldLibraryId: libraryExpanded.extraData?.oldLibraryId || null,
|
|
||||||
name: libraryExpanded.name,
|
|
||||||
folders,
|
|
||||||
displayOrder: libraryExpanded.displayOrder,
|
|
||||||
icon: libraryExpanded.icon,
|
|
||||||
mediaType: libraryExpanded.mediaType,
|
|
||||||
provider: libraryExpanded.provider,
|
|
||||||
settings: libraryExpanded.settings,
|
|
||||||
lastScan: libraryExpanded.lastScan?.valueOf() || null,
|
|
||||||
lastScanVersion: libraryExpanded.lastScanVersion || null,
|
|
||||||
lastScanMetadataPrecedence: libraryExpanded.extraData?.lastScanMetadataPrecedence || null,
|
|
||||||
createdAt: libraryExpanded.createdAt.valueOf(),
|
|
||||||
lastUpdate: libraryExpanded.updatedAt.valueOf()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update library and library folders
|
|
||||||
* @param {object} oldLibrary
|
|
||||||
* @returns {Promise<Library|null>}
|
|
||||||
*/
|
|
||||||
static async updateFromOld(oldLibrary) {
|
|
||||||
const existingLibrary = await this.findByPk(oldLibrary.id, {
|
|
||||||
include: this.sequelize.models.libraryFolder
|
|
||||||
})
|
|
||||||
if (!existingLibrary) {
|
|
||||||
Logger.error(`[Library] Failed to update library ${oldLibrary.id} - not found`)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const library = this.getFromOld(oldLibrary)
|
|
||||||
|
|
||||||
const libraryFolders = oldLibrary.folders.map((folder) => {
|
|
||||||
return {
|
|
||||||
id: folder.id,
|
|
||||||
path: folder.fullPath,
|
|
||||||
libraryId: library.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
for (const libraryFolder of libraryFolders) {
|
|
||||||
const existingLibraryFolder = existingLibrary.libraryFolders.find((lf) => lf.id === libraryFolder.id)
|
|
||||||
if (!existingLibraryFolder) {
|
|
||||||
await this.sequelize.models.libraryFolder.create(libraryFolder)
|
|
||||||
} else if (existingLibraryFolder.path !== libraryFolder.path) {
|
|
||||||
await existingLibraryFolder.update({ path: libraryFolder.path })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const libraryFoldersRemoved = existingLibrary.libraryFolders.filter((lf) => !libraryFolders.some((_lf) => _lf.id === lf.id))
|
|
||||||
for (const existingLibraryFolder of libraryFoldersRemoved) {
|
|
||||||
await existingLibraryFolder.destroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
return existingLibrary.update(library)
|
|
||||||
}
|
|
||||||
|
|
||||||
static getFromOld(oldLibrary) {
|
|
||||||
const extraData = {}
|
|
||||||
if (oldLibrary.oldLibraryId) {
|
|
||||||
extraData.oldLibraryId = oldLibrary.oldLibraryId
|
|
||||||
}
|
|
||||||
if (oldLibrary.lastScanMetadataPrecedence) {
|
|
||||||
extraData.lastScanMetadataPrecedence = oldLibrary.lastScanMetadataPrecedence
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
id: oldLibrary.id,
|
|
||||||
name: oldLibrary.name,
|
|
||||||
displayOrder: oldLibrary.displayOrder,
|
|
||||||
icon: oldLibrary.icon || null,
|
|
||||||
mediaType: oldLibrary.mediaType || null,
|
|
||||||
provider: oldLibrary.provider,
|
|
||||||
settings: oldLibrary.settings?.toJSON() || {},
|
|
||||||
lastScan: oldLibrary.lastScan || null,
|
|
||||||
lastScanVersion: oldLibrary.lastScanVersion || null,
|
|
||||||
createdAt: oldLibrary.createdAt,
|
|
||||||
updatedAt: oldLibrary.lastUpdate,
|
|
||||||
extraData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy library by id
|
* Destroy library by id
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
@ -231,20 +122,6 @@ class Library extends Model {
|
|||||||
return libraries.map((l) => l.id)
|
return libraries.map((l) => l.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Find Library by primary key & return oldLibrary
|
|
||||||
* @param {string} libraryId
|
|
||||||
* @returns {Promise<oldLibrary|null>} Returns null if not found
|
|
||||||
*/
|
|
||||||
static async getOldById(libraryId) {
|
|
||||||
if (!libraryId) return null
|
|
||||||
const library = await this.findByPk(libraryId, {
|
|
||||||
include: this.sequelize.models.libraryFolder
|
|
||||||
})
|
|
||||||
if (!library) return null
|
|
||||||
return this.getOldLibrary(library)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the largest value in the displayOrder column
|
* Get the largest value in the displayOrder column
|
||||||
* Used for setting a new libraries display order
|
* Used for setting a new libraries display order
|
||||||
@ -308,6 +185,12 @@ class Library extends Model {
|
|||||||
get isBook() {
|
get isBook() {
|
||||||
return this.mediaType === 'book'
|
return this.mediaType === 'book'
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @returns {string[]}
|
||||||
|
*/
|
||||||
|
get lastScanMetadataPrecedence() {
|
||||||
|
return this.extraData?.lastScanMetadataPrecedence || []
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Update to use new model
|
* TODO: Update to use new model
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
const uuidv4 = require("uuid").v4
|
|
||||||
|
|
||||||
class Folder {
|
|
||||||
constructor(folder = null) {
|
|
||||||
this.id = null
|
|
||||||
this.fullPath = null
|
|
||||||
this.libraryId = null
|
|
||||||
this.addedAt = null
|
|
||||||
|
|
||||||
if (folder) {
|
|
||||||
this.construct(folder)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
construct(folder) {
|
|
||||||
this.id = folder.id
|
|
||||||
this.fullPath = folder.fullPath
|
|
||||||
this.libraryId = folder.libraryId
|
|
||||||
this.addedAt = folder.addedAt
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON() {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
fullPath: this.fullPath,
|
|
||||||
libraryId: this.libraryId,
|
|
||||||
addedAt: this.addedAt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setData(data) {
|
|
||||||
this.id = data.id || uuidv4()
|
|
||||||
this.fullPath = data.fullPath
|
|
||||||
this.libraryId = data.libraryId
|
|
||||||
this.addedAt = Date.now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module.exports = Folder
|
|
@ -1,95 +0,0 @@
|
|||||||
const Folder = require('./Folder')
|
|
||||||
const LibrarySettings = require('./settings/LibrarySettings')
|
|
||||||
const { filePathToPOSIX } = require('../utils/fileUtils')
|
|
||||||
|
|
||||||
class Library {
|
|
||||||
constructor(library = null) {
|
|
||||||
this.id = null
|
|
||||||
this.oldLibraryId = null // TODO: Temp
|
|
||||||
this.name = null
|
|
||||||
this.folders = []
|
|
||||||
this.displayOrder = 1
|
|
||||||
this.icon = 'database'
|
|
||||||
this.mediaType = 'book' // book, podcast
|
|
||||||
this.provider = 'google'
|
|
||||||
|
|
||||||
this.lastScan = 0
|
|
||||||
this.lastScanVersion = null
|
|
||||||
this.lastScanMetadataPrecedence = null
|
|
||||||
|
|
||||||
this.settings = null
|
|
||||||
|
|
||||||
this.createdAt = null
|
|
||||||
this.lastUpdate = null
|
|
||||||
|
|
||||||
if (library) {
|
|
||||||
this.construct(library)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get isPodcast() {
|
|
||||||
return this.mediaType === 'podcast'
|
|
||||||
}
|
|
||||||
get isBook() {
|
|
||||||
return this.mediaType === 'book'
|
|
||||||
}
|
|
||||||
|
|
||||||
construct(library) {
|
|
||||||
this.id = library.id
|
|
||||||
this.oldLibraryId = library.oldLibraryId
|
|
||||||
this.name = library.name
|
|
||||||
this.folders = (library.folders || []).map((f) => new Folder(f))
|
|
||||||
this.displayOrder = library.displayOrder || 1
|
|
||||||
this.icon = library.icon || 'database'
|
|
||||||
this.mediaType = library.mediaType
|
|
||||||
this.provider = library.provider || 'google'
|
|
||||||
|
|
||||||
this.settings = new LibrarySettings(library.settings)
|
|
||||||
if (library.settings === undefined) {
|
|
||||||
// LibrarySettings added in v2, migrate settings
|
|
||||||
this.settings.disableWatcher = !!library.disableWatcher
|
|
||||||
}
|
|
||||||
|
|
||||||
this.lastScan = library.lastScan
|
|
||||||
this.lastScanVersion = library.lastScanVersion
|
|
||||||
this.lastScanMetadataPrecedence = library.lastScanMetadataPrecedence
|
|
||||||
|
|
||||||
this.createdAt = library.createdAt
|
|
||||||
this.lastUpdate = library.lastUpdate
|
|
||||||
this.cleanOldValues() // mediaType changed for v2 and icon change for v2.2.2
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanOldValues() {
|
|
||||||
const availableIcons = ['database', 'audiobookshelf', 'books-1', 'books-2', 'book-1', 'microphone-1', 'microphone-3', 'radio', 'podcast', 'rss', 'headphones', 'music', 'file-picture', 'rocket', 'power', 'star', 'heart']
|
|
||||||
if (!availableIcons.includes(this.icon)) {
|
|
||||||
if (this.icon === 'audiobook') this.icon = 'audiobookshelf'
|
|
||||||
else if (this.icon === 'book') this.icon = 'books-1'
|
|
||||||
else if (this.icon === 'comic') this.icon = 'file-picture'
|
|
||||||
else this.icon = 'database'
|
|
||||||
}
|
|
||||||
|
|
||||||
const mediaTypes = ['podcast', 'book', 'video', 'music']
|
|
||||||
if (!this.mediaType || !mediaTypes.includes(this.mediaType)) {
|
|
||||||
this.mediaType = 'book'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON() {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
oldLibraryId: this.oldLibraryId,
|
|
||||||
name: this.name,
|
|
||||||
folders: (this.folders || []).map((f) => f.toJSON()),
|
|
||||||
displayOrder: this.displayOrder,
|
|
||||||
icon: this.icon,
|
|
||||||
mediaType: this.mediaType,
|
|
||||||
provider: this.provider,
|
|
||||||
settings: this.settings.toJSON(),
|
|
||||||
lastScan: this.lastScan,
|
|
||||||
lastScanVersion: this.lastScanVersion,
|
|
||||||
createdAt: this.createdAt,
|
|
||||||
lastUpdate: this.lastUpdate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module.exports = Library
|
|
@ -1,73 +0,0 @@
|
|||||||
const { BookCoverAspectRatio } = require('../../utils/constants')
|
|
||||||
|
|
||||||
class LibrarySettings {
|
|
||||||
constructor(settings) {
|
|
||||||
this.coverAspectRatio = BookCoverAspectRatio.SQUARE
|
|
||||||
this.disableWatcher = false
|
|
||||||
this.skipMatchingMediaWithAsin = false
|
|
||||||
this.skipMatchingMediaWithIsbn = false
|
|
||||||
this.autoScanCronExpression = null
|
|
||||||
this.audiobooksOnly = false
|
|
||||||
this.epubsAllowScriptedContent = false
|
|
||||||
this.hideSingleBookSeries = false // Do not show series that only have 1 book
|
|
||||||
this.onlyShowLaterBooksInContinueSeries = false // Skip showing books that are earlier than the max sequence read
|
|
||||||
this.metadataPrecedence = ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata']
|
|
||||||
this.podcastSearchRegion = 'us'
|
|
||||||
|
|
||||||
if (settings) {
|
|
||||||
this.construct(settings)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
construct(settings) {
|
|
||||||
this.coverAspectRatio = !isNaN(settings.coverAspectRatio) ? settings.coverAspectRatio : BookCoverAspectRatio.SQUARE
|
|
||||||
this.disableWatcher = !!settings.disableWatcher
|
|
||||||
this.skipMatchingMediaWithAsin = !!settings.skipMatchingMediaWithAsin
|
|
||||||
this.skipMatchingMediaWithIsbn = !!settings.skipMatchingMediaWithIsbn
|
|
||||||
this.autoScanCronExpression = settings.autoScanCronExpression || null
|
|
||||||
this.audiobooksOnly = !!settings.audiobooksOnly
|
|
||||||
this.epubsAllowScriptedContent = !!settings.epubsAllowScriptedContent
|
|
||||||
this.hideSingleBookSeries = !!settings.hideSingleBookSeries
|
|
||||||
this.onlyShowLaterBooksInContinueSeries = !!settings.onlyShowLaterBooksInContinueSeries
|
|
||||||
if (settings.metadataPrecedence) {
|
|
||||||
this.metadataPrecedence = [...settings.metadataPrecedence]
|
|
||||||
} else {
|
|
||||||
// Added in v2.4.5
|
|
||||||
this.metadataPrecedence = ['folderStructure', 'audioMetatags', 'nfoFile', 'txtFiles', 'opfFile', 'absMetadata']
|
|
||||||
}
|
|
||||||
this.podcastSearchRegion = settings.podcastSearchRegion || 'us'
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON() {
|
|
||||||
return {
|
|
||||||
coverAspectRatio: this.coverAspectRatio,
|
|
||||||
disableWatcher: this.disableWatcher,
|
|
||||||
skipMatchingMediaWithAsin: this.skipMatchingMediaWithAsin,
|
|
||||||
skipMatchingMediaWithIsbn: this.skipMatchingMediaWithIsbn,
|
|
||||||
autoScanCronExpression: this.autoScanCronExpression,
|
|
||||||
audiobooksOnly: this.audiobooksOnly,
|
|
||||||
epubsAllowScriptedContent: this.epubsAllowScriptedContent,
|
|
||||||
hideSingleBookSeries: this.hideSingleBookSeries,
|
|
||||||
onlyShowLaterBooksInContinueSeries: this.onlyShowLaterBooksInContinueSeries,
|
|
||||||
metadataPrecedence: [...this.metadataPrecedence],
|
|
||||||
podcastSearchRegion: this.podcastSearchRegion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update(payload) {
|
|
||||||
let hasUpdates = false
|
|
||||||
for (const key in payload) {
|
|
||||||
if (key === 'metadataPrecedence') {
|
|
||||||
if (payload[key] && Array.isArray(payload[key]) && payload[key].join() !== this[key].join()) {
|
|
||||||
this[key] = payload[key]
|
|
||||||
hasUpdates = true
|
|
||||||
}
|
|
||||||
} else if (this[key] !== payload[key]) {
|
|
||||||
this[key] = payload[key]
|
|
||||||
hasUpdates = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hasUpdates
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module.exports = LibrarySettings
|
|
@ -1,10 +1,9 @@
|
|||||||
const Path = require('path')
|
const Path = require('path')
|
||||||
const uuidv4 = require("uuid").v4
|
const uuidv4 = require('uuid').v4
|
||||||
const fs = require('../libs/fsExtra')
|
const fs = require('../libs/fsExtra')
|
||||||
const date = require('../libs/dateAndTime')
|
const date = require('../libs/dateAndTime')
|
||||||
|
|
||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
const Library = require('../objects/Library')
|
|
||||||
const { LogLevel } = require('../utils/constants')
|
const { LogLevel } = require('../utils/constants')
|
||||||
const { secondsToTimestamp, elapsedPretty } = require('../utils/index')
|
const { secondsToTimestamp, elapsedPretty } = require('../utils/index')
|
||||||
|
|
||||||
@ -12,7 +11,7 @@ class LibraryScan {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.id = null
|
this.id = null
|
||||||
this.type = null
|
this.type = null
|
||||||
/** @type {import('../objects/Library')} */
|
/** @type {import('../models/Library')} */
|
||||||
this.library = null
|
this.library = null
|
||||||
this.verbose = false
|
this.verbose = false
|
||||||
|
|
||||||
@ -33,13 +32,21 @@ class LibraryScan {
|
|||||||
this.logs = []
|
this.logs = []
|
||||||
}
|
}
|
||||||
|
|
||||||
get libraryId() { return this.library.id }
|
get libraryId() {
|
||||||
get libraryName() { return this.library.name }
|
return this.library.id
|
||||||
get libraryMediaType() { return this.library.mediaType }
|
}
|
||||||
get folders() { return this.library.folders }
|
get libraryName() {
|
||||||
|
return this.library.name
|
||||||
|
}
|
||||||
|
get libraryMediaType() {
|
||||||
|
return this.library.mediaType
|
||||||
|
}
|
||||||
|
get libraryFolders() {
|
||||||
|
return this.library.libraryFolders
|
||||||
|
}
|
||||||
|
|
||||||
get timestamp() {
|
get timestamp() {
|
||||||
return (new Date()).toISOString()
|
return new Date().toISOString()
|
||||||
}
|
}
|
||||||
|
|
||||||
get resultStats() {
|
get resultStats() {
|
||||||
@ -92,10 +99,15 @@ class LibraryScan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {import('../models/Library')} library
|
||||||
|
* @param {string} type
|
||||||
|
*/
|
||||||
setData(library, type = 'scan') {
|
setData(library, type = 'scan') {
|
||||||
this.id = uuidv4()
|
this.id = uuidv4()
|
||||||
this.type = type
|
this.type = type
|
||||||
this.library = new Library(library.toJSON()) // clone library
|
this.library = library
|
||||||
|
|
||||||
this.startedAt = Date.now()
|
this.startedAt = Date.now()
|
||||||
}
|
}
|
||||||
@ -142,7 +154,7 @@ class LibraryScan {
|
|||||||
|
|
||||||
const outputPath = Path.join(scanLogDir, this.logFilename)
|
const outputPath = Path.join(scanLogDir, this.logFilename)
|
||||||
const logLines = [JSON.stringify(this.toJSON())]
|
const logLines = [JSON.stringify(this.toJSON())]
|
||||||
this.logs.forEach(l => {
|
this.logs.forEach((l) => {
|
||||||
logLines.push(JSON.stringify(l))
|
logLines.push(JSON.stringify(l))
|
||||||
})
|
})
|
||||||
await fs.writeFile(outputPath, logLines.join('\n') + '\n')
|
await fs.writeFile(outputPath, logLines.join('\n') + '\n')
|
||||||
|
@ -45,7 +45,7 @@ class LibraryScanner {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {import('../objects/Library')} library
|
* @param {import('../models/Library')} library
|
||||||
* @param {boolean} [forceRescan]
|
* @param {boolean} [forceRescan]
|
||||||
*/
|
*/
|
||||||
async scan(library, forceRescan = false) {
|
async scan(library, forceRescan = false) {
|
||||||
@ -54,12 +54,12 @@ class LibraryScanner {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!library.folders.length) {
|
if (!library.libraryFolders.length) {
|
||||||
Logger.warn(`[LibraryScanner] Library has no folders to scan "${library.name}"`)
|
Logger.warn(`[LibraryScanner] Library has no folders to scan "${library.name}"`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (library.isBook && library.settings.metadataPrecedence.join() !== library.lastScanMetadataPrecedence?.join()) {
|
if (library.isBook && library.settings.metadataPrecedence.join() !== library.lastScanMetadataPrecedence.join()) {
|
||||||
const lastScanMetadataPrecedence = library.lastScanMetadataPrecedence?.join() || 'Unset'
|
const lastScanMetadataPrecedence = library.lastScanMetadataPrecedence?.join() || 'Unset'
|
||||||
Logger.info(`[LibraryScanner] Library metadata precedence changed since last scan. From [${lastScanMetadataPrecedence}] to [${library.settings.metadataPrecedence.join()}]`)
|
Logger.info(`[LibraryScanner] Library metadata precedence changed since last scan. From [${lastScanMetadataPrecedence}] to [${library.settings.metadataPrecedence.join()}]`)
|
||||||
forceRescan = true
|
forceRescan = true
|
||||||
@ -103,9 +103,12 @@ class LibraryScanner {
|
|||||||
library.lastScan = Date.now()
|
library.lastScan = Date.now()
|
||||||
library.lastScanVersion = packageJson.version
|
library.lastScanVersion = packageJson.version
|
||||||
if (library.isBook) {
|
if (library.isBook) {
|
||||||
library.lastScanMetadataPrecedence = library.settings.metadataPrecedence
|
const newExtraData = library.extraData || {}
|
||||||
|
newExtraData.lastScanMetadataPrecedence = library.settings.metadataPrecedence
|
||||||
|
library.extraData = newExtraData
|
||||||
|
library.changed('extraData', true)
|
||||||
}
|
}
|
||||||
await Database.libraryModel.updateFromOld(library)
|
await library.save()
|
||||||
|
|
||||||
task.setFinished(libraryScan.scanResultsString)
|
task.setFinished(libraryScan.scanResultsString)
|
||||||
TaskManager.taskFinished(task)
|
TaskManager.taskFinished(task)
|
||||||
@ -124,16 +127,16 @@ class LibraryScanner {
|
|||||||
async scanLibrary(libraryScan, forceRescan) {
|
async scanLibrary(libraryScan, forceRescan) {
|
||||||
// Make sure library filter data is set
|
// Make sure library filter data is set
|
||||||
// this is used to check for existing authors & series
|
// this is used to check for existing authors & series
|
||||||
await libraryFilters.getFilterData(libraryScan.library.mediaType, libraryScan.libraryId)
|
await libraryFilters.getFilterData(libraryScan.libraryMediaType, libraryScan.libraryId)
|
||||||
|
|
||||||
/** @type {LibraryItemScanData[]} */
|
/** @type {LibraryItemScanData[]} */
|
||||||
let libraryItemDataFound = []
|
let libraryItemDataFound = []
|
||||||
|
|
||||||
// Scan each library folder
|
// Scan each library folder
|
||||||
for (let i = 0; i < libraryScan.folders.length; i++) {
|
for (let i = 0; i < libraryScan.libraryFolders.length; i++) {
|
||||||
const folder = libraryScan.folders[i]
|
const folder = libraryScan.libraryFolders[i]
|
||||||
const itemDataFoundInFolder = await this.scanFolder(libraryScan.library, folder)
|
const itemDataFoundInFolder = await this.scanFolder(libraryScan.library, folder)
|
||||||
libraryScan.addLog(LogLevel.INFO, `${itemDataFoundInFolder.length} item data found in folder "${folder.fullPath}"`)
|
libraryScan.addLog(LogLevel.INFO, `${itemDataFoundInFolder.length} item data found in folder "${folder.path}"`)
|
||||||
libraryItemDataFound = libraryItemDataFound.concat(itemDataFoundInFolder)
|
libraryItemDataFound = libraryItemDataFound.concat(itemDataFoundInFolder)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,12 +286,12 @@ class LibraryScanner {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get scan data for library folder
|
* Get scan data for library folder
|
||||||
* @param {import('../objects/Library')} library
|
* @param {import('../models/Library')} library
|
||||||
* @param {import('../objects/Folder')} folder
|
* @param {import('../models/LibraryFolder')} folder
|
||||||
* @returns {LibraryItemScanData[]}
|
* @returns {LibraryItemScanData[]}
|
||||||
*/
|
*/
|
||||||
async scanFolder(library, folder) {
|
async scanFolder(library, folder) {
|
||||||
const folderPath = fileUtils.filePathToPOSIX(folder.fullPath)
|
const folderPath = fileUtils.filePathToPOSIX(folder.path)
|
||||||
|
|
||||||
const pathExists = await fs.pathExists(folderPath)
|
const pathExists = await fs.pathExists(folderPath)
|
||||||
if (!pathExists) {
|
if (!pathExists) {
|
||||||
|
@ -25,7 +25,7 @@ class Scanner {
|
|||||||
|
|
||||||
// Set to override existing metadata if scannerPreferMatchedMetadata setting is true and
|
// Set to override existing metadata if scannerPreferMatchedMetadata setting is true and
|
||||||
// the overrideDefaults option is not set or set to false.
|
// the overrideDefaults option is not set or set to false.
|
||||||
if ((overrideDefaults == false) && (Database.serverSettings.scannerPreferMatchedMetadata)) {
|
if (overrideDefaults == false && Database.serverSettings.scannerPreferMatchedMetadata) {
|
||||||
options.overrideCover = true
|
options.overrideCover = true
|
||||||
options.overrideDetails = true
|
options.overrideDetails = true
|
||||||
}
|
}
|
||||||
@ -57,7 +57,8 @@ class Scanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updatePayload = await this.quickMatchBookBuildUpdatePayload(libraryItem, matchData, options)
|
updatePayload = await this.quickMatchBookBuildUpdatePayload(libraryItem, matchData, options)
|
||||||
} else if (libraryItem.isPodcast) { // Podcast quick match
|
} else if (libraryItem.isPodcast) {
|
||||||
|
// Podcast quick match
|
||||||
var results = await PodcastFinder.search(searchTitle)
|
var results = await PodcastFinder.search(searchTitle)
|
||||||
if (!results.length) {
|
if (!results.length) {
|
||||||
return {
|
return {
|
||||||
@ -88,7 +89,8 @@ class Scanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hasUpdated) {
|
if (hasUpdated) {
|
||||||
if (libraryItem.isPodcast && libraryItem.media.metadata.feedUrl) { // Quick match all unmatched podcast episodes
|
if (libraryItem.isPodcast && libraryItem.media.metadata.feedUrl) {
|
||||||
|
// Quick match all unmatched podcast episodes
|
||||||
await this.quickMatchPodcastEpisodes(libraryItem, options)
|
await this.quickMatchPodcastEpisodes(libraryItem, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,12 +124,16 @@ class Scanner {
|
|||||||
for (const key in matchDataTransformed) {
|
for (const key in matchDataTransformed) {
|
||||||
if (matchDataTransformed[key]) {
|
if (matchDataTransformed[key]) {
|
||||||
if (key === 'genres') {
|
if (key === 'genres') {
|
||||||
if ((!libraryItem.media.metadata.genres.length || options.overrideDetails)) {
|
if (!libraryItem.media.metadata.genres.length || options.overrideDetails) {
|
||||||
var genresArray = []
|
var genresArray = []
|
||||||
if (Array.isArray(matchDataTransformed[key])) genresArray = [...matchDataTransformed[key]]
|
if (Array.isArray(matchDataTransformed[key])) genresArray = [...matchDataTransformed[key]]
|
||||||
else { // Genres should always be passed in as an array but just incase handle a string
|
else {
|
||||||
|
// Genres should always be passed in as an array but just incase handle a string
|
||||||
Logger.warn(`[Scanner] quickMatch genres is not an array ${matchDataTransformed[key]}`)
|
Logger.warn(`[Scanner] quickMatch genres is not an array ${matchDataTransformed[key]}`)
|
||||||
genresArray = matchDataTransformed[key].split(',').map(v => v.trim()).filter(v => !!v)
|
genresArray = matchDataTransformed[key]
|
||||||
|
.split(',')
|
||||||
|
.map((v) => v.trim())
|
||||||
|
.filter((v) => !!v)
|
||||||
}
|
}
|
||||||
updatePayload.metadata[key] = genresArray
|
updatePayload.metadata[key] = genresArray
|
||||||
}
|
}
|
||||||
@ -153,27 +159,38 @@ class Scanner {
|
|||||||
for (const key in matchData) {
|
for (const key in matchData) {
|
||||||
if (matchData[key] && detailKeysToUpdate.includes(key)) {
|
if (matchData[key] && detailKeysToUpdate.includes(key)) {
|
||||||
if (key === 'narrator') {
|
if (key === 'narrator') {
|
||||||
if ((!libraryItem.media.metadata.narratorName || options.overrideDetails)) {
|
if (!libraryItem.media.metadata.narratorName || options.overrideDetails) {
|
||||||
updatePayload.metadata.narrators = matchData[key].split(',').map(v => v.trim()).filter(v => !!v)
|
updatePayload.metadata.narrators = matchData[key]
|
||||||
|
.split(',')
|
||||||
|
.map((v) => v.trim())
|
||||||
|
.filter((v) => !!v)
|
||||||
}
|
}
|
||||||
} else if (key === 'genres') {
|
} else if (key === 'genres') {
|
||||||
if ((!libraryItem.media.metadata.genres.length || options.overrideDetails)) {
|
if (!libraryItem.media.metadata.genres.length || options.overrideDetails) {
|
||||||
var genresArray = []
|
var genresArray = []
|
||||||
if (Array.isArray(matchData[key])) genresArray = [...matchData[key]]
|
if (Array.isArray(matchData[key])) genresArray = [...matchData[key]]
|
||||||
else { // Genres should always be passed in as an array but just incase handle a string
|
else {
|
||||||
|
// Genres should always be passed in as an array but just incase handle a string
|
||||||
Logger.warn(`[Scanner] quickMatch genres is not an array ${matchData[key]}`)
|
Logger.warn(`[Scanner] quickMatch genres is not an array ${matchData[key]}`)
|
||||||
genresArray = matchData[key].split(',').map(v => v.trim()).filter(v => !!v)
|
genresArray = matchData[key]
|
||||||
|
.split(',')
|
||||||
|
.map((v) => v.trim())
|
||||||
|
.filter((v) => !!v)
|
||||||
}
|
}
|
||||||
updatePayload.metadata[key] = genresArray
|
updatePayload.metadata[key] = genresArray
|
||||||
}
|
}
|
||||||
} else if (key === 'tags') {
|
} else if (key === 'tags') {
|
||||||
if ((!libraryItem.media.tags.length || options.overrideDetails)) {
|
if (!libraryItem.media.tags.length || options.overrideDetails) {
|
||||||
var tagsArray = []
|
var tagsArray = []
|
||||||
if (Array.isArray(matchData[key])) tagsArray = [...matchData[key]]
|
if (Array.isArray(matchData[key])) tagsArray = [...matchData[key]]
|
||||||
else tagsArray = matchData[key].split(',').map(v => v.trim()).filter(v => !!v)
|
else
|
||||||
|
tagsArray = matchData[key]
|
||||||
|
.split(',')
|
||||||
|
.map((v) => v.trim())
|
||||||
|
.filter((v) => !!v)
|
||||||
updatePayload[key] = tagsArray
|
updatePayload[key] = tagsArray
|
||||||
}
|
}
|
||||||
} else if ((!libraryItem.media.metadata[key] || options.overrideDetails)) {
|
} else if (!libraryItem.media.metadata[key] || options.overrideDetails) {
|
||||||
updatePayload.metadata[key] = matchData[key]
|
updatePayload.metadata[key] = matchData[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -182,7 +199,10 @@ class Scanner {
|
|||||||
// Add or set author if not set
|
// Add or set author if not set
|
||||||
if (matchData.author && (!libraryItem.media.metadata.authorName || options.overrideDetails)) {
|
if (matchData.author && (!libraryItem.media.metadata.authorName || options.overrideDetails)) {
|
||||||
if (!Array.isArray(matchData.author)) {
|
if (!Array.isArray(matchData.author)) {
|
||||||
matchData.author = matchData.author.split(',').map(au => au.trim()).filter(au => !!au)
|
matchData.author = matchData.author
|
||||||
|
.split(',')
|
||||||
|
.map((au) => au.trim())
|
||||||
|
.filter((au) => !!au)
|
||||||
}
|
}
|
||||||
const authorPayload = []
|
const authorPayload = []
|
||||||
for (const authorName of matchData.author) {
|
for (const authorName of matchData.author) {
|
||||||
@ -227,7 +247,7 @@ class Scanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async quickMatchPodcastEpisodes(libraryItem, options = {}) {
|
async quickMatchPodcastEpisodes(libraryItem, options = {}) {
|
||||||
const episodesToQuickMatch = libraryItem.media.episodes.filter(ep => !ep.enclosureUrl) // Only quick match episodes without enclosure
|
const episodesToQuickMatch = libraryItem.media.episodes.filter((ep) => !ep.enclosureUrl) // Only quick match episodes without enclosure
|
||||||
if (!episodesToQuickMatch.length) return false
|
if (!episodesToQuickMatch.length) return false
|
||||||
|
|
||||||
const feed = await getPodcastFeed(libraryItem.media.metadata.feedUrl)
|
const feed = await getPodcastFeed(libraryItem.media.metadata.feedUrl)
|
||||||
@ -284,7 +304,7 @@ class Scanner {
|
|||||||
/**
|
/**
|
||||||
* Quick match library items
|
* Quick match library items
|
||||||
*
|
*
|
||||||
* @param {import('../objects/Library')} library
|
* @param {import('../models/Library')} library
|
||||||
* @param {import('../objects/LibraryItem')[]} libraryItems
|
* @param {import('../objects/LibraryItem')[]} libraryItems
|
||||||
* @param {LibraryScan} libraryScan
|
* @param {LibraryScan} libraryScan
|
||||||
* @returns {Promise<boolean>} false if scan canceled
|
* @returns {Promise<boolean>} false if scan canceled
|
||||||
@ -294,14 +314,12 @@ class Scanner {
|
|||||||
const libraryItem = libraryItems[i]
|
const libraryItem = libraryItems[i]
|
||||||
|
|
||||||
if (libraryItem.media.metadata.asin && library.settings.skipMatchingMediaWithAsin) {
|
if (libraryItem.media.metadata.asin && library.settings.skipMatchingMediaWithAsin) {
|
||||||
Logger.debug(`[Scanner] matchLibraryItems: Skipping "${libraryItem.media.metadata.title
|
Logger.debug(`[Scanner] matchLibraryItems: Skipping "${libraryItem.media.metadata.title}" because it already has an ASIN (${i + 1} of ${libraryItems.length})`)
|
||||||
}" because it already has an ASIN (${i + 1} of ${libraryItems.length})`)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if (libraryItem.media.metadata.isbn && library.settings.skipMatchingMediaWithIsbn) {
|
if (libraryItem.media.metadata.isbn && library.settings.skipMatchingMediaWithIsbn) {
|
||||||
Logger.debug(`[Scanner] matchLibraryItems: Skipping "${libraryItem.media.metadata.title
|
Logger.debug(`[Scanner] matchLibraryItems: Skipping "${libraryItem.media.metadata.title}" because it already has an ISBN (${i + 1} of ${libraryItems.length})`)
|
||||||
}" because it already has an ISBN (${i + 1} of ${libraryItems.length})`)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +343,7 @@ class Scanner {
|
|||||||
/**
|
/**
|
||||||
* Quick match all library items for library
|
* Quick match all library items for library
|
||||||
*
|
*
|
||||||
* @param {import('../objects/Library')} library
|
* @param {import('../models/Library')} library
|
||||||
*/
|
*/
|
||||||
async matchLibraryItems(library) {
|
async matchLibraryItems(library) {
|
||||||
if (library.mediaType === 'podcast') {
|
if (library.mediaType === 'podcast') {
|
||||||
@ -360,7 +378,7 @@ class Scanner {
|
|||||||
|
|
||||||
offset += limit
|
offset += limit
|
||||||
hasMoreChunks = libraryItems.length === limit
|
hasMoreChunks = libraryItems.length === limit
|
||||||
let oldLibraryItems = libraryItems.map(li => Database.libraryItemModel.getOldLibraryItem(li))
|
let oldLibraryItems = libraryItems.map((li) => Database.libraryItemModel.getOldLibraryItem(li))
|
||||||
|
|
||||||
const shouldContinue = await this.matchLibraryItemsChunk(library, oldLibraryItems, libraryScan)
|
const shouldContinue = await this.matchLibraryItemsChunk(library, oldLibraryItems, libraryScan)
|
||||||
if (!shouldContinue) {
|
if (!shouldContinue) {
|
||||||
@ -379,7 +397,7 @@ class Scanner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete LibraryScanner.cancelLibraryScan[libraryScan.libraryId]
|
delete LibraryScanner.cancelLibraryScan[libraryScan.libraryId]
|
||||||
LibraryScanner.librariesScanning = LibraryScanner.librariesScanning.filter(ls => ls.id !== library.id)
|
LibraryScanner.librariesScanning = LibraryScanner.librariesScanning.filter((ls) => ls.id !== library.id)
|
||||||
TaskManager.taskFinished(task)
|
TaskManager.taskFinished(task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1258,7 +1258,7 @@ async function handleOldLibraryItems(ctx) {
|
|||||||
*/
|
*/
|
||||||
async function handleOldLibraries(ctx) {
|
async function handleOldLibraries(ctx) {
|
||||||
const oldLibraries = await oldDbFiles.loadOldData('libraries')
|
const oldLibraries = await oldDbFiles.loadOldData('libraries')
|
||||||
const libraries = await ctx.models.library.getAllOldLibraries()
|
const libraries = await ctx.models.library.getAllWithFolders()
|
||||||
|
|
||||||
let librariesUpdated = 0
|
let librariesUpdated = 0
|
||||||
for (const library of libraries) {
|
for (const library of libraries) {
|
||||||
@ -1268,13 +1268,17 @@ async function handleOldLibraries(ctx) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const folderPaths = ol.folders?.map((f) => f.fullPath) || []
|
const folderPaths = ol.folders?.map((f) => f.fullPath) || []
|
||||||
return folderPaths.join(',') === library.folders.map((f) => f.fullPath).join(',')
|
return folderPaths.join(',') === library.libraryFolders.map((f) => f.path).join(',')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (matchingOldLibrary) {
|
if (matchingOldLibrary) {
|
||||||
library.oldLibraryId = matchingOldLibrary.id
|
const newExtraData = library.extraData || {}
|
||||||
|
newExtraData.oldLibraryId = matchingOldLibrary.id
|
||||||
|
library.extraData = newExtraData
|
||||||
|
library.changed('extraData', true)
|
||||||
|
|
||||||
oldDbIdMap.libraries[library.oldLibraryId] = library.id
|
oldDbIdMap.libraries[library.oldLibraryId] = library.id
|
||||||
await ctx.models.library.updateFromOld(library)
|
await library.save()
|
||||||
librariesUpdated++
|
librariesUpdated++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user