SRGSSR / pillarbox-web

Pillarbox is a versatile media playback ecosystem engineered for the web.
https://srgssr.github.io/pillarbox-web-demo/
MIT License
12 stars 1 forks source link

Custom media data support and tracker control #32

Closed amtins closed 11 months ago

amtins commented 1 year ago

Motivation

Define a set of default properties that can be used by various tracking or recommendation tools.

These properties are intended to be agnostic of any tools using them, and it will also be possible to add custom properties.

Proposition

The task of providing a set of default properties can be time-consuming and complicated, without guaranteeing a satisfactory result.

The simplest approach would be to define a namespace that allows any type of data to be included. However, in some cases, it may be necessary to disable one or more trackers when starting a new playback session.

So, rather than defining a standard, it's better to define a convention to follow.

Solution

Thanks to video.js ability to inject custom properties directly into the source, the two properties to be added are:

The important point is that the player has no functional dependency on any tracker and it is therefore its responsibility to follow this convention or not. This also avoids breaking the default behavior of video.js.

Example

Case using a plain old source with custom properties

// undefined disableTrackers and mediaData
player.src({
  src: 'https://example.com/main.m3u8',
  type: 'application/x-mpegUR',
  mediaData: { prop1: 'prop1', prop2: 'prop2' },
});

player.currentSource().disableTrackers; // undefined
player.currentSource().mediaData; // { prop1: 'prop1', prop2: prop2 }

// empty disableTrackers and mediaData
player.src({
  src: 'https://example.com/main.m3u8',
  type: 'application/x-mpegUR',
  disableTrackers: [],
  mediaData: { prop1: 'prop1', prop2: 'prop2' },
});

player.currentSource().disableTrackers; // []
player.currentSource().mediaData; // { prop1: 'prop1', prop2: prop2 }

Case using middleware to resolve a custom source

Description

// Simulates a hypothetical call to a backend
const mockBackendCall = (mediaId) => ({
  src: 'https://example.com/main.m3u8',
  type: 'application/x-mpegUR',
  mediaData: { prop1: 'mockValue1', prop2: 10 },
});

// Middleware that resolves a custom source
videojs.use('media/id', function (player) {
  return {
    setSource: (srcObj, next) => {
      const { src: id, disableTrackers, mediaData } = srcObj;
      const { src, type, mockMediaData } = mockBackendCall(id);
      const srcMediaData = {
        src,
        type,
        disableTrackers,
        mediaData: { ...mockMediaData, ...mediaData },
      };

      next(null, srcMediaData);
    },
  };
});

// No custom mediaData and no disableTrackers
player.src({
  src: '1',
  type: 'media/id',
});

player.currentSource().disableTrackers; // undefined
player.currentSource().mediaData; // { prop1: 'mockValue1', prop2: 10 }

// With custom mediaData where prop1 overrides prop1 from mockBackendCall, and no disableTrackers
player.src({
  src: '2',
  type: 'media/id',
  mediaData: {
    // will merge mediaData with mediaData coming from mockBackendCall
    prop1: 'value1', // override the mediaData.prop1 from mockBackendCall
    propX: 'valueX',
  },
});

player.currentSource().disableTrackers; // undefined
player.currentSource().mediaData; // { prop1: 'value1', prop2: 10, propX: 'valueX' }

// With custom mediaData and disableTrackers disables tracker x
player.src({
  src: '3',
  type: 'media/id',
  disableTrackers: ['x'], // disable tracker x
  mediaData: {
    propX: 'valueX',
    propY: 'valueY',
    propZ: 'valueZ',
  },
});

player.currentSource().disableTrackers; // ['x']
player.currentSource().mediaData; // { prop1: 'mockValue1', prop2: 10, propX: 'valueX', propY: 'valueY', propZ: 'valueZ' }

// With disableTrackers disabling all trackers, no custom mediaData
player.src({
  src: '4',
  type: 'media/id',
  disableTrackers: true, // disable tracking
});

player.currentSource().disableTrackers; // true
player.currentSource().mediaData; // { prop1: 'mockValue1', prop2: 10 }
amtins commented 11 months ago

Observation

It seems that mediaData isn't the right term after all, as it could be confused with media.html#media-data.

github-actions[bot] commented 7 months ago

:tada: This issue has been resolved in version 1.0.0 :tada:

The release is available on:

Your semantic-release bot :package::rocket: