Yes, the Limecraft IFrame Player API lets you embed our player on your website and control it using JavaScript.
Using the API's JavaScript functions, you can load playlists for playback, play, pause etc. those videos. You can also add event listeners that will execute in response to certain player events, such as a player state change or a video reaching the end.
1. Requirements
The user's browser must support the HTML5 postMessage feature. Most modern browsers support it. The player should be at least 500px wide.
Any web page that uses the Limecraft iFrame API must also implement the following JavaScript function: onLimecraftPlayerAPIReady. The API will call this function when the page has finished downloading the JavaScript for the player API, which enables you to then use the API on your page. Thus, this function might create the player objects that you want to display when the page loads.
2. Getting started
2.1 HTML structure
Create a HTML page with a div element (1) where the player should be created. also load the script https://platform.limecraft.com/player/player-api.js and define a function onLimecraftPlayerAPIReady.
<!DOCTYPE html>
<html>
<body>
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="lc-player" style="width: 800px; height: 600px;"></div>
<script>
// 2. This code loads the Limecraft IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://platform.limecraft.com/player/player-api.js";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and Limecraft Player)
// after the API code downloads.
function onLimecraftPlayerAPIReady() {
//we will set up the player here
}
</script>
</body>
</html>
2.2 Initialise the player in onLimecraftPlayerAPIReady
The function onLimecraftPlayerAPIReady s called by the Player API once it is ready to create a player. From then on you can create a new Limecraft.Player.
The onPlayerReady callback is fired once the player is initialised and ready to be controlled. All calls on playerInstance should happen after this function was called.
var player;
function onLimecraftPlayerAPIReady() {
//create a new Limecraft.Player
playerInstance = new Limecraft.Player({
//points to the <div> element we set up earlier in the HTML
selector: '#lc-player',
//called once the player is ready to be controlled
onPlayerReady: function () {
//Load a playlist with one video
playerInstance.setPlaylist([
{
sources: [
{
"src": "http://bit.ly/karl_heynen--tromso_the_arctic_gateway",
"type": "video/mp4"
}
],
title: "karl_heynen--tromso_the_arctic_gateway"
}
]);
}
});
}
3. Loading media
3.1 Generic loading of media
Use setPlaylist to load a video. The example below loads a single mp4 video.
playerInstance.setPlaylist([
//this is a playlist entry
{
sources: [
{
"src": "http://bit.ly/Snow_Bench_Looping_Background-HD", //any public url which is playable in a html video element
"type": "video/mp4" //the mime type
}
],
title: "Snow_Bench_Looping_Background-HD.mp4" //(optional) shown briefly after media is loaded
}
]);
Try It
These events can be useful for your application when loading media:
event | arg0 | arg1 | Description |
---|---|---|---|
lc:player:error | {String} reason | {Object} errorObject with a String message property | an error occured while trying to load media |
lc:player:playlist:loaded | {Array. | the playlist is loaded | |
state:changed | {String} newState | {String} oldState | the state changed |
You can optionally pass the framerate, and a timecode offset, so the frame-by-frame controls work. Some more options are detailed in the example playlist entry below:
playerInstance.setPlaylist([
//more advanced playlist entry
{
sources: [
{
"src": "http://bit.ly/Snow_Bench_Looping_Background-HD", //see above
"type": "video/mp4", //see above
"supported-players": "remote,local" //support playout in regular player (local) and Chromecast casting (remote)
}
],
frameRate: "25/1", //pass framerate as a fraction. Valid framerates include "25/1", "30000/1001", "30000/1001drop"
offsetFrames: 25, //offsetFrames controls the starting timecode of the video. This will set the start timecode to 00:00:01:00.
title: "Snow_Bench_Looping_Background-HD.mp4"
}
]);
Try It
As the name suggests, you can queue multiple items as a playlist.
playerInstance.setPlaylist([
{
sources: [
{
"src": "http://bit.ly/FDR_and_7th",
"type": "video/mp4"
}
],
title: "FDR_and_7th_Street_Skateboarding-HD"
},
{
sources: [
{
"src": "http://bit.ly/karl_heynen--tromso_the_arctic_gateway",
"type": "video/mp4"
}
],
title: "karl_heynen--tromso_the_arctic_gateway"
},
{
sources: [
{
"src": "http://bit.ly/Snow_Bench_Looping_Background-HD",
"type": "video/mp4"
}
],
title: "Snow_Bench_Looping_Background-HD.mp4"
}
]);
Try It
3.2 Load Flow clips by query or Flow ID
A typical use case when integrating with Limecraft Flow would be to perform a query against a production to get certain media, then create a playlist to play those media.
We created a call which does just this:
//this is just for the demo
if (!window.productionId) {
window.productionId = prompt("productionId?", 242);
}
if (!window.token) {
window.token = prompt("token?", "eyJ1c2VySSomethingSomethingiOmZhbHNlfQ");
}
if (!window.fqStr) {
window.fqStr = prompt("comma separated filter queries?", "funnel:MediaObjectAnnotation,circled:true");
}
playerInstance.setPlaylistToQuery({
productionId: window.productionId,
token: window.token,
fq: window.fqStr.split(","),
rows: 20,
offset: 0,
sort: "mediaObjectCreated asc"
});
Try It
Production ID
If you browse to your clip in Limecraft Flow, the productionID is the number in the URL just after "#productions/".
Token
When a user logs in with Limecraft Flow, he receives an access token. Such a token is requested here to be able to perform the search query. It should correspond to a user which is a participant of the production.
The login procedure should be done on the server side, and the user should preferably only have "VIEW" rights in the production. Note that anyone having this token can access the production in Limecraft Flow!
to get the access token of your own session, you can go to the developer console while in Limecraft Flow and run Limecraft.session.getToken(). Do not share that token with anyone else.
3.2.1 Load by Flow ID
If you want to play a single clip, you can do it like this:
//this is just for the demo
if (!window.productionId) {
window.productionId = prompt("productionId?", 242);
}
if (!window.token) {
window.token = prompt("token?", "eyJ1c2VySSomethingSomethingiOmZhbHNlfQ");
}
if (!window.mediaObjectId) {
window.mediaObjectId = prompt("What is the Flow ID (aka mediaObjectId) of the clip?", "12345");
}
playerInstance.setPlaylistToQuery({
productionId: window.productionId,
token: window.token,
fq: "+funnel:MediaObjectAnnotation +mediaObjectId:" + window.mediaObjectId,
rows: 1,
offset: 0
});
Try It
Flow ID
If you browse to your clip in Limecraft Flow and click on the "i" to show the clip info, the Flow ID of your clip is shown in the clip info sidebar on the right.
ProductionID and token parameters are explained above.
3.2.2 Query playlist events
These events help you keep track of the query playlist loading:
event | arg0 | arg1 | Description |
---|---|---|---|
queryplaylist:loading | the query is loading | ||
queryplaylist:loaded | {Object} object with playlist property | the query has executed and a playlist was generated | |
queryplaylist:error | {Object} error | An error occured, the query did not execute succesfully |
4. Events
You can subscribe to events to be updated about certain state changes. Bind your events in the onPlayerReady callback and implement your logic in the onPlayerEvent callback.
All Media Events triggered on the HTML5 video element can be subscribed to, but pass in a second argument (isVideoEvent: true) when binding them:
p.addListener("seeking", {isVideoEvent: true});
In addition, other events are exposed as well (documented in the appropriate sections of this document). For example, to be informed about the player position:
p.addListener("timeupdateframes");
4.1 Events example: render the playlist
playerInstance = new Limecraft.Player({
...
onPlayerReady: function (p) {
//bind the lc:player:playlist:loaded event, which is called
// when a playlist is loaded
p.addListener("lc:player:playlist:loaded");
...
},
onPlayerEvent: function (p, eventName, eventArgs) {
var playlistArray, i, playlistEl, itm, itmEl;
//render the playlist once it is loaded
if (eventName === "lc:player:playlist:loaded") {
renderPlaylist(eventArgs[0]);
}
}
});
function renderPlaylist(playlistArray) {
var i, playlistEl, itm, itmEl;
playlistEl = document.getElementById("playlist");
playlistEl.innerHTML = "";
for (i = 0; i < playlistArray.length; i += 1) {
itm = playlistArray[i];
itmEl = document.createElement("li");
itmEl.onclick = Limecraft.simpleBind(function () {
playerInstance.pluginCall("playlist.skipTo", this);
}, i);
itmEl.innerHTML = "<p>" + (i + 1) + ". " + itm.title + "</p>";
playlistEl.appendChild(itmEl);
}
}
5. Structure of a playlist entry
5.1 Timecode visualisation
FrameRate
Although optional, we advise to pass the framerate so the timecode counters are correct. If no framerate is passed, the player assumes 25 frames per second.
To avoid loss of precision, the frame rate is provided as a fracture.Append "drop" for dropframerates.
Examples:
- 25000/100
- 30000/1001
- 25/1
- 30000/1001drop
playerInstance.setPlaylist([
{
sources: [
{
"src": "http://bit.ly/Snow_Bench_Looping_Background-HD",
"type": "video/mp4"
}
],
title: "Snow_Bench_Looping_Background-HD.mp4",
frameRate: "30/1" //make this look like a 30fps video. Note the timecodes' frame part will go up to 29.
}
]);
Try It
OffsetFrames
Use offsetFrames to set a smart timecode of your video. Frame 0 of the video will get this timecode.
Examples:
- 0 (default, timecode starts at 00:00:00:00à
- 25 (25 frames. If frameRate is "25/1", this would set the start timecode at 00:00:01:00)
You can also use the offset parameter to pass the start timecode in seconds.
playerInstance.setPlaylist([
{
sources: [
{
"src": "http://bit.ly/Snow_Bench_Looping_Background-HD",
"type": "video/mp4"
}
],
title: "Snow_Bench_Looping_Background-HD.mp4",
offsetFrames: "50", //start at 00:00:02:00
frameRate: "25/1"
}
]);
Try It
5.2 Play a range of the video
Range, frameRange
If you want to show only a certain timerange of the video, you can pass in a range (in seconds). The user will not be able to seek outside this range.
Examples:
- 13,20 (13s > 20s)
- 20 (20 > end)
- ,25 (begin > 25s)
Note: a tech-savy user will still be able to play the entire video, so this is not to be used as a security measure.
playerInstance.setPlaylist([
{
sources: [
{
"src": "http://bit.ly/Snow_Bench_Looping_Background-HD", //any public url which is playable in a html video element
"type": "video/mp4" //the mime type
}
],
title: "Snow_Bench_Looping_Background-HD.mp4", //(optional) shown briefly after media is loaded
range: "3,5" //play from 00:00:03:00 until 00:00:05:00
}
]);
Try It
It is also possible to pass in the range in frames, using the frameRange parameter.
Example:
- 300,500
TimelineMode
Note that the timeline still shows the entire range of the video. If this is not desired, set the timelineMode to "range".
Possible values:
- "all" default
- "range" will clip the timeline to the range (frameRange) passed as options to the player.
playerInstance.setPlaylist([
{
sources: [
{
"src": "http://bit.ly/Snow_Bench_Looping_Background-HD", //any public url which is playable in a html video element
"type": "video/mp4" //the mime type
}
],
title: "Snow_Bench_Looping_Background-HD.mp4", //(optional) shown briefly after media is loaded
range: "3,5", //play from 00:00:03:00 until 00:00:05:00
timelineMode: "range"
}
]);
Try It
MarkRange, markFrameRange
Using markRange, you can highlight a range on the player's scrubber bar. Same syntax as range.
playerInstance.setPlaylist([
{
sources: [
{
"src": "http://bit.ly/Snow_Bench_Looping_Background-HD", //any public url which is playable in a html video element
"type": "video/mp4" //the mime type
}
],
title: "Snow_Bench_Looping_Background-HD.mp4", //(optional) shown briefly after media is loaded
markRange: "3,5" //optionally, also mark the range
}
]);
Try It
Use markFrameRange if you prefer to specify your range using frames. Same syntax as frameRange.
6. Take control
You can control the playout via JavaScript as shown in the code snippets below.
6.1 Play / pause
playerInstance.play();
Try It
playerInstance.pause();
Try It
playerInstance.togglePlayPause();
Try It
6.2 Playback speed
playerInstance.faster();
Try It
playerInstance.slower();
Try It
6.3 Seeking
//seek to 00:00:02:00
playerInstance.seek(2);
Try It
//seek to 00:00:01:00 if at 25fps
playerInstance.seekFrames(25);
Try It
//seek one second back
playerInstance.seekRelative(-1);
Try It
//seek 25 frames back
playerInstance.seekRelativeFrames(-25);
Try It
playerInstance.pause();
playerInstance.nextFrame();
Try It
playerInstance.pause();
playerInstance.previousFrame();
Try It
6.4 Playlist
playerInstance.playlistPrevious();
Try It
playerInstance.playlistNext();
Try It
6.5 On screen display and timecode overlay
The On Screen Display (osd) gives you a convenient way of showing information to the user.
//show a message for 4 seconds
playerInstance.osdShow("hello world!", 4000);
Try It
//showing a new message will hide the previous one
playerInstance.osdShow("hello moon!");
playerInstance.osdShow("hello earth!");
Try It
//hide the message, but only if it is still showing "hello world!"
playerInstance.osdHide("hello world!");
Try It
//hide anything shown on the osd
playerInstance.osdHide();
Try It
If the timecode overlay bothers you, you can turn it on and off.
playerInstance.timecodeShow();
Try It
playerInstance.timecodeHide();
Try It
playerInstance.timecodeToggle();
Try It
6.6 Header
A header can optionally be enabled for the player. The example below shows how to enable the header and set its contents.
function onLimecraftPlayerAPIReady() {
playerInstance = new Limecraft.Player({
// pass embedOptions.showHeader = true
embedOptions: {
showHeader: true
},
// set the header via playerInstance.setHeaderTitle
onMediaLoaded: function (event, data) {
if (data.searchResult) {
playerInstance.setHeaderTitle({
title: "[" +
(data.playlistIndex + 1) +
" / " +
(data.playlistLength) +
"]" +
" " +
(data.searchResult.mediaObjectName || "")
});
}
},
...
});