Skip to content

fix(preview): flag unplayable media when previewing a standalone asset#96

Open
ctrlaltking wants to merge 1 commit into
palmier-io:mainfrom
ctrlaltking:fix/preview-flag-unplayable-asset
Open

fix(preview): flag unplayable media when previewing a standalone asset#96
ctrlaltking wants to merge 1 commit into
palmier-io:mainfrom
ctrlaltking:fix/preview-flag-unplayable-asset

Conversation

@ctrlaltking

@ctrlaltking ctrlaltking commented Jun 22, 2026

Copy link
Copy Markdown

Summary

  • VideoEngine.previewAsset() builds AVPlayerItem(url: asset.url) directly with no error handling. If the source file can't actually decode (corrupt, truncated, unsupported codec variant), the preview just sits blank/frozen with no feedback anywhere — no log, no UI state change.
  • This detection already exists for the timeline composition path: CompositionBuilder probes each clip's tracks and records failures into offlineMediaRefs/unprocessableMediaRefs, which PreviewContainerView uses to show a "Couldn't Prepare Media" overlay with an explanation and a report button. That path never ran for an asset previewed standalone (before being placed on the timeline).
  • Reproduced the failure mode directly: AVURLAsset(url:).loadTracks(withMediaType: .video) on a garbage/corrupt file throws AVErrorFailedDependenciesKey "Cannot Open" — exactly the case that silently fails today.

Fix

After swapping in the player item in previewAsset(), probe the asset's tracks in the background. On failure, insert the asset id into editor.unprocessableMediaRefs, reusing the existing offline/unprocessable UI instead of leaving a silent blank player.

Test plan

  • swift build — clean build
  • swift test — full suite passes (one pre-existing failure in CompositionBuilderTests.fractionalSpeedAudioUsesTruncatedSourceFramesForCompositionInsertion confirmed present on unmodified main too, unrelated to this change)
  • Verified AVURLAsset.loadTracks throws on a corrupt file with a video extension, matching the failure mode this fix detects

Note

Low Risk
Small, preview-only change that toggles existing editor UI state; no auth, export, or timeline composition logic is modified.

Overview
Standalone media previews no longer fail silently when AVPlayerItem(url:) cannot decode the file. After swapping in the player item in previewAsset(), the engine asynchronously probes AVURLAsset.loadTracks(withMediaType:) for the correct audio or video track.

If decoding fails or no track is found, the asset id is added to editor.unprocessableMediaRefs (with a preview log); if the file becomes playable, the id is removed. That reuses the same unprocessable/offline overlay the timeline composition path already drives via CompositionBuilder, which never ran for library-only asset preview.

Reviewed by Cursor Bugbot for commit 7c99a33. Bugbot is set up for automated code reviews on this repo. Configure here.

previewAsset() created AVPlayerItem(url:) directly with no error
handling, so a corrupt or unsupported source file just left the
preview blank/frozen with no feedback. The timeline composition path
already detects this (offlineMediaRefs/unprocessableMediaRefs via
CompositionBuilder) and surfaces a "Couldn't Prepare Media" overlay —
this path never ran for assets previewed before being placed on the
timeline.

Probe the asset's tracks after swapping in the player item and mark
it unprocessable on failure, reusing the existing offline/unprocessable
UI instead of leaving a silent blank player.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7c99a33. Configure here.

Log.preview.error("previewAsset: media unplayable assetId=\(assetId.prefix(8))")
editor.unprocessableMediaRefs.insert(assetId)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale media probe race

Medium Severity

Each call to verifyAssetPlayable starts a new unstructured Task without cancelling earlier probes. openPreviewTab always calls activateTab, so re-opening the same asset can run overlapping loadTracks checks. A slower, older task can finish last and update unprocessableMediaRefs after a newer probe, showing or hiding the unplayable overlay incorrectly.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7c99a33. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant