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

Implemented Media Session API for video components #10476

Merged
merged 7 commits into from
Aug 2, 2017

Conversation

wassgha
Copy link
Contributor

@wassgha wassgha commented Jul 17, 2017


This implements the Media Session API inside the video manager as described in #7272

Changes

  • Added a new variable that players implementing the video-interface should expose : metaData which contains posterUrl (512x512 png image), title, album, artist.
  • Implemented guessing logic to fill in missing information from metaData (see to-do)
  • Update Media Session using gathered and guessed metaData when the video loads as well as when the video starts playing (so that we override the media session when switching between videos on the same page)
  • Added opt-out method preimplementsMediaSession for players already implementing the Media Session API (amp-youtube for example) so that we don't override their implementation
  • Implemented the preimplementsMediaSession on amp-youtube to opt-out
  • Added multiple parsers for album artwork in this order:
  1. poster attribute
  2. schema for NewsArticle usually contains a thumbnail
  3. meta images (og:image in particular if available)
  4. favicon

Deciding whether these other sources might be useful:

  1. First image in the body of the document
  2. first frame of the video

Excluded players list

List of video players that have a good implementation of the Media Session API already built-in.

  • amp-vimeo
  • amp-youtube

To-do

  • Determine which players may benefit from an opt-out like amp-youtube
  • Implement seek/next/previous track

Closes #7272 , Checks off an item on #4154

* Returns video's meta data (poster, artist, album, etc.)
* @return {!VideoMetaDef} metadata
*/
get metaData() {}
Copy link
Contributor

Choose a reason for hiding this comment

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

getMetaData() for consistency

@@ -362,3 +379,13 @@ export const VideoAnalyticsType = {
* }}
*/
export let VideoAnalyticsDetailsDef;

/**
* @typedef {{
Copy link
Contributor

Choose a reason for hiding this comment

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

define on top of the file

@@ -87,6 +87,23 @@ export class VideoInterface {
hideControls() {}

/**
* Returns video's meta data (poster, artist, album, etc.)
Copy link
Contributor

Choose a reason for hiding this comment

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

mention it will be used for session API


}

getDefaultPoster_() {
Copy link
Contributor

Choose a reason for hiding this comment

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

let's not do default. it doesn't really add value and just makes the JS files bigger

*
* @return {boolean}
*/
optOutOfAutomaticMediaSessionAPI() {}
Copy link
Contributor

Choose a reason for hiding this comment

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

preimplementsMediaSession sounded better

artwork: [
{
src: this.metaData_.posterUrl,
sizes: '512x512',
Copy link
Contributor

Choose a reason for hiding this comment

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

do they scale properly?

});

navigator.mediaSession.setActionHandler('play', function() {
this.video.play();
Copy link
Contributor

Choose a reason for hiding this comment

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

play(/*isAutoplay*/ false)

metaData = {};
}
if (!metaData.artist) {
metaData.artist = 'No artist';
Copy link
Contributor

Choose a reason for hiding this comment

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

we should not mutate their object. Use map() from object.js to create a map using their object as initial data and then mutate (and cache) the map

if (!metaData.artist) {
metaData.artist = 'No artist';
}
if (!metaData.posterUrl) {
Copy link
Contributor

Choose a reason for hiding this comment

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

poster is very amp-video specific. We should just expect poster to be in meta data, manager can't do anything reasonable without it (except for a default which I argue we should not have)

Copy link
Contributor

Choose a reason for hiding this comment

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

(oh unless do fallback to AMP specific thumbnail in the schema.org metadata and then to the favicon)

|| this.ampdoc_.win.document.title;
}
if (!metaData.album) {
metaData.album = 'No album';
Copy link
Contributor

Choose a reason for hiding this comment

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

what happens if we don't set it? we don't have good localization story for bultin text like "no album" yet.

@wassgha wassgha force-pushed the media-session branch 2 times, most recently from 5c90a36 to dbadc6b Compare July 24, 2017 19:46
@wassgha wassgha force-pushed the media-session branch 5 times, most recently from a494d11 to 22cfa6c Compare July 30, 2017 05:31
@wassgha
Copy link
Contributor Author

wassgha commented Jul 30, 2017

@aghassemi should be ready for a final review :) . If we want to implement next/previous from lightbox 2.0 in the same PR, we need to talk since I don't have much information about that.

@@ -240,6 +240,21 @@ class Amp3QPlayer extends AMP.BaseElement {
}

/** @override */
getMetaData() {
return {
Copy link
Contributor

Choose a reason for hiding this comment

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

let's allow these to be just

getMetadata() {
 /// Not implemented
}

and handle undefined/null in the video manager

* Updates the Media Session API's metadata
* @param {!./ampdoc-impl.AmpDoc} ampdoc
* @param {!./video-interface.VideoMetaDef} metaData
* @param {function} playHandler
Copy link
Contributor

Choose a reason for hiding this comment

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

function()=

// Clear mediaSession (required to fix a bug when switching between two
// videos)
navigator.mediaSession.metadata = new win.MediaMetadata({
title: '',
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: as a constant variable defined outside and typed as video-interface.VideoMetaDef

const schema = doc.querySelector('script[type="application/ld+json"]');
if (!schema) {
// No schema element found
return undefined;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: just return;


// Image definition in schema could be one of :
if (schemaJson.image['@list']
&& schemaJson.image['@list'][0]
Copy link
Contributor

Choose a reason for hiding this comment

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

undefined/null check is already covered by the typeof check

]
});
// Add metaData
navigator.mediaSession.metadata = new win.MediaMetadata(metaData);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: do a sweep of variable naming for this PR so we always do (M/m)etadata instead of (M/m)etaData to match native naming.

@@ -305,6 +305,21 @@ class AmpVideo extends AMP.BaseElement {
}

/** @override */
getMetaData() {
return {
'artwork': [],
Copy link
Contributor

Choose a reason for hiding this comment

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

amp-video should do the lookups for poster instead of manager.


if (!this.metaData_.artwork || this.metaData_.artwork.length == 0) {
const posterUrl = this.video.element.getAttribute('poster')
|| this.internalElement_.getAttribute('poster')
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto comment about poster being the responsibility of amp-video

if (!this.metaData_.title) {
const title = this.video.element.getAttribute('title')
|| this.video.element.getAttribute('aria-label')
|| this.internalElement_.getAttribute('title')
Copy link
Contributor

Choose a reason for hiding this comment

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

probably should not look into internalElement (there shouldn't be any cases where inner element has has but not the custom element wrapper of it)

@@ -17,6 +17,16 @@
import {ActionTrust} from './action-trust'; /* eslint no-unused-vars: 0 */

/**
* @typedef {{
* artwork: string,
Copy link
Contributor

Choose a reason for hiding this comment

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

artwork is array right?

@wassgha wassgha force-pushed the media-session branch 7 times, most recently from 5e95027 to 8221fd2 Compare August 1, 2017 16:42
@aghassemi
Copy link
Contributor

aghassemi commented Aug 1, 2017

@erwinmombay for the addEventListener extern, see google/closure-compiler#1959 and https://github.com/google/closure-compiler/blob/master/contrib/externs/w3c_eventsource.js it is supposed to be fixed already by closure compiler, an upgrade might be simpler than doing our own override?

// 1. "image": "http://..",
return schemaJson['image'];
} else if (schemaJson['image']['@list']
&& schemaJson['image']['@list'][0]
Copy link
Contributor

@aghassemi aghassemi Aug 1, 2017

Choose a reason for hiding this comment

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

ditto: unnecessary check here and 2 more places below

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Didn't pass when I removed them :(

@@ -105,6 +115,28 @@ export class VideoInterface {
hideControls() {}

/**
* Returns video's meta data (artwork, title, artist, album, etc.) for use
* with the Media Session API
* artwork (string): URL to the poster image (preferably a 512x512 PNG)
Copy link
Contributor

Choose a reason for hiding this comment

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

array for the artwork

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants