-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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
AMP jwplayer #2660
AMP jwplayer #2660
Changes from all commits
a589396
3666afa
0e42170
1f79c86
6f282a4
bbc2390
2b5479d
751af66
eb8af57
927024b
55ef237
7018a7d
b2f30a6
c75b200
5d8548b
1906bd1
d45e282
92f947b
0a8a60d
8381c36
6b56232
a742336
c81c2b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
<!doctype html> | ||
<html ⚡> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>JWPlayer AMP 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-jwplayer" src="https://cdn.ampproject.org/v0/amp-jwplayer-0.1.js"></script> | ||
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript> | ||
<script async src="https://cdn.ampproject.org/v0.js"></script> | ||
</head> | ||
<body> | ||
<h2>JWPlayer AMP Examples</h2> | ||
|
||
<h3>Responsive</h3> | ||
|
||
<amp-jwplayer | ||
data-media-id="BZ6tc0gy" | ||
data-player-id="uoIbMPm3" | ||
layout="responsive" width="16" height="9"> | ||
</amp-jwplayer> | ||
|
||
<h3>Non-responsive, with a playlist</h3> | ||
|
||
<amp-jwplayer | ||
data-playlist-id="482jsTAr" | ||
data-player-id="uoIbMPm3" | ||
width="480" height="270"> | ||
</amp-jwplayer> | ||
|
||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/** | ||
* Copyright 2016 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 {getLengthNumeral, isLayoutSizeDefined} from '../../../src/layout'; | ||
import {loadPromise} from '../../../src/event-helper'; | ||
import {setStyles} from '../../../src/style'; | ||
import {user} from '../../../src/log'; | ||
|
||
class AmpJWPlayer extends AMP.BaseElement { | ||
|
||
/** @override */ | ||
preconnectCallback(onLayout) { | ||
// Host that serves player configuration and content redirects | ||
this.preconnect.url('https://content.jwplatform.com', onLayout); | ||
// CDN which hosts jwplayer assets | ||
this.preconnect.url('https://ssl.p.jwpcdn.com', onLayout); | ||
} | ||
|
||
/** @override */ | ||
isLayoutSupported(layout) { | ||
return isLayoutSizeDefined(layout); | ||
} | ||
|
||
/** @override */ | ||
buildCallback() { | ||
const width = this.element.getAttribute('width'); | ||
const height = this.element.getAttribute('height'); | ||
|
||
/** @private @const {number} */ | ||
this.width_ = getLengthNumeral(width); | ||
|
||
/** @private @const {number} */ | ||
this.height_ = getLengthNumeral(height); | ||
|
||
if (!this.getPlaceholder()) { | ||
this.buildImagePlaceholder_(); | ||
} | ||
} | ||
|
||
|
||
/** @override */ | ||
layoutCallback() { | ||
/** @private @const {string} */ | ||
this.contentid_ = user.assert( | ||
(this.element.getAttribute('data-playlist-id') || | ||
this.element.getAttribute('data-media-id')), | ||
'Either the data-media-id or the data-playlist-id ' + | ||
'attributes must be specified for <amp-jwplayer> %s', | ||
this.element); | ||
|
||
/** @private @const {string} */ | ||
this.playerid_ = user.assert( | ||
this.element.getAttribute('data-player-id'), | ||
'The data-player-id attribute is required for <amp-jwplayer> %s', | ||
this.element); | ||
|
||
|
||
const iframe = document.createElement('iframe'); | ||
const src = 'https://content.jwplatform.com/players/' + | ||
encodeURIComponent(this.contentid_) + '-' + | ||
encodeURIComponent(this.playerid_) + '.html'; | ||
|
||
iframe.setAttribute('frameborder', '0'); | ||
iframe.setAttribute('allowfullscreen', 'true'); | ||
iframe.src = src; | ||
this.applyFillContent(iframe); | ||
iframe.width = this.width_; | ||
iframe.height = this.height_; | ||
this.element.appendChild(iframe); | ||
/** @private {?Element} */ | ||
this.iframe_ = iframe; | ||
return loadPromise(iframe); | ||
} | ||
|
||
/** @override */ | ||
pauseCallback() { | ||
if (this.iframe_ && this.iframe_.contentWindow) { | ||
// The /players page can respond to "play" and "pause" commands from the | ||
// iframe's parent | ||
this.iframe_.contentWindow./*OK*/postMessage('pause', | ||
'https://content.jwplatform.com'); | ||
} | ||
} | ||
|
||
/** @private */ | ||
buildImagePlaceholder_() { | ||
const imgPlaceholder = new Image(); | ||
|
||
setStyles(imgPlaceholder, { | ||
'object-fit': 'cover', | ||
'visibility': 'hidden', | ||
}); | ||
|
||
imgPlaceholder.src = 'https://content.jwplatform.com/thumbs/' + | ||
encodeURIComponent(this.contentid_) + '-720.jpg'; | ||
imgPlaceholder.setAttribute('placeholder', ''); | ||
imgPlaceholder.width = this.width_; | ||
imgPlaceholder.height = this.height_; | ||
|
||
this.element.appendChild(imgPlaceholder); | ||
this.applyFillContent(imgPlaceholder); | ||
|
||
loadPromise(imgPlaceholder).then(() => { | ||
setStyles(imgPlaceholder, { | ||
'visibility': '', | ||
}); | ||
}).catch(() => { | ||
// Thumbnails aren't available for all media content. | ||
// On a 404, remove the placeholder image. | ||
this.element.removeChild(imgPlaceholder); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please do this part as:
Or alternatively, you can wait for image to load before adding it to DOM. That way you can avoid playing with visibility as well. |
||
}); | ||
} | ||
|
||
}; | ||
|
||
AMP.registerElement('amp-jwplayer', AmpJWPlayer); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
/** | ||
* Copyright 2016 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-jwplayer'); | ||
import {adopt} from '../../../../src/runtime'; | ||
|
||
adopt(window); | ||
|
||
describe('amp-jwplayer', () => { | ||
|
||
function getjwplayer(attributes) { | ||
return createIframePromise().then(iframe => { | ||
const jw = iframe.doc.createElement('amp-jwplayer'); | ||
for (const key in attributes) { | ||
jw.setAttribute(key, attributes[key]); | ||
} | ||
jw.setAttribute('width', '320'); | ||
jw.setAttribute('height', '180'); | ||
jw.setAttribute('layout', 'responsive'); | ||
iframe.doc.body.appendChild(jw); | ||
jw.implementation_.layoutCallback(); | ||
return jw; | ||
}); | ||
} | ||
|
||
it('renders', () => { | ||
return getjwplayer({ | ||
'data-media-id': 'Wferorsv', | ||
'data-player-id': 'sDZEo0ea', | ||
}).then(jw => { | ||
const iframe = jw.querySelector('iframe'); | ||
expect(iframe).to.not.be.null; | ||
expect(iframe.tagName).to.equal('IFRAME'); | ||
expect(iframe.src).to.equal( | ||
'https://content.jwplatform.com/players/Wferorsv-sDZEo0ea.html'); | ||
expect(iframe.getAttribute('width')).to.equal('320'); | ||
expect(iframe.getAttribute('height')).to.equal('180'); | ||
}); | ||
}); | ||
|
||
it('renders with a playlist', () => { | ||
return getjwplayer({ | ||
'data-playlist-id': '482jsTAr', | ||
'data-player-id': 'sDZEo0ea', | ||
}).then(jw => { | ||
const iframe = jw.querySelector('iframe'); | ||
expect(iframe).to.not.be.null; | ||
expect(iframe.tagName).to.equal('IFRAME'); | ||
expect(iframe.src).to.equal( | ||
'https://content.jwplatform.com/players/482jsTAr-sDZEo0ea.html'); | ||
}); | ||
}); | ||
|
||
it('fails if no media is specified', () => { | ||
return getjwplayer({ | ||
'data-player-id': 'sDZEo0ea', | ||
}).should.eventually.be.rejectedWith( | ||
/Either the data-media-id or the data-playlist-id attributes must be/ | ||
); | ||
}); | ||
|
||
it('fails if no player is specified', () => { | ||
return getjwplayer({ | ||
'data-media-id': 'Wferorsv', | ||
}).should.eventually.be.rejectedWith( | ||
/The data-player-id attribute is required for/ | ||
); | ||
}); | ||
|
||
it('renders with a bad playlist', () => { | ||
return getjwplayer({ | ||
'data-playlist-id': 'zzz', | ||
'data-player-id': 'sDZEo0ea', | ||
}).then(jw => { | ||
const iframe = jw.querySelector('iframe'); | ||
expect(iframe).to.not.be.null; | ||
expect(iframe.tagName).to.equal('IFRAME'); | ||
expect(iframe.src).to.equal( | ||
'https://content.jwplatform.com/players/zzz-sDZEo0ea.html'); | ||
}); | ||
}); | ||
|
||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
<!--- | ||
Copyright 2016 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. | ||
--> | ||
|
||
### <a name="amp-jwplayer"></a> `amp-jwplayer` | ||
|
||
<table> | ||
<tr> | ||
<td width="40%"><strong>Description</strong></td> | ||
<td>An <code>amp-jwplayer</code> component displays a cloud-hosted JW Player.</td> | ||
</tr> | ||
<tr> | ||
<td width="40%"><strong>Availability</strong></td> | ||
<td>Stable</td> | ||
</tr> | ||
<tr> | ||
<td width="40%"><strong>Required Script</strong></td> | ||
<td><code><script async custom-element="amp-jwplayer" src="https://cdn.ampproject.org/v0/amp-jwplayer-0.1.js"></script></code></td> | ||
</tr> | ||
<tr> | ||
<td width="40%"><strong>Examples</strong></td> | ||
<td><a href="https://github.com/ampproject/amphtml/blob/master/examples/jwplayer.amp.html">jwplayer.amp.html</a></td> | ||
</tr> | ||
</table> | ||
|
||
The following lists validation errors specific to the `amp-jwplayer` tag | ||
(see also `amp-jwplayer` in the [AMP validator specification](https://github.com/ampproject/amphtml/blob/master/validator/validator.protoascii): | ||
|
||
<table> | ||
<tr> | ||
<th width="40%"><strong>Validation Error</strong></th> | ||
<th>Description</th> | ||
</tr> | ||
<tr> | ||
<td width="40%"><a href="/docs/reference/validation_errors.html#tag-required-by-another-tag-is-missing">TAG_REQUIRED_BY_MISSING</a></td> | ||
<td>Error thrown when required <code>amp-jwplayer</code> extension <code>.js</code> script tag is missing or incorrect.</td> | ||
</tr> | ||
<tr> | ||
<td width="40%"><a href="/docs/reference/validation_errors.html#mandatory-attribute-missing">MANDATORY_ATTR_MISSING</a></td> | ||
<td>Error thrown when <code>data-account</code> attribute is missing.</td> | ||
</tr> | ||
<tr> | ||
<td width="40%"><a href="/docs/reference/validation_errors.html#implied-layout-isnt-supported-by-amp-tag">IMPLIED_LAYOUT_INVALID</a></td> | ||
<td>Error thrown when implied layout is set to <code>CONTAINER</code>; this layout type isn't supported.</td> | ||
</tr> | ||
<tr> | ||
<td width="40%"><a href="/docs/reference/validation_errors.html#mandatory-attribute-missing">MANDATORY_ONEOF_ATTR_MISSING</a></td> | ||
<td>Error thrown when either the <code>data-media-id</code> or <code>data-playlist-id</code> attributes are missing.</td> | ||
</tr> | ||
<tr> | ||
<td width="40%"><a href="/docs/reference/validation_errors.html#implied-layout-isnt-supported-by-amp-tag">IMPLIED_LAYOUT_INVALID</a></td> | ||
<td>Error thrown when implied layout is set to <code>CONTAINER</code>; this layout type isn't supported.</td> | ||
</tr> | ||
<tr> | ||
<td width="40%"><a href="/docs/reference/validation_errors.html#specified-layout-isnt-supported-by-amp-tag">SPECIFIED_LAYOUT_INVALID</a></td> | ||
<td>Error thrown when specified layout is set to <code>CONTAINER</code>; this layout type isn't supported.</td> | ||
</tr> | ||
<tr> | ||
<td width="40%"><a href="/docs/reference/validation_errors.html#invalid-property-value">INVALID_PROPERTY_VALUE_IN_ATTR_VALUE</a></td> | ||
<td>Error thrown when invalid value is given for attributes <code>height</code> or <code>width</code>. For example, <code>height=auto</code> triggers this error for all supported layout types, with the exception of <code>NODISPLAY</code>.</td> | ||
</tr> | ||
</table> | ||
|
||
#### Example | ||
|
||
The `width` and `height` attributes determine the aspect ratio of the player embedded in responsive layouts. | ||
|
||
Example: | ||
|
||
```html | ||
<amp-jwplayer | ||
data-player-id="aBcD1234" | ||
data-media-id="5678WxYz" | ||
layout="responsive" | ||
width="16" height="9"> | ||
</amp-jwplayer> | ||
``` | ||
|
||
Non-responsive layout is also supported. | ||
|
||
Example: | ||
|
||
```html | ||
<amp-jwplayer | ||
data-player-id="aBcD1234" | ||
data-playlist-id="5678WxYz" | ||
width="160" height="90"> | ||
</amp-jwplayer> | ||
``` | ||
|
||
#### Attributes | ||
|
||
**data-player-id** | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please document which of these attributes are required? |
||
|
||
JW Platform player id. This is an 8-digit alphanumeric sequence that can be found in the [Players](https://dashboard.jwplayer.com/#/players) section in your JW Player Dashboard. | ||
|
||
**data-media-id** | ||
|
||
The JW Platform media id. This is an 8-digit alphanumeric sequence that can be found in the [Content](https://dashboard.jwplayer.com/#/content) section in your JW Player Dashboard. | ||
|
||
**data-playlist-id** | ||
|
||
The JW Platform playlist id. This is an 8-digit alphanumeric sequence that can be found in the [Playlists](https://dashboard.jwplayer.com/#/content/playlists) section in your JW Player Dashboard. If both a `data-playlist-id` and `data-media-id` are specified, `data-playlist-id` takes precedence. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does jwplayer support poster images that can be shown without loading the player?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cramforce We do support poster images in the platform, but not all media assets have them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check out how we do this for youtube. It has handling for the case where the poster image is missing.