From 8710816a6fe6a4dcb2b5f892ec6c03c4d095fe5b Mon Sep 17 00:00:00 2001 From: Harry Rose Date: Tue, 17 Mar 2026 18:59:12 +0000 Subject: [PATCH] Remove autoGenerateChapters flag, migration and version bump --- client/package.json | 2 +- package.json | 2 +- server/managers/PodcastManager.js | 2 +- ...34.0-add-auto-generate-podcast-chapters.js | 83 ------------------- server/models/Podcast.js | 11 --- server/models/PodcastEpisode.js | 7 +- .../parsePodcastDescriptionForChapters.js | 2 - ...add-auto-generate-podcast-chapters.test.js | 64 -------------- 8 files changed, 6 insertions(+), 167 deletions(-) delete mode 100644 server/migrations/v2.34.0-add-auto-generate-podcast-chapters.js delete mode 100644 test/server/migrations/v2.34.0-add-auto-generate-podcast-chapters.test.js diff --git a/client/package.json b/client/package.json index dd0f3a0c..a1503a50 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf-client", - "version": "2.34.0", + "version": "2.33.0", "buildNumber": 1, "description": "Self-hosted audiobook and podcast client", "main": "index.js", diff --git a/package.json b/package.json index 10ba26f6..3108b517 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "audiobookshelf", - "version": "2.34.0", + "version": "2.33.0", "buildNumber": 1, "description": "Self-hosted audiobook and podcast server", "main": "index.js", diff --git a/server/managers/PodcastManager.js b/server/managers/PodcastManager.js index 82e0dbd3..bdf6fc76 100644 --- a/server/managers/PodcastManager.js +++ b/server/managers/PodcastManager.js @@ -204,7 +204,7 @@ class PodcastManager { return false } - const podcastEpisode = await Database.podcastEpisodeModel.createFromRssPodcastEpisode(this.currentDownload.rssPodcastEpisode, libraryItem.media.id, libraryItem.media.autoGenerateChapters, audioFile) + const podcastEpisode = await Database.podcastEpisodeModel.createFromRssPodcastEpisode(this.currentDownload.rssPodcastEpisode, libraryItem.media.id, audioFile) libraryItem.libraryFiles.push(libraryFile.toJSON()) // Re-calculating library item size because this wasnt being updated properly for podcasts in v2.20.0 and below diff --git a/server/migrations/v2.34.0-add-auto-generate-podcast-chapters.js b/server/migrations/v2.34.0-add-auto-generate-podcast-chapters.js deleted file mode 100644 index c5567abe..00000000 --- a/server/migrations/v2.34.0-add-auto-generate-podcast-chapters.js +++ /dev/null @@ -1,83 +0,0 @@ -const util = require('util') - -/** - * @typedef MigrationContext - * @property {import('sequelize').QueryInterface} queryInterface - a suquelize QueryInterface object. - * @property {import('../Logger')} logger - a Logger object. - * - * @typedef MigrationOptions - * @property {MigrationContext} context - an object containing the migration context. - */ - -const migrationVersion = '2.34.0' -const migrationName = `${migrationVersion}-add-auto-generate-podcast-chapters` -const loggerPrefix = `[${migrationVersion} migration]` - -/** - * This upward migration adds a boolean autoGenerateChapters column to the podcasts table and defaults it to false. - * - * @param {MigrationOptions} options - an object containing the migration context. - * @returns {Promise} - A promise that resolves when the migration is complete. - */ -async function up({ context: { queryInterface, logger } }) { - logger.info(`${loggerPrefix} UPGRADE BEGIN: ${migrationName}`) - - await addColumn(queryInterface, logger, 'podcasts', 'autoGenerateChapters', { type: queryInterface.sequelize.Sequelize.BOOLEAN, allowNull: false, defaultValue: false }) - - logger.info(`${loggerPrefix} UPGRADE END: ${migrationName}`) -} - -/** - * This downward migration removes the autoGenerateChapters column on the podcasts table, - * - * @param {MigrationOptions} options - an object containing the migration context. - * @returns {Promise} - A promise that resolves when the migration is complete. - */ -async function down({ context: { queryInterface, logger } }) { - logger.info(`${loggerPrefix} DOWNGRADE BEGIN: ${migrationName}`) - - await removeColumn(queryInterface, logger, 'podcasts', 'autoGenerateChapters') - - logger.info(`${loggerPrefix} DOWNGRADE END: ${migrationName}`) -} - -/** - * Utility function to add a column to a table. If the column already exists, it logs a message and continues. - * - * @param {import('sequelize').QueryInterface} queryInterface - a suquelize QueryInterface object. - * @param {import('../Logger')} logger - a Logger object. - * @param {string} table - the name of the table to add the column to. - * @param {string} column - the name of the column to add. - * @param {Object} options - the options for the column. - */ -async function addColumn(queryInterface, logger, table, column, options) { - logger.info(`${loggerPrefix} adding column "${column}" to table "${table}"`) - const tableDescription = await queryInterface.describeTable(table) - if (!tableDescription[column]) { - await queryInterface.addColumn(table, column, options) - logger.info(`${loggerPrefix} added column "${column}" to table "${table}"`) - } else { - logger.info(`${loggerPrefix} column "${column}" already exists in table "${table}"`) - } -} - -/** - * Utility function to remove a column from a table. If the column does not exist, it logs a message and continues. - * - * @param {import('sequelize').QueryInterface} queryInterface - a suquelize QueryInterface object. - * @param {import('../Logger')} logger - a Logger object. - * @param {string} table - the name of the table to remove the column from. - * @param {string} column - the name of the column to remove. - */ -async function removeColumn(queryInterface, logger, table, column) { - logger.info(`${loggerPrefix} removing column "${column}" from table "${table}"`) - const tableDescription = await queryInterface.describeTable(table) - if (tableDescription[column]) { - await queryInterface.sequelize.query(`ALTER TABLE ${table} DROP COLUMN ${column}`) - logger.info(`${loggerPrefix} removed column "${column}" from table "${table}"`) - } else { - logger.info(`${loggerPrefix} column "${column}" does not exist in table "${table}"`) - } -} - -module.exports = { up, down } diff --git a/server/models/Podcast.js b/server/models/Podcast.js index bb0e0453..a96e1dd0 100644 --- a/server/models/Podcast.js +++ b/server/models/Podcast.js @@ -53,8 +53,6 @@ class Podcast extends Model { this.maxEpisodesToKeep /** @type {number} */ this.maxNewEpisodesToDownload - /** @type {boolean} */ - this.autoGenerateChapters /** @type {string} */ this.coverPath /** @type {string[]} */ @@ -108,7 +106,6 @@ class Podcast extends Model { explicit: !!payload.metadata.explicit, autoDownloadEpisodes: !!payload.autoDownloadEpisodes, autoDownloadSchedule: autoDownloadSchedule || global.ServerSettings.podcastEpisodeSchedule, - autoGenerateChapters: !!payload.autoGenerateChapters, lastEpisodeCheck: new Date(), maxEpisodesToKeep: 0, maxNewEpisodesToDownload: 3, @@ -148,7 +145,6 @@ class Podcast extends Model { autoDownloadEpisodes: DataTypes.BOOLEAN, autoDownloadSchedule: DataTypes.STRING, lastEpisodeCheck: DataTypes.DATE, - autoGenerateChapters: DataTypes.BOOLEAN, maxEpisodesToKeep: DataTypes.INTEGER, maxNewEpisodesToDownload: DataTypes.INTEGER, coverPath: DataTypes.STRING, @@ -277,10 +273,6 @@ class Podcast extends Model { this.autoDownloadSchedule = payload.autoDownloadSchedule hasUpdates = true } - if (payload.autoGenerateChapters !== undefined && payload.autoGenerateChapters !== this.autoGenerateChapters) { - this.autoGenerateChapters = !!payload.autoGenerateChapters - hasUpdates = true - } if (typeof payload.lastEpisodeCheck === 'number' && payload.lastEpisodeCheck !== this.lastEpisodeCheck?.valueOf()) { this.lastEpisodeCheck = payload.lastEpisodeCheck hasUpdates = true @@ -449,7 +441,6 @@ class Podcast extends Model { autoDownloadEpisodes: this.autoDownloadEpisodes, autoDownloadSchedule: this.autoDownloadSchedule, lastEpisodeCheck: this.lastEpisodeCheck?.valueOf() || null, - autoGenerateChapters: this.autoGenerateChapters, maxEpisodesToKeep: this.maxEpisodesToKeep, maxNewEpisodesToDownload: this.maxNewEpisodesToDownload } @@ -466,7 +457,6 @@ class Podcast extends Model { autoDownloadEpisodes: this.autoDownloadEpisodes, autoDownloadSchedule: this.autoDownloadSchedule, lastEpisodeCheck: this.lastEpisodeCheck?.valueOf() || null, - autoGenerateChapters: this.autoGenerateChapters, maxEpisodesToKeep: this.maxEpisodesToKeep, maxNewEpisodesToDownload: this.maxNewEpisodesToDownload, size: this.size @@ -491,7 +481,6 @@ class Podcast extends Model { autoDownloadEpisodes: this.autoDownloadEpisodes, autoDownloadSchedule: this.autoDownloadSchedule, lastEpisodeCheck: this.lastEpisodeCheck?.valueOf() || null, - autoGenerateChapters: this.autoGenerateChapters, maxEpisodesToKeep: this.maxEpisodesToKeep, maxNewEpisodesToDownload: this.maxNewEpisodesToDownload, size: this.size diff --git a/server/models/PodcastEpisode.js b/server/models/PodcastEpisode.js index c253f479..7c107a87 100644 --- a/server/models/PodcastEpisode.js +++ b/server/models/PodcastEpisode.js @@ -58,10 +58,9 @@ class PodcastEpisode extends Model { * * @param {import('../utils/podcastUtils').RssPodcastEpisode} rssPodcastEpisode * @param {string} podcastId - * @param {boolean} autoGenerateChapters * @param {import('../objects/files/AudioFile')} audioFile */ - static async createFromRssPodcastEpisode(rssPodcastEpisode, podcastId, autoGenerateChapters, audioFile) { + static async createFromRssPodcastEpisode(rssPodcastEpisode, podcastId, audioFile) { const podcastEpisode = { index: null, season: rssPodcastEpisode.season, @@ -88,8 +87,8 @@ class PodcastEpisode extends Model { podcastEpisode.chapters = audioFile.chapters.map((ch) => ({ ...ch })) } else if (rssPodcastEpisode.chapters?.length) { podcastEpisode.chapters = rssPodcastEpisode.chapters.map((ch) => ({ ...ch })) - } else if (autoGenerateChapters) { - Logger.info("[PodcastEpisode] New episode doesn't have chapters, attempting to generate them from timestamps", rssPodcastEpisode.title) + } else { + Logger.debug("[PodcastEpisode] New episode doesn't have chapters, attempting to generate them from timestamps", rssPodcastEpisode.title) try { podcastEpisode.chapters = parsePodcastDescriptionForChapters.parse(podcastEpisode.description, podcastEpisode.audioFile.duration) } catch (error) { diff --git a/server/utils/parsers/parsePodcastDescriptionForChapters.js b/server/utils/parsers/parsePodcastDescriptionForChapters.js index 3f90e847..53585d64 100644 --- a/server/utils/parsers/parsePodcastDescriptionForChapters.js +++ b/server/utils/parsers/parsePodcastDescriptionForChapters.js @@ -26,8 +26,6 @@ module.exports.parse = (podcastDescription, audioDurationSecs) => { throw new Error('Audio duration must not be null') } - Logger.info('Description!', podcastDescription) - // This number is arbitrary, but there have been examples where descriptions of the chapter are on the same line as the chapter title // This results in a unpleasant UX where the chapter is very long, it's also possible that an overly long chapter title is the result of a parsing failure const maxChapterTitleLength = 200 diff --git a/test/server/migrations/v2.34.0-add-auto-generate-podcast-chapters.test.js b/test/server/migrations/v2.34.0-add-auto-generate-podcast-chapters.test.js deleted file mode 100644 index 04822be4..00000000 --- a/test/server/migrations/v2.34.0-add-auto-generate-podcast-chapters.test.js +++ /dev/null @@ -1,64 +0,0 @@ -const chai = require('chai') -const sinon = require('sinon') -const { expect } = chai - -const { DataTypes, Sequelize } = require('sequelize') -const Logger = require('../../../server/Logger') - -const { up, down } = require('../../../server/migrations/v2.34.0-add-auto-generate-podcast-chapters') - -describe('Migration v2.34.0-add-auto-generate-podcast-chapters', () => { - let sequelize - let queryInterface - let loggerInfoStub - - beforeEach(async () => { - sequelize = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false }) - queryInterface = sequelize.getQueryInterface() - loggerInfoStub = sinon.stub(Logger, 'info') - - await queryInterface.createTable('podcasts', { - id: { type: DataTypes.INTEGER, allowNull: false, primaryKey: true, unique: true }, - title: { type: DataTypes.STRING, allowNull: false }, - titleIgnorePrefix: { type: DataTypes.STRING, allowNull: false } - }) - - await queryInterface.bulkInsert('podcasts', [ - { id: 1, title: 'The Podcast 1', titleIgnorePrefix: 'Podcast 1, The' }, - { id: 2, title: 'The Podcast 2', titleIgnorePrefix: 'Podcast 2, The' } - ]) - }) - - afterEach(() => { - sinon.restore() - }) - - describe('up', () => { - it('should add autoGenerateChapters column to podcasts', async () => { - await up({ context: { queryInterface, logger: Logger } }) - - const [podcasts] = await queryInterface.sequelize.query('SELECT * FROM podcasts') - expect(podcasts).to.deep.equal([ - { id: 1, autoGenerateChapters: 0, title: 'The Podcast 1', titleIgnorePrefix: 'Podcast 1, The' }, - { id: 2, autoGenerateChapters: 0, title: 'The Podcast 2', titleIgnorePrefix: 'Podcast 2, The' } - ]) - }) - }) - - describe('down', () => { - it('should remove autoGenerateChapters column from podcasts', async () => { - await up({ context: { queryInterface, logger: Logger } }) - try { - await down({ context: { queryInterface, logger: Logger } }) - } catch (error) { - console.log(error) - } - - const [podcasts] = await queryInterface.sequelize.query('SELECT * FROM podcasts') - expect(podcasts).to.deep.equal([ - { id: 1, title: 'The Podcast 1', titleIgnorePrefix: 'Podcast 1, The' }, - { id: 2, title: 'The Podcast 2', titleIgnorePrefix: 'Podcast 2, The' } - ]) - }) - }) -})