mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-07 18:01:42 +00:00
[Enhancement] Simple ratings from audible.com
This commit is contained in:
parent
0c7b738b7c
commit
831d50320c
13 changed files with 202 additions and 3 deletions
|
|
@ -16,3 +16,5 @@ Please add a record of every database migration that you create to this file. Th
|
|||
| v2.19.1 | v2.19.1-copy-title-to-library-items | Copies title and titleIgnorePrefix to the libraryItems table, creates update triggers and indices |
|
||||
| v2.19.4 | v2.19.4-improve-podcast-queries | Adds numEpisodes to podcasts, adds podcastId to mediaProgresses, copies podcast title to libraryItems |
|
||||
| v2.20.0 | v2.20.0-improve-author-sort-queries | Adds AuthorNames(FirstLast\|LastFirst) to libraryItems to improve author sort queries |
|
||||
| v2.26.0 | v2.26.0-create-auth-tables | Creates auth tables for new authentication system |
|
||||
| v2.31.0 | v2.31.0-add-book-rating | Adds rating column to books table for Audible star ratings |
|
||||
|
|
|
|||
68
server/migrations/v2.31.0-add-book-rating.js
Normal file
68
server/migrations/v2.31.0-add-book-rating.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* @typedef MigrationContext
|
||||
* @property {import('sequelize').QueryInterface} queryInterface - a Sequelize QueryInterface object.
|
||||
* @property {import('../Logger')} logger - a Logger object.
|
||||
*
|
||||
* @typedef MigrationOptions
|
||||
* @property {MigrationContext} context - an object containing the migration context.
|
||||
*/
|
||||
|
||||
const migrationVersion = '2.31.0'
|
||||
const migrationName = `${migrationVersion}-add-book-rating`
|
||||
const loggerPrefix = `[${migrationVersion} migration]`
|
||||
|
||||
/**
|
||||
* This migration script adds the rating column to the books table.
|
||||
*
|
||||
* @param {MigrationOptions} options - an object containing the migration context.
|
||||
* @returns {Promise<void>} - A promise that resolves when the migration is complete.
|
||||
*/
|
||||
async function up({ context: { queryInterface, logger } }) {
|
||||
logger.info(`${loggerPrefix} UPGRADE BEGIN: ${migrationName}`)
|
||||
|
||||
if (await queryInterface.tableExists('books')) {
|
||||
const tableDescription = await queryInterface.describeTable('books')
|
||||
if (!tableDescription.rating) {
|
||||
logger.info(`${loggerPrefix} Adding rating column to books table`)
|
||||
await queryInterface.addColumn('books', 'rating', {
|
||||
type: queryInterface.sequelize.Sequelize.DataTypes.FLOAT,
|
||||
allowNull: true
|
||||
})
|
||||
logger.info(`${loggerPrefix} Added rating column to books table`)
|
||||
} else {
|
||||
logger.info(`${loggerPrefix} rating column already exists in books table`)
|
||||
}
|
||||
} else {
|
||||
logger.info(`${loggerPrefix} books table does not exist`)
|
||||
}
|
||||
|
||||
logger.info(`${loggerPrefix} UPGRADE END: ${migrationName}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* This migration script removes the rating column from the books table.
|
||||
*
|
||||
* @param {MigrationOptions} options - an object containing the migration context.
|
||||
* @returns {Promise<void>} - A promise that resolves when the migration is complete.
|
||||
*/
|
||||
async function down({ context: { queryInterface, logger } }) {
|
||||
logger.info(`${loggerPrefix} DOWNGRADE BEGIN: ${migrationName}`)
|
||||
|
||||
if (await queryInterface.tableExists('books')) {
|
||||
const tableDescription = await queryInterface.describeTable('books')
|
||||
if (tableDescription.rating) {
|
||||
logger.info(`${loggerPrefix} Removing rating column from books table`)
|
||||
await queryInterface.removeColumn('books', 'rating')
|
||||
logger.info(`${loggerPrefix} Removed rating column from books table`)
|
||||
} else {
|
||||
logger.info(`${loggerPrefix} rating column does not exist in books table`)
|
||||
}
|
||||
} else {
|
||||
logger.info(`${loggerPrefix} books table does not exist`)
|
||||
}
|
||||
|
||||
logger.info(`${loggerPrefix} DOWNGRADE END: ${migrationName}`)
|
||||
}
|
||||
|
||||
module.exports = { up, down }
|
||||
|
||||
|
|
@ -97,6 +97,8 @@ class Book extends Model {
|
|||
this.isbn
|
||||
/** @type {string} */
|
||||
this.asin
|
||||
/** @type {number} */
|
||||
this.rating
|
||||
/** @type {string} */
|
||||
this.language
|
||||
/** @type {boolean} */
|
||||
|
|
@ -153,6 +155,7 @@ class Book extends Model {
|
|||
description: DataTypes.TEXT,
|
||||
isbn: DataTypes.STRING,
|
||||
asin: DataTypes.STRING,
|
||||
rating: DataTypes.FLOAT,
|
||||
language: DataTypes.STRING,
|
||||
explicit: DataTypes.BOOLEAN,
|
||||
abridged: DataTypes.BOOLEAN,
|
||||
|
|
@ -355,6 +358,7 @@ class Book extends Model {
|
|||
description: this.description,
|
||||
isbn: this.isbn,
|
||||
asin: this.asin,
|
||||
rating: this.rating,
|
||||
language: this.language,
|
||||
explicit: !!this.explicit,
|
||||
abridged: !!this.abridged
|
||||
|
|
@ -373,6 +377,27 @@ class Book extends Model {
|
|||
|
||||
if (payload.metadata) {
|
||||
const metadataStringKeys = ['title', 'subtitle', 'publishedYear', 'publishedDate', 'publisher', 'description', 'isbn', 'asin', 'language']
|
||||
if (payload.metadata.rating !== undefined) {
|
||||
let ratingValue = null
|
||||
if (payload.metadata.rating !== null) {
|
||||
if (typeof payload.metadata.rating === 'object' && payload.metadata.rating.average) {
|
||||
ratingValue = Number(payload.metadata.rating.average)
|
||||
} else {
|
||||
ratingValue = Number(payload.metadata.rating)
|
||||
}
|
||||
}
|
||||
// Treat 0 as null (no rating)
|
||||
if (ratingValue === 0) ratingValue = null
|
||||
if (ratingValue !== null && !isNaN(ratingValue) && ratingValue > 0) {
|
||||
if (this.rating !== ratingValue) {
|
||||
this.rating = ratingValue
|
||||
hasUpdates = true
|
||||
}
|
||||
} else if (ratingValue === null && this.rating !== null) {
|
||||
this.rating = null
|
||||
hasUpdates = true
|
||||
}
|
||||
}
|
||||
metadataStringKeys.forEach((key) => {
|
||||
if (typeof payload.metadata[key] == 'number') {
|
||||
payload.metadata[key] = String(payload.metadata[key])
|
||||
|
|
@ -567,6 +592,7 @@ class Book extends Model {
|
|||
description: this.description,
|
||||
isbn: this.isbn,
|
||||
asin: this.asin,
|
||||
rating: this.rating,
|
||||
language: this.language,
|
||||
explicit: this.explicit,
|
||||
abridged: this.abridged
|
||||
|
|
@ -589,6 +615,7 @@ class Book extends Model {
|
|||
description: this.description,
|
||||
isbn: this.isbn,
|
||||
asin: this.asin,
|
||||
rating: this.rating,
|
||||
language: this.language,
|
||||
explicit: this.explicit,
|
||||
abridged: this.abridged
|
||||
|
|
|
|||
|
|
@ -592,6 +592,7 @@ class LibraryItem extends Model {
|
|||
description: mediaExpanded.description,
|
||||
isbn: mediaExpanded.isbn,
|
||||
asin: mediaExpanded.asin,
|
||||
rating: mediaExpanded.rating,
|
||||
language: mediaExpanded.language,
|
||||
explicit: !!mediaExpanded.explicit,
|
||||
abridged: !!mediaExpanded.abridged
|
||||
|
|
|
|||
|
|
@ -839,6 +839,7 @@ class BookScanner {
|
|||
description: libraryItem.media.description,
|
||||
isbn: libraryItem.media.isbn,
|
||||
asin: libraryItem.media.asin,
|
||||
rating: libraryItem.media.rating,
|
||||
language: libraryItem.media.language,
|
||||
explicit: !!libraryItem.media.explicit,
|
||||
abridged: !!libraryItem.media.abridged
|
||||
|
|
|
|||
|
|
@ -274,6 +274,9 @@ module.exports = {
|
|||
return [['duration', dir]]
|
||||
} else if (sortBy === 'media.metadata.publishedYear') {
|
||||
return [[Sequelize.literal(`CAST(\`book\`.\`publishedYear\` AS INTEGER)`), dir]]
|
||||
} else if (sortBy === 'media.metadata.rating') {
|
||||
const nullDir = sortDesc ? 'DESC NULLS FIRST' : 'ASC NULLS LAST'
|
||||
return [[Sequelize.literal(`\`book\`.\`rating\` ${nullDir}`)]]
|
||||
} else if (sortBy === 'media.metadata.authorNameLF') {
|
||||
// Sort by author name last first, secondary sort by title
|
||||
return [[Sequelize.literal('`libraryItem`.`authorNamesLastFirst` COLLATE NOCASE'), dir], getTitleOrder()]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue