Update filterData for authors/series when added/removed

This commit is contained in:
advplyr 2023-08-18 14:40:36 -05:00
parent 7222171c5b
commit 9d7d4c6902
12 changed files with 152 additions and 13 deletions

View File

@ -343,6 +343,10 @@ export default {
}
this.$store.commit('libraries/removeCollection', collection)
},
seriesRemoved({ id, libraryId }) {
if (this.currentLibraryId !== libraryId) return
this.$store.commit('libraries/removeSeriesFromFilterData', id)
},
playlistAdded(playlist) {
if (playlist.userId !== this.user.id || this.currentLibraryId !== playlist.libraryId) return
this.$store.commit('libraries/addUpdateUserPlaylist', playlist)
@ -442,6 +446,9 @@ export default {
this.socket.on('collection_updated', this.collectionUpdated)
this.socket.on('collection_removed', this.collectionRemoved)
// Series Listeners
this.socket.on('series_removed', this.seriesRemoved)
// User Playlist Listeners
this.socket.on('playlist_added', this.playlistAdded)
this.socket.on('playlist_updated', this.playlistUpdated)

View File

@ -234,6 +234,10 @@ export const mutations = {
setNumUserPlaylists(state, numUserPlaylists) {
state.numUserPlaylists = numUserPlaylists
},
removeSeriesFromFilterData(state, seriesId) {
if (!seriesId || !state.filterData) return
state.filterData.series = state.filterData.series.filter(se => se.id !== seriesId)
},
updateFilterDataWithItem(state, libraryItem) {
if (!libraryItem || !state.filterData) return
if (state.currentLibraryId !== libraryItem.libraryId) return

View File

@ -34,6 +34,16 @@ class Database {
return this.sequelize?.models || {}
}
/** @type {typeof import('./models/Author')} */
get authorModel() {
return this.models.author
}
/** @type {typeof import('./models/Series')} */
get seriesModel() {
return this.models.series
}
async checkHasDb() {
if (!await fs.pathExists(this.dbPath)) {
Logger.info(`[Database] absdatabase.sqlite not found at ${this.dbPath}`)
@ -481,6 +491,66 @@ class Database {
}
}
}
removeSeriesFromFilterData(libraryId, seriesId) {
if (!this.libraryFilterData[libraryId]) return
this.libraryFilterData[libraryId].series = this.libraryFilterData[libraryId].series.filter(se => se.id !== seriesId)
}
addSeriesToFilterData(libraryId, seriesName, seriesId) {
if (!this.libraryFilterData[libraryId]) return
// Check if series is already added
if (this.libraryFilterData[libraryId].series.some(se => se.id === seriesId)) return
this.libraryFilterData[libraryId].series.push({
id: seriesId,
name: seriesName
})
}
removeAuthorFromFilterData(libraryId, authorId) {
if (!this.libraryFilterData[libraryId]) return
this.libraryFilterData[libraryId].authors = this.libraryFilterData[libraryId].authors.filter(au => au.id !== authorId)
}
addAuthorToFilterData(libraryId, authorName, authorId) {
if (!this.libraryFilterData[libraryId]) return
// Check if author is already added
if (this.libraryFilterData[libraryId].authors.some(au => au.id === authorId)) return
this.libraryFilterData[libraryId].authors.push({
id: authorId,
name: authorName
})
}
/**
* Used when updating items to make sure author id exists
* If library filter data is set then use that for check
* otherwise lookup in db
* @param {string} libraryId
* @param {string} authorId
* @returns {Promise<boolean>}
*/
async checkAuthorExists(libraryId, authorId) {
if (!this.libraryFilterData[libraryId]) {
return this.authorModel.checkExistsById(authorId)
}
return this.libraryFilterData[libraryId].authors.some(au => au.id === authorId)
}
/**
* Used when updating items to make sure series id exists
* If library filter data is set then use that for check
* otherwise lookup in db
* @param {string} libraryId
* @param {string} seriesId
* @returns {Promise<boolean>}
*/
async checkSeriesExists(libraryId, seriesId) {
if (!this.libraryFilterData[libraryId]) {
return this.seriesModel.checkExistsById(seriesId)
}
return this.libraryFilterData[libraryId].series.some(se => se.id === seriesId)
}
}
module.exports = new Database()

View File

@ -113,6 +113,8 @@ class AuthorController {
// Remove old author
await Database.removeAuthor(req.author.id)
SocketAuthority.emitter('author_removed', req.author.toJSON())
// Update filter data
Database.removeAuthorFromFilterData(req.author.libraryId, req.author.id)
// Send updated num books for merged author
const numBooks = await Database.models.libraryItem.getForAuthor(existingAuthor).length

View File

@ -859,12 +859,12 @@ class LibraryController {
/**
* GET: /api/libraries/:id/authors
* Get authors for library
* @param {*} req
* @param {*} res
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
async getAuthors(req, res) {
const { bookWhere, replacements } = libraryItemsBookFilters.getUserPermissionBookWhereQuery(req.user)
const authors = await Database.models.author.findAll({
const authors = await Database.authorModel.findAll({
where: {
libraryId: req.library.id
},

View File

@ -124,7 +124,7 @@ class LibraryItemController {
// Book specific - Get all series being removed from this item
let seriesRemoved = []
if (libraryItem.isBook && mediaPayload.metadata?.series) {
const seriesIdsInUpdate = (mediaPayload.metadata?.series || []).map(se => se.id)
const seriesIdsInUpdate = mediaPayload.metadata.series?.map(se => se.id) || []
seriesRemoved = libraryItem.media.metadata.series.filter(se => !seriesIdsInUpdate.includes(se.id))
}

View File

@ -83,6 +83,15 @@ class Author extends Model {
})
}
/**
* Check if author exists
* @param {string} authorId
* @returns {Promise<boolean>}
*/
static async checkExistsById(authorId) {
return (await this.count({ where: { id: authorId } })) > 0
}
/**
* Initialize model
* @param {import('../Database').sequelize} sequelize

View File

@ -75,6 +75,15 @@ class Series extends Model {
})
}
/**
* Check if series exists
* @param {string} seriesId
* @returns {Promise<boolean>}
*/
static async checkExistsById(seriesId) {
return (await this.count({ where: { id: seriesId } })) > 0
}
/**
* Initialize model
* @param {import('../Database').sequelize} sequelize

View File

@ -472,10 +472,20 @@ class ApiRouter {
}
}
/**
* Remove an empty series & close an open RSS feed
* @param {import('../models/Series')} series
*/
async removeEmptySeries(series) {
await this.rssFeedManager.closeFeedForEntityId(series.id)
Logger.info(`[ApiRouter] Series "${series.name}" is now empty. Removing series`)
await Database.removeSeries(series.id)
// Remove series from library filter data
Database.removeSeriesFromFilterData(series.libraryId, series.id)
SocketAuthority.emitter('series_removed', {
id: series.id,
libraryId: series.libraryId
})
}
async getUserListeningSessionsHelper(userId) {
@ -546,7 +556,7 @@ class ApiRouter {
const mediaMetadata = mediaPayload.metadata
// Create new authors if in payload
if (mediaMetadata.authors && mediaMetadata.authors.length) {
if (mediaMetadata.authors?.length) {
const newAuthors = []
for (let i = 0; i < mediaMetadata.authors.length; i++) {
const authorName = (mediaMetadata.authors[i].name || '').trim()
@ -555,6 +565,12 @@ class ApiRouter {
continue
}
// Ensure the ID for the author exists
if (mediaMetadata.authors[i].id && !(await Database.checkAuthorExists(libraryId, mediaMetadata.authors[i].id))) {
Logger.warn(`[ApiRouter] Author id "${mediaMetadata.authors[i].id}" does not exist`)
mediaMetadata.authors[i].id = null
}
if (!mediaMetadata.authors[i].id || mediaMetadata.authors[i].id.startsWith('new')) {
let author = Database.authors.find(au => au.libraryId === libraryId && au.checkNameEquals(authorName))
if (!author) {
@ -562,6 +578,8 @@ class ApiRouter {
author.setData(mediaMetadata.authors[i], libraryId)
Logger.debug(`[ApiRouter] Created new author "${author.name}"`)
newAuthors.push(author)
// Update filter data
Database.addAuthorToFilterData(libraryId, author.name, author.id)
}
// Update ID in original payload
@ -584,6 +602,12 @@ class ApiRouter {
continue
}
// Ensure the ID for the series exists
if (mediaMetadata.series[i].id && !(await Database.checkSeriesExists(libraryId, mediaMetadata.series[i].id))) {
Logger.warn(`[ApiRouter] Series id "${mediaMetadata.series[i].id}" does not exist`)
mediaMetadata.series[i].id = null
}
if (!mediaMetadata.series[i].id || mediaMetadata.series[i].id.startsWith('new')) {
let seriesItem = Database.series.find(se => se.libraryId === libraryId && se.checkNameEquals(seriesName))
if (!seriesItem) {
@ -591,6 +615,8 @@ class ApiRouter {
seriesItem.setData(mediaMetadata.series[i], libraryId)
Logger.debug(`[ApiRouter] Created new series "${seriesItem.name}"`)
newSeries.push(seriesItem)
// Update filter data
Database.addSeriesToFilterData(libraryId, seriesItem.name, seriesItem.id)
}
// Update ID in original payload

View File

@ -486,6 +486,8 @@ class Scanner {
_author = new Author()
_author.setData(tempMinAuthor, libraryItem.libraryId)
newAuthors.push(_author)
// Update filter data
Database.addAuthorToFilterData(libraryItem.libraryId, _author.name, _author.id)
}
return {
@ -502,11 +504,17 @@ class Scanner {
const newSeries = []
libraryItem.media.metadata.series = libraryItem.media.metadata.series.map((tempMinSeries) => {
let _series = Database.series.find(se => se.libraryId === libraryItem.libraryId && se.checkNameEquals(tempMinSeries.name))
if (!_series) _series = newSeries.find(se => se.libraryId === libraryItem.libraryId && se.checkNameEquals(tempMinSeries.name)) // Check new unsaved series
if (!_series) {
// Check new unsaved series
_series = newSeries.find(se => se.libraryId === libraryItem.libraryId && se.checkNameEquals(tempMinSeries.name))
}
if (!_series) { // Must create new series
_series = new Series()
_series.setData(tempMinSeries, libraryItem.libraryId)
newSeries.push(_series)
// Update filter data
Database.addSeriesToFilterData(libraryItem.libraryId, _series.name, _series.id)
}
return {
id: _series.id,
@ -924,6 +932,8 @@ class Scanner {
author.setData({ name: authorName }, libraryItem.libraryId)
await Database.createAuthor(author)
SocketAuthority.emitter('author_added', author.toJSON())
// Update filter data
Database.addAuthorToFilterData(libraryItem.libraryId, author.name, author.id)
}
authorPayload.push(author.toJSONMinimal())
}
@ -940,6 +950,8 @@ class Scanner {
seriesItem = new Series()
seriesItem.setData({ name: seriesMatchItem.series }, libraryItem.libraryId)
await Database.createSeries(seriesItem)
// Update filter data
Database.addSeriesToFilterData(libraryItem.libraryId, seriesItem.name, seriesItem.id)
SocketAuthority.emitter('series_added', seriesItem.toJSON())
}
seriesPayload.push(seriesItem.toJSONMinimal(seriesMatchItem.sequence))

View File

@ -221,7 +221,7 @@ module.exports = {
}))
}
const { rows: series, count } = await Database.models.series.findAndCountAll({
const { rows: series, count } = await Database.seriesModel.findAndCountAll({
where: seriesWhere,
limit,
offset: 0,
@ -291,7 +291,7 @@ module.exports = {
async getNewestAuthors(library, user, limit) {
if (library.mediaType !== 'book') return { authors: [], count: 0 }
const { rows: authors, count } = await Database.models.author.findAndCountAll({
const { rows: authors, count } = await Database.authorModel.findAndCountAll({
where: {
libraryId: library.id,
createdAt: {
@ -461,7 +461,7 @@ module.exports = {
if (book.language) data.languages.add(book.language)
}
const series = await Database.models.series.findAll({
const series = await Database.seriesModel.findAll({
where: {
libraryId: oldLibrary.id
},
@ -469,7 +469,7 @@ module.exports = {
})
series.forEach((s) => data.series.push({ id: s.id, name: s.name }))
const authors = await Database.models.author.findAll({
const authors = await Database.authorModel.findAll({
where: {
libraryId: oldLibrary.id
},

View File

@ -278,7 +278,7 @@ module.exports = {
* @returns {object} { booksToExclude, bookSeriesToInclude }
*/
async getCollapseSeriesBooksToExclude(bookFindOptions, seriesWhere) {
const allSeries = await Database.models.series.findAll({
const allSeries = await Database.seriesModel.findAll({
attributes: [
'id',
'name',
@ -642,7 +642,7 @@ module.exports = {
const userPermissionBookWhere = this.getUserPermissionBookWhereQuery(user)
bookWhere.push(...userPermissionBookWhere.bookWhere)
const { rows: series, count } = await Database.models.series.findAndCountAll({
const { rows: series, count } = await Database.seriesModel.findAndCountAll({
where: [
{
libraryId
@ -751,7 +751,7 @@ module.exports = {
const userPermissionBookWhere = this.getUserPermissionBookWhereQuery(user)
// Step 1: Get the first book of every series that hasnt been started yet
const seriesNotStarted = await Database.models.series.findAll({
const seriesNotStarted = await Database.seriesModel.findAll({
where: [
{
libraryId