Skip to content

Commit

Permalink
✨ VideoWrapper Preact component with autoplay and mediasession (#29486)
Browse files Browse the repository at this point in the history
VideoWrapper takes a component to instantiate and control.

This lays between the HTMLMediaElement interface and an outer context component (VideoController or similar), and implements AMP-style autoplay and mediasession. This may not be necessary depending on whether we move up these two features to a future context layer, but advancing this implementation anyhow.
  • Loading branch information
alanorozco committed Sep 17, 2020
1 parent 43d58d9 commit 462f3fd
Show file tree
Hide file tree
Showing 10 changed files with 739 additions and 30 deletions.
12 changes: 6 additions & 6 deletions css/video-autoplay.css
Expand Up @@ -57,13 +57,13 @@ amp-story .amp-video-eq {
width: 20px;
z-index: 1;
}
.amp-video-eq .amp-video-eq-col {
.amp-video-eq-col {
flex: 1;
height: 100%;
margin-right: 1px;
position: relative;
}
.amp-video-eq .amp-video-eq-col div {
.amp-video-eq-col div {
animation-name: amp-video-eq-animation;
animation-timing-function: linear;
animation-iteration-count: infinite;
Expand All @@ -74,16 +74,16 @@ amp-story .amp-video-eq {
width: 100%;
will-change: transform;
}
.amp-video-eq .amp-video-eq-col div {
.amp-video-eq-col div {
animation-play-state: paused;
}
.amp-video-eq[unpausable] .amp-video-eq-col div {
[unpausable] .amp-video-eq-col div {
animation-name: none;
}
.amp-video-eq[unpausable].amp-video-eq-play .amp-video-eq-col div {
[unpausable].amp-video-eq-play .amp-video-eq-col div {
animation-name: amp-video-eq-animation;
}
.amp-video-eq.amp-video-eq-play .amp-video-eq-col div {
.amp-video-eq-play .amp-video-eq-col div {
animation-play-state: running;
}
.amp-video-eq-1-1 {
Expand Down
10 changes: 3 additions & 7 deletions extensions/amp-audio/0.1/amp-audio.js
Expand Up @@ -20,6 +20,7 @@ import {
parseOgImage,
parseSchemaImage,
setMediaSession,
validateMediaMetadata,
} from '../../../src/mediasession-helper';
import {Layout, isLayoutSizeFixed} from '../../../src/layout';
import {assertHttpsUrl} from '../../../src/url';
Expand Down Expand Up @@ -289,13 +290,8 @@ export class AmpAudio extends AMP.BaseElement {
};

// Update the media session
setMediaSession(
this.element,
this.win,
this.metadata_,
playHandler,
pauseHandler
);
validateMediaMetadata(this.element, this.metadata_);
setMediaSession(this.win, this.metadata_, playHandler, pauseHandler);
}
}

Expand Down
123 changes: 123 additions & 0 deletions extensions/amp-video/1.0/storybook/Basic.js
@@ -0,0 +1,123 @@
/**
* Copyright 2020 The AMP HTML Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as Preact from '../../../../src/preact';
import {VideoWrapper} from '../video-wrapper';
import {boolean, number, object, text, withKnobs} from '@storybook/addon-knobs';
import {withA11y} from '@storybook/addon-a11y';

export default {
title: 'Video Wrapper',
component: VideoWrapper,
decorators: [withA11y, withKnobs],
};

const VideoTagPlayer = ({i}) => {
const group = `Player ${i + 1}`;

const width = text('width', '640px', group);
const height = text('height', '360px', group);

const ariaLabel = text('aria-label', 'Video Player', group);
const autoplay = boolean('autoplay', true, group);
const controls = boolean('controls', true, group);
const mediasession = boolean('mediasession', true, group);
const noaudio = boolean('noaudio', false, group);
const loop = boolean('loop', false, group);
const poster = text(
'poster',
'https://amp.dev/static/inline-examples/images/kitten-playing.png',
group
);

const artist = text('artist', '', group);
const album = text('album', '', group);
const artwork = text('artwork', '', group);
const title = text('title', '', group);

const sources = object(
'sources',
[
{
src:
'https://amp.dev/static/inline-examples/videos/kitten-playing.webm',
type: 'video/webm',
},
{
src: 'https://amp.dev/static/inline-examples/videos/kitten-playing.mp4',
type: 'video/mp4',
},
],
group
);

return (
<VideoWrapper
component="video"
ariaLabel={ariaLabel}
autoplay={autoplay}
controls={controls}
mediasession={mediasession}
noaudio={noaudio}
loop={loop}
poster={poster}
artist={artist}
album={album}
artwork={artwork}
title={title}
style={{width, height}}
>
{sources.map((props) => (
<source {...props}></source>
))}
</VideoWrapper>
);
};

const Spacer = ({height}) => {
return (
<div
style={{
height,
background: `linear-gradient(to bottom, #bbb, #bbb 10%, #fff 10%, #fff)`,
backgroundSize: '100% 10px',
}}
></div>
);
};

export const Default = () => {
const amount = number('Amount', 1, {}, 'Page');
const spacerHeight = text('Space', '80vh', 'Page');
const spaceAbove = boolean('Space above', false, 'Page');
const spaceBelow = boolean('Space below', false, 'Page');

const players = [];
for (let i = 0; i < amount; i++) {
players.push(<VideoTagPlayer key={i} i={i} />);
if (i < amount - 1) {
players.push(<Spacer height={spacerHeight} />);
}
}

return (
<>
{spaceAbove && <Spacer height={spacerHeight} />}
{players}
{spaceBelow && <Spacer height={spacerHeight} />}
</>
);
};

0 comments on commit 462f3fd

Please sign in to comment.