diff --git a/src/pages/tools/converters/audio-converter/service.ts b/src/pages/tools/converters/audio-converter/service.ts index e2676c3..aaac23e 100644 --- a/src/pages/tools/converters/audio-converter/service.ts +++ b/src/pages/tools/converters/audio-converter/service.ts @@ -1,6 +1,12 @@ import { FFmpeg } from '@ffmpeg/ffmpeg'; import { fetchFile } from '@ffmpeg/util'; +import { InitialValuesType, AUDIO_FORMATS } from './types'; +import { getFileExtension } from 'utils/file'; +/** + * optimzed call for FFmpeg instance creation, + * avoiding to download required FFmpeg binaries on every reload + */ const ffmpeg = new FFmpeg(); let isLoaded = false; @@ -21,80 +27,50 @@ async function loadFFmpeg() { */ export async function convertAudio( input: File, - outputFormat: 'mp3' | 'aac' | 'wav' + options: InitialValuesType ): Promise { await loadFFmpeg(); // Use the original input extension for input filename - const inputExtMatch = input.name.match(/\.[^.]+$/); - const inputExt = inputExtMatch ? inputExtMatch[0] : '.audio'; + const inputExt = getFileExtension(input.name); - const inputFileName = `input${inputExt}`; - const outputFileName = `output.${outputFormat}`; + if (inputExt === options.outputFormat) return input; + + const inputFileName = inputExt ? `input.${inputExt}` : 'input'; + const outputFileName = `output.${options.outputFormat}`; // Write the input file to FFmpeg FS await ffmpeg.writeFile(inputFileName, await fetchFile(input)); // Build the FFmpeg args depending on the output format // You can customize the codec and bitrate options per format here - let args: string[]; - switch (outputFormat) { - case 'mp3': - args = [ - '-i', - inputFileName, - '-c:a', - 'libmp3lame', - '-b:a', - '192k', - outputFileName - ]; - break; + const format = AUDIO_FORMATS[options.outputFormat]; + const { codec, bitrate, mimeType } = format; - case 'aac': - args = [ - '-i', - inputFileName, - '-c:a', - 'aac', - '-b:a', - '192k', - outputFileName - ]; - break; - - case 'wav': - args = ['-i', inputFileName, '-c:a', 'pcm_s16le', outputFileName]; - break; - - default: - throw new Error(`Unsupported output format: ${outputFormat}`); - } + const args = bitrate + ? ['-i', inputFileName, '-c:a', codec, '-b:a', bitrate, outputFileName] + : ['-i', inputFileName, '-c:a', codec, outputFileName]; // Execute ffmpeg with arguments - await ffmpeg.exec(args); + try { + await ffmpeg.exec(args); - // Read the output file from FFmpeg FS - const data = await ffmpeg.readFile(outputFileName); + // Read the output file from FFmpeg FS + const data = await ffmpeg.readFile(outputFileName); - // Determine MIME type by outputFormat - let mimeType = ''; - switch (outputFormat) { - case 'mp3': - mimeType = 'audio/mpeg'; - break; - case 'aac': - mimeType = 'audio/aac'; - break; - case 'wav': - mimeType = 'audio/wav'; - break; + // Create a new File with the original name but new extension + const baseName = input.name.replace(/\.[^.]+$/, ''); + const convertedFileName = `${baseName}.${options.outputFormat}`; + + return new File([data], convertedFileName, { type: mimeType }); + } finally { + // Clean up FFmpeg virtual filesystem + try { + await ffmpeg.deleteFile(inputFileName); + await ffmpeg.deleteFile(outputFileName); + } catch (e) { + // Ignore cleanup errors + } } - - // Create a new File with the original name but new extension - const baseName = input.name.replace(/\.[^.]+$/, ''); - const convertedFileName = `${baseName}.${outputFormat}`; - - return new File([data], convertedFileName, { type: mimeType }); }