The Yousearch Plugin rebuilt

This tutorial aims to demonstrate step-by-step how to write a simple plugin for the JW Player (there's also a general plugin tutorial?). The plugin in question executes a Youtube search and loads the results in the player. The tutorial assumes you have Adobe Flash CS3 installed. The endresult can be seen in action below and downloaded here. Contents of this page:

Get the Flash Player to see this player.

Setup

First, you'll need to download the com.jeroenwijering.events package. If you have Subversion, you can also checkout the source:

svn co http://developer.longtailvideo.com/svn/trunk/as3/com/jeroenwijering/events

Keep the events folder in the com/jeroenwijering directory!

Next, create a folder called plugins in the jeroenwijering folder. In there, create a file, called Yousearch.as. When you're done, your stage should contain the searchbox and your project folder should now look like this:

/yousearch.fla
/com/jeroenwijering/events/AbstractView.as
/com/jeroenwijering/events/ControllerEvent.as
/com/jeroenwijering/events/ModelEvent.as
/com/jeroenwijering/events/ModelStates.as
/com/jeroenwijering/events/PluginInterface.as
/com/jeroenwijering/events/ViewEvent.as
/com/jeroenwijering/plugins/YouSearch.as

Graphics

Next, you‚'ll create the graphics for your plugin:

  1. Open Adobe Flash CS3
  2. Create a new Flash file, Actionscript 3.0
  3. Size your stage to 280px by 40px
  4. Create a Textarea on the stage, and name it query in the Properties box. Enter ... in the text field.
  5. Create a Movieclip symbol named search. This will be your search button.
  6. Create a Movieclip symbol named icon and draw a small search icon in it. This will be the icon on the controlbar that toggles the searchbox on/off.
  7. In the Document class input in the Properties menu, type com.jeroenwijering.plugins.Yousearch.
  8. Save the file as yousearch.fla in the root folder of your project.

The graphics don't have to exactly resemble the graphics of the original Yousearch plugin, as long as all clips and their correct names are set. If you don't want to build the graphics yourself, here's a download of the yousearch.fla file

Code

Now, open Yousearch.as in your Actionscript editor of choice and enter the following code:

package com.jeroenwijering.plugins {
	
/* The events package contains references to the Player */
import com.jeroenwijering.events.*;

import flash.display.MovieClip;
import flash.events.*;
import flash.text.TextField;
	
public class YouSearch extends MovieClip implements PluginInterface {

	/** This function is called by the JW Player when the plugin is loaded. **/
	public function initializePlugin(vie:AbstractView):void {
	};

}	

}

Technically, we have already written a plugin! Granted, it's a plugin that does nothing at all. Notice that Abstractview parameter? This is a reference to its view that the Player passes to all of the plugins it loads. Let's save a copy of it so we can refer to it later:

	/** Reference to the View of the player. **/
	private var view:AbstractView;

	/** This function is called by the JW Player when the plugin is loaded. **/
	public function initializePlugin(vie:AbstractView):void {
		view = vie;
	};

Doing Something

Now that we have a reference to the View, we can communicate with the player through its event model. First, let's make sure our plugin fits the size of the player. The Controller broadcasts an event, RESIZE, whenever the players' size changes. Add the following to initializePlugin():

public function initializePlugin(vie:AbstractView):void {
	view = vie;
	view.addControllerListener(ControllerEvent.RESIZE,resizeHandler);
	resizeHandler();
};

/** Handle a resize. **/
private function resizeHandler(evt:ControllerEvent=undefined):void {
	// Do nothing for now
};

Notice the view.addControllerListener call. We use that function to listen for Controller events. If we wanted to listen for a View event, we would use view.addViewListener(). For Model events, we use (you guessed it) view.addModelListener. For a complete documentation on events, check out the events reference.

Before we can do anything to the plugins' graphical elements, we'll need to set up some references to, and handlers for, the stage objects. We can do that neatly in our constructor:

/** Reference to the graphics. **/
private var clip:MovieClip;

/** Constructor; links the graphics. **/
public function YouSearch():void {
	clip = this;
	clip.search.buttonMode = true;
	clip.search.mouseChildren = false;
};

And now, we have something to do when then player sends its resize event. let's simply align the searchbox to the middle of the player:

private function resizeHandler(evt:ControllerEvent=undefined):void {
	clip.x = view.config['width']/2-140;
	clip.y = view.config['height']/2-20;
}

The view.config object has a lot of useful configuration information. Check out the Flashvars wiki page for a complete overview.

Instead of stacking themselves on top of the player, plugins can also claim screenspace for themselves (e.g. if you want to display the search box below the controlbar). Here's some more info.

Searching Youtube

While it's great to have a floating search box in the middle of our player, it might be nice if it did something useful. Let's write some event handlers into our constructor to add some functionality:

/** Constructor; links the graphics. **/
public function YouSearch():void {
	clip = this;
	clip.search.addEventListener(MouseEvent.CLICK,clickHandler);
	clip.query.addEventListener(FocusEvent.FOCUS_IN,focusHandler);
	clip.query.addEventListener(KeyboardEvent.KEY_DOWN,keyHandler);
	clip.search.buttonMode = true;
	clip.search.mouseChildren = false;
};

/** Start a search when the 'search' button is clicked. **/
private function clickHandler(evt:MouseEvent=null):void {
	var que:String = encodeURI(clip.query.text);
	if(que.length > 3) { 
		view.sendEvent('LOAD','http://gdata.youtube.com/feeds/api/videos?vq='+que+'&format=5');
	}
	clip.query.text = '';
};

/** Clear the textfield if it is focussed. **/
private function focusHandler(evt:FocusEvent):void {
	if(clip.query.text == '...') {
		clip.query.text = '';
	}
};

/** Start a search when pressing the enter key. **/
private function keyHandler(evt:KeyboardEvent):void {
	if(evt.charCode == 13) { 
		clickHandler();
	}
};

The view.sendEvent tells the Player to load the specified URL into the playlist. The parameter string can point to a single video file (http://mysite/video.flv) or a playlist, in one of several supported formats. Youtube returns an ATOM feed, which is supported b the player.

Note that the focusHandler() function is not much of a deal, but simply nice in terms of user experience. Likewise for the keyHandler(), which simply forwards an ENTER press to the clickHandler().

Toggling visibility

Finally, we'd like to be able to show and hide the search box. We will always hide the box when a video starts playing (so it doesn't obscure the view) and we will always show it when a video is completed (so users will stick to our site). This can be done by setting up another listener, to the STATE event of the Model:

/** The initialize call is invoked by the player View. **/
public function initializePlugin(vie:AbstractView):void {
	view = vie;
	view.addModelListener(ModelEvent.STATE,stateHandler);
	view.addControllerListener(ControllerEvent.RESIZE,resizeHandler);
	resizeHandler();
};

/** Show or hide the clip. **/
private function showClip(val:Boolean):void {
	clip.visible = val;
	if(val) {
		clip.icon.alpha = 1;
	} else { 
		clip.icon.alpha = 0.3;
	}
};

/** Show the searchbox on video completed and hide it when playing. **/
private function stateHandler(evt:ModelEvent):void { 
	switch(evt.data.newstate) {
		case ModelStates.PLAYING:
			showClip(false);
			break;
		case ModelStates.COMPLETED:
			showClip(true);
			break;
	}
};

When the Modelevent.STATE event is dispatched, the events' data object contains a newstate property, corresponding to the new playback state. All states are defined in the Modelstates class.

Conclusion

That's all there is to it! Your source code is completed and should now look something like this. Now you can go back to the yousearch.fla file and publish the plugin through file » publish. The resulting yousearch.swf is your new plugin.

If you're not sure on what to do next, please also read the more general tutorial? on building plugins.

Feel free to experiment with listening to other player events, customizing the look and feel of your Flash, and connecting to different sites and mash-ups. When you've created additional plugins, be sure to submit them to the world. Good luck!