Skip to content

Say so when a verified NFT video cannot be decoded - #3063

Open
jlobue10 wants to merge 3 commits into
Chia-Network:release/2.7.4from
jlobue10:feat/nft-unplayable-media-notice
Open

Say so when a verified NFT video cannot be decoded#3063
jlobue10 wants to merge 3 commits into
Chia-Network:release/2.7.4from
jlobue10:feat/nft-unplayable-media-notice

Conversation

@jlobue10

@jlobue10 jlobue10 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Follow-up from the #3058 investigation, independent of #3060 / #3061 / #3062. Targets release/2.7.4 like them.

Problem

The NFT player runs in an iframe whose sandbox forbids scripts, so when Chromium rejects a stream nothing can report it. A verified, fully cached video that Chromium cannot decode shows as an empty player that looks like a download still in progress, and the gallery's preview filter counts it as available.

The concrete case: HEVC (H.265) videos on Linux. Chromium ships no HEVC software decoder anywhere and on Linux only offers HEVC through VA-API hardware decoding, which is gated behind flags and refused on NVIDIA GPUs by default. Verified on a wallet holding 12 videos from one collection: the 6 encoded as H.264 play, the 6 encoded as HEVC Main 10 fail with DEMUXER_ERROR_NO_SUPPORTED_STREAMS on Electron 39 and 43.4.0, with or without the Chromium HEVC/VA-API feature flags. All 12 are hash-verified in the cache.

Change

  • probeMediaPlayability(src, kind) loads only the metadata of a cache:// URL into a detached <video>/<audio> element (the renderer's CSP already allows media-src cache:). Only a definite verdict counts: MEDIA_ERR_SRC_NOT_SUPPORTED / MEDIA_ERR_DECODEunsupported, loadedmetadataplayable; a network error, abort or timeout → unknown, and the caller proceeds as before so a probe hiccup never hides a working file. Verdicts are remembered per cache URL (bounded) for the renderer's lifetime so scrolling does not re-probe.
  • NFTPreview probes before handing a video or audio file to the sandboxed player. An unplayable preview video falls back to the NFT's verified preview image when it has one (the next source in useNFTVerifyHash's own priority order). Otherwise the tile shows "This video format cannot be played here" (or the audio variant) instead of an empty player, and previewStatus reports UNAVAILABLE so the gallery's preview filter classifies it correctly. The detail view gets the same notice.

Verification

  • Nine unit tests for the probe (playable, unsupported via both error codes, network error not blamed on the file, timeout, abort, element released, verdict remembered, unknown re-probed). The gui jest config has no DOM, so the probe takes an element factory and the tests inject a fake element.
  • packages/gui jest: 379/379. eslint and prettier clean; tsc error count for NFTPreview.tsx unchanged (11 pre-existing, all missing asset/type declarations).
  • Built into a local checkout with the HEVC collection above; will report the live-GUI check on this thread.

🤖 Generated with Claude Code


Note

Low Risk
GUI-only NFT preview behavior with conservative probe semantics (ambiguous failures still try the player); data-file verification is unchanged.

Overview
NFT previews no longer show a blank sandboxed player when Chromium cannot decode a hash-verified video or audio file (e.g. HEVC on Linux). A new probeMediaPlayability helper loads cached cache:// media metadata in a detached element, treats decode / not-supported errors as unsupported, and caches definite verdicts so scrolling does not re-probe.

NFTPreview runs that probe before embedding media in the scriptless iframe. Unsupported preview URIs are recorded and passed to useNFTVerifyHash via excludedPreviewUris, so verification skips them and picks the next preview source (preview image, then data file). The tile shows “This video/audio format cannot be played here” when nothing else applies, and gallery previewStatus marks those tiles UNAVAILABLE instead of available.

useNFTVerifyHash filters excluded URIs from preview video/image candidate lists and masks them from current state so the UI can advance without a one-frame flash of the bad file.

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

The NFT player runs in an iframe whose sandbox forbids scripts, so when
Chromium rejects a stream nothing can report it: a verified, fully cached
video that Chromium cannot decode — HEVC on Linux, where Chromium ships no
HEVC decoder and hardware decoding is unavailable — shows as an empty
player that looks like a download still in progress, and the gallery's
preview filter counts it as available.

Before handing a cached video or audio file to the player, probe it with a
detached media element (metadata only, from the cache:// URL the renderer's
CSP already allows). Only a definite verdict from the media pipeline
counts — a source-not-supported or decode error — so a network hiccup in
the probe never hides a working file. An unplayable preview video falls
back to the NFT's verified preview image when it has one; otherwise the
tile says the format cannot be played here and reports itself as
unavailable to the gallery filter. Verdicts are remembered per cache URL
for the renderer's lifetime so scrolling does not re-probe.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ni9VuLznDQTZh2V8aBis76
@jlobue10
jlobue10 requested a review from a team as a code owner September 3, 2026 15:56
Comment thread packages/gui/src/components/nfts/NFTPreview.tsx Outdated
@jlobue10

jlobue10 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Live check on Linux (Electron 39 checkout built from this branch, wallet with HEVC/H.264 videos in the collection described above): after restarting the GUI, the HEVC tiles now show "This video format cannot be played here" instead of an empty player, while the H.264 videos in the same collection keep playing.

The preview-image fallback for an unplayable preview video could never
fire: useNFTVerifyHash only verifies the preview image when the preview
video failed to verify, and an unplayable video did verify.

Instead of second-guessing the selection in NFTPreview, hand the unplayable
URIs back to the verifier as excludedPreviewUris. It then skips them for
the preview sources and settles on the next one in its own priority order
(preview image, then the data file), exactly as if the video had not been
there. The data file is never skipped — isVerified is derived from it — so
an unplayable data file still ends up as the notice. NFTPreview keeps the
full list of URIs it has found unplayable, so a fallback that turns out
unplayable too does not bring the first one back.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ni9VuLznDQTZh2V8aBis76
Comment thread packages/gui/src/hooks/useNFTVerifyHash.ts
…verified

On the frame NFTPreview marks the uri it is showing as unplayable, the
verifier still holds that verified state and selected it, so the tile
settled on the notice and reported the NFT unavailable before the new
pass had moved on to the preview image — long enough for an available-only
gallery filter to unmount the tile and abort the fallback.

Mask excluded uris out of the stored preview states as well as the
candidates, and count a change of the excluded set as a pending preview
pass, so the hook reports verifying (and the tile keeps loading) until the
next source has been verified.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ni9VuLznDQTZh2V8aBis76
@danieljperry

Copy link
Copy Markdown
Contributor

bugbot review

@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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 3e3d4f1. Configure here.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants