update for flac metadata on iphone/rpi
This commit is contained in:
+45
-27
@@ -26,6 +26,8 @@ const AUDIO_METADATA_EXTENSIONS = new Set([
|
||||
|
||||
let ffmpegInstance: FFmpeg | null = null
|
||||
let ffmpegLoadPromise: Promise<FFmpeg> | null = null
|
||||
let ffmpegOperationPromise: Promise<void> = Promise.resolve()
|
||||
let ffmpegTempFileCounter = 0
|
||||
|
||||
function sanitizeExtension(extension?: string | null) {
|
||||
return (extension || '').trim().replace(/^\./, '').toLowerCase()
|
||||
@@ -54,6 +56,17 @@ async function getFFmpeg() {
|
||||
}
|
||||
}
|
||||
|
||||
function createTempFileStem() {
|
||||
ffmpegTempFileCounter += 1
|
||||
return `metadata-${Date.now()}-${ffmpegTempFileCounter}`
|
||||
}
|
||||
|
||||
function queueFFmpegOperation<T>(operation: () => Promise<T>) {
|
||||
const pending = ffmpegOperationPromise.then(operation, operation)
|
||||
ffmpegOperationPromise = pending.then(() => undefined, () => undefined)
|
||||
return pending
|
||||
}
|
||||
|
||||
function buildMetadataArgs(metadata: AudioTagMetadata) {
|
||||
const args: string[] = []
|
||||
if (metadata.title) args.push('-metadata', `title=${metadata.title}`)
|
||||
@@ -74,37 +87,42 @@ export function supportsContainerMetadataEmbedding(extension?: string | null, mi
|
||||
export async function embedContainerAudioMetadata(blob: Blob, extension: string | undefined, metadata: AudioTagMetadata) {
|
||||
if (!metadata.title && !metadata.artist && !metadata.album && !metadata.trackNumber) return blob
|
||||
|
||||
const normalizedExtension = sanitizeExtension(extension) || 'audio'
|
||||
const ffmpeg = await getFFmpeg()
|
||||
const { fetchFile } = await import('@ffmpeg/util')
|
||||
const inputPath = `input.${normalizedExtension}`
|
||||
const outputPath = `output.${normalizedExtension}`
|
||||
return queueFFmpegOperation(async () => {
|
||||
const normalizedExtension = sanitizeExtension(extension) || 'audio'
|
||||
const ffmpeg = await getFFmpeg()
|
||||
const { fetchFile } = await import('@ffmpeg/util')
|
||||
const tempStem = createTempFileStem()
|
||||
const inputPath = `${tempStem}-input.${normalizedExtension}`
|
||||
const outputPath = `${tempStem}-output.${normalizedExtension}`
|
||||
|
||||
await ffmpeg.writeFile(inputPath, await fetchFile(blob))
|
||||
await ffmpeg.writeFile(inputPath, await fetchFile(blob))
|
||||
|
||||
try {
|
||||
const exitCode = await ffmpeg.exec([
|
||||
'-i', inputPath,
|
||||
'-map', '0',
|
||||
'-map_metadata', '-1',
|
||||
'-c', 'copy',
|
||||
...buildMetadataArgs(metadata),
|
||||
outputPath,
|
||||
])
|
||||
try {
|
||||
const exitCode = await ffmpeg.exec([
|
||||
'-nostdin',
|
||||
'-y',
|
||||
'-i', inputPath,
|
||||
'-map', '0',
|
||||
'-map_metadata', '-1',
|
||||
'-c', 'copy',
|
||||
...buildMetadataArgs(metadata),
|
||||
outputPath,
|
||||
])
|
||||
|
||||
if (exitCode !== 0) {
|
||||
throw new Error(`FFmpeg metadata update failed (${exitCode})`)
|
||||
if (exitCode !== 0) {
|
||||
throw new Error(`FFmpeg metadata update failed (${exitCode})`)
|
||||
}
|
||||
|
||||
const outputData = await ffmpeg.readFile(outputPath)
|
||||
const outputBytes = outputData instanceof Uint8Array ? outputData : new Uint8Array(new TextEncoder().encode(String(outputData)))
|
||||
const outputCopy = new Uint8Array(outputBytes.byteLength)
|
||||
outputCopy.set(outputBytes)
|
||||
return new Blob([outputCopy], { type: blob.type || 'application/octet-stream' })
|
||||
} finally {
|
||||
try { await ffmpeg.deleteFile(inputPath) } catch {}
|
||||
try { await ffmpeg.deleteFile(outputPath) } catch {}
|
||||
}
|
||||
|
||||
const outputData = await ffmpeg.readFile(outputPath)
|
||||
const outputBytes = outputData instanceof Uint8Array ? outputData : new Uint8Array(new TextEncoder().encode(String(outputData)))
|
||||
const outputCopy = new Uint8Array(outputBytes.byteLength)
|
||||
outputCopy.set(outputBytes)
|
||||
return new Blob([outputCopy], { type: blob.type || 'application/octet-stream' })
|
||||
} finally {
|
||||
try { await ffmpeg.deleteFile(inputPath) } catch {}
|
||||
try { await ffmpeg.deleteFile(outputPath) } catch {}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export type { AudioTagMetadata }
|
||||
Reference in New Issue
Block a user