mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-02-28 21:19:42 +00:00
Merge cf18cd9fbf into 1d0b7e383a
This commit is contained in:
commit
c8946d563f
8 changed files with 100 additions and 2 deletions
|
|
@ -150,6 +150,29 @@ class ToolsController {
|
|||
res.sendStatus(200)
|
||||
}
|
||||
|
||||
/**
|
||||
* POST: /api/tools/batch/update-metadata-files
|
||||
* Start batch request to update all metadata files
|
||||
*
|
||||
* @this import('../routers/ApiRouter')
|
||||
*
|
||||
* @param {RequestWithUser} req
|
||||
* @param {Response} res
|
||||
*/
|
||||
async updateAllItemMetadata(req, res) {
|
||||
if (!req.user.isAdminOrUp) {
|
||||
Logger.warn(`Non-admin user "${req.user.username}" other than admin attempted to batch scan library items`)
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
|
||||
const libraryItems = await Database.libraryItemModel.findAll()
|
||||
for (const libraryItem of libraryItems) {
|
||||
await libraryItem.saveMetadataFile()
|
||||
}
|
||||
|
||||
res.sendStatus(200)
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {RequestWithUser} req
|
||||
|
|
|
|||
|
|
@ -16,3 +16,4 @@ 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.31.1 | v2.31.1-update-metadata-json-with-id | Adds ids to the locally stored metadata.json to help file moves keep track of the items |
|
||||
|
|
|
|||
48
server/migrations/v2.31.1-update-metadata-json-with-id.js
Normal file
48
server/migrations/v2.31.1-update-metadata-json-with-id.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @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.1'
|
||||
const migrationName = `${migrationVersion}-update-metadata-json-with-id`
|
||||
const loggerPrefix = `[${migrationVersion} migration]`
|
||||
|
||||
/**
|
||||
* This upward migration creates a sessions table and apiKeys 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: { logger } }) {
|
||||
// Upwards migration script
|
||||
logger.info(`${loggerPrefix} UPGRADE BEGIN: ${migrationName}`)
|
||||
// Re-save all metadata json files, the id field will be added
|
||||
const libraryItems = await Database.libraryItemModel.findAll()
|
||||
for (const libraryItem of libraryItems) {
|
||||
await libraryItem.saveMetadataFile()
|
||||
}
|
||||
logger.info(`${loggerPrefix} UPGRADE END: ${migrationName}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* This downward migration script removes the sessions table and apiKeys 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: { logger } }) {
|
||||
// Downward migration script
|
||||
logger.info(`${loggerPrefix} DOWNGRADE BEGIN: ${migrationName}`)
|
||||
// Re-save all metadata json files, the id field will be removed
|
||||
const libraryItems = await Database.libraryItemModel.findAll()
|
||||
for (const libraryItem of libraryItems) {
|
||||
await libraryItem.saveMetadataFile()
|
||||
}
|
||||
logger.info(`${loggerPrefix} DOWNGRADE END: ${migrationName}`)
|
||||
}
|
||||
|
||||
module.exports = { up, down }
|
||||
|
|
@ -574,6 +574,7 @@ class LibraryItem extends Model {
|
|||
let jsonObject = {}
|
||||
if (this.mediaType === 'book') {
|
||||
jsonObject = {
|
||||
id: this.id,
|
||||
tags: mediaExpanded.tags || [],
|
||||
chapters: mediaExpanded.chapters?.map((c) => ({ ...c })) || [],
|
||||
title: mediaExpanded.title,
|
||||
|
|
@ -598,6 +599,7 @@ class LibraryItem extends Model {
|
|||
}
|
||||
} else {
|
||||
jsonObject = {
|
||||
id: this.id,
|
||||
tags: mediaExpanded.tags || [],
|
||||
title: mediaExpanded.title,
|
||||
author: mediaExpanded.author,
|
||||
|
|
@ -647,7 +649,7 @@ class LibraryItem extends Model {
|
|||
}
|
||||
}
|
||||
|
||||
Logger.debug(`[LibraryItem] Saved metadata for "${this.media.title}" file to "${metadataFilePath}"`)
|
||||
Logger.debug(`[LibraryItem] Saved metadata for "${mediaExpanded.title}" file to "${metadataFilePath}"`)
|
||||
|
||||
return metadataLibraryFile
|
||||
})
|
||||
|
|
|
|||
|
|
@ -298,6 +298,7 @@ class ApiRouter {
|
|||
this.router.delete('/tools/item/:id/encode-m4b', ToolsController.middleware.bind(this), ToolsController.cancelM4bEncode.bind(this))
|
||||
this.router.post('/tools/item/:id/embed-metadata', ToolsController.middleware.bind(this), ToolsController.embedAudioFileMetadata.bind(this))
|
||||
this.router.post('/tools/batch/embed-metadata', ToolsController.middleware.bind(this), ToolsController.batchEmbedMetadata.bind(this))
|
||||
this.router.post('/tools/batch/update-metadata-files', ToolsController.middleware.bind(this), ToolsController.updateAllItemMetadata.bind(this))
|
||||
|
||||
//
|
||||
// RSS Feed Routes (Admin and up)
|
||||
|
|
|
|||
|
|
@ -821,6 +821,7 @@ class BookScanner {
|
|||
const metadataFilePath = Path.join(metadataPath, `metadata.${global.ServerSettings.metadataFileFormat}`)
|
||||
|
||||
const jsonObject = {
|
||||
id: libraryItem.id,
|
||||
tags: libraryItem.media.tags || [],
|
||||
chapters: libraryItem.media.chapters?.map((c) => ({ ...c })) || [],
|
||||
title: libraryItem.media.title,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ const LibraryItemScanner = require('./LibraryItemScanner')
|
|||
const LibraryScan = require('./LibraryScan')
|
||||
const LibraryItemScanData = require('./LibraryItemScanData')
|
||||
const Task = require('../objects/Task')
|
||||
const abmetadataGenerator = require('../utils/generators/abmetadataGenerator')
|
||||
|
||||
class LibraryScanner {
|
||||
constructor() {
|
||||
|
|
@ -574,7 +575,7 @@ class LibraryScanner {
|
|||
let updatedLibraryItemDetails = {}
|
||||
if (!existingLibraryItem) {
|
||||
const isSingleMedia = isSingleMediaFile(fileUpdateGroup, itemDir)
|
||||
existingLibraryItem = (await findLibraryItemByItemToItemInoMatch(library.id, fullPath)) || (await findLibraryItemByItemToFileInoMatch(library.id, fullPath, isSingleMedia)) || (await findLibraryItemByFileToItemInoMatch(library.id, fullPath, isSingleMedia, fileUpdateGroup[itemDir]))
|
||||
existingLibraryItem = (await findLibraryItemByItemToItemInoMatch(library.id, fullPath)) || (await findLibraryItemByItemToFileInoMatch(library.id, fullPath, isSingleMedia)) || (await findLibraryItemByFileToItemInoMatch(library.id, fullPath, isSingleMedia, fileUpdateGroup[itemDir])) || (await findLibraryItemByItemToMetadata(fullPath, isSingleMedia))
|
||||
if (existingLibraryItem) {
|
||||
// Update library item paths for scan
|
||||
existingLibraryItem.path = fullPath
|
||||
|
|
@ -709,3 +710,23 @@ async function findLibraryItemByFileToItemInoMatch(libraryId, fullPath, isSingle
|
|||
if (existingLibraryItem) Logger.debug(`[LibraryScanner] Found library item with inode matching one of "${itemFileInos.join(',')}" at path "${existingLibraryItem.path}"`)
|
||||
return existingLibraryItem
|
||||
}
|
||||
|
||||
async function findLibraryItemByItemToMetadata(fullPath, isSingleMedia) {
|
||||
if (isSingleMedia) return null
|
||||
const metadataText = await fileUtils.readTextFile(Path.join(fullPath, 'metadata.json'))
|
||||
if (!metadataText) return null
|
||||
const abMetadata = abmetadataGenerator.parseJson(metadataText) || {}
|
||||
// check if metadata id exists in the database
|
||||
const existingLibraryItem = await Database.libraryItemModel.getExpandedById(abMetadata.id)
|
||||
|
||||
if (existingLibraryItem) {
|
||||
Logger.debug(`[LibraryScanner] Found library item with metadata id matching one of "${abMetadata.id}" at path "${existingLibraryItem.path}"`)
|
||||
|
||||
for (const { metadata } of existingLibraryItem.getLibraryFiles())
|
||||
if (await fs.pathExists(metadata.path)) {
|
||||
Logger.debug(`[LibraryScanner] Conflicting library files exist "${metadata.path}"`)
|
||||
return null
|
||||
}
|
||||
}
|
||||
return existingLibraryItem
|
||||
}
|
||||
|
|
|
|||
|
|
@ -421,6 +421,7 @@ class PodcastScanner {
|
|||
const metadataFilePath = Path.join(metadataPath, `metadata.${global.ServerSettings.metadataFileFormat}`)
|
||||
|
||||
const jsonObject = {
|
||||
id: libraryItem.id,
|
||||
tags: libraryItem.media.tags || [],
|
||||
title: libraryItem.media.title,
|
||||
author: libraryItem.media.author,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue