(content: string)
| 215 | } |
| 216 | |
| 217 | function parseVtt(content: string): Word[] { |
| 218 | // Strip the WEBVTT header and any metadata blocks |
| 219 | const body = content.replace(/^WEBVTT[^\n]*\n/, "").replace(/^[A-Z-]+:.*\n/gm, ""); |
| 220 | // VTT is structurally similar to SRT (without numeric indices) |
| 221 | const blocks = body.trim().split(/\n\n+/); |
| 222 | const words: Word[] = []; |
| 223 | |
| 224 | for (const block of blocks) { |
| 225 | const lines = block.trim().split("\n"); |
| 226 | const timeLine = lines.find((l) => l.includes("-->")); |
| 227 | if (!timeLine) continue; |
| 228 | |
| 229 | const [startStr, endStr] = timeLine.split("-->").map((s) => s.trim()); |
| 230 | if (!startStr || !endStr) continue; |
| 231 | |
| 232 | const text = lines |
| 233 | .slice(lines.indexOf(timeLine) + 1) |
| 234 | .join(" ") |
| 235 | .replace(/<[^>]+>/g, "") // strip HTML tags |
| 236 | .trim(); |
| 237 | if (!text) continue; |
| 238 | |
| 239 | words.push({ |
| 240 | text, |
| 241 | start: parseVttTimestamp(startStr), |
| 242 | end: parseVttTimestamp(endStr), |
| 243 | }); |
| 244 | } |
| 245 | return words; |
| 246 | } |
| 247 | |
| 248 | // --------------------------------------------------------------------------- |
| 249 | // Timestamp helpers |
no test coverage detected