flnxi-Wu/lib/audio-processor.ts
WuYongJie 63ec6b7dfb fix: 修复排行榜按钮消失、tag排序和输入框浅色模式问题
1. 排行榜悬浮窗关闭后小按钮消失问题
   - 修复面板居中模式关闭时按钮位置错误
   - 保存并恢复按钮的居中状态

2. 首页tag按钮按素材数量排序
   - 添加按素材数量降序排序逻辑

3. 上传弹窗输入框浅色模式文字不可见
   - 添加 text-slate-900 确保浅色模式下文字可见
   - 添加 placeholder 样式确保占位符正确显示
2025-12-14 21:41:29 +08:00

84 lines
1.9 KiB
TypeScript

/**
* 音频处理工具
*
* 提供音频文件的解析和处理功能
*
* @module audio-processor
* @created 2025-12-14
*/
import { parseBuffer } from 'music-metadata'
/**
* 音频元数据
*/
export interface AudioMetadata {
duration: number // 时长(秒)
durationFormatted: string // 格式化时长 (mm:ss)
format: string // 音频格式
bitrate?: number // 比特率
sampleRate?: number // 采样率
channels?: number // 声道数
}
/**
* 格式化时长为 mm:ss 格式
*/
export function formatDuration(seconds: number): string {
const mins = Math.floor(seconds / 60)
const secs = Math.floor(seconds % 60)
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
}
/**
* 解析音频文件获取元数据
*
* @param buffer - 音频文件的 Buffer
* @param mimeType - 音频文件的 MIME 类型
* @returns 音频元数据
*/
export async function parseAudioMetadata(
buffer: Buffer,
mimeType?: string
): Promise<AudioMetadata | null> {
try {
const metadata = await parseBuffer(buffer, { mimeType })
const duration = metadata.format.duration || 0
return {
duration,
durationFormatted: formatDuration(duration),
format: metadata.format.container || 'unknown',
bitrate: metadata.format.bitrate,
sampleRate: metadata.format.sampleRate,
channels: metadata.format.numberOfChannels,
}
} catch (error) {
console.error('[AudioProcessor] Failed to parse audio metadata:', error)
return null
}
}
/**
* 检查文件是否为音频文件
*/
export function isAudioFile(mimeType: string): boolean {
return mimeType.startsWith('audio/')
}
/**
* 支持的音频格式
*/
export const SUPPORTED_AUDIO_FORMATS = [
'audio/mpeg', // MP3
'audio/wav', // WAV
'audio/x-wav',
'audio/flac', // FLAC
'audio/aac', // AAC
'audio/mp4', // M4A
'audio/x-m4a',
'audio/ogg', // OGG
'audio/webm', // WebM
]