(wavBuffer: Buffer)
| 154 | } |
| 155 | |
| 156 | export async function convertWavToMp3(wavBuffer: Buffer): Promise<Buffer> { |
| 157 | const ffmpeg = getFfmpegPath(); |
| 158 | const ffmpegArgs = [ |
| 159 | "-i", |
| 160 | "pipe:0", |
| 161 | "-acodec", |
| 162 | "libmp3lame", |
| 163 | "-b:a", |
| 164 | "128k", |
| 165 | "-f", |
| 166 | "mp3", |
| 167 | "-pipe:1", |
| 168 | ]; |
| 169 | |
| 170 | return new Promise((resolve, reject) => { |
| 171 | const proc = spawn(ffmpeg, ffmpegArgs, { stdio: ["pipe", "pipe", "pipe"] }); |
| 172 | |
| 173 | const chunks: Buffer[] = []; |
| 174 | let stderr = ""; |
| 175 | |
| 176 | proc.stdout?.on("data", (chunk: Buffer) => { |
| 177 | chunks.push(chunk); |
| 178 | }); |
| 179 | |
| 180 | proc.stderr?.on("data", (data: Buffer) => { |
| 181 | stderr += data.toString(); |
| 182 | }); |
| 183 | |
| 184 | proc.on("error", (err: Error) => { |
| 185 | reject(new Error(`WAV to MP3 conversion failed: ${err.message}`)); |
| 186 | }); |
| 187 | |
| 188 | proc.on("close", (code: number | null) => { |
| 189 | if (code === 0) { |
| 190 | resolve(Buffer.concat(chunks)); |
| 191 | } else { |
| 192 | reject( |
| 193 | new Error( |
| 194 | `WAV to MP3 conversion failed with code ${code}: ${stderr}`, |
| 195 | ), |
| 196 | ); |
| 197 | } |
| 198 | }); |
| 199 | |
| 200 | proc.stdin?.write(wavBuffer); |
| 201 | proc.stdin?.end(); |
| 202 | }); |
| 203 | } |
| 204 | |
| 205 | export async function checkHasAudioTrack(videoUrl: string): Promise<boolean> { |
| 206 | let ffmpeg: string; |
nothing calls this directly
no test coverage detected