( videoId: string, userId: string, video: typeof videos.$inferSelect, )
| 148 | } |
| 149 | |
| 150 | async function fetchTranscript( |
| 151 | videoId: string, |
| 152 | userId: string, |
| 153 | video: typeof videos.$inferSelect, |
| 154 | ): Promise<TranscriptData | null> { |
| 155 | "use step"; |
| 156 | |
| 157 | const vtt = await Effect.gen(function* () { |
| 158 | const [bucket] = yield* Storage.getAccessForVideo( |
| 159 | decodeStorageVideo(video), |
| 160 | ); |
| 161 | return yield* bucket.getObject(`${userId}/${videoId}/transcription.vtt`); |
| 162 | }).pipe(runPromise); |
| 163 | |
| 164 | if (Option.isNone(vtt)) { |
| 165 | return null; |
| 166 | } |
| 167 | |
| 168 | const segments = parseVttWithTimestamps(vtt.value); |
| 169 | const text = segments |
| 170 | .map((s) => s.text) |
| 171 | .join(" ") |
| 172 | .trim(); |
| 173 | |
| 174 | if (text.length < 10) { |
| 175 | return null; |
| 176 | } |
| 177 | |
| 178 | return { segments, text }; |
| 179 | } |
| 180 | |
| 181 | async function markSkipped( |
| 182 | videoId: string, |
no test coverage detected