(content: string)
| 184 | } |
| 185 | |
| 186 | function parseSrt(content: string): Word[] { |
| 187 | // SRT doesn't have word-level timestamps — parse as phrase-level entries. |
| 188 | // Each cue becomes one "word" entry (the full phrase). |
| 189 | const blocks = content.trim().split(/\n\n+/); |
| 190 | const words: Word[] = []; |
| 191 | |
| 192 | for (const block of blocks) { |
| 193 | const lines = block.trim().split("\n"); |
| 194 | // SRT format: index, timestamp line, text lines |
| 195 | const timeLine = lines.find((l) => l.includes("-->")); |
| 196 | if (!timeLine) continue; |
| 197 | |
| 198 | const [startStr, endStr] = timeLine.split("-->").map((s) => s.trim()); |
| 199 | if (!startStr || !endStr) continue; |
| 200 | |
| 201 | const text = lines |
| 202 | .slice(lines.indexOf(timeLine) + 1) |
| 203 | .join(" ") |
| 204 | .replace(/<[^>]+>/g, "") // strip HTML tags |
| 205 | .trim(); |
| 206 | if (!text) continue; |
| 207 | |
| 208 | words.push({ |
| 209 | text, |
| 210 | start: parseSrtTimestamp(startStr), |
| 211 | end: parseSrtTimestamp(endStr), |
| 212 | }); |
| 213 | } |
| 214 | return words; |
| 215 | } |
| 216 | |
| 217 | function parseVtt(content: string): Word[] { |
| 218 | // Strip the WEBVTT header and any metadata blocks |
no test coverage detected