Skip to content
Open
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
26 changes: 22 additions & 4 deletions extensions/amp-youtube/0.1/amp-youtube.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ class AmpYoutube extends AMP.BaseElement {
/** @private {?string} */
this.liveChannelid_ = null;

/** @private {?string} */
this.channelid_ = null;

/** @private {?boolean} */
this.muted_ = false;

Expand Down Expand Up @@ -137,6 +140,7 @@ class AmpYoutube extends AMP.BaseElement {
buildCallback() {
this.videoid_ = this.getVideoId_();
this.liveChannelid_ = this.getLiveChannelId_();
this.channelid_ = this.getChannelId_();
this.assertDatasourceExists_();

const deferred = new Deferred();
Expand All @@ -156,7 +160,11 @@ class AmpYoutube extends AMP.BaseElement {
const baseUrl = `https://www.youtube${urlSuffix}.com/embed/`;
const descriptor = this.videoid_
? `${encodeURIComponent(this.videoid_ || '')}?`
: `live_stream?channel=${encodeURIComponent(this.liveChannelid_ || '')}&`;
: this.liveChannelid_
? `live_stream?channel=${encodeURIComponent(this.liveChannelid_ || '')}&`
: // Channel embeds use the channel's uploads playlist. The uploads
// playlist id is the channel id prefixed with "UU".
`?listType=playlist&list=UU${encodeURIComponent(this.channelid_ || '')}&`;
return `${baseUrl}${descriptor}enablejsapi=1&amp=1`;
}

Expand Down Expand Up @@ -331,6 +339,14 @@ class AmpYoutube extends AMP.BaseElement {
return this.element.getAttribute('data-live-channelid');
}

/**
* @return {?string}
* @private
*/
getChannelId_() {
return this.element.getAttribute('data-channelid');
}

/**
* @return {?string}
* @private
Expand All @@ -353,11 +369,13 @@ class AmpYoutube extends AMP.BaseElement {
assertDatasourceExists_() {
const datasourceExists =
!(this.videoid_ && this.liveChannelid_) &&
(this.videoid_ || this.liveChannelid_);
!(this.videoid_ && this.channelid_) &&
!(this.liveChannelid_ && this.channelid_) &&
(this.videoid_ || this.liveChannelid_ || this.channelid_);
userAssert(
datasourceExists,
'Exactly one of data-videoid or ' +
'data-live-channelid should be present for <amp-youtube> %s',
'Exactly one of data-videoid, data-live-channelid or ' +
'data-channelid should be present for <amp-youtube> %s',
this.element
);
}
Expand Down
60 changes: 58 additions & 2 deletions extensions/amp-youtube/0.1/test/test-amp-youtube.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import {VideoEvents_Enum} from '../../../../src/video-interface';

const EXAMPLE_VIDEOID = 'mGENRKrdoGY';
const EXAMPLE_LIVE_CHANNELID = 'UCB8Kb4pxYzsDsHxzBfnid4Q';
const EXAMPLE_CHANNELID = 'UCB8Kb4pxYzsDsHxzBfnid4Q';
const EXAMPLE_VIDEOID_URL = `https://www.youtube.com/embed/${EXAMPLE_VIDEOID}?enablejsapi=1&amp=1&playsinline=1`;
const EXAMPLE_LIVE_CHANNELID_URL = `https://www.youtube.com/embed/live_stream?channel=${EXAMPLE_LIVE_CHANNELID}&enablejsapi=1&amp=1&playsinline=1`;
const EXAMPLE_CHANNELID_URL = `https://www.youtube.com/embed/?listType=playlist&list=UU${EXAMPLE_CHANNELID}&enablejsapi=1&amp=1&playsinline=1`;
const EXAMPLE_NO_COOKIE_VIDEOID_URL = `https://www.youtube-nocookie.com/embed/${EXAMPLE_VIDEOID}?enablejsapi=1&amp=1&playsinline=1`;

describes.realWin(
Expand Down Expand Up @@ -256,6 +258,14 @@ describes.realWin(
expect(iframe.src).to.equal(EXAMPLE_LIVE_CHANNELID_URL);
});

it('renders for channel ids', async () => {
const yt = await getYt({'data-channelid': EXAMPLE_CHANNELID});
const iframe = yt.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.tagName).to.equal('IFRAME');
expect(iframe.src).to.equal(EXAMPLE_CHANNELID_URL);
});

it('uses privacy-enhanced mode', async () => {
const yt = await getYt({
'data-videoid': EXAMPLE_VIDEOID,
Expand All @@ -267,14 +277,60 @@ describes.realWin(
expect(iframe.src).to.equal(EXAMPLE_NO_COOKIE_VIDEOID_URL);
});

it('requires data-videoid or data-live-channelid', () => {
it('requires exactly one datasource (empty)', () => {
return allowConsoleError(() => {
return getYt({}).should.eventually.be.rejectedWith(
/Exactly one of data-videoid or data-live-channelid should/
/Exactly one of data-videoid, data-live-channelid or data-channelid should/
);
});
});

it('rejects data-videoid and data-channelid together', () => {
return allowConsoleError(() => {
return getYt({
'data-videoid': EXAMPLE_VIDEOID,
'data-channelid': EXAMPLE_CHANNELID,
}).should.eventually.be.rejectedWith(
/Exactly one of data-videoid, data-live-channelid or data-channelid should/
);
});
});

it('rejects data-live-channelid and data-channelid together', () => {
return allowConsoleError(() => {
return getYt({
'data-live-channelid': EXAMPLE_LIVE_CHANNELID,
'data-channelid': EXAMPLE_CHANNELID,
}).should.eventually.be.rejectedWith(
/Exactly one of data-videoid, data-live-channelid or data-channelid should/
);
});
});

it('rejects all three datasources together', () => {
return allowConsoleError(() => {
return getYt({
'data-videoid': EXAMPLE_VIDEOID,
'data-live-channelid': EXAMPLE_LIVE_CHANNELID,
'data-channelid': EXAMPLE_CHANNELID,
}).should.eventually.be.rejectedWith(
/Exactly one of data-videoid, data-live-channelid or data-channelid should/
);
});
});

it('uses no-cookie mode for channel embeds', async () => {
const yt = await getYt({
'data-channelid': EXAMPLE_CHANNELID,
'credentials': 'omit',
});
const iframe = yt.querySelector('iframe');
expect(iframe).to.not.be.null;
expect(iframe.src).to.contain('youtube-nocookie.com');
expect(iframe.src).to.contain('listType=playlist');
expect(iframe.src).to.contain('list=UU' + EXAMPLE_CHANNELID);
});

it('adds an img placeholder in prerender mode if source is videoid', async () => {
const yt = await getYt(
{'data-videoid': EXAMPLE_VIDEOID},
Expand Down
4 changes: 2 additions & 2 deletions extensions/amp-youtube/0.1/test/validator-amp-youtube.out
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ FAIL
| <!-- Invalid: data-videoid and data-live-channelid both missing. -->
| <amp-youtube width="480" height="270"></amp-youtube>
>> ^~~~~~~~~
amp-youtube/0.1/test/validator-amp-youtube.html:34:2 The tag 'amp-youtube' is missing a mandatory attribute - pick one of ['data-live-channelid', 'data-videoid']. (see https://amp.dev/documentation/components/amp-youtube)
amp-youtube/0.1/test/validator-amp-youtube.html:34:2 The tag 'amp-youtube' is missing a mandatory attribute - pick one of ['data-live-channelid', 'data-videoid', 'data-channelid']. (see https://amp.dev/documentation/components/amp-youtube)
| <!-- Invalid: dimensions are missing. -->
| <amp-youtube data-videoid="dQw4w9WgXcQ">
>> ^~~~~~~~~
Expand All @@ -49,7 +49,7 @@ amp-youtube/0.1/test/validator-amp-youtube.html:39:2 The attribute 'data-videoid
| <!-- Invalid: cannot have both data-videoid and data-live-channelid -->
| <amp-youtube width="480" height="270"
>> ^~~~~~~~~
amp-youtube/0.1/test/validator-amp-youtube.html:43:2 Mutually exclusive attributes encountered in tag 'amp-youtube' - pick one of ['data-live-channelid', 'data-videoid']. (see https://amp.dev/documentation/components/amp-youtube)
amp-youtube/0.1/test/validator-amp-youtube.html:43:2 Mutually exclusive attributes encountered in tag 'amp-youtube' - pick one of ['data-live-channelid', 'data-videoid', 'data-channelid']. (see https://amp.dev/documentation/components/amp-youtube)
| data-live-channelid="UCB8Kb4pxYzsDsHxzBfnid4Q"
| data-videoid="dQw4w9WgXcQ">
| </amp-youtube>
Expand Down
4 changes: 2 additions & 2 deletions extensions/amp-youtube/1.0/test/validator-amp-youtube.out
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ FAIL
| <!-- Invalid: data-videoid and data-live-channelid both missing. -->
| <amp-youtube width="480" height="270"></amp-youtube>
>> ^~~~~~~~~
amp-youtube/1.0/test/validator-amp-youtube.html:42:4 The tag 'amp-youtube' is missing a mandatory attribute - pick one of ['data-live-channelid', 'data-videoid']. (see https://amp.dev/documentation/components/amp-youtube)
amp-youtube/1.0/test/validator-amp-youtube.html:42:4 The tag 'amp-youtube' is missing a mandatory attribute - pick one of ['data-live-channelid', 'data-videoid', 'data-channelid']. (see https://amp.dev/documentation/components/amp-youtube)
|
| <!-- Invalid: dimensions are missing. -->
| <amp-youtube data-videoid="dQw4w9WgXcQ"> </amp-youtube>
Expand All @@ -62,7 +62,7 @@ amp-youtube/1.0/test/validator-amp-youtube.html:48:4 The attribute 'data-videoid
| <!-- Invalid: cannot have both data-videoid and data-live-channelid -->
| <amp-youtube
>> ^~~~~~~~~
amp-youtube/1.0/test/validator-amp-youtube.html:56:4 Mutually exclusive attributes encountered in tag 'amp-youtube' - pick one of ['data-live-channelid', 'data-videoid']. (see https://amp.dev/documentation/components/amp-youtube)
amp-youtube/1.0/test/validator-amp-youtube.html:56:4 Mutually exclusive attributes encountered in tag 'amp-youtube' - pick one of ['data-live-channelid', 'data-videoid', 'data-channelid']. (see https://amp.dev/documentation/components/amp-youtube)
| width="480"
| height="270"
| data-live-channelid="UCB8Kb4pxYzsDsHxzBfnid4Q"
Expand Down
4 changes: 4 additions & 0 deletions extensions/amp-youtube/amp-youtube.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ For example, in this URL: `https://www.youtube.com/watch?v=Z1q71gFeRqM`, `Z1q71g

The Youtube channel id that provides a stable livestream url. For example, in this URL: `https://www.youtube.com/embed/live_stream?channel=UCB8Kb4pxYzsDsHxzBfnid4Q`, `UCB8Kb4pxYzsDsHxzBfnid4Q` is the channel id. You can provide a `data-live-channelid` instead of a `data-videoid` attribute to embed a stable url for a live stream instead of a video. Channels do not come with default placeholders. You can provide a placeholder for the video per example 2 above.

### data-channelid

The YouTube channel id whose uploads playlist should be embedded. For example, in this URL: `https://www.youtube.com/embed?listType=playlist&list=UUUB8Kb4pxYzsDsHxzBfnid4Q`, `UB8Kb4pxYzsDsHxzBfnid4Q` is the channel id (the uploads playlist id is the channel id prefixed with `UU`). You can provide a `data-channelid` instead of a `data-videoid` attribute to embed a channel's uploads instead of a single video. Channels do not come with default placeholders. You can provide a placeholder for the video per example 2 above.

### data-param-\*

All `data-param-*` attributes (with the exception of `data-param-autoplay` and `data-param-loop`) will be added as query parameter to the YouTube iframe src. This may be used to pass custom values through to YouTube plugins, such as whether to show controls.
Expand Down
9 changes: 7 additions & 2 deletions extensions/amp-youtube/validator-amp-youtube.protoascii
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,17 @@ tags: { # <amp-youtube>
}
attrs: {
name: "data-live-channelid"
mandatory_oneof: "['data-live-channelid', 'data-videoid']"
mandatory_oneof: "['data-live-channelid', 'data-videoid', 'data-channelid']"
value_regex: "[^=/?:]+"
}
attrs: {
name: "data-videoid"
mandatory_oneof: "['data-live-channelid', 'data-videoid']"
mandatory_oneof: "['data-live-channelid', 'data-videoid', 'data-channelid']"
value_regex: "[^=/?:]+"
}
attrs: {
name: "data-channelid"
mandatory_oneof: "['data-live-channelid', 'data-videoid', 'data-channelid']"
value_regex: "[^=/?:]+"
}
attrs: {
Expand Down
1 change: 1 addition & 0 deletions src/bento/components/bento-youtube/1.0/base-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ BaseElement['props'] = {
'controls': {attr: 'controls', type: 'boolean'},
'videoid': {attr: 'data-videoid'},
'liveChannelid': {attr: 'data-live-channelid'},
'channelid': {attr: 'data-channelid'},
'dock': {attr: 'dock', media: true},
'credentials': {attr: 'credentials'},
// TODO(wg-components): Current behavior defaults to loading="auto".
Expand Down
21 changes: 16 additions & 5 deletions src/bento/components/bento-youtube/1.0/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ function createDefaultInfo() {
function BentoYoutubeWithRef(
{
autoplay,
channelid,
credentials,
liveChannelid,
loop,
Expand All @@ -80,15 +81,19 @@ function BentoYoutubeWithRef(
ref
) {
const datasourceExists =
!(videoid && liveChannelid) && (videoid || liveChannelid);
!(videoid && liveChannelid) &&
!(videoid && channelid) &&
!(liveChannelid && channelid) &&
(videoid || liveChannelid || channelid);

if (!datasourceExists) {
throw new Error(
'Exactly one of data-videoid or data-live-channelid should be present for <amp-youtube>'
'Exactly one of data-videoid, data-live-channelid or ' +
'data-channelid should be present for <amp-youtube>'
);
}

let src = getEmbedUrl(credentials, videoid, liveChannelid);
let src = getEmbedUrl(credentials, videoid, liveChannelid, channelid);
if (!('playsinline' in params)) {
params['playsinline'] = '1';
}
Expand Down Expand Up @@ -205,7 +210,7 @@ function BentoYoutubeWithRef(
* @return {string}
* @private
*/
function getEmbedUrl(credentials, videoid, liveChannelid) {
function getEmbedUrl(credentials, videoid, liveChannelid, channelid) {
let urlSuffix = '';
if (credentials === 'omit') {
urlSuffix = '-nocookie';
Expand All @@ -214,10 +219,16 @@ function getEmbedUrl(credentials, videoid, liveChannelid) {
let descriptor = '';
if (videoid) {
descriptor = `${encodeURIComponent(videoid)}?`;
} else {
} else if (liveChannelid) {
descriptor = `live_stream?channel=${encodeURIComponent(
liveChannelid || ''
)}&`;
} else {
// Channel embeds use the channel's uploads playlist. The uploads
// playlist id is the channel id prefixed with "UU".
descriptor = `?listType=playlist&list=UU${encodeURIComponent(
channelid || ''
)}&`;
}
return `${baseUrl}${descriptor}enablejsapi=1&amp=1`;
}
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/errors.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

<amp-youtube
id="yt0"
data-expectederror="Exactly one of data-videoid or data-live-channelid should be"
data-expectederror="Exactly one of data-videoid, data-live-channelid or data-channelid should be"
YYYYYY="mGENRKrdoGY"
layout="responsive"
width="480" height="270"></amp-youtube>
Expand Down