mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-11-03 19:07:00 -05:00 
			
		
		
		
	Merge pull request #3204 from mikiher/embed-permissions
Fix permission issues in embed/merge
This commit is contained in:
		
						commit
						a77f4e9d77
					
				@ -7,7 +7,7 @@ const { writeConcatFile } = require('../utils/ffmpegHelpers')
 | 
				
			|||||||
const ffmpegHelpers = require('../utils/ffmpegHelpers')
 | 
					const ffmpegHelpers = require('../utils/ffmpegHelpers')
 | 
				
			||||||
const Ffmpeg = require('../libs/fluentFfmpeg')
 | 
					const Ffmpeg = require('../libs/fluentFfmpeg')
 | 
				
			||||||
const SocketAuthority = require('../SocketAuthority')
 | 
					const SocketAuthority = require('../SocketAuthority')
 | 
				
			||||||
const fileUtils = require('../utils/fileUtils')
 | 
					const { isWritable, copyToExisting } = require('../utils/fileUtils')
 | 
				
			||||||
const TrackProgressMonitor = require('../objects/TrackProgressMonitor')
 | 
					const TrackProgressMonitor = require('../objects/TrackProgressMonitor')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AbMergeManager {
 | 
					class AbMergeManager {
 | 
				
			||||||
@ -64,7 +64,7 @@ class AbMergeManager {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  async runAudiobookMerge(libraryItem, task, encodingOptions) {
 | 
					  async runAudiobookMerge(libraryItem, task, encodingOptions) {
 | 
				
			||||||
    // Make sure the target directory is writable
 | 
					    // Make sure the target directory is writable
 | 
				
			||||||
    if (!(await fileUtils.isWritable(libraryItem.path))) {
 | 
					    if (!(await isWritable(libraryItem.path))) {
 | 
				
			||||||
      Logger.error(`[AbMergeManager] Target directory is not writable: ${libraryItem.path}`)
 | 
					      Logger.error(`[AbMergeManager] Target directory is not writable: ${libraryItem.path}`)
 | 
				
			||||||
      task.setFailed('Target directory is not writable')
 | 
					      task.setFailed('Target directory is not writable')
 | 
				
			||||||
      this.removeTask(task, true)
 | 
					      this.removeTask(task, true)
 | 
				
			||||||
@ -139,18 +139,35 @@ class AbMergeManager {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Move library item tracks to cache
 | 
					    // Move library item tracks to cache
 | 
				
			||||||
    for (const trackPath of task.data.originalTrackPaths) {
 | 
					    for (const [index, trackPath] of task.data.originalTrackPaths.entries()) {
 | 
				
			||||||
      const trackFilename = Path.basename(trackPath)
 | 
					      const trackFilename = Path.basename(trackPath)
 | 
				
			||||||
      const moveToPath = Path.join(task.data.itemCachePath, trackFilename)
 | 
					      const moveToPath = Path.join(task.data.itemCachePath, trackFilename)
 | 
				
			||||||
      Logger.debug(`[AbMergeManager] Backing up original track "${trackPath}" to ${moveToPath}`)
 | 
					      Logger.debug(`[AbMergeManager] Backing up original track "${trackPath}" to ${moveToPath}`)
 | 
				
			||||||
 | 
					      if (index === 0) {
 | 
				
			||||||
 | 
					        // copy the first track to the cache directory
 | 
				
			||||||
 | 
					        await fs.copy(trackPath, moveToPath).catch((err) => {
 | 
				
			||||||
 | 
					          Logger.error(`[AbMergeManager] Failed to copy track "${trackPath}" to "${moveToPath}"`, err)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        // move the rest of the tracks to the cache directory
 | 
				
			||||||
        await fs.move(trackPath, moveToPath, { overwrite: true }).catch((err) => {
 | 
					        await fs.move(trackPath, moveToPath, { overwrite: true }).catch((err) => {
 | 
				
			||||||
          Logger.error(`[AbMergeManager] Failed to move track "${trackPath}" to "${moveToPath}"`, err)
 | 
					          Logger.error(`[AbMergeManager] Failed to move track "${trackPath}" to "${moveToPath}"`, err)
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Move m4b to target
 | 
					    // Move m4b to target, preserving the original track's permissions
 | 
				
			||||||
    Logger.debug(`[AbMergeManager] Moving m4b from ${task.data.tempFilepath} to ${task.data.targetFilepath}`)
 | 
					    Logger.debug(`[AbMergeManager] Moving m4b from ${task.data.tempFilepath} to ${task.data.targetFilepath}`)
 | 
				
			||||||
    await fs.move(task.data.tempFilepath, task.data.targetFilepath)
 | 
					    try {
 | 
				
			||||||
 | 
					      await copyToExisting(task.data.tempFilepath, task.data.originalTrackPaths[0])
 | 
				
			||||||
 | 
					      await fs.rename(task.data.originalTrackPaths[0], task.data.targetFilepath)
 | 
				
			||||||
 | 
					      await fs.remove(task.data.tempFilepath)
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      Logger.error(`[AbMergeManager] Failed to move m4b from ${task.data.tempFilepath} to ${task.data.targetFilepath}`, err)
 | 
				
			||||||
 | 
					      task.setFailed('Failed to move m4b file')
 | 
				
			||||||
 | 
					      this.removeTask(task, true)
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Remove ffmetadata file
 | 
					    // Remove ffmetadata file
 | 
				
			||||||
    await fs.remove(task.data.ffmetadataPath)
 | 
					    await fs.remove(task.data.ffmetadataPath)
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@ const ffmpgegUtils = require('../libs/fluentFfmpeg/utils')
 | 
				
			|||||||
const fs = require('../libs/fsExtra')
 | 
					const fs = require('../libs/fsExtra')
 | 
				
			||||||
const Path = require('path')
 | 
					const Path = require('path')
 | 
				
			||||||
const Logger = require('../Logger')
 | 
					const Logger = require('../Logger')
 | 
				
			||||||
const { filePathToPOSIX } = require('./fileUtils')
 | 
					const { filePathToPOSIX, copyToExisting } = require('./fileUtils')
 | 
				
			||||||
const LibraryItem = require('../objects/LibraryItem')
 | 
					const LibraryItem = require('../objects/LibraryItem')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function escapeSingleQuotes(path) {
 | 
					function escapeSingleQuotes(path) {
 | 
				
			||||||
@ -250,11 +250,12 @@ module.exports.writeFFMetadataFile = writeFFMetadataFile
 | 
				
			|||||||
 * @param {string} metadataFilePath - Path to the ffmetadata file.
 | 
					 * @param {string} metadataFilePath - Path to the ffmetadata file.
 | 
				
			||||||
 * @param {number} track - The track number to embed in the audio file.
 | 
					 * @param {number} track - The track number to embed in the audio file.
 | 
				
			||||||
 * @param {string} mimeType - The MIME type of the audio file.
 | 
					 * @param {string} mimeType - The MIME type of the audio file.
 | 
				
			||||||
 * @param {Ffmpeg} ffmpeg - The Ffmpeg instance to use (optional). Used for dependency injection in tests.
 | 
					 | 
				
			||||||
 * @param {function(number): void|null} progressCB - A callback function to report progress.
 | 
					 * @param {function(number): void|null} progressCB - A callback function to report progress.
 | 
				
			||||||
 | 
					 * @param {Ffmpeg} ffmpeg - The Ffmpeg instance to use (optional). Used for dependency injection in tests.
 | 
				
			||||||
 | 
					 * @param {function(string, string): Promise<void>} copyFunc - The function to use for copying files (optional). Used for dependency injection in tests.
 | 
				
			||||||
 * @returns {Promise<void>} A promise that resolves if the operation is successful, rejects otherwise.
 | 
					 * @returns {Promise<void>} A promise that resolves if the operation is successful, rejects otherwise.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
async function addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, progressCB = null, ffmpeg = Ffmpeg()) {
 | 
					async function addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, progressCB = null, ffmpeg = Ffmpeg(), copyFunc = copyToExisting) {
 | 
				
			||||||
  const isMp4 = mimeType === 'audio/mp4'
 | 
					  const isMp4 = mimeType === 'audio/mp4'
 | 
				
			||||||
  const isMp3 = mimeType === 'audio/mpeg'
 | 
					  const isMp3 = mimeType === 'audio/mpeg'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -316,7 +317,8 @@ async function addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataF
 | 
				
			|||||||
        Logger.debug('[ffmpegHelpers] ffmpeg stderr:', stderr)
 | 
					        Logger.debug('[ffmpegHelpers] ffmpeg stderr:', stderr)
 | 
				
			||||||
        Logger.debug('[ffmpegHelpers] Moving temp file to audio file path:', `"${tempFilePath}"`, '->', `"${audioFilePath}"`)
 | 
					        Logger.debug('[ffmpegHelpers] Moving temp file to audio file path:', `"${tempFilePath}"`, '->', `"${audioFilePath}"`)
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
          await fs.move(tempFilePath, audioFilePath, { overwrite: true })
 | 
					          await copyFunc(tempFilePath, audioFilePath)
 | 
				
			||||||
 | 
					          await fs.remove(tempFilePath)
 | 
				
			||||||
          resolve()
 | 
					          resolve()
 | 
				
			||||||
        } catch (error) {
 | 
					        } catch (error) {
 | 
				
			||||||
          Logger.error(`[ffmpegHelpers] Failed to move temp file to audio file path: "${tempFilePath}" -> "${audioFilePath}"`, error)
 | 
					          Logger.error(`[ffmpegHelpers] Failed to move temp file to audio file path: "${tempFilePath}" -> "${audioFilePath}"`, error)
 | 
				
			||||||
 | 
				
			|||||||
@ -464,3 +464,46 @@ module.exports.getDirectoriesInPath = async (dirPath, level) => {
 | 
				
			|||||||
    return []
 | 
					    return []
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copies a file from the source path to an existing destination path, preserving the destination's permissions.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param {string} srcPath - The path of the source file.
 | 
				
			||||||
 | 
					 * @param {string} destPath - The path of the existing destination file.
 | 
				
			||||||
 | 
					 * @returns {Promise<void>} A promise that resolves when the file has been successfully copied.
 | 
				
			||||||
 | 
					 * @throws {Error} If there is an error reading the source file or writing the destination file.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					async function copyToExisting(srcPath, destPath) {
 | 
				
			||||||
 | 
					  return new Promise((resolve, reject) => {
 | 
				
			||||||
 | 
					    // Create a readable stream from the source file
 | 
				
			||||||
 | 
					    const readStream = fs.createReadStream(srcPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Create a writable stream to the destination file
 | 
				
			||||||
 | 
					    const writeStream = fs.createWriteStream(destPath, { flags: 'w' })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Pipe the read stream to the write stream
 | 
				
			||||||
 | 
					    readStream.pipe(writeStream)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Handle the end of the stream
 | 
				
			||||||
 | 
					    writeStream.on('finish', () => {
 | 
				
			||||||
 | 
					      Logger.debug(`[copyToExisting] Successfully copied file from ${srcPath} to ${destPath}`)
 | 
				
			||||||
 | 
					      resolve()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Handle errors
 | 
				
			||||||
 | 
					    readStream.on('error', (error) => {
 | 
				
			||||||
 | 
					      Logger.error(`[copyToExisting] Error reading from source file ${srcPath}: ${error.message}`)
 | 
				
			||||||
 | 
					      readStream.close()
 | 
				
			||||||
 | 
					      writeStream.close()
 | 
				
			||||||
 | 
					      reject(error)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    writeStream.on('error', (error) => {
 | 
				
			||||||
 | 
					      Logger.error(`[copyToExisting] Error writing to destination file ${destPath}: ${error.message}`)
 | 
				
			||||||
 | 
					      readStream.close()
 | 
				
			||||||
 | 
					      writeStream.close()
 | 
				
			||||||
 | 
					      reject(error)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					module.exports.copyToExisting = copyToExisting
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,11 @@
 | 
				
			|||||||
const { expect } = require('chai')
 | 
					const { expect } = require('chai')
 | 
				
			||||||
const sinon = require('sinon')
 | 
					const sinon = require('sinon')
 | 
				
			||||||
const { generateFFMetadata, addCoverAndMetadataToFile } = require('../../../server/utils/ffmpegHelpers')
 | 
					const fileUtils = require('../../../server/utils/fileUtils')
 | 
				
			||||||
const fs = require('../../../server/libs/fsExtra')
 | 
					const fs = require('../../../server/libs/fsExtra')
 | 
				
			||||||
const EventEmitter = require('events')
 | 
					const EventEmitter = require('events')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { generateFFMetadata, addCoverAndMetadataToFile } = require('../../../server/utils/ffmpegHelpers')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
global.isWin = process.platform === 'win32'
 | 
					global.isWin = process.platform === 'win32'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('generateFFMetadata', () => {
 | 
					describe('generateFFMetadata', () => {
 | 
				
			||||||
@ -81,9 +83,10 @@ describe('addCoverAndMetadataToFile', () => {
 | 
				
			|||||||
    ffmpegStub.run = sinon.stub().callsFake(() => {
 | 
					    ffmpegStub.run = sinon.stub().callsFake(() => {
 | 
				
			||||||
      ffmpegStub.emit('end')
 | 
					      ffmpegStub.emit('end')
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
    const fsMove = sinon.stub(fs, 'move').resolves()
 | 
					    const copyStub = sinon.stub().resolves()
 | 
				
			||||||
 | 
					    const fsRemoveStub = sinon.stub(fs, 'remove').resolves()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return { audioFilePath, coverFilePath, metadataFilePath, track, mimeType, ffmpegStub, fsMove }
 | 
					    return { audioFilePath, coverFilePath, metadataFilePath, track, mimeType, ffmpegStub, copyStub, fsRemoveStub }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let audioFilePath = null
 | 
					  let audioFilePath = null
 | 
				
			||||||
@ -92,7 +95,8 @@ describe('addCoverAndMetadataToFile', () => {
 | 
				
			|||||||
  let track = null
 | 
					  let track = null
 | 
				
			||||||
  let mimeType = null
 | 
					  let mimeType = null
 | 
				
			||||||
  let ffmpegStub = null
 | 
					  let ffmpegStub = null
 | 
				
			||||||
  let fsMove = null
 | 
					  let copyStub = null
 | 
				
			||||||
 | 
					  let fsRemoveStub = null
 | 
				
			||||||
  beforeEach(() => {
 | 
					  beforeEach(() => {
 | 
				
			||||||
    const input = createTestSetup()
 | 
					    const input = createTestSetup()
 | 
				
			||||||
    audioFilePath = input.audioFilePath
 | 
					    audioFilePath = input.audioFilePath
 | 
				
			||||||
@ -101,12 +105,13 @@ describe('addCoverAndMetadataToFile', () => {
 | 
				
			|||||||
    track = input.track
 | 
					    track = input.track
 | 
				
			||||||
    mimeType = input.mimeType
 | 
					    mimeType = input.mimeType
 | 
				
			||||||
    ffmpegStub = input.ffmpegStub
 | 
					    ffmpegStub = input.ffmpegStub
 | 
				
			||||||
    fsMove = input.fsMove
 | 
					    copyStub = input.copyStub
 | 
				
			||||||
 | 
					    fsRemoveStub = input.fsRemoveStub
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should add cover image and metadata to audio file', async () => {
 | 
					  it('should add cover image and metadata to audio file', async () => {
 | 
				
			||||||
    // Act
 | 
					    // Act
 | 
				
			||||||
    await addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, null, ffmpegStub)
 | 
					    await addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, null, ffmpegStub, copyStub)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Assert
 | 
					    // Assert
 | 
				
			||||||
    expect(ffmpegStub.input.calledThrice).to.be.true
 | 
					    expect(ffmpegStub.input.calledThrice).to.be.true
 | 
				
			||||||
@ -125,10 +130,11 @@ describe('addCoverAndMetadataToFile', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    expect(ffmpegStub.run.calledOnce).to.be.true
 | 
					    expect(ffmpegStub.run.calledOnce).to.be.true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    expect(fsMove.calledOnce).to.be.true
 | 
					    expect(copyStub.calledOnce).to.be.true
 | 
				
			||||||
    expect(fsMove.firstCall.args[0]).to.equal('/path/to/audio/file.tmp.mp3')
 | 
					    expect(copyStub.firstCall.args[0]).to.equal('/path/to/audio/file.tmp.mp3')
 | 
				
			||||||
    expect(fsMove.firstCall.args[1]).to.equal('/path/to/audio/file.mp3')
 | 
					    expect(copyStub.firstCall.args[1]).to.equal('/path/to/audio/file.mp3')
 | 
				
			||||||
    expect(fsMove.firstCall.args[2]).to.deep.equal({ overwrite: true })
 | 
					    expect(fsRemoveStub.calledOnce).to.be.true
 | 
				
			||||||
 | 
					    expect(fsRemoveStub.firstCall.args[0]).to.equal('/path/to/audio/file.tmp.mp3')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Restore the stub
 | 
					    // Restore the stub
 | 
				
			||||||
    sinon.restore()
 | 
					    sinon.restore()
 | 
				
			||||||
@ -139,7 +145,7 @@ describe('addCoverAndMetadataToFile', () => {
 | 
				
			|||||||
    coverFilePath = null
 | 
					    coverFilePath = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Act
 | 
					    // Act
 | 
				
			||||||
    await addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, null, ffmpegStub)
 | 
					    await addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, null, ffmpegStub, copyStub)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Assert
 | 
					    // Assert
 | 
				
			||||||
    expect(ffmpegStub.input.calledTwice).to.be.true
 | 
					    expect(ffmpegStub.input.calledTwice).to.be.true
 | 
				
			||||||
@ -157,10 +163,11 @@ describe('addCoverAndMetadataToFile', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    expect(ffmpegStub.run.calledOnce).to.be.true
 | 
					    expect(ffmpegStub.run.calledOnce).to.be.true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    expect(fsMove.calledOnce).to.be.true
 | 
					    expect(copyStub.callCount).to.equal(1)
 | 
				
			||||||
    expect(fsMove.firstCall.args[0]).to.equal('/path/to/audio/file.tmp.mp3')
 | 
					    expect(copyStub.firstCall.args[0]).to.equal('/path/to/audio/file.tmp.mp3')
 | 
				
			||||||
    expect(fsMove.firstCall.args[1]).to.equal('/path/to/audio/file.mp3')
 | 
					    expect(copyStub.firstCall.args[1]).to.equal('/path/to/audio/file.mp3')
 | 
				
			||||||
    expect(fsMove.firstCall.args[2]).to.deep.equal({ overwrite: true })
 | 
					    expect(fsRemoveStub.calledOnce).to.be.true
 | 
				
			||||||
 | 
					    expect(fsRemoveStub.firstCall.args[0]).to.equal('/path/to/audio/file.tmp.mp3')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Restore the stub
 | 
					    // Restore the stub
 | 
				
			||||||
    sinon.restore()
 | 
					    sinon.restore()
 | 
				
			||||||
@ -174,7 +181,7 @@ describe('addCoverAndMetadataToFile', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Act
 | 
					    // Act
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      await addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, null, ffmpegStub)
 | 
					      await addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, null, ffmpegStub, copyStub)
 | 
				
			||||||
      expect.fail('Expected an error to be thrown')
 | 
					      expect.fail('Expected an error to be thrown')
 | 
				
			||||||
    } catch (error) {
 | 
					    } catch (error) {
 | 
				
			||||||
      // Assert
 | 
					      // Assert
 | 
				
			||||||
@ -198,7 +205,8 @@ describe('addCoverAndMetadataToFile', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    expect(ffmpegStub.run.calledOnce).to.be.true
 | 
					    expect(ffmpegStub.run.calledOnce).to.be.true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    expect(fsMove.called).to.be.false
 | 
					    expect(copyStub.called).to.be.false
 | 
				
			||||||
 | 
					    expect(fsRemoveStub.called).to.be.false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Restore the stub
 | 
					    // Restore the stub
 | 
				
			||||||
    sinon.restore()
 | 
					    sinon.restore()
 | 
				
			||||||
@ -210,7 +218,7 @@ describe('addCoverAndMetadataToFile', () => {
 | 
				
			|||||||
    audioFilePath = '/path/to/audio/file.m4b'
 | 
					    audioFilePath = '/path/to/audio/file.m4b'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Act
 | 
					    // Act
 | 
				
			||||||
    await addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, null, ffmpegStub)
 | 
					    await addCoverAndMetadataToFile(audioFilePath, coverFilePath, metadataFilePath, track, mimeType, null, ffmpegStub, copyStub)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Assert
 | 
					    // Assert
 | 
				
			||||||
    expect(ffmpegStub.input.calledThrice).to.be.true
 | 
					    expect(ffmpegStub.input.calledThrice).to.be.true
 | 
				
			||||||
@ -229,10 +237,11 @@ describe('addCoverAndMetadataToFile', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    expect(ffmpegStub.run.calledOnce).to.be.true
 | 
					    expect(ffmpegStub.run.calledOnce).to.be.true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    expect(fsMove.calledOnce).to.be.true
 | 
					    expect(copyStub.calledOnce).to.be.true
 | 
				
			||||||
    expect(fsMove.firstCall.args[0]).to.equal('/path/to/audio/file.tmp.m4b')
 | 
					    expect(copyStub.firstCall.args[0]).to.equal('/path/to/audio/file.tmp.m4b')
 | 
				
			||||||
    expect(fsMove.firstCall.args[1]).to.equal('/path/to/audio/file.m4b')
 | 
					    expect(copyStub.firstCall.args[1]).to.equal('/path/to/audio/file.m4b')
 | 
				
			||||||
    expect(fsMove.firstCall.args[2]).to.deep.equal({ overwrite: true })
 | 
					    expect(fsRemoveStub.calledOnce).to.be.true
 | 
				
			||||||
 | 
					    expect(fsRemoveStub.firstCall.args[0]).to.equal('/path/to/audio/file.tmp.m4b')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Restore the stub
 | 
					    // Restore the stub
 | 
				
			||||||
    sinon.restore()
 | 
					    sinon.restore()
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user