Repository navigation
Struck-word removal ignores the Entire/Edited media choice #605
Description
Exported text drops struck words regardless of which media it is shipped with. When Entire media is chosen the original AV file is exported untouched — it still speaks every struck word — while the transcript and captions beside it have those words deleted. The text then describes audio that is not what plays.
The rule this should follow: the text must match the media that ships with it.
- Entire media — the original AV file, untouched. Nothing is cut. Struck words are still audible, so they are ordinary words for export: they belong in the transcript and the captions.
- Edited media — gap removal and word removal are applied. The media is cut, the transcript and captions are re-timed to suit, and struck words are genuinely absent.
Measured
Striking a word with the toolbar control, then taking each export:
| media shipped | struck words in the text | verdict | |
|---|---|---|---|
| Export Media → Entire media | original, untouched | removed | wrong |
| Export Media → Edited media | cut and re-timed | removed | correct |
| Interactive Transcript modal | original (linked by name) | kept | correct |
download-html |
original context | kept | correct |
download-vtt / download-srt / download-vtt-words |
original context | kept | correct |
saved project (.hyperaudio, working copy) |
— | kept, struck: true |
correct |
Cause
media-export.js already gets the mode right when computing the timeline:
const sections = edited ? editedSections(duration) : [{ start: 0, end: duration }];With Entire media, sections spans the whole timeline, so mapTime is an identity and no re-timing happens — correct. But buildRetimedTranscriptHtml deleted struck spans before it consulted sections at all, and that deletion was not conditioned on edited. So the removal ignored the choice the user made.
Fix
dropStruck is threaded through the four builders — buildRetimedTranscriptHtml, genRetimedCaptions, buildInteractiveExportHtml, buildCaptionChunks — and every call site passes edited. That covers the interactive transcript, the sidecar captions, the burned-in captions and the flattened project container. Retiming needs no flag: Entire media already passes whole-timeline sections.
The exported page's copy button follows from this and needed no mode of its own. It used to filter struck words itself; it no longer does, because the document already reflects the choice — an Edited-media export contains no struck words to copy, and an Entire-media export shows them. Copying what is shown is right in both cases, and a filter there could only disagree with the page.
Do not touch the save
Striking is reversible working state: it travels in the save with struck: true and becomes final only in an export. Verified correct and unchanged.
serializeTranscriptHtml is shared across export paths — putting any of this inside it would look tidy and would put the removal one refactor from the save path. buildRetimedTranscriptHtml is the safe shape: clone the transcript, act on the clone, leave the live DOM alone.
Correction to an earlier revision of this issue
An earlier version listed the standalone caption downloads (download-vtt, download-srt, download-vtt-words) as a second fix site, on the grounds that they excluded struck words. That was wrong: the reading came from a stale href, populated before the strike. Once regenerated they contain struck words like everything else, and were already correct. There is one fix site, not two.
Also worth doing
Say what Entire media means where it is chosen — see #608 — and consider confirming before an export that ships an uncut file (#610).
Activity
[-]Exported transcripts leak struck words to anyone who selects the text by hand[/-][+]Interactive transcript exports contain struck words; the VTT beside them does not[/+][-]Interactive transcript exports contain struck words; the VTT beside them does not[/-][+]Struck-word removal ignores the Entire/Edited media choice[/+]Keep struck words where the format can mark them (#611)
Test what the page copies, not what the clipboard returns (#606)