You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(mobile): video previews survive re-signed URLs and a late-attached player item - #32196
On mobile, video previews in PR descriptions often never appear. The video plays, but its first-frame preview stays black until the app restarts. Two bugs in the preview loader cause it:
Each preview request was tied to the video's signed URL. A re-signed URL, which comes with reconnects and playback, cancelled the extraction in progress and queued it again from the start. With frequent re-signing a preview never finished, while every attempt still made range requests.
On iOS, expo-video's replaceAsync resolves before the item is attached to the player. A frame requested before then comes back empty, without an error.
Change
An extraction that has started now finishes and caches its frame, so a request with a re-signed URL for the same video reuses it. Queued extractions are still skipped when their screen is left. Only one extraction runs at a time, so finishing one costs at most the existing 15-second cap.
The loader waits for expo-video's sourceChange event before requesting the frame. Both platforms emit it once the item is attached.
This adds no retries and lowers the number of requests.
Related PRs
This follows #25988, which kept before/after video tables intact in PR descriptions. #32195 fixes a separate iOS bug where a preview that does load is drawn cropped; the two PRs are independent. A fix for videos keeping their own aspect ratio will follow once these merge.
Scope and approval
A focused fix of an obvious bug: previews for attached videos fail to load. It changes only the mobile thumbnail loader.
Verification
vp test run src/lib/videoThumbnails.test.ts src/lib/filePreview.test.ts src/components in apps/mobile: passes. The new tests cover reusing a started extraction for a re-signed URL, waiting for the item to attach, and a clean timeout that does not block the next request. All three fail on current main.
vp run typecheck in apps/mobile, vp lint and vp fmt --check on the changed files: pass.
With signed URLs forced to refresh every second, the previous loader started 178 extractions in 30 seconds and showed none of three previews. With this change it started 9 and showed all three.
iOS simulator, cold start on current main and with this change: below. Android emulator, checked on an earlier main: previews already loaded there, and still do.
iOS — cold start, opening a PR with three attached videos (the two in the table are still drawn cropped; #32195 fixes that)
Before
After
loader-ios-before.mp4
loader-ios-after.mp4
Claude Opus 5.5 in Claude Code, running in T3 Code.
Macroscope's review found this PR approvable — Video previews now wait for player attachment and preserve in-flight thumbnail extraction across URL refreshes or navigation. The change is limited to transient preview handling, with bounded work and existing cleanup retained.
You can add or adjust custom eligibility rules. Learn more.
Reviewing files that changed from the base of the PR and between 6ad7cd6 and 2257e4d.
You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.
Use the checkbox below for a quick retry:
Trigger review
No actionable comments were generated in the recent review.
Walkthrough
Thumbnail extraction now waits for the player source to become available and times out after 15 seconds if it does not. An extraction can complete after its caller aborts. Tests cover reuse, attachment, timeout, and cleanup.
Changes: Video thumbnail extraction
Layer / File(s)
Summary
Extraction lifecycle and validation apps/mobile/src/lib/videoThumbnails.ts, apps/mobile/src/lib/videoThumbnails.test.ts, apps/mobile/src/components/VideoThumbnailImage.tsx
Extraction waits for a non-null player source, times out after 15 seconds, and removes its source-change subscription during cleanup. An abort before extraction prevents it from starting; an abort during extraction does not discard a produced thumbnail. Tests cover extraction reuse, delayed attachment, timeout, and cleanup. The component comment now describes this behavior.
Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.
Tested 6ad7cd6 on the iOS Simulator (iPhone 17 Pro Max, iOS 26.5) against a dev server. The test video was a synthetic 39 MB, 20 s H.264 .mov. Uploads went through a local proxy limited to 256 KiB/s, and timeline downloads to 2 MiB/s. It fixes the black composer tile.
Pooled iPhone 18 Pro iOS simulator, light appearance, 402×874 logical viewport, fresh isolated state on each commit. Fresh dev client paired to its server; PRs → Search → 32196 → open the PR → scroll to Attachments. Observe without playback or remounting for 140 seconds.
Both attached source videos have bright frame 0, mean luminance approximately 0.894. The original paired scenarios:prove run failed on base and passed on head; the failing base was recaptured with the identical scenario and a longer recording-cleanup budget. The defect was intermittent: two of four completed base visits reproduced it.
Not shown:
The PR-description symptom is proven, but this run does not isolate signed-URL cancellation from late player-item attachment; neither timing condition was forced independently.
The composer path with a large H.264 MOV and throttled upload, and Android behavior, were not exercised.
Recovery of the failing base tile after remount was not captured: its first-visit assertion stops the scenario before reopening.
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
size:M30-99 changed lines (additions + deletions).vouch:unvouchedAuthor is not yet trusted in the VOUCHED list.
3 participants
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.
Problem
On mobile, video previews in PR descriptions often never appear. The video plays, but its first-frame preview stays black until the app restarts. Two bugs in the preview loader cause it:
replaceAsyncresolves before the item is attached to the player. A frame requested before then comes back empty, without an error.Change
sourceChangeevent before requesting the frame. Both platforms emit it once the item is attached.This adds no retries and lowers the number of requests.
Related PRs
This follows #25988, which kept before/after video tables intact in PR descriptions. #32195 fixes a separate iOS bug where a preview that does load is drawn cropped; the two PRs are independent. A fix for videos keeping their own aspect ratio will follow once these merge.
Scope and approval
A focused fix of an obvious bug: previews for attached videos fail to load. It changes only the mobile thumbnail loader.
Verification
vp test run src/lib/videoThumbnails.test.ts src/lib/filePreview.test.ts src/componentsinapps/mobile: passes. The new tests cover reusing a started extraction for a re-signed URL, waiting for the item to attach, and a clean timeout that does not block the next request. All three fail on currentmain.vp run typecheckinapps/mobile,vp lintandvp fmt --checkon the changed files: pass.mainand with this change: below. Android emulator, checked on an earliermain: previews already loaded there, and still do.iOS — cold start, opening a PR with three attached videos (the two in the table are still drawn cropped; #32195 fixes that)
loader-ios-before.mp4
loader-ios-after.mp4
Claude Opus 5.5 in Claude Code, running in T3 Code.