Skip to content

Commit

Permalink
feat: More complete support for stitched ad scenarios. (#415)
Browse files Browse the repository at this point in the history
  • Loading branch information
misteroneill committed Aug 23, 2018
1 parent 35c9e54 commit a533bbb
Show file tree
Hide file tree
Showing 28 changed files with 720 additions and 91 deletions.
29 changes: 1 addition & 28 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,3 @@
# CONTRIBUTING

We welcome contributions from everyone!

## Getting Started

Make sure you have NodeJS 0.10 or higher and npm installed.

1. Fork this repository and clone your fork
1. Install dependencies: `npm install`
1. Run a development server: `npm start`

### Making Changes

Refer to the [video.js plugin conventions][conventions] for more detail on best practices and tooling for video.js plugin authorship.

When you've made your changes, push your commit(s) to your fork and issue a pull request against the original repository.

### Running Tests

Testing is a crucial part of any software project. For all but the most trivial changes (typos, etc) test cases are expected. Tests are run in actual browsers using [Karma][karma].

- In all available and supported browsers: `npm test`
- In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc.
- While development server is running (`npm start`), navigate to [`http://localhost:9999/test/`][local]


[karma]: http://karma-runner.github.io/
[local]: http://localhost:9999/test/
[conventions]: https://github.com/videojs/generator-videojs-plugin/blob/master/docs/conventions.md
See: [docs/developer/index.md](docs/developer/index.md)
2 changes: 1 addition & 1 deletion docs/developer/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ npm run test

### In browser

Run `./node_modules/.bin/karma start --no-single-run --browsers Chrome test/karma.conf.js` then open `localhost:9876/debug.html`. This can be useful for debugging tests.
Run `npm start` and a Chrome instance will launch with Karma's debug interface at `localhost:9876`, allowing you to debug tests. Also, a static server will run and allow you to look at examples at `localhost:9999`.

## What's Next

Expand Down
25 changes: 25 additions & 0 deletions examples/stitched-ad-plugin/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.ad-event {
background-color: #ffe400;
}
.content-event {
background-color: #66a8cc;
}
.content-adplugin-event {
background-color: #00a866;
}
ol {
list-style-type: none;
padding: 0;
font-family: monospace;
white-space: pre;
}

/* cue-text-tracks-example Styles */

.ad-container .vjs-play-progress.vjs-slider-bar {
background-color: #ff0000;
}

.ad-container .vjs-big-play-button {
display: none;
}
99 changes: 99 additions & 0 deletions examples/stitched-ad-plugin/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
(function() {
'use strict';
var pad = function(n, x, c) {
return (new Array(n).join(c || '0') + x).slice(-n);
};
var padRight = function(n, x, c) {
return (x + (new Array(n).join(c || '0'))).slice(0, n);
};

var player = window.player = videojs('examplePlayer');

// initalize example ad plugin for this player
player.exampleStitchedAds({
debug: true
});

var log = document.querySelector('.log');
var Html5 = videojs.getTech('Html5');

var eventList = Html5.Events.concat(Html5.Events.map(function(evt) {
return 'ad' + evt;
})).concat(Html5.Events.map(function(evt) {
return 'content' + evt;
})).concat([
// events emitted by ad plugin
'adtimeout',
'contentupdate',
'contentplayback',
'readyforpreroll',
'readyforpostroll',
// events emitted by third party ad implementors
'adsready',
'adscanceled',
'adplaying',
'adstart', // startLinearAdMode()
'adend', // endLinearAdMode()
'nopreroll',
'nopostroll'

]).filter(function(evt) {
var events = {
progress: 1,
timeupdate: 1,
suspend: 1,
emptied: 1,
durationchange: 1,
contentprogress: 1,
contenttimeupdate: 1,
contentsuspend: 1,
contentemptied: 1,
adprogress: 1,
adtimeupdate: 1,
adsuspend: 1,
ademptied: 1,
adabort: 1
}

return !(evt in events);
});

player.on(eventList, function(event) {
var d , str, li, evt;

evt = event.type;
li = document.createElement('li');

d = new Date();
d = '' +
pad(2, d.getHours()) + ':' +
pad(2, d.getMinutes()) + ':' +
pad(2, d.getSeconds()) + '.' +
pad(3, d.getMilliseconds());

if (event.type.indexOf('ad') === 0) {
li.className = 'ad-event';
} else if (event.type.indexOf('content') === 0) {
li.className = 'content-event';
}

str = d + ' ' + evt;

if (evt === 'contentupdate') {
str += ' ' + event.oldValue + " -> " + event.newValue;
li.className = 'content-adplugin-event';
}
if (evt === 'contentchanged') {
li.className = 'content-adplugin-event';
}
if (evt === 'contentplayback') {
li.className = 'content-adplugin-event';
}
if (evt === 'adplay') {
player.trigger('ads-ad-started');
}

li.innerHTML = str;
log.insertBefore(li, log.firstChild);
});
})();
38 changes: 38 additions & 0 deletions examples/stitched-ad-plugin/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Stitched Ads Example</title>
<link rel="stylesheet" href="../../node_modules/video.js/dist/video-js.css">
<script src="../../node_modules/video.js/dist/video.js"></script>
<link rel="stylesheet" href="../../dist/videojs-contrib-ads.css">
<script src="../../dist/videojs-contrib-ads.js"></script>
<link rel="stylesheet" href="app.css">
</head>
<body>
<h1>Stitched Ads Example</h1>

<p>This page uses the built files, so you must do a local build before the example will work.</p>

<p>This is a limited example implementation that puts the player into and out of ad mode for 5 seconds at specific times.</p>

<video
id="examplePlayer"
class="video-js vjs-default-skin"
width="640"
height="264"
poster="http://vjs.zencdn.net/v/oceans.png"
controls>
<source src="http://vjs.zencdn.net/v/oceans.mp4" type="video/mp4">
<source src="http://vjs.zencdn.net/v/oceans.webm" type="video/webm">
<source src="http://vjs.zencdn.net/v/oceans.ogv" type="video/ogg">
</video>

<h2>Events</h2>

<ol class="log"></ol>

<script src="./plugin.js"></script>
<script src="./app.js"></script>
</body>
</html>
68 changes: 68 additions & 0 deletions examples/stitched-ad-plugin/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@

// This is an example of a very simple, naive stitched ads plugin. This means
// there is a single source within which are the "ads".
//
// We'll simulate a preroll for the first 5 seconds of playback, a midroll at
// 15 seconds, and a postroll.
//
// In reality, it's left up to the integration to define when and where ad
// mode is started and ended via some kind of mapping or manifest.
//
videojs.registerPlugin('exampleStitchedAds', function(options) {
var player = this;

options = options || {};
options.stitchedAds = true;

// Initialize contrib-ads.
player.ads(options);

player.on('canplay', function() {
player.one('playing', function() {
var havePlayedPreroll = false;
var haveStartedMidroll = false;
var haveStartedPostroll = false;
var havePlayedMidroll = false;

// Simulate a pre-roll immediately upon playback starting.
player.ads.startLinearAdMode();

// Simulate a mid-roll at 15 seconds and a post-roll at 5 seconds from
// the end. Need to listen to both timeupdate and adtimeupdate because
// redispatch will prefix during ads.
player.on(['timeupdate', 'adtimeupdate'], function(e) {
var currentTime = player.currentTime();
var duration = player.duration();

// End the pre-roll.
if (!havePlayedPreroll && currentTime >= 5) {
havePlayedPreroll = true;
player.ads.endLinearAdMode();
return;
}

// Start the mid-roll.
if (!haveStartedMidroll && currentTime >= 15) {
haveStartedMidroll = true;
player.ads.startLinearAdMode();
return;
}

// End the mid-roll.
if (!havePlayedMidroll && currentTime >= 20) {
havePlayedMidroll = true;
player.ads.endLinearAdMode();
return;
}

// Start the post-roll.
// The post-roll will be ended automatically via the `adended` event.
if (!haveStartedPostroll && currentTime >= duration - 5) {
haveStartedPostroll = true;
player.ads.startLinearAdMode();
return;
}
});
});
});
});
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<li><a href="examples/basic-ad-plugin/">Example ad plugin.</a></li>
<li><a href="examples/basic-ad-plugin/cue-text-tracks-example.html">Example cueTextTracks plugin.</a></li>
<li><a href="examples/module-import">Example using modules</a></li>
<li><a href="examples/stitched-ad-plugin/">Example stitched ad plugin.</a></li>
</ul>
<script src="node_modules/es5-shim/es5-shim.js"></script>
<script src="node_modules/video.js/dist/video.js"></script>
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@
"postclean": "mkdirp dist test/dist",
"lint": "eslint src",
"prestart": "npm run build",
"start": "npm-run-all -p start:server watch",
"start": "npm-run-all -p start:* watch",
"start:server": "static -a 0.0.0.0 -p 9999 -H '{\"Cache-Control\": \"no-cache, must-revalidate\"}' .",
"start:test": "karma start --no-single-run --browsers Chrome test/karma.conf.js",
"pretest": "npm-run-all lint build",
"test": "karma start test/karma.conf.js",
"preversion": "npm test",
Expand Down
15 changes: 9 additions & 6 deletions scripts/modules.rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import babel from 'rollup-plugin-babel';
import json from 'rollup-plugin-json';

export default {
moduleName: 'videojsContribAds',
entry: 'src/plugin.js',
name: 'videojsContribAds',
input: 'src/plugin.js',
external: [
'global/document',
'global/window',
Expand All @@ -19,6 +19,13 @@ export default {
globals: {
'video.js': 'videojs'
},
output: [{
file: 'dist/videojs-contrib-ads.cjs.js',
format: 'cjs',
}, {
file: 'dist/videojs-contrib-ads.es.js',
format: 'es'
}],
legacy: true,
plugins: [
json(),
Expand All @@ -37,9 +44,5 @@ export default {
'transform-object-assign'
]
})
],
targets: [
{dest: 'dist/videojs-contrib-ads.cjs.js', format: 'cjs'},
{dest: 'dist/videojs-contrib-ads.es.js', format: 'es'}
]
};
10 changes: 6 additions & 4 deletions scripts/test.rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import multiEntry from 'rollup-plugin-multi-entry';
import resolve from 'rollup-plugin-node-resolve';

export default {
moduleName: 'videojsContribAdsTests',
entry: 'test/**/test.*.js',
dest: 'test/dist/bundle.js',
format: 'iife',
name: 'videojsContribAdsTests',
input: 'test/**/test.*.js',
output: {
file: 'test/dist/bundle.js',
format: 'iife'
},
external: [
'qunit',
'qunitjs',
Expand Down
10 changes: 6 additions & 4 deletions scripts/umd.rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import json from 'rollup-plugin-json';
import resolve from 'rollup-plugin-node-resolve';

export default {
moduleName: 'videojsContribAds',
entry: 'src/plugin.js',
dest: 'dist/videojs-contrib-ads.js',
format: 'umd',
name: 'videojsContribAds',
input: 'src/plugin.js',
output: {
file: 'dist/videojs-contrib-ads.js',
format: 'umd'
},
external: ['video.js'],
globals: {
'video.js': 'videojs'
Expand Down
4 changes: 2 additions & 2 deletions src/adBreak.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function start(player) {
player.trigger('adstart');

// Capture current player state snapshot
if (!player.ads.shouldPlayContentBehindAd(player)) {
if (player.ads.shouldTakeSnapshots()) {
player.ads.snapshot = snapshot.getPlayerSnapshot(player);
}

Expand Down Expand Up @@ -64,7 +64,7 @@ function end(player, callback) {
}

// Restore snapshot
if (!player.ads.shouldPlayContentBehindAd(player)) {
if (player.ads.shouldTakeSnapshots()) {
snapshot.restorePlayerSnapshot(player, callback);

// Reset the volume to pre-ad levels
Expand Down
Loading

0 comments on commit a533bbb

Please sign in to comment.