Skip to content

Instantly share code, notes, and snippets.

@snikch
Created October 4, 2010 04:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save snikch/609262 to your computer and use it in GitHub Desktop.
Save snikch/609262 to your computer and use it in GitHub Desktop.
JWPlayer 5 Captions Plugin, with y axis margin variable.
package {
import com.longtailvideo.jwplayer.events.ViewEvent;
import com.longtailvideo.jwplayer.events.MediaEvent;
import com.longtailvideo.jwplayer.events.PlayerStateEvent;
import com.longtailvideo.jwplayer.events.PlaylistEvent;
import com.longtailvideo.jwplayer.player.IPlayer;
import com.longtailvideo.jwplayer.player.PlayerState;
import com.longtailvideo.jwplayer.plugins.IPlugin;
import com.longtailvideo.jwplayer.plugins.PluginConfig;
import com.longtailvideo.jwplayer.utils.Logger;
import com.longtailvideo.jwplayer.utils.Configger;
import com.jeroenwijering.parsers.*;
import flash.display.MovieClip;
import flash.display.Bitmap;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.net.*;
import flash.filters.DropShadowFilter;
public class Captions2 extends MovieClip implements IPlugin {
[Embed(source="controlbar.png")]
private const ControlbarIcon:Class;
[Embed(source="dock.png")]
private const DockIcon:Class;
/** Configuration list of the plugin. **/
private var pluginConf:PluginConfig;
/** Reference to the JW Player API. **/
private var api:IPlayer;
/** List with configuration settings. **/
public var config:Object = {
back:false,
file:undefined,
fontsize:20,
state:true,
margin:0
};
/** XML connect and parse object. **/
private var loader:URLLoader;
/** Icon for the controlbar. **/
private var icon:Bitmap;
/** Reference to the textfield. **/
public var field:TextField;
/** Reference to the background graphic. **/
private var back:MovieClip;
/** The array the captions are loaded into. **/
private var captions:Array;
/** Textformat entry for the captions. **/
private var format:TextFormat;
/** Currently active caption. **/
private var current:Number;
/** Reference to the dock button. **/
private var button:MovieClip;
public function Captions2() {
loader = new URLLoader();
loader.addEventListener(Event.COMPLETE,loaderHandler);
};
/** This function is automatically called by the player after the plugin has loaded. **/
public function initPlugin(player:IPlayer, conf:PluginConfig):void {
api = player;
pluginConf = conf;
if(conf['file'])
config['file'] = conf['file'];
if(conf['margin'])
config['margin'] = conf['margin'];
if(conf['fontsize'])
config['fontsize'] = conf['fontsize'];
if(conf['state'] == true)
config['state'] = true;
else
config['state'] = false;
drawClip();
api.addEventListener(PlaylistEvent.JWPLAYER_PLAYLIST_ITEM,itemHandler);
api.addEventListener(ViewEvent.JWPLAYER_VIEW_REDRAW, resizeHandler);
api.addEventListener(MediaEvent.JWPLAYER_MEDIA_TIME,timeHandler);
api.addEventListener(PlayerStateEvent.JWPLAYER_PLAYER_STATE,stateHandler);
api.addEventListener(MediaEvent.JWPLAYER_MEDIA_META,metaHandler);
mouseEnabled = false;
mouseChildren = false;
Logger.log('initializing','captions2');
if(api.config.dock) {
button = api.controls.dock.addButton(new DockIcon(),'is on',clickHandler);
} else {
icon = new ControlbarIcon();
api.controls.controlbar.addButton(icon,'captions',clickHandler);
}
hide(config['state']);
}
/** Clicking the hide button. **/
private function clickHandler(evt:MouseEvent):void {
hide(!config['state']);
Configger.saveCookie("captions2.state", config.state);
};
/** Show/hide the captions **/
public function hide(stt:Boolean):void {
config['state'] = stt;
visible = config['state'];
if(config['state']) {
if(button) {
button.field.text = 'is on';
} else {
icon.alpha = 1;
}
} else {
if(button) {
button.field.text = 'is off';
} else {
icon.alpha = 0.3;
}
}
};
/** This should be a unique, lower-case identifier (e.g. "myplugin") **/
public function get id():String {
return "captions2";
}
/** Called when the player has resized. The dimensions of the plugin are passed in here. **/
public function resizeHandler(evt:ViewEvent=undefined):void {
// Lay out plugin here, if necessary.
field.y = (api.config['height']-field.height)-config['margin'];
//back.y = (view.config['height']-height)-config['margin'];
field.x = (api.config['width']-field.width)/2;
}
public function resize(wid:Number, hei:Number):void
{
}
private function drawClip():void {
back = new MovieClip();
back.graphics.beginFill(0x000000,0.75);
back.graphics.drawRect(0,0,400,20);
addChild(back);
format = new TextFormat();
format.color = 0xFFFFFF;
format.size = config['fontsize'];
format.align = "center";
format.font = "_sans";
format.leading = 4;
field = new TextField();
field.width = 400;
field.height = 10;
field.y = 5;
field.autoSize = "center";
field.selectable = false;
field.multiline = true;
field.wordWrap = true;
field.defaultTextFormat = format;
addChild(field);
if(config['back'] == false) {
back.alpha = 0;
field.filters = new Array(new DropShadowFilter(0,45,0,1,2,2,10,3));
}
};
/** Captions are loaded; now display them. **/
private function loaderHandler(evt:Event):void {
Logger.log('Loader Handler called', 'captions2');
var ext:String = config['file'].substr(-3);
if(ext == 'srt' || ext == 'txt') {
captions = SRTParser.parseCaptions(String(evt.target.data));
} else {
captions = TTParser.parseCaptions(XML(evt.target.data));
}
if(captions.length == 0) {
Logger.log('Not a valid TimedText or SRT file.','captions');
}
};
/** Check for captions with a new item. **/
private function itemHandler(evt:PlaylistEvent=null):void {
Logger.log('Item Handler called','captions2');
current = 0;
captions = new Array();
pluginConf['file'] = undefined;
field.htmlText = '';
// drop metadata caption support
var file:String;
if (api.playlist.currentItem['captions.file']) {
file = api.playlist.currentItem['captions.file'];
} else if (api.playlist.currentItem['captions']) {
file = api.playlist.currentItem['captions'];
} else if (config['file']) {
file = config['file'];
}
Logger.log('Attempting to load file' , 'captions2');
Logger.log(pluginConf['file'] , 'captions2');
if(file) {
pluginConf['file'] = file;
try {
loader.load(new URLRequest(pluginConf['file']));
} catch (err:Error) {
Logger.log(err.message,'captions2');
}
}
};
/** Check timing of the player to sync captions. **/
private function timeHandler(evt:MediaEvent):void {
var pos:Number = evt.position;
if(captions && captions.length > 0 && (
captions[current]['begin'] > pos ||
(captions[current+1] && captions[current+1]['begin'] < pos))) {
setCaption(pos);
}
};
/** Check timing of the player to sync captions. **/
private function stateHandler(evt:PlayerStateEvent):void {
if((evt.newstate == 'PLAYING' ||
evt.newstate == 'PAUSED') && config['state']) {
visible = true;
} else {
visible = false;
}
};
/** Check for captions in metadata. **/
private function metaHandler(evt:MediaEvent):void {
var txt:String;
var fnd:Boolean = false;
if (evt.metadata.type == 'caption') {
txt = evt.metadata.captions;
fnd = true;
} else if (evt.metadata.type == 'textdata') {
txt = evt.metadata.text;
fnd = true;
}
if (fnd == true) {
field.htmlText = txt+' ';
resizeHandler();
}
};
/** Set a caption on screen. **/
private function setCaption(pos:Number):void {
for(var i:Number=0; i<captions.length; i++) {
if(captions[i]['begin'] < pos && (i == captions.length - 1 || captions[i+1]['begin'] > pos)) {
current = i;
field.htmlText = captions[i]['text'];
resizeHandler();
Logger.log(captions[i]['text'],'caption');
return;
}
}
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment