A BEML Brightcove Player with a Flex Search Widget

Written by Bob de Wit. Posted in Brightcove, Developer Blog, Flex

This article will detail how to develop and plug in a search widget into a Brightcove Player using BEML. I’ve created the search widget in Flex, since the markup is very similar to BEML. The article and sample code have been updated to show filtering of the search results based on a playlist selection. Working demo here

Preparation

Before creating your own widgets to plug into a Brightcove Player using BEML, make sure you read the introduction help pages to ensure you are clear on the required preparation steps. We will be using the Media API, so that you can search for videos throughout your entire account. Also make sure you have a read token handy.

Creating The Pieces

There are three main pieces to create for a search widget: the repeating display logic for the results, the widget that needs to receive a reference from the Brightcove Player it’s been plugged into, and the BEML template that actually plugs in the widget.

The Result List Component

To display the results, we’ll use a simple repeater in Flex, like this:
<!--?xml version=“1.0″ encoding=“utf-8?-->
<![CDATA[
import mx.formatters.NumberBase;
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
import com.adobe.serialization.json.JSON;
import mx.controls.Alert;
import mx.managers.CursorManager;
import mx.core.Application;

public function SetDataProvider( dp:Object ):void
{
tileRepeater.dataProvider = dp;
}

private function SelectVideo(video:Object):void
{
//Alert.show( "Video ID Selected: " + video.id );
Application.application.selectVideo(video);
}
]]>

&nbsp;
As for the widget itself, here is the complete code listing (using the list repeater we just defined above). I’ve added functions and handlers to loop the results from the search function to be correlated with a playlist id, selected from a combobox, as well as the initialization code to populate the combobox.
<!--?xml version="1.0" encoding="utf-8"?-->
<![CDATA[
import mx.formatters.NumberBase;
import mx.managers.CursorManager;
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
import com.adobe.serialization.json.JSON;
import mx.controls.Alert;

//Replace with your own read token
private var ReadToken: String = "Lkn9dGUsCgNfRD8cKipEmuLcr-Oo3u8wV7hdHV945Fw.";

//Brightcove Service URL
private var ServiceURL: String = "http://api.brightcove.com/services/library";

//Placeholder for BC Player Reference
private var BCPlayer: Object = null;

//Placeholder for the result dataprovider
private var Results: ArrayCollection;

//Initialize App
private function InitApp():void
{
//Initialize by getting all playlists in the account
GetPlayLists();
}

//BEML Widget function to receive reference to BC Experience

public function  setInterface(player:Object):void
{
BCPlayer = player;
}

public function selectVideo(video:Object):void
{
if (BCPlayer != null)
{
var Content:Object = BCPlayer.getModule("content");
var Player:Object = BCPlayer.getModule("videoPlayer");
Player.loadVideo(video.id );
}
else
{
Alert.show("You have selected video " + video.id + ", but you are not running this widget from within a Brightcove Player" );
}
}

private function GetPlayLists():void
{
var request:URLRequest = new URLRequest(ServiceURL);
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;
request.method = URLRequestMethod.GET;

//Set Busy Cursor
CursorManager.setBusyCursor();

//Define the REST API variables to be passed
var variables:URLVariables = new URLVariables();
variables.token = ReadToken;
variables.command = "find_all_playlists";
variables.fields = "id,name";

// assign the data to be sent by GET
request.data = variables;

// add event listener
loader.addEventListener(Event.COMPLETE, handlePlayListsResults);
loader.load(request);
}

private function handlePlayListsResults(evt:Event):void
{
//Remove Busy Cursor
CursorManager.removeBusyCursor();

//Get the returned JSON data string
var response:String = evt.target.data as String;

//Uncomment this if you want to see the raw response string
//Alert.show(response);

//The list of returned videos is embedded in the "items" property
//of the root JSON object, so we will decode to a container object
var container:Object = (JSON.decode(response) as Object);

//create a new ArrayCollection passing the de-serialized Array
//ArrayCollections work better as DataProviders, as they can
//be watched for changes.
var dp:ArrayCollection = new ArrayCollection(container.items);

//Add an "all playlist" option to the dataprovider
dp.addItemAt( { "id" : 0, "name" : "Search All Playlists" }, 0 );

//pass the ArrayCollection to the VideoList as its dataProvider.
PlayLists.dataProvider = dp;
PlayLists.labelField = "name";
}

private function ButtonCallAPIClick(): void
{
var request:URLRequest = new URLRequest(ServiceURL);
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;
request.method = URLRequestMethod.GET;

//Set Busy Cursor
CursorManager.setBusyCursor();

//Define the REST API variables to be passed
var variables:URLVariables = new URLVariables();

// First, Add your read token and the search text - if any
variables.token = ReadToken;

if( SearchTerm.text != "" )
{
variables.text = SearchTerm.text;
variables.command = "find_videos_by_text";
}
else
{
variables.command = "find_all_videos";
}

// assign the data to be sent by GET
request.data = variables;

// add event listener
loader.addEventListener(Event.COMPLETE, handleResults);
loader.load(request);

}

private function handleResults(evt:Event):void
{
//Remove Busy Cursor
CursorManager.removeBusyCursor();

//Get the returned JSON data string
var response:String = evt.target.data as String;

//Uncomment this if you want to see the raw response string
//Alert.show(response);

//The list of returned videos is embedded in the "items" property
//of the root JSON object, so we will decode to a container object
var container:Object = (JSON.decode(response) as Object);

//create a new ArrayCollection passing the de-serialized Array
//ArrayCollections work better as DataProviders, as they can
//be watched for changes.
var dp:ArrayCollection = new ArrayCollection(container.items);

//Convert the UNIX date into an AS3 Date
for(var i:int = 0; i< dp.length; i++)
{
var video:Object = dp.getItemAt(i);
var n:Number = video.publishedDate;
video.publishedDate = new Date(n);
}

Results = dp;

//Filter the results based on the playlist selection
//in the combobox. If All Playlists, then id = 0

if ( PlayLists.selectedItem.id == 0 )
{

//All Playlists option selected, so we can just
//pass the ArrayCollection to the VideoList as its dataProvider.
videoList.SetDataProvider(Results);
}
else
{
FilterResults();
}

}

private function FilterResults():void
{
var request:URLRequest = new URLRequest(ServiceURL);
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;
request.method = URLRequestMethod.GET;

//Set Busy Cursor
CursorManager.setBusyCursor();

//Define the REST API variables to be passed
var variables:URLVariables = new URLVariables();
variables.token = ReadToken;
variables.command = "find_playlist_by_id";
variables.playlist_id = PlayLists.selectedItem.id;
variables.fields = "videoIds";

// assign the data to be sent by GET
request.data = variables;

// add event listener
loader.addEventListener(Event.COMPLETE, handleFilterResults);
loader.load(request);
}

private function handleFilterResults(evt:Event):void
{
//Remove Busy Cursor
CursorManager.removeBusyCursor();

//Get the returned JSON data string
var response:String = evt.target.data as String;

//Uncomment this if you want to see the raw response string
//Alert.show(response);

//The list of returned videos is embedded in the "items" property
//of the root JSON object, so we will decode to a container object
var container:Object = (JSON.decode(response) as Object);

//create a new ArrayCollection passing the de-serialized Array
//ArrayCollections work better as DataProviders, as they can
//be watched for changes.
var dp:ArrayCollection = new ArrayCollection(container.videoIds);
var found:Boolean = false;

for( var i:int = Results.length -1; i >= 0; i-- )
{
var video: Object = Results.getItemAt(i);
found = false;
for( var j:int = 0; j < dp.length; j++ )
{
var plitem: Object = dp.getItemAt(j);

if( video.id == plitem )
{
found = true;
}
}
if( ! found )
{
Results.removeItemAt(i);
}
}
videoList.SetDataProvider(Results);
}

]]>





&nbsp;

&nbsp;
To plug this widget into a BEML template, first make sure you have a cross-domain policy file in place in the root folder where you will place the compiled swf online, for example like this:
xsi:noNamespaceSchemaLocation=“http://www.adobe.com/xml/schemas/PolicyFile.xsd”&gt;
Then, create a new BEML template with the following markup:
 
All that remains to do now is to create a player based on this template and publish it (make sure to enable the API access in the player’s configuration). Enjoy!

Trackback from your site.

Comments (5)

  • raffaele

    |

    Cool this application.
    I’m a newer develop flex application. But I’m very interested in this application.
    Could you send me the source code for this application?

    Thank you very much

    Reply

    • raffaele

      |

      sorry i have wrong the email address

      Reply

      • Bob de Wit

        |

        Hi Rafaele,

        all the code is listed above – note: you will need access to a Brightcove account with API access to implement this not just Flex.

        Reply

  • raffaele

    |

    Hi Bob,

    i have write you private message on your brightcove account.
    sorry but i don’t have experience with Flex application. When you have time could you help me?

    If you have a email address, i send you my flex project.

    i have 3 problems. i use abobe flash builder 4 (trial)

    1) When i copy yor script in my page ( mxml ) i have a error

    1120: Access of undefined property JSON. BCSearch3.mxml /BCSearch3/src line 128 Flex Problem

    1046: Type was not found or was not a compile-time constant: VideoList. BCSearch3.mxml /BCSearch3/src line 397 Flex Problem

    2) i dont’ know cross domain. I must create a another file or class with code? which is the extension? I insert in src/default package ?

    3) what is the connection between player and Flex application?

    this search work on my account is correct? no in my defined player.

    p.s Sorry for my english.

    Reply

    • Bob de Wit

      |

      Hi Raffaele,

      I think you are having problems on multiple fronts:

      1) You can’t just mix Flex 3 and 4 code – if you want to use the code sample in FB4 you will have most likely have to do some converting of components.

      2) The JSON functions I use are in an open source Adobe Extension Library called CoreLib.

      3) VideoList is a repeater component I externalized for the sample code as it was not important for the topic of the sample.

      4) crossdomain.xml files are an important principle of Flash security that was introduced by Adobe quite some time ago. I recommend you read up on this topic on Adobe LiveDocs.

      5) The Flex App is loaded into the player through the BEML Template code. As I mentioned, you need to have access to a Brightcove account with the facility to create player templates in BEML yourself for this sample.

      HTH

      Reply

Leave a comment