mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-08 18:31:43 +00:00
Enable audible scrape of personal user account to list preorders
This commit is contained in:
parent
3ccdcaec1a
commit
792210d8cd
16 changed files with 1316 additions and 2 deletions
131
server/migrations/v2.33.2-setup-audible.js
Normal file
131
server/migrations/v2.33.2-setup-audible.js
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/**
|
||||
* @typedef MigrationContext
|
||||
* @property {import('sequelize').QueryInterface} queryInterface
|
||||
* @property {import('../Logger')} logger
|
||||
*
|
||||
* @typedef MigrationOptions
|
||||
* @property {MigrationContext} context
|
||||
*/
|
||||
|
||||
const migrationVersion = '2.33.2'
|
||||
const migrationName = `${migrationVersion}-setup-audible`
|
||||
const loggerPrefix = `[${migrationVersion} migration]`
|
||||
|
||||
/**
|
||||
* Creates audibleAccounts and audibleBooks tables if they don't exist,
|
||||
* adds missing columns to existing tables, and ensures all indexes exist.
|
||||
*
|
||||
* @param {MigrationOptions} options
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function up({ context: { queryInterface, logger } }) {
|
||||
logger.info(`${loggerPrefix} UPGRADE BEGIN: ${migrationName}`)
|
||||
|
||||
const DataTypes = queryInterface.sequelize.Sequelize.DataTypes
|
||||
|
||||
// Safe index creation — silently ignores "already exists" errors
|
||||
const addIndexSafe = async (table, fields, options = {}) => {
|
||||
try {
|
||||
await queryInterface.addIndex(table, fields, options)
|
||||
} catch (err) {
|
||||
logger.info(`${loggerPrefix} index on ${table}(${fields.join(',')}) already exists, skipping`)
|
||||
}
|
||||
}
|
||||
|
||||
// audibleAccounts table
|
||||
const accountsDesc = await queryInterface.describeTable('audibleAccounts').catch(() => null)
|
||||
if (!accountsDesc) {
|
||||
logger.info(`${loggerPrefix} creating table "audibleAccounts"`)
|
||||
await queryInterface.createTable('audibleAccounts', {
|
||||
id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true },
|
||||
email: { type: DataTypes.STRING, allowNull: false },
|
||||
region: { type: DataTypes.STRING, allowNull: false, defaultValue: 'us' },
|
||||
encryptedToken: { type: DataTypes.TEXT, allowNull: false },
|
||||
encryptedCookies: { type: DataTypes.TEXT, allowNull: true },
|
||||
libraryId: { type: DataTypes.UUID, allowNull: true },
|
||||
shelfPosition: { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0 },
|
||||
lastSync: { type: DataTypes.DATE },
|
||||
isActive: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true },
|
||||
createdAt: { type: DataTypes.DATE, allowNull: false },
|
||||
updatedAt: { type: DataTypes.DATE, allowNull: false },
|
||||
userId: { type: DataTypes.UUID, references: { model: 'users', key: 'id' }, onDelete: 'CASCADE' }
|
||||
})
|
||||
logger.info(`${loggerPrefix} created table "audibleAccounts"`)
|
||||
} else {
|
||||
if (!accountsDesc.encryptedCookies) {
|
||||
logger.info(`${loggerPrefix} adding column "encryptedCookies" to "audibleAccounts"`)
|
||||
await queryInterface.addColumn('audibleAccounts', 'encryptedCookies', { type: DataTypes.TEXT, allowNull: true })
|
||||
}
|
||||
if (!accountsDesc.libraryId) {
|
||||
logger.info(`${loggerPrefix} adding column "libraryId" to "audibleAccounts"`)
|
||||
await queryInterface.addColumn('audibleAccounts', 'libraryId', { type: DataTypes.TEXT, allowNull: true })
|
||||
}
|
||||
if (!accountsDesc.shelfPosition) {
|
||||
logger.info(`${loggerPrefix} adding column "shelfPosition" to "audibleAccounts"`)
|
||||
await queryInterface.addColumn('audibleAccounts', 'shelfPosition', { type: DataTypes.INTEGER, allowNull: false, defaultValue: 0 })
|
||||
}
|
||||
}
|
||||
|
||||
// Indexes on audibleAccounts (applied to both new and existing tables)
|
||||
await addIndexSafe('audibleAccounts', ['userId'])
|
||||
await addIndexSafe('audibleAccounts', ['email', 'userId'], { unique: true, name: 'audibleAccounts_email_userId_unique' })
|
||||
|
||||
// audibleBooks table
|
||||
const booksDesc = await queryInterface.describeTable('audibleBooks').catch(() => null)
|
||||
if (!booksDesc) {
|
||||
logger.info(`${loggerPrefix} creating table "audibleBooks"`)
|
||||
await queryInterface.createTable('audibleBooks', {
|
||||
id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true },
|
||||
asin: { type: DataTypes.STRING, allowNull: false },
|
||||
title: { type: DataTypes.STRING, allowNull: false },
|
||||
subtitle: { type: DataTypes.STRING },
|
||||
authors: { type: DataTypes.JSON, defaultValue: [] },
|
||||
narrators: { type: DataTypes.JSON, defaultValue: [] },
|
||||
seriesName: { type: DataTypes.STRING },
|
||||
seriesPosition: { type: DataTypes.STRING },
|
||||
releaseDate: { type: DataTypes.STRING },
|
||||
coverUrl: { type: DataTypes.TEXT },
|
||||
publisherName: { type: DataTypes.STRING },
|
||||
summary: { type: DataTypes.TEXT },
|
||||
runtimeLengthMin: { type: DataTypes.INTEGER },
|
||||
status: { type: DataTypes.STRING, allowNull: false, defaultValue: 'available' },
|
||||
lastChecked: { type: DataTypes.DATE },
|
||||
createdAt: { type: DataTypes.DATE, allowNull: false },
|
||||
updatedAt: { type: DataTypes.DATE, allowNull: false },
|
||||
audibleAccountId: { type: DataTypes.UUID, references: { model: 'audibleAccounts', key: 'id' }, onDelete: 'CASCADE' }
|
||||
})
|
||||
logger.info(`${loggerPrefix} created table "audibleBooks"`)
|
||||
} else {
|
||||
logger.info(`${loggerPrefix} table "audibleBooks" already exists`)
|
||||
}
|
||||
|
||||
// Indexes on audibleBooks (applied to both new and existing tables)
|
||||
await addIndexSafe('audibleBooks', ['audibleAccountId'])
|
||||
await addIndexSafe('audibleBooks', ['asin', 'audibleAccountId'], { unique: true, name: 'audibleBooks_asin_accountId_unique' })
|
||||
|
||||
logger.info(`${loggerPrefix} UPGRADE END: ${migrationName}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MigrationOptions} options
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function down({ context: { queryInterface, logger } }) {
|
||||
logger.info(`${loggerPrefix} DOWNGRADE BEGIN: ${migrationName}`)
|
||||
|
||||
const booksDesc = await queryInterface.describeTable('audibleBooks').catch(() => null)
|
||||
if (booksDesc) {
|
||||
await queryInterface.dropTable('audibleBooks')
|
||||
logger.info(`${loggerPrefix} dropped table "audibleBooks"`)
|
||||
}
|
||||
|
||||
const accountsDesc = await queryInterface.describeTable('audibleAccounts').catch(() => null)
|
||||
if (accountsDesc) {
|
||||
await queryInterface.dropTable('audibleAccounts')
|
||||
logger.info(`${loggerPrefix} dropped table "audibleAccounts"`)
|
||||
}
|
||||
|
||||
logger.info(`${loggerPrefix} DOWNGRADE END: ${migrationName}`)
|
||||
}
|
||||
|
||||
module.exports = { up, down }
|
||||
Loading…
Add table
Add a link
Reference in a new issue