mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-03-02 14:09:43 +00:00
Merge branch 'advplyr:master' into feat/metadata-id-matching
This commit is contained in:
commit
cf18cd9fbf
45 changed files with 843 additions and 118 deletions
|
|
@ -113,7 +113,7 @@ class AuthorController {
|
|||
payload.lastFirst = Database.authorModel.getLastFirst(payload.name)
|
||||
}
|
||||
|
||||
// Check if author name matches another author and merge the authors
|
||||
// Check if author name matches another author in the same library and merge the authors
|
||||
let existingAuthor = null
|
||||
if (authorNameUpdate) {
|
||||
existingAuthor = await Database.authorModel.findOne({
|
||||
|
|
@ -121,7 +121,8 @@ class AuthorController {
|
|||
id: {
|
||||
[sequelize.Op.not]: req.author.id
|
||||
},
|
||||
name: payload.name
|
||||
name: payload.name,
|
||||
libraryId: req.author.libraryId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -782,7 +782,14 @@ class User extends Model {
|
|||
error: 'Library item not found',
|
||||
statusCode: 404
|
||||
}
|
||||
} else if (libraryItem.mediaType !== 'book') {
|
||||
Logger.error(`[User] createUpdateMediaProgress: library item ${progressPayload.libraryItemId} is not a book`)
|
||||
return {
|
||||
error: 'Library item is not a book',
|
||||
statusCode: 400
|
||||
}
|
||||
}
|
||||
|
||||
mediaItemId = libraryItem.media.id
|
||||
mediaProgress = libraryItem.media.mediaProgresses?.[0]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,8 +57,13 @@ class Audible {
|
|||
})
|
||||
}
|
||||
|
||||
const genresFiltered = genres ? genres.filter((g) => g.type == 'genre').map((g) => g.name) : []
|
||||
const tagsFiltered = genres ? genres.filter((g) => g.type == 'tag').map((g) => g.name) : []
|
||||
let genresCleaned = []
|
||||
let tagsCleaned = []
|
||||
|
||||
if (genres && Array.isArray(genres)) {
|
||||
genresCleaned = [...new Set(genres.filter((g) => g.type == 'genre').map((g) => g.name))]
|
||||
tagsCleaned = [...new Set(genres.filter((g) => g.type == 'tag').map((g) => g.name))]
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
|
|
@ -71,8 +76,8 @@ class Audible {
|
|||
cover: image,
|
||||
asin,
|
||||
isbn,
|
||||
genres: genresFiltered.length ? genresFiltered : null,
|
||||
tags: tagsFiltered.length ? tagsFiltered.join(', ') : null,
|
||||
genres: genresCleaned.length ? genresCleaned : null,
|
||||
tags: tagsCleaned.length ? tagsCleaned : null,
|
||||
series: series.length ? series : null,
|
||||
language: language ? language.charAt(0).toUpperCase() + language.slice(1) : null,
|
||||
duration: runtimeLengthMin && !isNaN(runtimeLengthMin) ? Number(runtimeLengthMin) : 0,
|
||||
|
|
|
|||
|
|
@ -89,6 +89,27 @@ class CustomProviderAdapter {
|
|||
})
|
||||
.filter((s) => s !== undefined)
|
||||
}
|
||||
/**
|
||||
* Validates and dedupes tags/genres array
|
||||
* Can be comma separated string or array of strings
|
||||
* @param {string|string[]} tagsGenres
|
||||
* @returns {string[]}
|
||||
*/
|
||||
const validateTagsGenresArray = (tagsGenres) => {
|
||||
if (!tagsGenres || (typeof tagsGenres !== 'string' && !Array.isArray(tagsGenres))) return undefined
|
||||
|
||||
// If string, split by comma and trim each item
|
||||
if (typeof tagsGenres === 'string') tagsGenres = tagsGenres.split(',')
|
||||
// If array, ensure all items are strings
|
||||
else if (!tagsGenres.every((t) => typeof t === 'string')) return undefined
|
||||
|
||||
// Trim and filter out empty strings
|
||||
tagsGenres = tagsGenres.map((t) => t.trim()).filter(Boolean)
|
||||
if (!tagsGenres.length) return undefined
|
||||
|
||||
// Dedup
|
||||
return [...new Set(tagsGenres)]
|
||||
}
|
||||
|
||||
// re-map keys to throw out
|
||||
return matches.map((match) => {
|
||||
|
|
@ -105,8 +126,8 @@ class CustomProviderAdapter {
|
|||
cover: toStringOrUndefined(cover),
|
||||
isbn: toStringOrUndefined(isbn),
|
||||
asin: toStringOrUndefined(asin),
|
||||
genres: Array.isArray(genres) && genres.every((g) => typeof g === 'string') ? genres : undefined,
|
||||
tags: toStringOrUndefined(tags),
|
||||
genres: validateTagsGenresArray(genres),
|
||||
tags: validateTagsGenresArray(tags),
|
||||
series: validateSeriesArray(series),
|
||||
language: toStringOrUndefined(language),
|
||||
duration: !isNaN(duration) && duration !== null ? Number(duration) : undefined
|
||||
|
|
|
|||
|
|
@ -259,18 +259,17 @@ class Scanner {
|
|||
SocketAuthority.emitter('author_added', author.toOldJSON())
|
||||
// Update filter data
|
||||
Database.addAuthorToFilterData(libraryItem.libraryId, author.name, author.id)
|
||||
|
||||
await Database.bookAuthorModel
|
||||
.create({
|
||||
authorId: author.id,
|
||||
bookId: libraryItem.media.id
|
||||
})
|
||||
.then(() => {
|
||||
Logger.info(`[Scanner] quickMatchBookBuildUpdatePayload: Added author "${author.name}" to "${libraryItem.media.title}"`)
|
||||
libraryItem.media.authors.push(author)
|
||||
hasAuthorUpdates = true
|
||||
})
|
||||
}
|
||||
await Database.bookAuthorModel
|
||||
.create({
|
||||
authorId: author.id,
|
||||
bookId: libraryItem.media.id
|
||||
})
|
||||
.then(() => {
|
||||
Logger.info(`[Scanner] quickMatchBookBuildUpdatePayload: Added author "${author.name}" to "${libraryItem.media.title}"`)
|
||||
libraryItem.media.authors.push(author)
|
||||
hasAuthorUpdates = true
|
||||
})
|
||||
}
|
||||
const authorsRemoved = libraryItem.media.authors.filter((a) => !matchData.author.find((ma) => ma.toLowerCase() === a.name.toLowerCase()))
|
||||
if (authorsRemoved.length) {
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ module.exports = {
|
|||
} else if (group === 'publishedDecades') {
|
||||
const startYear = parseInt(value)
|
||||
const endYear = parseInt(value, 10) + 9
|
||||
mediaWhere = Sequelize.where(Sequelize.literal('CAST(`book`.`publishedYear` AS INTEGER)'), {
|
||||
mediaWhere = Sequelize.where(Sequelize.literal('CAST(publishedYear AS INTEGER)'), {
|
||||
[Sequelize.Op.between]: [startYear, endYear]
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue