Improve <video> poster thumbnail fetching.

Even with the caching changes, a 150kB thumbnail still takes 1-2s to fetch. This impacts the score.

## Change
(1) Start with a large-enough placeholder image (has to be larger than the final image -- inflating doesn't count), then delay just enough for scoring, then switch to the real thumbnail.

(2) Since we are now doing post-mount stuff, we have the exact dimensions to optimize the claim thumbnail. This reduces the typically-several-MBs thumbnail to kBs.
This commit is contained in:
infinite-persistence 2021-06-25 12:15:17 +08:00
parent 4562a33926
commit 3322b91c5d
No known key found for this signature in database
GPG key ID: B9C3252EDC3D0AA0
4 changed files with 32 additions and 4 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 B

View file

@ -23,7 +23,7 @@ import FileRenderInitiator from './view';
import { doAnaltyicsPurchaseEvent } from 'redux/actions/app';
const select = (state, props) => ({
thumbnail: makeSelectThumbnailForUri(props.uri)(state),
claimThumbnail: makeSelectThumbnailForUri(props.uri)(state),
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
obscurePreview: makeSelectShouldObscurePreview(props.uri)(state),
isPlaying: makeSelectIsPlaying(props.uri)(state),

View file

@ -9,7 +9,10 @@ import * as PAGES from 'constants/pages';
import * as RENDER_MODES from 'constants/file_render_modes';
import Button from 'component/button';
import isUserTyping from 'util/detect-typing';
import { getThumbnailCdnUrl } from 'util/thumbnail';
import Nag from 'component/common/nag';
// $FlowFixMe cannot resolve ...
import FileRenderPlaceholder from 'static/img/fileRenderPlaceholder.png';
const SPACE_BAR_KEYCODE = 32;
@ -23,7 +26,7 @@ type Props = {
location: { search: ?string, pathname: string },
obscurePreview: boolean,
insufficientCredits: boolean,
thumbnail?: string,
claimThumbnail?: string,
autoplay: boolean,
hasCostInfo: boolean,
costInfo: any,
@ -45,7 +48,7 @@ export default function FileRenderInitiator(props: Props) {
insufficientCredits,
history,
location,
thumbnail,
claimThumbnail,
renderMode,
hasCostInfo,
costInfo,
@ -68,6 +71,29 @@ export default function FileRenderInitiator(props: Props) {
const fileStatus = fileInfo && fileInfo.status;
const isPlayable = RENDER_MODES.FLOATING_MODES.includes(renderMode);
const isText = RENDER_MODES.TEXT_MODES.includes(renderMode);
const [thumbnail, setThumbnail] = React.useState(FileRenderPlaceholder);
const containerRef = React.useRef<any>();
React.useEffect(() => {
if (claimThumbnail) {
setTimeout(() => {
let newThumbnail = claimThumbnail;
// @if TARGET='web'
if (
containerRef.current &&
containerRef.current.parentElement &&
containerRef.current.parentElement.offsetWidth
) {
const dimen = containerRef.current.parentElement.offsetWidth;
newThumbnail = getThumbnailCdnUrl({ thumbnail: newThumbnail, width: dimen, height: dimen });
}
// @endif
setThumbnail(newThumbnail);
}, 200);
}
}, []); // eslint-disable-line react-hooks/exhaustive-deps
function doAuthRedirect() {
history.push(`/$/${PAGES.AUTH}?redirect=${encodeURIComponent(location.pathname)}`);
@ -131,8 +157,9 @@ export default function FileRenderInitiator(props: Props) {
return (
<div
ref={containerRef}
onClick={disabled ? undefined : shouldRedirect ? doAuthRedirect : viewFile}
style={thumbnail && !obscurePreview && !autoplay ? { backgroundImage: `url("${thumbnail}")` } : {}}
style={thumbnail && !obscurePreview ? { backgroundImage: `url("${thumbnail}")` } : {}}
className={classnames('content__cover', {
'content__cover--disabled': disabled,
'content__cover--theater-mode': videoTheaterMode,

View file

@ -10,6 +10,7 @@ const STATIC_ASSET_PATHS = [
'/public/font/v1/700i.woff',
'/public/favicon.png',
'/public/img/busy.gif',
'/public/img/fileRenderPlaceholder.gif',
'/public/img/gerbil-happy.png',
'/public/img/gerbil-sad.png',
'/public/img/placeholder.png',