Give a video its shape before it has any data
CI / Typecheck, test, build (pull_request) Successful in 26s
CI / Typecheck, test, build (pull_request) Successful in 26s
A Reddit video sat in the wrong box until you pressed play, for two reasons that looked like one. The renderer put only `aspect-ratio` on the `<video>`. A video with no data has a natural size of 300x150, and WebKit sizes a replaced element from that rather than from the ratio, so a portrait video got a squat landscape box and kept it until playback supplied real dimensions. Chromium stretch-fits instead and gets it right, which is why this only showed on Safari. A video's size before its data arrives is its poster's, so one with no poster of its own now gets an empty SVG of the right shape as a stand-in: a data URI, so it costs no request. Measured in both engines across portrait, landscape, square and small. And Reddit's videos with sound had no poster to be sized by, because `fromRedditVideo` attached the still from `preview.images` to the MP4 branch alone. The still belongs to the video, not to the format it is served in, so every post with sound showed an empty box where a silent one showed a frame. It now goes on both. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01PLkmgp1fWbA4XbarxKdRKt
This commit is contained in:
@@ -104,6 +104,10 @@ function fromRedditVideo(video: RedditVideo, poster: string | undefined): Media[
|
||||
const common = {
|
||||
...sized(video.width, video.height),
|
||||
...(video.duration ? { durationSec: video.duration } : {}),
|
||||
// The still belongs to the video and not to the format it is served in.
|
||||
// The HLS branch used to drop it, which is why a post with sound showed
|
||||
// an empty box where every silent one showed a frame.
|
||||
...(poster ? { poster: { url: poster } } : {}),
|
||||
};
|
||||
|
||||
if (video.has_audio !== false && video.hls_url) {
|
||||
@@ -114,12 +118,7 @@ function fromRedditVideo(video: RedditVideo, poster: string | undefined): Media[
|
||||
if (url === video.hls_url) {
|
||||
return [{ kind: 'video', url, hls: true, direct: true, ...common }];
|
||||
}
|
||||
return [{
|
||||
kind: 'video',
|
||||
url,
|
||||
...(poster ? { poster: { url: poster } } : {}),
|
||||
...common,
|
||||
}];
|
||||
return [{ kind: 'video', url, ...common }];
|
||||
}
|
||||
|
||||
/** One entry of a gallery post. Reddit keeps the pictures somewhere other
|
||||
|
||||
+19
-1
@@ -14,11 +14,29 @@ function aspect(item: Media): string {
|
||||
return item.width && item.height ? `aspect-ratio: ${item.width} / ${item.height};` : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* A stand-in poster carrying nothing but the video's shape.
|
||||
*
|
||||
* The ratio above is not enough on its own before the video has any data: a
|
||||
* `<video>` in that state has a natural size of 300x150, and WebKit sizes it
|
||||
* from that rather than from the ratio, so a portrait video sat in a squat
|
||||
* landscape box until you pressed play and it snapped to shape. A video's
|
||||
* size before its data arrives is its poster's, which makes an empty SVG of
|
||||
* the right shape enough to put the box right, and as a data URI it costs no
|
||||
* request. Only for a video the platform gave no poster for, since a real one
|
||||
* already says the same thing.
|
||||
*/
|
||||
function placeholderPoster(item: Media): string | undefined {
|
||||
if (!item.width || !item.height) return undefined;
|
||||
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${item.width}" height="${item.height}"/>`;
|
||||
return `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
||||
}
|
||||
|
||||
function renderItem(item: Media, index: number): Raw {
|
||||
const src = proxyUrlFor(item);
|
||||
|
||||
if (item.kind === 'video') {
|
||||
const poster = item.poster ? proxyUrlFor(item.poster) : undefined;
|
||||
const poster = item.poster ? proxyUrlFor(item.poster) : placeholderPoster(item);
|
||||
return html`<figure class="item item--video" data-index="${index}">
|
||||
<video
|
||||
controls
|
||||
|
||||
Reference in New Issue
Block a user