Version 1.3.7 - #583
Merged
Merged
Conversation
…RL (#561) The page was never self-contained — its media is a separate file beside it, and the bundle ships as one folder — so embedding the captions bought nothing while carrying a percent-encoded copy of the whole track inside the HTML. Files are also the only shape that extends: a translated transcript wants one <track srclang> per language, which no data: URL can express. The .vtt now rides along whenever an interactive transcript is exported without burned-in captions, and the modal says so. With the names sanitised since #560, the page's media and caption references need no encoding either — plain, readable filenames throughout.
Media served through a host application's own URL scheme (#547) is fetched to embed it in a .hyperaudio file, and that fetch was unguarded: when the handler could not produce the file — moved, renamed, permissions changed, not ready yet — the raw TypeError escaped as 'Failed to fetch' and the save was abandoned. Its sibling branch for http(s) media has always caught, explained, and offered a link save. Now both do. The wording differs deliberately: no server is involved here, so it says the application could not provide the file rather than blaming CORS. Same class of bug as #573 — an unguarded read of media that can legitimately fail, surfacing as an opaque browser message. The test declares a scheme with no handler, so the fetch genuinely rejects, and asserts the explanation and that cancelling is a real choice.
…last (#577) Regions were only built BETWEEN kept words — regionStart derives from prevKeptEnd, which is null until a kept word exists — so the lead-in was never a candidate however long, and the trailing region existed only when struck words followed the last kept word. The two gaps most likely to be long were the two it ignored: the #371 fixture opens 2.24s before its first word and ends 24.7s before the media does. Both edges are now ordinary regions under the same threshold and edge buffer. The tail is left alone when the duration is unknown rather than guessed, and struck words in the lead-in are consumed by that region so they cannot be cut twice. PLAYBACK needed its own half: it jumps via checkStrikeThrus, which only examined the bands BETWEEN kept sections, so correct sections alone changed nothing a listener would notice. It now jumps to the first kept section from before it, and lets the media end past the last one — which is what Mark's testing caught, since my first round of tests exercised only the export path.
WebKit's WebCodecs AudioEncoder picks HE-AAC for MONO input below 32 kHz — a sharp, measured boundary — and the muxed track that results is unreadable to AVFoundation: zero audio tracks, so the export is SILENT in QuickTime, Safari and Finder preview while appearing to have succeeded. Voice notes, telephony, voicemail and much interview audio live below that line. Forcing the codec string to mp4a.40.2 does not help; that was measured too, and the note is in the code so nobody spends a day on it again. Audio below 32 kHz is now resampled first, to a rate the source divides exactly (16k -> 48k, 22.05k -> 44.1k) and clear of the cliff rather than sitting on it. Upsampling cannot restore bandwidth the source never had, nor lose any. If resampling fails the original buffer is used: a silent export is bad, breaking one that used to work is worse. Applied on every engine — sniffing for WebKit would risk guessing wrong about a variant, and the early return means anything at 32 kHz or above pays nothing. Both export paths funnel their buffers through ONE addAudio, used by the direct branch AND the stretcher's emit, so no call site can be forgotten — and the lift sits after SoundTouch, which keeps working on the smaller source-rate buffers rather than three times the samples. WHAT THE TESTS PROVE: the transformation, not the cure. They run in Chromium, which does not exhibit the bug, and Playwright's WebKit is not Safari's AVFoundation stack. File-level verification lives in the WKWebView + AVAssetReader harness offered in the issue. Diagnosis and measurements: maboa.
That route passed the live track's src straight into the page, and the src is a data:text/vtt URL — a percent-encoded copy of the whole caption track inside the HTML, and a shape no <track srclang> per language can extend to. #561 fixed the media-export route; this is the other one. The page and its .vtt now travel together in ONE archive. Two separate downloads would let the browser de-duplicate the second to 'name (1).vtt' and silently break the page's reference — the same hazard the media export zips to avoid. With no captions the download stays a single HTML file and the empty <track> is dropped, so the page never points at a file that is not there; if JSZip fails to load, it falls back to that same trackless page rather than failing the export. The VTT checkbox's note is now conditional: the sidecar rides along with an interactive transcript, but NOT when captions are burned into the picture — the case where a blanket claim would be wrong, and the reason a missing <track> looked like a bug.
At 1000px the compact band placed the card's top at 58px while the navbar is 74px tall, so the navbar's grey band painted over the card's top edge — the lost rounded corners — and over the ⓘ/copy buttons pinned to it, which is why they looked faint and clipped. Constant, not intermittent: what varied was whether a resize happened to repaint in an order that briefly looked right. The 58px assumed a compact navbar (#480) that the navbar has since outgrown. Two changes, both about removing assumptions. --card-top is now measured in responsive.js from the navbar's real bottom plus the 4px of canvas the wide layout has always shown, re-measured on resize and by a ResizeObserver, so a late-arriving toolbar control cannot strand it. And every corner button — ⓘ, copy, and the touch-only undo/redo pair — derives its top from that variable plus a per-band --text-inset, rather than carrying its own constant per breakpoint: five hard-coded values and two now-empty media blocks are gone. The mobile band still computes its own --card-top in CSS (the player is pinned under the navbar there), so the inline value is removed below 948px, where an inline property would outrank the media query. The CSS constants survive only as pre-paint defaults, and the stale 58 became 78 so nothing flashes before the script runs. Consequence, accepted deliberately: in the 949-1120px band the card starts 20px lower than before, because those 20px were underneath the navbar rather than visible. Note for the record: I first blamed a z-index change of my own; Mark doubted it, and the measurement proved him right — the constant was stale long before.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Exports that carry their captions, gap skipping that reaches the edges, and a card that stays clear of the navbar.
.vttas a file beside the page and link it by name. The media export writes it into the bundle; the FILE → Interactive Transcript route downloads a zip holding the page and its captions together, because two separate downloads let the browser rename the second and silently break the link. A page with no captions stays a single file with no empty<track>.Fixes #561. Fixes #574. Fixes #577. Fixes #579. Fixes #580. Fixes #581.
Suite: 89 unit + 255 e2e green (1 known Playwright-WebKit OPFS skip).