Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Brightcove player component #1052

Merged
merged 1 commit into from
Dec 4, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions examples/brightcove.amp.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!doctype html>
<html ⚡>
<head>
<meta charset="utf-8">
<title>Brightcove Player Example</title>
<link rel="canonical" href="amps.html" >
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
<link href='https://fonts.googleapis.com/css?family=Georgia|Open+Sans|Roboto' rel='stylesheet' type='text/css'>
<script async custom-element="amp-brightcove" src="/dist/v0/amp-brightcove-0.1.max.js"></script>
<style>body {opacity: 0}</style><noscript><style>body {opacity: 1}</style></noscript>
<script async src="https://cdn.ampproject.org/v0.js"></script>
</head>
<body>
<h2>Brightcove Player</h2>

<amp-brightcove
data-account="906043040001"
data-video-id="1401169490001"
data-player-id="180a5658-8be8-4f33-8eba-d562ab41b40c"
layout="responsive" width="480" height="270">
</amp-brightcove>

</body>
</html>
1 change: 1 addition & 0 deletions extensions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Current list of extended components:
| --------------------------------------------- | ------------------------------------------------------------------------------------------- |
| [`amp-anim`](amp-anim/amp-anim.md) | Runtime-managed animated image, most typically a GIF. |
| [`amp-audio`](amp-audio/amp-audio.md) | Replacement for the HTML5 `audio` tag. |
| [`amp-brightcove`](amp-brightcove/amp-brightcove.md) | Displays a Brightcove Video Cloud or Perform player. |
| [`amp-carousel`](amp-carousel/amp-carousel.md) | Generic carousel for displaying multiple similar pieces of content along a horizontal axis. |
| [`amp-fit-text`](amp-fit-text/amp-fit-text.md) | Expand or shrink font size to fit the content within the space given. |
| [`amp-font`](amp-font/amp-font.md) | Trigger and monitor the loading of custom fonts. |
Expand Down
92 changes: 92 additions & 0 deletions extensions/amp-brightcove/0.1/amp-brightcove.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Copyright 2015 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 {isLayoutSizeDefined} from '../../../src/layout';
import {loadPromise} from '../../../src/event-helper';


class AmpBrightcove extends AMP.BaseElement {

/** @override */
createdCallback() {
this.preconnect.url('https://players.brightcove.net');
}

/** @override */
isLayoutSupported(layout) {
return isLayoutSizeDefined(layout);
}

/** @override */
layoutCallback() {
const width = this.element.getAttribute('width');
const height = this.element.getAttribute('height');
const account = AMP.assert(
this.element.getAttribute('data-account'),
'The data-account attribute is required for <amp-brightcove> %s',
this.element);
const playerid = (this.element.getAttribute('data-player-id') || 'default');
const embed = (this.element.getAttribute('data-embed') || 'default');
const iframe = document.createElement('iframe');
let src = 'https://players.brightcove.net/' + encodeURIComponent(account) + '/' + encodeURIComponent(playerid) + '_' + encodeURIComponent(embed) + '/index.html';
if (this.element.getAttribute('data-playlist-id')) {
src += '?playlistId=';
src += this.encodeId_(this.element.getAttribute('data-playlist-id'));
} else if (this.element.getAttribute('data-video-id')) {
src += '?videoId=';
src += this.encodeId_(this.element.getAttribute('data-video-id'));
}
iframe.setAttribute('frameborder', '0');
iframe.setAttribute('allowfullscreen', 'true');
iframe.src = src;
this.applyFillContent(iframe);
iframe.width = width;
iframe.height = height;
this.element.appendChild(iframe);
/** @private {?Element} */
this.iframe_ = iframe;
return loadPromise(iframe);
Copy link
Contributor

Choose a reason for hiding this comment

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

Please also whitelist your element in the https://github.com/ampproject/amphtml/blob/master/src/layout.js#L73 - it's a minor thing, but a good touch.

}

/** @private */
encodeId_(id) {
/* id is either a Brightcove-assigned id, or a customer-generated reference id.
reference ids are prefixed 'ref:' and the colon must be preserved unencoded */
if (id.substring(0,4) === 'ref:') {
return 'ref:' + encodeURIComponent(id.substring(4));
} else {
return encodeURIComponent(id);
}
}

/** @override */
documentInactiveCallback() {
/*
This stops playback with the postMessage API.
Add this script to the player in the player configuration in the Studio
or via the Player Management API:

http://players.brightcove.net/906043040001/plugins/postmessage_pause.js

It's not a 'real' video.js plugin, just a plain script running in
the iframe so needs no configuration options.
*/
this.iframe_.contentWindow./*OK*/postMessage('pause', 'https://players.brightcove.net');
return false;
}
};

AMP.registerElement('amp-brightcove', AmpBrightcove);
67 changes: 67 additions & 0 deletions extensions/amp-brightcove/0.1/test/test-amp-brightcove.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Copyright 2015 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 {createIframePromise} from '../../../../testing/iframe';
require('../amp-brightcove');
import {adopt} from '../../../../src/runtime';

adopt(window);

describe('amp-brightcove', () => {

function getBrightcove(accountId, videoId, opt_responsive) {
return createIframePromise().then(iframe => {
const bc = iframe.doc.createElement('amp-brightcove');
bc.setAttribute('data-account', accountId);
bc.setAttribute('width', '111');
bc.setAttribute('height', '222');
if (videoId) {
bc.setAttribute('data-video-id', videoId);
}
if (opt_responsive) {
bc.setAttribute('layout', 'responsive');
}
iframe.doc.body.appendChild(bc);
bc.implementation_.layoutCallback();
return bc;
});
}

it('renders', () => {
return getBrightcove('906043040001','ref:ampdemo').then(bc => {
const iframe = bc.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.tagName).to.equal('IFRAME');
expect(iframe.src).to.equal(
'https://players.brightcove.net/906043040001/default_default/index.html?videoId=ref:ampdemo');
expect(iframe.getAttribute('width')).to.equal('111');
expect(iframe.getAttribute('height')).to.equal('222');
});
});

it('renders responsively', () => {
return getBrightcove('906043040001', 'ref:ampdemo', true).then(bc => {
const iframe = bc.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.className).to.match(/-amp-fill-content/);
});
});

it('requires data-account', () => {
return getBrightcove('').should.eventually.be.rejectedWith(
/The data-account attribute is required for/);
});
});
63 changes: 63 additions & 0 deletions extensions/amp-brightcove/amp-brightcove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<!---
Copyright 2015 Brightcove. 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.
-->

### <a name="amp-brightcove"></a> `amp-brightcove`
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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


An `amp-brightcove` component displays a Brightcove [Video Cloud](https://www.brightcove.com/en/online-video-platform) or [Perform](https://www.brightcove.com/en/perform) player.

Example:
```html
<amp-brightcove
data-account="12345"
data-player="default"
data-embed="default"
data-video-id="1234"
layout="responsive"
width="480" height="270">
</amp-brightcove>
```

The width and height will determine the aspect ratio of the player embed in responsive layouts.

#### Attributes

**data-account**

The Brightcove Video Cloud or Perform account id

**data-player**

The Brightcove player id. This is a GUID or "default". The default value is "default".

**data-embed**

The Brightcove player id. This is a GUID or "default". The default value and most common value is "default".

**data-video-id**

The Video Cloud video id. Most Video Cloud players will need this.
This is not used for Perform players.

**data-playlist-id**

The Video Cloud playlist id. For AMP HTML uses a video id will normally be used instead. If both a playlist and a video are specified, the playlist takes precedence.
This is not used for Perform players.

#### Player configuration

This script should be added to the configuration of Brightcove Players used with this component. This allows the AMP document to pause the player. Only the script need be added, no plugin name or JSON are needed.

* http://players.brightcove.net/906043040001/plugins/postmessage_pause.js
3 changes: 2 additions & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ function buildExtensions(options) {
// Each extension and version must be listed individually here.
buildExtension('amp-anim', '0.1', false, options);
buildExtension('amp-audio', '0.1', false, options);
buildExtension('amp-brightcove', '0.1', false, options);
buildExtension('amp-carousel', '0.1', true, options);
buildExtension('amp-fit-text', '0.1', true, options);
buildExtension('amp-font', '0.1', false, options);
Expand All @@ -84,7 +85,7 @@ function buildExtensions(options) {
*/
buildExtension('amp-slides', '0.1', false, options);
buildExtension('amp-twitter', '0.1', false, options);
buildExtension('amp-vine', '0.1', false, options);
buildExtension('amp-vine', '0.1', false, options);
buildExtension('amp-youtube', '0.1', false, options);
}

Expand Down
1 change: 1 addition & 0 deletions spec/amp-html-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ In these cases, services may set up endpoints that produce data that conforms to
- [amp-ad](../builtins/amp-ad.md)
- [amp-pixel](../builtins/amp-pixel.md)
- [amp-video](../builtins/amp-video.md)
- [amp-brightcove](../extensions/amp-brightcove/amp-brightcove.md)
- [amp-carousel](../extensions/amp-carousel/amp-carousel.md)
- [amp-font](../extensions/amp-font/amp-font.md)
- [amp-lightbox](../extensions/amp-lightbox/amp-lightbox.md)
Expand Down
1 change: 1 addition & 0 deletions src/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const naturalDimensions_ = {
*/
export const LOADING_ELEMENTS_ = {
'AMP-ANIM': true,
'AMP-BRIGHTCOVE': true,
'AMP-IFRAME': true,
'AMP-IMG': true,
'AMP-INSTAGRAM': true,
Expand Down
4 changes: 4 additions & 0 deletions test/integration/test-example-validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ describe('example', function() {

const examples = [
'ads.amp.html',
'brightcove.amp.html',
'metadata-examples/article-json-ld.amp.html',
'metadata-examples/article-microdata.amp.html',
'metadata-examples/recipe-json-ld.amp.html',
Expand Down Expand Up @@ -67,6 +68,9 @@ describe('example', function() {

// TODO(dvoytenko): Remove once validator supports "amp-font" element.
/DISALLOWED_TAG amp-font/,

// Remove once validator supports "amp-brightcove".
/DISALLOWED_TAG amp-brightcove/
];

const usedWhitelist = [];
Expand Down