JW Player 5.3 introduced HTML5 support and a new JavaScript API Reference that runs seamlessly across all modes of the player. However, because Flash plugins can't run in HTML5 mode and because the player had no method for loading pre-packaged JavaScript code, there was no good way to easily distribute code that relied on the new API.
With JW Player 5.5, we are introducing a new *JavaScript* Plugin API. All of the power and flexibility of the 5.3 player's JavaScript API is now available with a simple distribution mechanism similar to that of Flash plugins. This means your plugins will run seamlessly in both Flash and HTML5 mode, with no additional work on your part.
We have added in mechanisms for placing visual assets in the player's display area, adding dock buttons, and allowing JavaScript plugins to expose a public API. All of these together create a strong foundation on which to build powerful plugins.
Building plugins for the JW Player requires a fairly minimal toolset. Specifically, you'll need:
We also recommend that you set up a local web server for testing (tools like XAMPP for Windows and MAMP for Mac make this incredibly quick).
Here is a very basic example plugin, which displays some text on top of the player:
(function(jwplayer){
var template = function(player, config, div) {
function setup(evt) {
div.style.color = 'white';
div.innerHTML = config.text;
};
player.onReady(setup);
this.resize = function(width, height) {};
};
jwplayer().registerPlugin('helloworld', template);
})(jwplayer);
Let's walk through this line by line:
Now that we've got our plugin, we need to load it into a player. Store the plugin in a folder, together with the player.swf and jwplayer.js files from the player download. Also add in a test video. Then create another file called helloworld.html in the same directory with the following contents:
<html>
<head>
<script src="./jwplayer.js" type="text/javascript"></script>
</head>
<body>
<div id="player"></div>
<script type="text/javascript">
jwplayer('player').setup({
flashplayer: './player.swf',
file: './video.mp4',
plugins: {
'./helloworld.js': {
text: 'Hello world!'
}
}
});
</script>
</body>
</html>
This HTML file embeds the player, assigns the plugin to the player, and sets the text option of the plugin to Hello World''. Let's walk through it:
That's it! You've created and embedded your first JW Player plugin. Make sure you test this plugin either online or at a local webserver (see Introduction). Just loading the page in your local browser will give a security error!
As you could see in the example, a plugin requires two blocks of code: the code used for loading/registering the plugin, and the plugin code itself. Let's first walk through the loading mechanism.
A plugin can be embedded into a player through the plugins option block. There are two ways to embed a plugin:
jwplayer('player').setup({
flashplayer: '/assets/player.swf',
file: '/assets/video.mp4',
plugins: {
'/assets/helloworld.js': { text: 'Hello world!' }
}
});
jwplayer('player').setup({
flashplayer: '/assets/player.swf',
file: '/assets/video.mp4',
plugins: {
'helloworld': { text: 'Hello world!' }
}
});
The player looks at the file extension (.js) to determine if a plugin is locally loaded or loaded from our CDN. In the latter case, the player constructs the plugin URL through a simple mechanism ( http://plugins.longtailvideo.com + ID + .js).
Note there is a third option for embedding a plugin: a local SWF: "/assets/helloworld.swf": { text: "Hello world!" }. That option is solely useful for ActionScript-only plugins though.
Multiple plugins can be loaded in one player, and hosted + local plugins can be combined. Plugins also can have no options:
jwplayer('player').setup({
flashplayer: '/assets/player.swf',
file: '/assets/video.mp4',
plugins: {
'helloworld': { text: 'Hello world!' },
'/assets/localtest.js': { id: 2889, startup: true },
'viral': { }
}
});
The plugin javascript is loaded and inserted into the DOM by the first player that has the plugin set in its plugins block. If multiple players use the same plugin, the plugin is still loaded/inserted once.
When a JavaScript plugin file is inserted into the DOM, it is executed by the browser. Part of every plugin is the jwplayer().registerPlugin() call (see our example above). As the name says, it registers the plugin with the JW Player, making its code available to every player on the page:
jwplayer().registerPlugin(id, jsPlugin);
The registerPlugin() method has an interesting feature: it can be used to load an ActionScript (SWF) plugin, in addition to the regular plugin JavaScript. With this feature, you can write hybrid plugins. These plugins can leverage the power and performance of Flash, but work in HTML5 mode too:
jwplayer().registerPlugin(id, jsPlugin, swfURL);
In Flash mode, both the JavaScript and the ActionScript plugin are instantiated. In HTML5 mode, only the JavaScript plugin is instantiated. In your plugin, you can detect which mode is active by doing a player.getRenderingMode() API call.
As you could see in the example, a plugin needs two blocks of code: the code used for loading/registering the plugin, and the plugin code itself. Let's now take a look at the plugin itself.
The constructor (called template in the example) is the entry point for a plugin. It is called by every player on the page that wants to use this plugin. The constructor accepts three arguments: player, config and div:
In addition to the arguments that are passed into the JS, there is one required method for all plugins: this.resize(). It is automatically called by the player when it resizes, sending the new width and height of the video display (not the display + controlbar!) as values.
The this.resize method is also called on startup, when the player does an initial resize. Therefore, it's good practice to have the setup of your visuals triggered by this resize() call. For example, here's an example of a plugin's resize method that keeps the plugin centered in the player:
this.resize = function(width, height) {
div.style.position = 'absolute';
div.style.height = '60px';
div.style.width = '60px';
div.style.left = Math.round(width/2-30)+'px';
div.style.top = Math.round(height/2-30)+'px';
};
Every plugin has full access to the playlist of the player, both for retrieving playlist data and for changing/reloading the playlist. In addition to this, a plugin can leverage the playlist for offering per-video configuration options. A best practice for this is having your users set an option per playlistitem that has the structure pluginID.optionName.
For example, the HD plugin allows setting an hd.file option per playlist item:
jwplayer('mydiv').setup({
flashplayer:'/assets/player.swf',
playlist: [
{ file: '/video/bunny.mp4', 'hd.file': '/video/bunny-hq.mp4' },
{ file: '/video/dream.mp4', 'hd.file': '/video/dream-hq.mp4' },
{ file: '/video/sintel.mp4', 'hd.file': '/video/sintel-hq.mp4' }
],
plugins: {
hd: {}
}
});
Inside your plugin, you can simply access these options through the playlist calls of the JavaScript API. For example, you can add a listener to onPlaylistItem, which is called every time the player advances to the next video (included the one on startup):
var retrieveHD = function(index) {
var item = player.getPlaylistItem(index);
if(item['hd.file']) {
// Set HD version for this playlist entry.
} else if (options['file'] && index == 0) {
// Set HD version for single video.
} else {
// No HD for this playlist entry.
}
};
player.onPlaylistItem(retrieveHD);
The else if statement in this code block refers to the case in which not a playlist, but a single file, was loaded in the player. The embed code would then have looked like this:
jwplayer('mydiv').setup({
file: '/video/bunny.mp4',
flashplayer:'/assets/player.swf',
plugins: {
hd: { 'file': '/video/bunny-hq.mp4' }
}
});
In addition to simply dumping HTML over the video display, plugins can create a structured, elegant button that fits in nicely with the player's aesthetic. The JW Player implements a so-called dock for grouping these third-party buttons. You can add a button by using the dock's public setButton method. It has the following signature:
player.getPlugin("dock").setButton(id, handler, outGraphic, overGraphic);
Let's say we wanted our Hello World plugin to create a popup whenever we click a dock button. We go ahead and add in a call to setButton() in setup:
(function(jwplayer){
var template = function(player, config, div){
var sayhello = function() {
alert('Hello World!');
}
function setup(evt) {
player.getPlugin("dock").setButton('helloworld', sayhello, 'hello-out.png', 'hello-over.png');
}
player.onReady(setup);
this.resize = function(width, height) {
}
}
jwplayer().registerPlugin('helloworld', template);
})(jwplayer);
The PNG images placed in the dock are generally about 50x50px, consisting of a large icon and a short descriptive text. If you browse through the Addons Library, you'll see plenty of plugins using the dock.
Note that you can also update and remove a dock button (e.g. for toggles or for per-playlistitem features). To update the dock button, simply call setButton() again with the same id, but a different handler or graphics. To remove a dock button, call setButton() with just the id you originally used (no handler/graphics).
Under water, the dock is a player plugin like any other. It exposes its setButton() call through a standardized mechanism. Any plugin can use this mechanism for offering API calls, to both other plugins and the surrounding page. To access a plugin's API, simply use the getPlugin('pluginid') method like this:
jwplayer().getPlugin('pluginid').publicMethod();
Inside a plugin, all functions of the form this.FUNCTION_NAME = function(ARGUMENTS) { will be publicly accessible. For example, take our our Hello World plugin. Let's say we wanted to expose a method called setText that allowed us to update the text. This would look something like:
(function(jwplayer){
var template = function(player, config, div){
function setup(evt) {
div.innerHTML = config.text;
}
player.onReady(setup);
this.setText = function(text) {
div.innerHTML = text;
}
this.resize = function(width, height) {}
}
jwplayer().registerPlugin('helloworld', template);
})(jwplayer);
The ability to create a public plugin API is available only for JavaScript plugins. For hybrid ActionScript/JavaScript plugins, you can create a bridge between the JS and the SWF. That way, the same API can be exposed, regardless of the player being in Flash or HTML5 mode.
When you're happy with the functionalities of your plugin, it's time to wrap it up for release. There's a few things you should do to optimize the loading of the plugin. If you want to share your plugin with others (please do!), you can submit it to our Addons library.
We highly recommend minifying your JS using either the YUI Compressor or the Google Closure Compiler. This will simply reduce the size of your plugin - it will have no impact on performance.
If you're using images in your plugin, you can base64 encode and then embed them into the javascript. This will:
Many tools exist, both online and offline, to base64 encode an image. Here is an example page where you can simply upload your image and copy/paste the resulting Base64 hash.
If you are interested in sharing your plugin, you can submit it to our AddOns library. Plugins that end up in the library are used in thousands of websites, so you may get a lot of exposure. Additionally, other developers can learn from your code, or contribute back their bugfixes/enhancements.
When submitting a plugin to us, please include the following data:
When ready, you can pack all data in a ZIP and send it to us through this form. We'll get back to you within a few hours!