mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2024-12-25 16:18:54 +01:00
Add startup function to remove invalid records from DB
This commit is contained in:
parent
a44ee913c4
commit
10011bd6a3
@ -156,6 +156,7 @@ class Database {
|
|||||||
await this.buildModels(force)
|
await this.buildModels(force)
|
||||||
Logger.info(`[Database] Db initialized with models:`, Object.keys(this.sequelize.models).join(', '))
|
Logger.info(`[Database] Db initialized with models:`, Object.keys(this.sequelize.models).join(', '))
|
||||||
|
|
||||||
|
await this.cleanDatabase()
|
||||||
await this.loadData()
|
await this.loadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,27 +381,6 @@ class Database {
|
|||||||
return this.models.libraryItem.fullUpdateFromOld(oldLibraryItem)
|
return this.models.libraryItem.fullUpdateFromOld(oldLibraryItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateBulkLibraryItems(oldLibraryItems) {
|
|
||||||
if (!this.sequelize) return false
|
|
||||||
let updatesMade = 0
|
|
||||||
for (const oldLibraryItem of oldLibraryItems) {
|
|
||||||
await oldLibraryItem.saveMetadata()
|
|
||||||
const hasUpdates = await this.models.libraryItem.fullUpdateFromOld(oldLibraryItem)
|
|
||||||
if (hasUpdates) {
|
|
||||||
updatesMade++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return updatesMade
|
|
||||||
}
|
|
||||||
|
|
||||||
async createBulkLibraryItems(oldLibraryItems) {
|
|
||||||
if (!this.sequelize) return false
|
|
||||||
for (const oldLibraryItem of oldLibraryItems) {
|
|
||||||
await oldLibraryItem.saveMetadata()
|
|
||||||
await this.models.libraryItem.fullCreateFromOld(oldLibraryItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async removeLibraryItem(libraryItemId) {
|
async removeLibraryItem(libraryItemId) {
|
||||||
if (!this.sequelize) return false
|
if (!this.sequelize) return false
|
||||||
await this.models.libraryItem.removeById(libraryItemId)
|
await this.models.libraryItem.removeById(libraryItemId)
|
||||||
@ -675,6 +655,40 @@ class Database {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean invalid records in database
|
||||||
|
* Series should have atleast one Book
|
||||||
|
* Book and Podcast must have an associated LibraryItem
|
||||||
|
*/
|
||||||
|
async cleanDatabase() {
|
||||||
|
// Remove invalid Podcast records
|
||||||
|
const podcastsWithNoLibraryItem = await this.podcastModel.findAll({
|
||||||
|
where: Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM libraryItems li WHERE li.mediaId = podcast.id)`), 0)
|
||||||
|
})
|
||||||
|
for (const podcast of podcastsWithNoLibraryItem) {
|
||||||
|
Logger.warn(`Found podcast "${podcast.title}" with no libraryItem - removing it`)
|
||||||
|
await podcast.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove invalid Book records
|
||||||
|
const booksWithNoLibraryItem = await this.bookModel.findAll({
|
||||||
|
where: Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM libraryItems li WHERE li.mediaId = book.id)`), 0)
|
||||||
|
})
|
||||||
|
for (const book of booksWithNoLibraryItem) {
|
||||||
|
Logger.warn(`Found book "${book.title}" with no libraryItem - removing it`)
|
||||||
|
await book.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove empty series
|
||||||
|
const emptySeries = await this.seriesModel.findAll({
|
||||||
|
where: Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM bookSeries bs WHERE bs.seriesId = series.id)`), 0)
|
||||||
|
})
|
||||||
|
for (const series of emptySeries) {
|
||||||
|
Logger.warn(`Found series "${series.name}" with no books - removing it`)
|
||||||
|
await series.destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = new Database()
|
module.exports = new Database()
|
@ -50,10 +50,14 @@ class BookSeries extends Model {
|
|||||||
book.belongsToMany(series, { through: BookSeries })
|
book.belongsToMany(series, { through: BookSeries })
|
||||||
series.belongsToMany(book, { through: BookSeries })
|
series.belongsToMany(book, { through: BookSeries })
|
||||||
|
|
||||||
book.hasMany(BookSeries)
|
book.hasMany(BookSeries, {
|
||||||
|
onDelete: 'CASCADE'
|
||||||
|
})
|
||||||
BookSeries.belongsTo(book)
|
BookSeries.belongsTo(book)
|
||||||
|
|
||||||
series.hasMany(BookSeries)
|
series.hasMany(BookSeries, {
|
||||||
|
onDelete: 'CASCADE'
|
||||||
|
})
|
||||||
BookSeries.belongsTo(series)
|
BookSeries.belongsTo(series)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,53 +63,6 @@ class LibraryItem extends Model {
|
|||||||
this.updatedAt
|
this.updatedAt
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads all podcast episodes, all library items in chunks of 500, then maps them to old library items
|
|
||||||
* @todo this is a temporary solution until we can use the sqlite without loading all the library items on init
|
|
||||||
*
|
|
||||||
* @returns {Promise<objects.LibraryItem[]>} old library items
|
|
||||||
*/
|
|
||||||
static async loadAllLibraryItems() {
|
|
||||||
let start = Date.now()
|
|
||||||
Logger.info(`[LibraryItem] Loading podcast episodes...`)
|
|
||||||
const podcastEpisodes = await this.sequelize.models.podcastEpisode.findAll()
|
|
||||||
Logger.info(`[LibraryItem] Finished loading ${podcastEpisodes.length} podcast episodes in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
|
||||||
|
|
||||||
start = Date.now()
|
|
||||||
Logger.info(`[LibraryItem] Loading library items...`)
|
|
||||||
let libraryItems = await this.getAllOldLibraryItemsIncremental()
|
|
||||||
Logger.info(`[LibraryItem] Finished loading ${libraryItems.length} library items in ${((Date.now() - start) / 1000).toFixed(2)}s`)
|
|
||||||
|
|
||||||
// Map LibraryItem to old library item
|
|
||||||
libraryItems = libraryItems.map(li => {
|
|
||||||
if (li.mediaType === 'podcast') {
|
|
||||||
li.media.podcastEpisodes = podcastEpisodes.filter(pe => pe.podcastId === li.media.id)
|
|
||||||
}
|
|
||||||
return this.getOldLibraryItem(li)
|
|
||||||
})
|
|
||||||
|
|
||||||
return libraryItems
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads all LibraryItem in batches of 500
|
|
||||||
* @todo temporary solution
|
|
||||||
*
|
|
||||||
* @param {Model<LibraryItem>[]} libraryItems
|
|
||||||
* @param {number} offset
|
|
||||||
* @returns {Promise<Model<LibraryItem>[]>}
|
|
||||||
*/
|
|
||||||
static async getAllOldLibraryItemsIncremental(libraryItems = [], offset = 0) {
|
|
||||||
const limit = 500
|
|
||||||
const rows = await this.getLibraryItemsIncrement(offset, limit)
|
|
||||||
libraryItems.push(...rows)
|
|
||||||
if (!rows.length || rows.length < limit) {
|
|
||||||
return libraryItems
|
|
||||||
}
|
|
||||||
Logger.info(`[LibraryItem] Loaded ${rows.length} library items. ${libraryItems.length} loaded so far.`)
|
|
||||||
return this.getAllOldLibraryItemsIncremental(libraryItems, offset + rows.length)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets library items partially expanded, not including podcast episodes
|
* Gets library items partially expanded, not including podcast episodes
|
||||||
* @todo temporary solution
|
* @todo temporary solution
|
||||||
@ -120,10 +73,6 @@ class LibraryItem extends Model {
|
|||||||
*/
|
*/
|
||||||
static getLibraryItemsIncrement(offset, limit, where = null) {
|
static getLibraryItemsIncrement(offset, limit, where = null) {
|
||||||
return this.findAll({
|
return this.findAll({
|
||||||
benchmark: true,
|
|
||||||
logging: (sql, timeMs) => {
|
|
||||||
console.log(`[Query] Elapsed ${timeMs}ms.`)
|
|
||||||
},
|
|
||||||
where,
|
where,
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
|
@ -547,10 +547,6 @@ module.exports = {
|
|||||||
distinct: true,
|
distinct: true,
|
||||||
attributes: bookAttributes,
|
attributes: bookAttributes,
|
||||||
replacements,
|
replacements,
|
||||||
benchmark: true,
|
|
||||||
logging: (sql, timeMs) => {
|
|
||||||
console.log(`[Query] Elapsed ${timeMs}ms`)
|
|
||||||
},
|
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
model: Database.libraryItemModel,
|
model: Database.libraryItemModel,
|
||||||
|
@ -141,10 +141,6 @@ module.exports = {
|
|||||||
offset,
|
offset,
|
||||||
distinct: true,
|
distinct: true,
|
||||||
subQuery: false,
|
subQuery: false,
|
||||||
benchmark: true,
|
|
||||||
logging: (sql, timeMs) => {
|
|
||||||
console.log(`[Query] Series filter/sort. Elapsed ${timeMs}ms`)
|
|
||||||
},
|
|
||||||
attributes: seriesAttributes,
|
attributes: seriesAttributes,
|
||||||
replacements: userPermissionBookWhere.replacements,
|
replacements: userPermissionBookWhere.replacements,
|
||||||
include: [
|
include: [
|
||||||
|
Loading…
Reference in New Issue
Block a user