UNPKG

vite-combine-audio

Version:

Combines audio files into a single file to be used as an audio sprite

1 lines 16.7 kB
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["import { ResolvedConfig } from 'vite';\r\nimport * as fse from 'fs-extra';\r\nimport * as path from 'path';\r\nimport { execSync } from 'child_process';\r\nimport ffmpegPath from 'ffmpeg-static'; // Import the ffmpeg-static binary\r\nimport { writeFileSync, existsSync, createReadStream } from 'node:fs';\r\n\r\ntype Options = {\r\n fileRegex?: RegExp; // Regex to match audio files (default: /\\.mp3$/)\r\n outputTypes?: string[]; // Default output types\r\n filename?: string; // Default filename for the merged audio file\r\n tempDir?: string; // Default temporary directory\r\n outputDir?: string; // Default output directory\r\n};\r\n\r\nfunction debounce(func: Function, wait: number) {\r\n let timeout: NodeJS.Timeout;\r\n return function executedFunction(...args: any[]) {\r\n //@ts-ignore\r\n const context: any = this;\r\n const later = () => {\r\n //@ts-ignore\r\n timeout = undefined;\r\n func.apply(context, args);\r\n };\r\n clearTimeout(timeout);\r\n timeout = setTimeout(later, wait);\r\n };\r\n}\r\n\r\nexport default function combineAudio(options: Options = {}) {\r\n let config: ResolvedConfig;\r\n // Store paths of all .mp3 files\r\n const audioFiles: string[] = [];\r\n\r\n // Default filename for the merged audio file\r\n let filename = options.filename || 'merged-audio';\r\n // Default temporary and output directories\r\n let tempDir: string = options.tempDir || 'temp/audio';\r\n let outputDir: string = options.outputDir || 'audio';\r\n let tempBuildDir: string = options.tempDir || 'temp/audio';\r\n let outputBuildDir: string = options.outputDir || 'dist/audio';\r\n\r\n // Cumulative current time for audio file starts\r\n let currentTime = 0;\r\n\r\n const fileRegex = options.fileRegex || /\\.mp3$/;\r\n const outputTypes = options.outputTypes || ['.mp3', '.webm']; // Default output types\r\n\r\n let lastAudioLength = 0; // Store the last length of audio files\r\n let runBuild = debounce(() => {\r\n if (lastAudioLength !== audioFiles.length && config.command === 'serve') {\r\n lastAudioLength = audioFiles.length; // Update the last length of audio files\r\n // Run the build process after a delay\r\n plugin.buildEnd();\r\n }\r\n }, 500);\r\n\r\n let plugin = {\r\n name: 'audio-build',\r\n\r\n configResolved(_config: ResolvedConfig) {\r\n config = _config;\r\n // console.log('config:', config); // Log the resolved config for debugging\r\n\r\n tempDir = (config.base + tempDir).replace(/\\\\/g, '/'); // Normalize path for Windows compatibility\r\n outputDir = (config.base + outputDir).replace(/\\\\/g, '/'); // Normalize path for Windows compatibility\r\n\r\n tempBuildDir = path.resolve(config.root, tempBuildDir); // Resolve the path for development server\r\n outputBuildDir = path.resolve(config.root, outputBuildDir); // Resolve the path for development server\r\n },\r\n\r\n async transform(src: string, id: string) {\r\n if (fileRegex.test(id)) {\r\n\r\n // Collect all valid files\r\n if(!audioFiles.includes(id)){\r\n audioFiles.push(id);\r\n }\r\n\r\n let file = id;\r\n let dataItem: {\r\n output: Array<string>,\r\n filename: string,\r\n startTime: number,\r\n duration: number\r\n } = {} as any; // Initialize dataItem with an empty object\r\n\r\n let outputs = [];\r\n if (config.command === 'build') {\r\n if(outputTypes.includes('.webm')){\r\n outputs.push(path.join(outputDir, filename+'.webm'));\r\n }\r\n if(outputTypes.includes('.mp3')){\r\n outputs.push(path.join(outputDir, filename+'.mp3'));\r\n }\r\n }\r\n else{\r\n if (outputTypes.includes('.webm')) {\r\n outputs.push(path.join(tempDir, filename + '.webm'));\r\n }\r\n if (outputTypes.includes('.mp3')) {\r\n outputs.push(path.join(tempDir, filename + '.mp3'));\r\n }\r\n }\r\n\r\n\r\n // Generate metadata for each file\r\n try {\r\n const sanitizedFilePath = file.replace(/\\\\/g, '/');\r\n\r\n // Log the command for debugging\r\n // console.log(`Running command: \"${ffmpegPath}\" -i \"${sanitizedFilePath}\"`);\r\n\r\n // Get the duration of the current file using ffmpeg-static\r\n const durationOutput = execSync(\r\n `\"${ffmpegPath}\" -i \"${sanitizedFilePath}\" 2>&1`,\r\n { encoding: 'utf-8' }\r\n );\r\n\r\n const durationMatch = durationOutput.match(/Duration: (\\d+):(\\d+):(\\d+\\.\\d+)/);\r\n if (durationMatch) {\r\n const [, hours, minutes, seconds] = durationMatch;\r\n const duration =\r\n parseInt(hours) * 3600 * 1000 + // Hours to milliseconds\r\n parseInt(minutes) * 60 * 1000 + // Minutes to milliseconds\r\n Math.round(parseFloat(seconds) * 1000); // Seconds to milliseconds\r\n\r\n dataItem = {\r\n output: outputs,\r\n filename: path.basename(file),\r\n startTime: currentTime,\r\n duration\r\n };\r\n\r\n currentTime += duration; // Update the start time for the next file\r\n }\r\n } catch (error: any) {\r\n // Extract metadata from the error output\r\n const durationMatch = error.stdout.match(/Duration: (\\d+):(\\d+):(\\d+\\.\\d+)/);\r\n\r\n if (durationMatch) {\r\n const [, hours, minutes, seconds] = durationMatch;\r\n const duration =\r\n parseInt(hours) * 3600 * 1000 + // Hours to milliseconds\r\n parseInt(minutes) * 60 * 1000 + // Minutes to milliseconds\r\n Math.round(parseFloat(seconds) * 1000); // Seconds to milliseconds\r\n\r\n dataItem = {\r\n output: outputs,\r\n filename: path.basename(file),\r\n startTime: currentTime,\r\n duration\r\n };\r\n\r\n currentTime += duration; // Update the start time for the next file\r\n } else {\r\n console.error(`Error getting duration for ${file}:`, error);\r\n }\r\n }\r\n\r\n runBuild(); // Call the debounced function\r\n\r\n return {\r\n code: `export default ${JSON.stringify(dataItem)};`,\r\n map: null,\r\n };\r\n }\r\n },\r\n\r\n async buildEnd() {\r\n console.log('Audio files:', audioFiles); // Log the collected audio files\r\n\r\n if (audioFiles.length === 0) return;\r\n\r\n // Ensure the output directory exists\r\n fse.ensureDirSync(outputBuildDir);\r\n fse.ensureDirSync(tempBuildDir);\r\n\r\n // Create a temporary file listing all .mp3 files for ffmpeg\r\n const concatFilePath = path.join(tempBuildDir, 'concat-list.txt');\r\n const concatFileContent = audioFiles\r\n .map((file) => `file '${file.replace(/\\\\/g, '/')}'`) // Escape Windows paths\r\n .join('\\n');\r\n writeFileSync(concatFilePath, concatFileContent);\r\n\r\n // Merge the .mp3 files using ffmpeg-static\r\n try {\r\n let mp3Path = path.join(tempBuildDir, filename+'.mp3');\r\n execSync(\r\n `\"${ffmpegPath}\" -loglevel error -y -f concat -safe 0 -i \"${concatFilePath}\" -c copy \"${mp3Path}\"`,\r\n { stdio: 'inherit' }\r\n );\r\n }\r\n catch (error) {\r\n console.error('Error merging audio files:', error);\r\n throw error;\r\n }\r\n\r\n // Generate the .webm file\r\n if (outputTypes.includes('.webm')){\r\n const webmPath = path.join(tempBuildDir, filename+'.webm');\r\n let mp3Path = path.join(tempBuildDir, filename + '.mp3');\r\n try {\r\n execSync(\r\n `\"${ffmpegPath}\" -loglevel error -y -i \"${mp3Path}\" -c:a libvorbis \"${webmPath}\"`,\r\n { stdio: 'inherit' }\r\n );\r\n }\r\n catch (error) {\r\n console.error('Error converting merged audio to .webm:', error);\r\n throw error;\r\n }\r\n }\r\n\r\n // Clean up the temporary concat file\r\n fse.remove(concatFilePath);\r\n },\r\n\r\n writeBundle() {\r\n // Ensure the merged file is preserved in the dist folder\r\n if(outputTypes.includes('.mp3')){\r\n let mp3Path = path.join(tempBuildDir, filename + '.mp3');\r\n let mp3OuputPath = path.join(outputBuildDir, filename + '.mp3');\r\n fse.move(mp3Path, mp3OuputPath);\r\n }\r\n\r\n if (outputTypes.includes('.webm')){\r\n const webmPath = path.join(tempBuildDir, filename+'.webm');\r\n const outputwebmPath = path.join(outputBuildDir, filename+'.webm');\r\n fse.move(webmPath, outputwebmPath);\r\n }\r\n },\r\n\r\n configureServer(server: any) {\r\n // Serve the merged audio file during development\r\n server.middlewares.use((req: any, res: any, next: any) => {\r\n let tempMp3Path = path.join(tempDir, filename + '.mp3').replace(/\\\\/g, '/');\r\n let tempWebmPath = path.join(tempDir, filename + '.webm').replace(/\\\\/g, '/');\r\n\r\n if (req.url === tempMp3Path || req.url === tempWebmPath) {\r\n // if (audioFiles.indexOf(req.url) !== -1) {\r\n const filePath = path.join(config.root, req.url).replace(/\\\\/g, '/');\r\n\r\n if (existsSync(filePath)) {\r\n res.setHeader('Content-Type', req.url.endsWith('.mp3') ? 'audio/mpeg' : 'audio/webm');\r\n createReadStream(filePath).pipe(res);\r\n return;\r\n }\r\n else {\r\n res.statusCode = 404;\r\n res.end('File not found');\r\n return;\r\n }\r\n }\r\n next();\r\n });\r\n },\r\n };\r\n\r\n return plugin;\r\n}"],"names":[],"mappings":"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"}