diff --git a/static/contrib/mediaplayer b/static/contrib/mediaplayer
new file mode 120000
index 0000000..4965ec7
--- /dev/null
+++ b/static/contrib/mediaplayer
@@ -0,0 +1 @@
+mediaplayer-3.15/
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/README.HTML b/static/contrib/mediaplayer-3.15/README.HTML
new file mode 100755
index 0000000..6fa9e1f
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/README.HTML
@@ -0,0 +1,54 @@
+
+
+
+
+ JW FLV Media Player
+
+
+
+
+
+
+ Example
+ Here's a simple example of the JW FLV Media Player embedded in a page. Copy-paste the source code and put the files on your site to get started.
+
+
+
+
+
+
+
+
+
+
+ Quickstart
+ The easiest way to get going with the mediaplayer is by using the setup wizard. Select an example, set the file or playlist you want to play and copy-paste the embed code to your site!
+
+ Licensing
+ The FLV Media Player is licensed under a Creative Commons License. It allows you to use, modify and redistribute the script for free for noncommercial purposes. For corporate use, please apply for a 20 euros commercial license!
+
+ Documentation
+
+ - All supported flashvars (variables) you can set to customize the mediaplayer.
+ - All supported playlist formats you can use, plus some implementation info.
+ - A large list of all third-party plugins for the mediaplayer.
+ - A tutorial on embedding the mediaplayer in your site.
+ - A tutorial with all functions of the javascript API.
+ - A tutorial on adding captions and an audiodescription (accessibility).
+
+
+
+
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/afraid.flv b/static/contrib/mediaplayer-3.15/afraid.flv
new file mode 100755
index 0000000..51fa47d
Binary files /dev/null and b/static/contrib/mediaplayer-3.15/afraid.flv differ
diff --git a/static/contrib/mediaplayer-3.15/afraid.jpg b/static/contrib/mediaplayer-3.15/afraid.jpg
new file mode 100755
index 0000000..b53abc3
Binary files /dev/null and b/static/contrib/mediaplayer-3.15/afraid.jpg differ
diff --git a/static/contrib/mediaplayer-3.15/mediaplayer.html b/static/contrib/mediaplayer-3.15/mediaplayer.html
new file mode 100755
index 0000000..4ae4807
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/mediaplayer.html
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+Example
+Here's a simple example of the mediaplayer embedded in a page. Copy-paste the code to get started.
+
+
+
+
+
+
+
+
+
+Documentation
+The easiest way to get going with the mediaplayer is by using the setup wizard. Select an example, set the file or playlist you want to play and copy-paste the embed code to your site! If you want to learn more, here's the complete documentation:
+
+- All supported flashvars (variables) you can set to customize the mediaplayer.
+- All supported playlist formats you can use, plus some implementation info.
+- A large list of all third-party plugins for the mediaplayer.
+- A tutorial on embedding the mediaplayer in your site.
+- A tutorial with all functions of the javascript API.
+- A tutorial on adding captions and an audiodescription (accessibility).
+
+
+
+
+
+
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/mediaplayer.swf b/static/contrib/mediaplayer-3.15/mediaplayer.swf
new file mode 100755
index 0000000..cb103d5
Binary files /dev/null and b/static/contrib/mediaplayer-3.15/mediaplayer.swf differ
diff --git a/static/contrib/mediaplayer-3.15/source/Kroeger_563.ttf b/static/contrib/mediaplayer-3.15/source/Kroeger_563.ttf
new file mode 100755
index 0000000..b484157
Binary files /dev/null and b/static/contrib/mediaplayer-3.15/source/Kroeger_563.ttf differ
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/ASXParser.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/ASXParser.as
new file mode 100644
index 0000000..fa1f907
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/ASXParser.as
@@ -0,0 +1,67 @@
+/**
+* Parses ASX feeds and returns an indexed array with all elements
+*
+* @author Jeroen Wijering
+* @version 1.0
+**/
+
+
+import com.jeroenwijering.feeds.AbstractParser;
+import com.jeroenwijering.utils.StringMagic;
+
+
+class com.jeroenwijering.feeds.ASXParser extends AbstractParser {
+
+
+ /** Contructor **/
+ function ASXParser() { super(); };
+
+
+ /** build an array with all regular elements **/
+ private function setElements() {
+ elements = new Object();
+ elements["title"] = "title";
+ elements["author"] = "author";
+ elements["abstract"] = "description";
+ };
+
+
+ /** Convert RSS structure to array **/
+ private function parse(xml:XML):Array {
+ var arr = new Array();
+ var tpl = xml.firstChild.firstChild;
+ while(tpl != null) {
+ if (tpl.nodeName.toLowerCase() == "entry") {
+ var obj = new Object();
+ for(var j=0; j -1) {
+ var idx = dat.indexOf(" ");
+ dat = dat.substr(0,idx) + dat.substr(idx+1);
+ }
+ var myDate = new Date(dat.substr(0,4),dat.substr(5,2)-1,
+ dat.substr(8,2),dat.substr(11,2),dat.substr(14,2),
+ dat.substr(17,2));
+ var stamp = Math.round(myDate.valueOf()/1000) -
+ myDate.getTimezoneOffset()*60;
+ if(dat.length > 20) {
+ var hr:Number = Number(dat.substr(20,2));
+ var mn:Number = Number(dat.substr(23,2));
+ if(dat.charAt(19) == "-") {
+ stamp = stamp - hr*3600 - mn*60;
+ } else {
+ stamp += hr*3600 + mn*60;
+ }
+ }
+ return stamp;
+ } else {
+ return dat;
+ }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/FeedListener.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/FeedListener.as
new file mode 100755
index 0000000..a1face4
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/FeedListener.as
@@ -0,0 +1,19 @@
+/**
+* Interface for all objects that need real-time feed updates.
+*
+* @author Jeroen Wijering
+* @version 1.0
+**/
+
+
+import com.jeroenwijering.feeds.*;
+
+
+interface com.jeroenwijering.feeds.FeedListener {
+
+
+ /** invoked when the feed object has updated **/
+ function onFeedUpdate(typ:String);
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/FeedManager.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/FeedManager.as
new file mode 100755
index 0000000..6980b1f
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/FeedManager.as
@@ -0,0 +1,258 @@
+/**
+* Parses RSS, ATOM and XSPF lists and returns them as a numerical array.
+*
+* @author Jeroen Wijering
+* @version 1.7
+**/
+
+
+import com.jeroenwijering.feeds.*;
+
+
+class com.jeroenwijering.feeds.FeedManager {
+
+
+ /** The array the XML is parsed into. **/
+ public var feed:Array;
+ /** XML file **/
+ private var feedXML:XML;
+ /** Flag for captions. **/
+ public var captions:Boolean;
+ /** Flag for extra audiotrack. **/
+ public var audio:Boolean;
+ /** Flag for all items in mp3 **/
+ public var onlymp3s:Boolean;
+ /** Flag for chapter index **/
+ public var ischapters:Boolean;
+ /** Flag for enclosures **/
+ private var enclosures:Boolean;
+ /** Reference to the parser object **/
+ private var parser:AbstractParser;
+ /** An array with objects listening to feed updates **/
+ private var listeners:Array;
+ /** A prefix string for all files **/
+ private var prefix:String = "";
+ /** Stream to use **/
+ private var stream:String;
+ /** Array with all file elements **/
+ private var elements:Object = {
+ file:"",
+ fallback:"",
+ title:"",
+ link:"",
+ id:"",
+ image:"",
+ author:"",
+ captions:"",
+ audio:"",
+ category:"",
+ start:"",
+ type:"",
+ duration:""
+ };
+ /** array with all supported filetypes **/
+ private var filetypes:Array = new Array(
+ "flv","mp3","rbs","jpg","gif","png","rtmp",
+ "swf","mp4","m4v","m4a","mov","3gp","3g2"
+ );
+
+
+ /** Constructor. **/
+ function FeedManager(enc:Boolean,jvs:String,pre:String,str:String) {
+ enc == true ? enclosures = true: enclosures = false;
+ if(jvs == "true") { enableJavascript(); }
+ pre == undefined ? null: prefix = pre;
+ str == undefined ? null: stream = "_"+str;
+ listeners = new Array();
+ };
+
+
+ /** Enable javascript access to loadFile command. **/
+ private function enableJavascript() {
+ if(flash.external.ExternalInterface.available) {
+ flash.external.ExternalInterface.addCallback(
+ "loadFile",this,loadFile);
+ flash.external.ExternalInterface.addCallback(
+ "addItem",this,addItem);
+ flash.external.ExternalInterface.addCallback(
+ "removeItem",this,removeItem);
+ flash.external.ExternalInterface.addCallback(
+ "itemData",this,itemData);
+ flash.external.ExternalInterface.addCallback(
+ "getLength",this,getLength);
+ }
+ };
+
+
+ /** Load an XML playlist or single media file. **/
+ public function loadFile(obj:Object) {
+ for (var itm in elements) {
+ if(obj[itm] != undefined && obj[itm].indexOf('asfunction')==-1) {
+ _root[itm] = obj[itm];
+ } else if(feed != undefined) {
+ delete _root[itm];
+ }
+ }
+ feed = new Array();
+ var ftp = "xml";
+ for(var i = filetypes.length; --i >= 0;) {
+ if(obj['file'].substr(0,4).toLowerCase() == "rtmp") {
+ ftp = "rtmp";
+ } else if(_root.type == filetypes[i] ||
+ obj['file'].substr(-3).toLowerCase() == filetypes[i]) {
+ ftp = filetypes[i];
+ }
+ }
+ if (ftp == "xml" && obj['file'].indexOf('asfunction') == -1) {
+ loadXML(unescape(obj['file']));
+ } else {
+ feed[0] = new Object();
+ feed[0]['type'] = ftp;
+ for(var cfv in elements) {
+ if(_root[cfv] != undefined) {
+ feed[0][cfv] = unescape(_root[cfv]);
+ }
+ }
+ playersPostProcess();
+ }
+ };
+
+
+ /** Parse an XML file, return the array when done. **/
+ private function loadXML(url:String) {
+ var ref = this;
+ feedXML = new XML();
+ feedXML.ignoreWhite = true;
+ feedXML.onLoad = function(scs:Boolean) {
+ if(scs) {
+ var fmt = this.firstChild.nodeName.toLowerCase();
+ if( fmt == 'rss') {
+ ref.parser = new RSSParser(ref.prefix);
+ ref.feed = ref.parser.parse(this);
+ } else if (fmt == 'feed') {
+ ref.parser = new ATOMParser(ref.prefix);
+ ref.feed = ref.parser.parse(this);
+ } else if (fmt == 'playlist') {
+ ref.parser = new XSPFParser(ref.prefix);
+ ref.feed = ref.parser.parse(this);
+ } else if (fmt == 'asx') {
+ ref.parser = new ASXParser(ref.prefix);
+ ref.feed = ref.parser.parse(this);
+ }
+ if(_root.audio != undefined) {
+ ref.feed[0]["audio"] = unescape(_root.audio);
+ }
+ ref.playersPostProcess(url);
+ }
+ };
+ if(_root._url.indexOf("file://") > -1) { feedXML.load(url); }
+ else if(url.indexOf('?') > -1) { feedXML.load(url+'&'+random(999)); }
+ else { feedXML.load(url+'?'+random(999)); }
+ };
+
+
+ /** set a number of flags specifically used by the players **/
+ private function playersPostProcess(url:String) {
+ onlymp3s = true;
+ feed.length > 1 ? ischapters = true: ischapters = false;
+ captions = false;
+ audio = false;
+ for(var i=0; i= feed.length) {
+ feed.push(obj);
+ } else {
+ var arr1 = feed.slice(0,idx);
+ var arr2 = feed.slice(idx);
+ arr1.push(obj);
+ feed = arr1.concat(arr2);
+ }
+ updateListeners('add');
+ };
+
+
+ /** Remove an item from the feed **/
+ public function removeItem(idx:Number) {
+ if(feed.length == 1) {
+ return;
+ } else if(arguments.length == 0 || idx >= feed.length) {
+ feed.pop();
+ } else {
+ feed.splice(idx,1);
+ }
+ updateListeners('remove');
+ };
+
+
+ /** Retrieve playlist data for a specific item **/
+ public function itemData(idx:Number):Object {
+ return feed[idx];
+ };
+
+
+ /** Add a feed update listener. **/
+ public function addListener(lst:Object) {
+ listeners.push(lst);
+ };
+
+
+ /** Remove a feed update listener. **/
+ public function removeListener(lst:Object) {
+ for(var i = listeners.length; --i >= 0; ) {
+ if(listeners[i] == lst) {
+ listeners.splice(i,1);
+ return;
+ }
+ }
+ };
+
+
+ /** Notify all listeners of a feed update **/
+ private function updateListeners(typ:String) {
+ for(var i = listeners.length; --i >= 0; ) {
+ listeners[i].onFeedUpdate(typ);
+ }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/RSSParser.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/RSSParser.as
new file mode 100755
index 0000000..c56ca57
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/RSSParser.as
@@ -0,0 +1,128 @@
+/**
+* Parses ATOM feeds and returns an indexed array with all elements
+*
+* @author Jeroen Wijering
+* @version 1.5
+**/
+
+
+import com.jeroenwijering.feeds.AbstractParser;
+import com.jeroenwijering.utils.StringMagic;
+
+
+class com.jeroenwijering.feeds.RSSParser extends AbstractParser {
+
+
+ /** Contructor **/
+ function RSSParser() { super(); };
+
+
+ /** build an array with all regular elements **/
+ private function setElements() {
+ elements = new Object();
+ elements["title"] = "title";
+ elements["guid"] = "id";
+ elements["category"] = "category";
+ elements["link"] = "link";
+ elements["geo:lat"] = "latitude";
+ elements["geo:long"] = "longitude";
+ elements["geo:city"] = "city";
+ };
+
+
+ /** Convert RSS structure to array **/
+ private function parse(xml:XML):Array {
+ var arr = new Array();
+ var tpl = xml.firstChild.firstChild.firstChild;
+ var ttl;
+ while(tpl != null) {
+ if (tpl.nodeName.toLowerCase() == "item") {
+ var obj = new Object();
+ for(var j=0; j 0 ||
+ obj["file"].indexOf(".png") > 0 ||
+ obj["file"].indexOf(".gif") > 0) {
+ obj["image"] = obj["file"];
+ }
+ }
+ if(obj["author"] == undefined) { obj["author"] = ttl; }
+ arr.push(obj);
+ } else if (tpl.nodeName == "title") {
+ ttl = tpl.firstChild.nodeValue;
+ }
+ tpl = tpl.nextSibling;
+ }
+ return arr;
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/XSPFParser.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/XSPFParser.as
new file mode 100755
index 0000000..cafd311
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/feeds/XSPFParser.as
@@ -0,0 +1,75 @@
+/**
+* Parses ATOM feeds and returns an indexed array with all elements.
+*
+* @author Jeroen Wijering
+* @version 1.5
+**/
+
+
+import com.jeroenwijering.feeds.AbstractParser;
+import com.jeroenwijering.utils.StringMagic;
+
+
+class com.jeroenwijering.feeds.XSPFParser extends AbstractParser {
+
+
+ /** Contructor **/
+ function XSPFParser() { super(); };
+
+
+ /** build an array with all regular elements **/
+ private function setElements() {
+ elements = new Object();
+ elements["title"] = "title";
+ elements["creator"] = "author";
+ elements["info"] = "link";
+ elements["image"] = "image";
+ elements["identifier"] = "id";
+ elements["album"] = "category";
+ };
+
+
+ /** Convert ATOM structure to array **/
+ private function parse(xml:XML):Array {
+ var arr = new Array();
+ var tpl = xml.firstChild.firstChild;
+ while(tpl != null) {
+ if (tpl.nodeName == 'trackList') {
+ for(var i=0; i 0) {
+ currentPosition = feeder.feed[idx]["start"];
+ }
+ if(fnd == true) {
+ isActive = true;
+ sendUpdate("item",idx);
+ } else {
+ isActive = false;
+ }
+ };
+
+
+ /** Start function. **/
+ private function setStart(prm:Number) {};
+
+
+ /** Pause function. **/
+ private function setPause(prm:Number) {};
+
+
+ /** Stop function. **/
+ private function setStop() {};
+
+
+ /** Set volume and pass through if active. **/
+ private function setVolume(vol:Number) {
+ if(isActive == true) { sendUpdate("volume",vol); }
+ };
+
+
+ /** Send updates to the views. **/
+ private function sendUpdate(typ:String,prm:Number,pr2:Number) {
+ for(var i=0; iNumber(config["height"])) {
+ config["displayheight"] = config["height"];
+ }
+ if (config["displaywidth"] == undefined) {
+ config["displaywidth"] = config["width"];
+ }
+ config["bwstreams"] == undefined ? loadFile(): checkStream();
+ };
+
+
+ /** Placeholder function for bandwidth checking **/
+ private function checkStream() {};
+
+
+ /** Load the file or playlist **/
+ private function loadFile(str:String) {
+ feeder = new FeedManager(true,config["enablejs"],config['prefix'],str);
+ feeder.addListener(this);
+ feeder.loadFile({file:config["file"]});
+ };
+
+
+ /** Invoked by the feedmanager **/
+ public function onFeedUpdate(typ:String) {
+ if(controller == undefined) {
+ config["clip"]._visible = true;
+ config["clip"]._parent.activity._visible = false;
+ setupMCV();
+ }
+ };
+
+
+ /** Setup all necessary MCV blocks. **/
+ private function setupMCV() {
+ controller = new AbstractController(config,feeder);
+ var asv = new AbstractView(controller,config,feeder);
+ var vws:Array = new Array(asv);
+ var asm = new AbstractModel(vws,controller,config,feeder);
+ var mds:Array = new Array(asm);
+ controller.startMCV(mds);
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/AbstractView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/AbstractView.as
new file mode 100755
index 0000000..7897528
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/AbstractView.as
@@ -0,0 +1,91 @@
+/**
+* Basic view class of the players MCV pattern, extended by all views.
+* Create you own views by extending this one.
+*
+* @author Jeroen Wijering
+* @version 1.2
+**/
+
+
+import com.jeroenwijering.players.*;
+
+
+class com.jeroenwijering.players.AbstractView {
+
+
+ /** Controller reference **/
+ private var controller:AbstractController;
+ /** reference to config Array **/
+ private var config:Object;
+ /** reference to feed Array **/
+ private var feeder:Object;
+
+
+ /** Constructor **/
+ function AbstractView(ctr:AbstractController,cfg:Object,fed:Object) {
+ controller = ctr;
+ config = cfg;
+ feeder = fed;
+ };
+
+
+ /** Receive updates from the models. **/
+ public function getUpdate(typ:String,pr1:Number,pr2:Number):Void {
+ trace("view: "+typ+": "+pr1+","+pr2);
+ switch(typ) {
+ case "state":
+ setState(pr1);
+ break;
+ case "load":
+ setLoad(pr1);
+ break;
+ case "time":
+ setTime(pr1,pr2);
+ break;
+ case "item":
+ setItem(pr1);
+ break;
+ case "size":
+ setSize(pr1,pr2);
+ break;
+ case "volume":
+ setVolume(pr1);
+ break;
+ default:
+ trace("View: incompatible update received");
+ break;
+ }
+ };
+
+
+ /** Empty state handler **/
+ private function setState(pr1:Number) {};
+
+
+ /** Empty load handler **/
+ private function setLoad(pr1:Number) {};
+
+
+ /** Empty time handler **/
+ private function setTime(pr1:Number,pr2:Number) {};
+
+
+ /** Empty item handler **/
+ private function setItem(pr1:Number) {};
+
+
+ /** Empty item handler **/
+ private function setSize(pr1:Number,pr2:Number) {};
+
+
+ /** Empty volume handler **/
+ private function setVolume(pr1:Number) {};
+
+
+ /** Send event to the controller. **/
+ private function sendEvent(typ:String,prm:Number) {
+ controller.getEvent(typ,prm);
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/AudioView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/AudioView.as
new file mode 100755
index 0000000..05aa838
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/AudioView.as
@@ -0,0 +1,103 @@
+/**
+* Extra audiotrack management of the players MCV pattern.
+*
+* @author Jeroen Wijering
+* @version 1.1
+**/
+
+
+import com.jeroenwijering.players.*;
+
+class com.jeroenwijering.players.AudioView extends AbstractView {
+
+
+ /** The MovieClip to which the sounds will be attached **/
+ private var audioClip:MovieClip;
+ /** The Sound object we'll use**/
+ private var audioObject:Sound;
+ /** Currently active feeditem **/
+ private var currentItem:Number;
+ /** The current elapsed time **/
+ private var currentTime:Number = 0;
+ /** The last stop position **/
+ private var stopTime:Number;
+ /** The current audio time **/
+ private var audioTime:Number;
+ /** Save the current state **/
+ private var currentState:Number;
+ /** Check whether an MP3 file is loaded **/
+ private var isLoaded:String;
+ /** Sync the audio with emtry or not **/
+ private var sync:Boolean;
+
+
+ /** Constructor, loads caption file. **/
+ function AudioView(ctr:AbstractController,cfg:Object,fed:Object,
+ snc:Boolean) {
+ super(ctr,cfg,fed);
+ sync = snc;
+ var ref = this;
+ audioClip = config['clip'].createEmptyMovieClip('audio',
+ config['clip'].getNextHighestDepth());
+ audioClip.setStart = function() {
+ if(ref.stopTime == undefined && ref.sync == false) {
+ ref.audioObject.loadSound(ref.feeder.feed[0]['audio'],true);
+ ref.audioObject.setVolume(Number(ref.config['volume']));
+ ref.audioObject.start(0);
+ } else if (ref.sync == false) {
+ ref.audioObject.start(ref.stopTime);
+ } else if(ref.currentState == 2) {
+ ref.audioObject.start(ref.currentTime);
+ }
+ };
+ audioClip.setStop = function() {
+ ref.audioObject.stop();
+ ref.stopTime = ref.audioObject.position/1000;
+ };
+ audioObject = new Sound (audioClip);
+ if(config['useaudio'] == "true" && sync == false) {
+ audioClip.setStart();
+ }
+ if(sync == false) {
+ audioObject.onSoundComplete = function() {
+ this.start();
+ };
+ }
+ };
+
+
+ private function setItem(idx:Number) {
+ currentItem = idx;
+ };
+
+
+ private function setState(stt:Number) {
+ currentState = stt;
+ if(sync == false) { return; }
+ if(stt == 2 && config['useaudio'] == "true") {
+ audioObject.start(currentTime);
+ } else {
+ audioObject.stop();
+ }
+ };
+
+
+ private function setTime(elp:Number,rem:Number) {
+ if(sync == false) { return; }
+ if(Math.abs(elp-currentTime) > 1) {
+ currentTime = elp;
+ audioTime = audioObject.position/1000;
+ if(Math.abs(currentTime - audioTime) > 1 &&
+ config['useaudio'] == "true") {
+ audioObject.start(currentTime);
+ }
+ }
+ if (isLoaded != feeder.feed[currentItem]['audio']) {
+ isLoaded = feeder.feed[currentItem]['audio'];
+ audioObject.loadSound(isLoaded,true);
+ audioObject.setVolume(Number(config['volume']));
+ }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/CallbackView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/CallbackView.as
new file mode 100755
index 0000000..7294710
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/CallbackView.as
@@ -0,0 +1,93 @@
+/**
+* Callback to serverside script for statistics handling.
+* It sends the current file,title,id and state on start and complete.
+*
+* @author Jeroen Wijering
+* @author Nate Hanna
+* @version 1.7
+**/
+
+
+import com.jeroenwijering.players.*;
+
+
+class com.jeroenwijering.players.CallbackView extends AbstractView {
+
+
+ /** Currently playing item **/
+ private var currentItem:Number;
+ /** Currently playing item **/
+ private var varsObject:LoadVars;
+ /** Boolean for if a start call has already been sent for an item. **/
+ private var playSent:Boolean = false;
+ /** Small interval so both complete and play events won't be issued **/
+ private var playSentInt:Number;
+ /** Timestamp of the start of the movie **/
+ private var startStamp:Number;
+
+
+ /** Constructor **/
+ function CallbackView(ctr:AbstractController,cfg:Object,fed:Object) {
+ super(ctr,cfg,fed);
+ if(config['callback'] != "analytics") {
+ varsObject = new LoadVars();
+ }
+ };
+
+
+ /** Send a callback on state change **/
+ private function setState(pr1:Number) {
+ var dat = new Date();
+ if(pr1 == 3) {
+ var dur = Math.round(dat.valueOf()/1000 - startStamp);
+ sendVars("stop",dur,true);
+ playSent = false;
+ } else if (pr1 == 2 && playSent == false) {
+ playSentInt = setInterval(this,"sendVars",500,"start",0);
+ playSent = true;
+ startStamp = dat.valueOf()/1000;
+ }
+ };
+
+
+ /** save the currently playing item **/
+ private function setItem(pr1:Number) {
+ if(playSent == true && currentItem != undefined) {
+ var dat = new Date();
+ var dur = Math.round(dat.valueOf()/1000 - startStamp);
+ sendVars("stop",dur,false);
+ playSent = false;
+ }
+ currentItem = pr1;
+ };
+
+
+ /** sending the current file,title,id,state,timestamp to callback **/
+ private function sendVars(stt:String,dur:Number,cpl:Boolean) {
+ clearInterval(playSentInt);
+ if(config['callback'] == "urchin" || config['callback'] == "analytics") {
+ var fil = feeder.feed[currentItem]["file"];
+ var fcn = "javascript:pageTracker._trackPageview";
+ if(config['callback'] == "urchin") {
+ fcn = "javascript:urchinTracker";
+ }
+ if(fil.indexOf('http') != undefined) {
+ fil = fil.substring(fil.indexOf('/',7)+1);
+ }
+ if(stt == "start") {
+ getURL(fcn+"('/start_stream/"+fil+"');");
+ } else if (stt == "stop" && cpl == true) {
+ getURL(fcn+"('/end_stream/"+fil+"');");
+ }
+ } else {
+ varsObject.file = feeder.feed[currentItem]["file"];
+ varsObject.title = feeder.feed[currentItem]["title"];
+ varsObject.id = feeder.feed[currentItem]["id"];
+ varsObject.state = stt;
+ varsObject.duration = dur;
+ varsObject.sendAndLoad(config["callback"],varsObject,"POST");
+ }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/CaptionsParser.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/CaptionsParser.as
new file mode 100755
index 0000000..9ac924c
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/CaptionsParser.as
@@ -0,0 +1,157 @@
+/**
+* Parses SRT lists and W3C Timed Text captions.
+*
+* @author Jeroen Wijering
+* @version 1.3
+**/
+
+
+import com.jeroenwijering.utils.StringMagic;
+
+
+class com.jeroenwijering.players.CaptionsParser {
+
+
+ /** URL of the xml file to parse. **/
+ private var parseURL:String;
+ /** The array the XML is parsed into **/
+ public var parseArray:Array;
+ /** LoadVars Object the SRT file is loaded into. **/
+ private var parseLV:LoadVars;
+ /** Flash XML object the TT file is loaded into. **/
+ private var parseXML:XML;
+
+
+ /** Constructor. **/
+ function CaptionsParser() {};
+
+
+ /** Parse an XML list. **/
+ public function parse(url:String):Void {
+ parseURL = url;
+ parseArray = new Array();
+ parseURL.indexOf(".srt") == -1 ? parseTT(): parseSRT();
+ };
+
+
+ /** Convert SRT file to subtitle array **/
+ private function parseSRT() {
+ var ref = this;
+ parseLV = new LoadVars();
+ parseLV.onLoad = function(scs:Boolean) {
+ if(scs) {
+ var str = "";
+ var j = -2;
+ while(j < unescape(this).length) {
+ var oj = j;
+ j = unescape(this).indexOf('=&',j+2);
+ j == -1 ? j = unescape(this).length: null;
+ str = "&"+unescape(this).substring(oj+2,j) + str;
+ }
+ var arr = str.split("\r\n\r\n");
+ for(var i=0; i -1) {
+ var brp = arr[i].indexOf("\r\n",tst+5);
+ arr[i] = arr[i].substr(0,brp)+"
" +
+ arr[i].substr(brp+2);
+ }
+ obj["txt"] = arr[i].substr(tst+2);
+ if(!isNaN(obj['bgn'])) {
+ ref.parseArray.push(obj);
+ }
+ delete obj;
+ }
+ } else {
+ ref.parseArray.push( {txt:"File not found: " +
+ ref.parseURL,bgn:1,dur:5});
+ }
+ if(ref.parseArray.length == 0) {
+ ref.parseArray.push({txt:"Empty file: " +
+ ref.parseURL,bgn:1,dur:5});
+ }
+ delete ref.parseLV;
+ ref.onParseComplete();
+ };
+ if(_root._url.indexOf("file://") > -1) {
+ parseLV.load(parseURL);
+ } else if(parseURL.indexOf('?') > -1) {
+ parseLV.load(parseURL+'&'+random(999));
+ } else {
+ parseLV.load(parseURL+'?'+random(999));
+ }
+ };
+
+
+ /** Covert TimedText file to subtitle array. **/
+ private function parseTT():Void {
+ var ref = this;
+ parseXML = new XML();
+ parseXML.ignoreWhite = true;
+ parseXML.onLoad = function(scs:Boolean) {
+ if(scs) {
+ if(this.firstChild.nodeName.toLowerCase() == "tt") {
+ var bdy = this.firstChild.childNodes[1];
+ if(bdy.firstChild.firstChild.attributes.begin==undefined){
+ for(var i=0; i -1) {
+ parseXML.load(parseURL);
+ } else if(parseURL.indexOf('?') > -1) {
+ parseXML.load(parseURL+'&'+random(999));
+ } else {
+ parseXML.load(parseURL+'?'+random(999));
+ }
+ };
+
+
+ /** Invoked when parsing is completed. **/
+ public function onParseComplete() { };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/CaptionsView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/CaptionsView.as
new file mode 100755
index 0000000..46964bd
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/CaptionsView.as
@@ -0,0 +1,144 @@
+/**
+* Captions display management of the players MCV pattern.
+*
+* @author Jeroen Wijering
+* @version 1.4
+**/
+
+
+import com.jeroenwijering.players.*;
+import flash.filters.DropShadowFilter;
+
+
+class com.jeroenwijering.players.CaptionsView extends AbstractView {
+
+
+ /** The current volume **/
+ private var parser:CaptionsParser;
+ /** The captions array **/
+ private var captions:Array;
+ /** The current elapsed time **/
+ private var currentTime:Number;
+ /** The captions textfield **/
+ private var clip:MovieClip;
+ /** Boolean for captionate captions **/
+ private var captionate:Boolean = false;
+ /** Time of last caption **/
+ private var capTime:Number;
+ /** Captionate track to use **/
+ private var capTrack:Number = 0;
+
+
+ /** Constructor, loads caption file. **/
+ function CaptionsView(ctr:AbstractController,cfg:Object,fed:Object) {
+ super(ctr,cfg,fed);
+ var ref = this;
+ Stage.addListener(this);
+ parser = new CaptionsParser();
+ parser.onParseComplete = function() {
+ this.parseArray.sortOn("bgn",Array.NUMERIC);
+ ref.captions = this.parseArray;
+ delete this;
+ }
+ clip = config["clip"].captions;
+ setDimensions();
+ };
+
+
+ /** onLoad override, sets capture sizes. **/
+ private function setDimensions() {
+ clip.txt.autoSize = "center";
+ clip.bck._height = clip.txt._height + 10;
+ if(Stage["displayState"] == "fullScreen") {
+ clip._width = Stage.width;
+ clip._yscale= clip._xscale;
+ clip._y = Stage.height - clip._height;
+ } else {
+ clip._width = config["displaywidth"];
+ clip._yscale = clip._xscale;
+ clip._y = config["displayheight"] - clip._height;
+ }
+ if(System.capabilities.version.indexOf("7,0,") == -1) {
+ var blr = 2 + Math.round(clip._yscale/100);
+ var flt = new flash.filters.DropShadowFilter(
+ 0,0,0x000000,1,blr,blr,50,2);
+ clip.filters = new Array(flt);
+ }
+ };
+
+
+ /** parse a new captions file every time an item is set **/
+ private function setItem(idx:Number) {
+ captions = new Array();
+ if(feeder.feed[idx]["captions"] == undefined) {
+ clip.bck._alpha = 0;
+ } else if(feeder.feed[idx]["captions"].indexOf("captionate") > -1 ||
+ feeder.feed[idx]["captions"] == "true") {
+ captionate = true;
+ var tck = Number(feeder.feed[idx]["captions"].substr(-1));
+ if(isNaN(tck)) {
+ capTrack = 0;
+ } else {
+ capTrack = tck;
+ }
+ } else {
+ parser.parse(feeder.feed[idx]["captions"]);
+ }
+ };
+
+
+ /** Check elapsed time, evaluate captions every second. **/
+ private function setTime(elp:Number,rem:Number) {
+ currentTime = elp;
+ if (captionate == false) {
+ setCaption();
+ }
+ };
+
+
+ /** Check if a new caption should be displayed **/
+ private function setCaption() {
+ var nxt:Number = captions.length;
+ for (var i=0; i currentTime) {
+ nxt = i;
+ break;
+ }
+ }
+ if(captions[nxt-1]["bgn"] + captions[nxt-1]["dur"] > currentTime) {
+ clip.txt.htmlText = captions[nxt-1]["txt"];
+ if(System.capabilities.version.indexOf("7,0,") > -1) {
+ clip.bck._alpha = 50;
+ clip.bck._height = Math.round(clip.txt._height + 10);
+ } else {
+ clip.bck._height = Math.round(clip.txt._height + 15);
+ }
+ if(Stage["displayState"] == "fullScreen") {
+ clip._y = Stage.height - clip._height;
+ } else {
+ clip._y = config["displayheight"] - clip._height;
+ }
+ } else {
+ clip.txt.htmlText = "";
+ }
+ };
+
+
+ /** Captionate input **/
+ public function onCaptionate(cap:Array) {
+ clip.txt.htmlText = cap[capTrack];
+ capTime = currentTime;
+ };
+
+
+ /** OnResize Handler: catches stage resizing **/
+ public function onResize() { setDimensions(); };
+
+
+ /** Catches fullscreen escape **/
+ public function onFullScreen(fs:Boolean) {
+ if(fs == false) { setDimensions(); }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/ControlbarView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/ControlbarView.as
new file mode 100755
index 0000000..8241389
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/ControlbarView.as
@@ -0,0 +1,444 @@
+/**
+* Controlbar user interface management of the players MCV pattern.
+*
+* @author Jeroen Wijering
+* @version 1.13
+**/
+
+
+import com.jeroenwijering.players.*;
+import com.jeroenwijering.utils.*;
+import com.jeroenwijering.feeds.FeedListener;
+
+
+class com.jeroenwijering.players.ControlbarView extends AbstractView
+ implements FeedListener {
+
+
+ /** currently active item **/
+ private var currentItem:Number;
+ /** full width of the scrubbars **/
+ private var barWidths:Number;
+ /** duration of the currently playing item **/
+ private var itemLength:Number;
+ /** progress of the currently playing item **/
+ private var itemProgress:Number = 0
+ /** do not rescale loadbar on rebuffering **/
+ private var wasLoaded:Boolean = false;
+ /** interval for hiding the display **/
+ private var hideInt:Number;
+
+
+ /** Constructor **/
+ function ControlbarView(ctr:AbstractController,cfg:Object,fed:Object) {
+ super(ctr,cfg,fed);
+ setColorsClicks();
+ setDimensions();
+ Stage.addListener(this);
+ feeder.addListener(this);
+ Mouse.addListener(this);
+ };
+
+
+ /** Sets up colors and clicks of all controlbar items. **/
+ private function setColorsClicks() {
+ var ref = this;
+ var tgt = config["clip"].controlbar;
+ tgt.col = new Color(tgt.back);
+ tgt.col.setRGB(config["backcolor"]);
+ tgt.playpause.col1 = new Color(tgt.playpause.ply);
+ tgt.playpause.col1.setRGB(config["frontcolor"]);
+ tgt.playpause.col2 = new Color(tgt.playpause.pas);
+ tgt.playpause.col2.setRGB(config["frontcolor"]);
+ tgt.playpause.onRollOver = function() {
+ this.col1.setRGB(ref.config["lightcolor"]);
+ this.col2.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.playpause.onRollOut = function() {
+ this.col1.setRGB(ref.config["frontcolor"]);
+ this.col2.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.playpause.onRelease = function() { ref.sendEvent("playpause"); };
+ tgt.stop.col = new Color(tgt.stop.icn);
+ tgt.stop.col.setRGB(config["frontcolor"]);
+ tgt.stop.onRollOver = function() {
+ this.col.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.stop.onRollOut = function() {
+ this.col.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.stop.onRelease = function() { ref.sendEvent("stop"); };
+ tgt.prev.col = new Color(tgt.prev.icn);
+ tgt.prev.col.setRGB(config["frontcolor"]);
+ tgt.prev.onRollOver = function() {
+ this.col.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.prev.onRollOut = function() {
+ this.col.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.prev.onRelease = function() { ref.sendEvent("prev"); };
+ tgt.next.col = new Color(tgt.next.icn);
+ tgt.next.col.setRGB(config["frontcolor"]);
+ tgt.next.onRollOver = function() {
+ this.col.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.next.onRollOut = function() {
+ this.col.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.next.onRelease = function() { ref.sendEvent("next"); };
+ tgt.scrub.elpTxt.textColor = config["frontcolor"];
+ tgt.scrub.remTxt.textColor = config["frontcolor"];
+ tgt.scrub.col = new Color(tgt.scrub.icn);
+ tgt.scrub.col.setRGB(config["frontcolor"]);
+ tgt.scrub.col2 = new Color(tgt.scrub.bar);
+ tgt.scrub.col2.setRGB(config["frontcolor"]);
+ tgt.scrub.col3 = new Color(tgt.scrub.bck);
+ tgt.scrub.col3.setRGB(config["frontcolor"]);
+ tgt.scrub.bck.onRollOver = function() {
+ this._parent.col.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.scrub.bck.onRollOut = function() {
+ this._parent.col.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.scrub.bck.onPress= function() {
+ this.onEnterFrame = function() {
+ var xm = this._parent._xmouse;
+ if(xm < this._parent.bck._width + this._parent.bck._x &&
+ xm > this._parent.bck._x) {
+ this._parent.icn._x = this._parent._xmouse - 1;
+ }
+ }
+ };
+ tgt.scrub.bck.onRelease= tgt.scrub.bck.onReleaseOutside= function() {
+ var sec = (this._parent._xmouse-this._parent.bar._x) /
+ ref.barWidths*ref.itemLength;
+ ref.sendEvent("scrub",Math.round(sec));
+ delete this.onEnterFrame;
+ };
+ tgt.scrub.bck.tabEnabled = false;
+ tgt.fs.col1 = new Color(tgt.fs.ns);
+ tgt.fs.col2 = new Color(tgt.fs.fs);
+ tgt.fs.col.setRGB(ref.config["frontcolor"]);
+ tgt.fs.col2.setRGB(ref.config["frontcolor"]);
+ tgt.fs.onRollOver = function() {
+ this.col1.setRGB(ref.config["lightcolor"]);
+ this.col2.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.fs.onRollOut = function() {
+ this.col1.setRGB(ref.config["frontcolor"]);
+ this.col2.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.fs.onRelease = function() {
+ ref.sendEvent("fullscreen");
+ this.col1.setRGB(ref.config["frontcolor"]);
+ this.col2.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.cc.col = new Color(tgt.cc.icn);
+ tgt.cc.col.setRGB(ref.config["frontcolor"]);
+ tgt.cc.onRollOver = function() {
+ this.col.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.cc.onRollOut = function() {
+ this.col.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.cc.onRelease = function() {
+ ref.sendEvent("captions");
+ };
+ tgt.au.col = new Color(tgt.au.icn);
+ tgt.au.col.setRGB(ref.config["frontcolor"]);
+ tgt.au.onRollOver = function() {
+ this.col.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.au.onRollOut = function() {
+ this.col.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.au.onRelease = function() {
+ ref.sendEvent("audio");
+ };
+ tgt.dl.col = new Color(tgt.dl.icn);
+ tgt.dl.col.setRGB(ref.config["frontcolor"]);
+ tgt.dl.onRollOver = function() {
+ this.col.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.dl.onRollOut = function() {
+ this.col.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.dl.onRelease = function() {
+ ref.sendEvent("getlink",ref.currentItem);
+ };
+ tgt.vol.col = new Color(tgt.vol.bar);
+ tgt.vol.col.setRGB(config["frontcolor"]);
+ tgt.vol.col2 = new Color(tgt.vol.bck);
+ tgt.vol.col2.setRGB(config["frontcolor"]);
+ tgt.vol.col3 = new Color(tgt.vol.icn);
+ tgt.vol.col3.setRGB(config["frontcolor"]);
+ tgt.vol.onRollOver = function() {
+ this.col.setRGB(ref.config["lightcolor"]);
+ this.col3.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.vol.onRollOut = function() {
+ this.col.setRGB(ref.config["frontcolor"]);
+ this.col3.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.vol.onRelease = function() {
+ this.onEnterFrame = function() {
+ this.msk._width = this._xmouse-12;
+ };
+ };
+ tgt.vol.onRelease = tgt.vol.onReleaseOutside = function() {
+ ref.sendEvent("volume",(this._xmouse-12)*5);
+ delete this.onEnterFrame;
+ };
+ };
+
+
+ /** Sets up dimensions of all controlbar items. **/
+ private function setDimensions() {
+ clearInterval(hideInt);
+ var tgt = config["clip"].controlbar;
+ var cbw = 400;
+ // overall position and width
+ if(Stage["displayState"] == "fullScreen") {
+ tgt._x = Math.round(Stage.width/2-200);
+ tgt._y = Stage.height - 40;
+ tgt._alpha = 100;
+ tgt.back._alpha = 50;
+ tgt.fs.fs._visible = false;
+ tgt.fs.ns._visible = true;
+ } else if(config["displayheight"] == config["height"]) {
+ tgt._y = config["displayheight"] - 40;
+ if(config["displaywidth"] > 450 &&
+ config["displaywidth"] == config["width"]) {
+ tgt._x = Math.round(Stage.width/2-200);
+ } else {
+ tgt._x = 20;
+ cbw = config["displaywidth"] - 40;
+ }
+ tgt.back._alpha = 40;
+ tgt.fs.fs._visible = true;
+ tgt.fs.ns._visible = false;
+ } else {
+ tgt._x = 0;
+ tgt._y = config["displayheight"];
+ cbw = config["width"];
+ tgt._alpha = 100;
+ tgt.back._alpha = 100;
+ tgt.fs.fs._visible = true;
+ tgt.fs.ns._visible = false;
+ }
+ if(config["largecontrols"] == "true") {
+ tgt._xscale = tgt._yscale = 200;
+ if(Stage["displayState"] == "fullScreen") {
+ tgt._y = Stage.height - 60;
+ cbw = 300;
+ tgt._x = Math.round(Stage.width/2 - 300);
+ } else {
+ cbw /= 2;
+ }
+ }
+ tgt.back._width = cbw;
+ // all buttons
+ if(config["displayheight"] < config["height"] - 40 ||
+ config["displaywidth"] < config["width"] - 40 ||
+ cbw < 200 || feeder.feed.length < 2) {
+ tgt.prev._visible = tgt.next._visible = false;
+ tgt.scrub.shd._width = cbw-17;
+ tgt.scrub._x = 17;
+ } else {
+ tgt.prev._visible = tgt.next._visible = true;
+ tgt.scrub.shd._width = cbw-51;
+ tgt.scrub._x = 51;
+ }
+ if(config['showstop'] == 'true') {
+ tgt.scrub.shd._width -= 17;
+ tgt.scrub._x += 17;
+ } else {
+ tgt.stop._visible = false;
+ tgt.prev._x = 17;
+ tgt.next._x = 34;
+ }
+ var xp = cbw;
+ if(cbw > 50) {
+ xp -= 37;
+ tgt.scrub.shd._width -= 37;
+ tgt.vol._x = xp;
+ } else {
+ xp -= 1;
+ tgt.scrub.shd._width -= 1;
+ tgt.vol._x = xp;
+ }
+ if (feeder.audio == true) {
+ xp -= 17;
+ tgt.scrub.shd._width -= 17;
+ tgt.au._x = xp;
+ tgt.au._visible = true;
+ } else {
+ tgt.au._visible = false;
+ }
+ if (feeder.captions == true) {
+ xp -= 17;
+ tgt.scrub.shd._width -= 17;
+ tgt.cc._x = xp;
+ tgt.cc._visible = true;
+ } else {
+ tgt.cc._visible = false;
+ }
+ if (config["showdownload"] == "true") {
+ xp -= 17;
+ tgt.scrub.shd._width -= 17;
+ tgt.dl._x = xp;
+ } else {
+ tgt.dl._visible = false;
+ }
+ if((Stage["displayState"] == undefined ||
+ config["usefullscreen"] == "false" ||
+ feeder.onlymp3s == true) &&
+ config["fsbuttonlink"] == undefined) {
+ tgt.fs._visible = false;
+ } else {
+ xp -= 18;
+ tgt.scrub.shd._width -= 18;
+ tgt.fs._x = xp;
+ }
+ if(config["showdigits"] == "false" || tgt.scrub.shd._width < 120 ||
+ System.capabilities.version.indexOf("7,0,") > -1) {
+ tgt.scrub.elpTxt._visible = tgt.scrub.remTxt._visible = false;
+ tgt.scrub.bar._x = tgt.scrub.bck._x = tgt.scrub.icn._x = 5;
+ barWidths = tgt.scrub.bck._width = tgt.scrub.shd._width - 10;
+ } else {
+ tgt.scrub.elpTxt._visible = tgt.scrub.remTxt._visible = true;
+ tgt.scrub.bar._x = tgt.scrub.bck._x = tgt.scrub.icn._x = 42;
+ barWidths = tgt.scrub.bck._width = tgt.scrub.shd._width - 84;
+ tgt.scrub.remTxt._x = tgt.scrub.shd._width - 39;
+ }
+ tgt.scrub.bar._width = 0;
+ };
+
+
+ /** Show and hide the play/pause button and show activity icon **/
+ private function setState(stt:Number) {
+ var tgt = config["clip"].controlbar.playpause;
+ switch(stt) {
+ case 0:
+ tgt.ply._visible = true;
+ tgt.pas._visible = false;
+ break;
+ case 1:
+ tgt.pas._visible = true;
+ tgt.ply._visible = false;
+ break;
+ case 2:
+ tgt.pas._visible = true;
+ tgt.ply._visible = false;
+ break;
+ }
+ };
+
+
+ /** Print current time to controlBar **/
+ private function setTime(elp:Number,rem:Number) {
+ itemLength = elp + rem;
+ itemProgress = Math.round(rem/(itemLength)*100);
+ var tgt = config["clip"].controlbar.scrub;
+ var w = Math.floor(elp/(elp+rem)*barWidths) - 2;
+ if(rem > 0) {
+ tgt.icn._visible = true;
+ tgt.bar._visible = true;
+ elp == 0 || w < 2 ? tgt.bar._width = 0: tgt.bar._width = w - 2;
+ tgt.icn._x = tgt.bar._width + tgt.bar._x + 1;
+ } else {
+ tgt.icn._visible = false;
+ tgt.bar._visible = false;
+ }
+ tgt.elpTxt.text = StringMagic.addLeading(elp/60) + ":" +
+ StringMagic.addLeading(elp%60);
+ if(tgt.bck._width == barWidths) {
+ if(config['showdigits'] == "total") {
+ tgt.remTxt.text = StringMagic.addLeading((elp+rem)/60)+ ":" +
+ StringMagic.addLeading((elp+rem)%60);
+ } else {
+ tgt.remTxt.text = StringMagic.addLeading(rem/60)+ ":" +
+ StringMagic.addLeading(rem%60);
+ }
+ }
+ };
+
+
+ /** New item is loaded **/
+ private function setItem(prm:Number) {
+ wasLoaded = false;
+ currentItem = prm;
+ config["clip"].controlbar.scrub.icn._alpha = 100;
+ };
+
+
+ /** Print current buffer amount to controlbar **/
+ private function setLoad(pct:Number) {
+ var tgt = config["clip"].controlbar.scrub;
+ if(wasLoaded == false) {
+ tgt.bck._width = Math.round(barWidths*pct/100);
+ }
+ tgt.remTxt.text = Math.round(pct)+" %";
+ pct == 100 ? wasLoaded = true: null;
+ };
+
+
+ /** Reflect current volume in volumebar **/
+ private function setVolume(pr1:Number) {
+ var tgt = config["clip"].controlbar.vol;
+ tgt.msk._width = Math.round(pr1/5);
+ if(pr1 == 0) {
+ tgt.icn._alpha = 40;
+ } else {
+ tgt.icn._alpha = 100;
+ }
+ };
+
+
+ /** Catches stage resizing **/
+ public function onResize() {
+ if(config['displayheight'] > config["height"]+10) {
+ config["height"] = config["displayheight"] = Stage.height;
+ config["width"] = config["displaywidth"] = Stage.width;
+ }
+ setDimensions();
+ };
+
+
+ /** Catches fullscreen escape **/
+ public function onFullScreen(fs:Boolean) {
+ if(fs == false) {
+ setDimensions();
+ Animations.fadeIn(config['clip'].controlbar);
+ } else {
+ hideInt = setInterval(this,"hideBar",500);
+ }
+ };
+
+
+ /** after a delay, the controlbar is hidden **/
+ private function hideBar() {
+ Animations.fadeOut(config['clip'].controlbar);
+ clearInterval(hideInt);
+ }
+
+
+ /** Mouse move shows controlbar **/
+ public function onMouseMove() {
+ if(config["displayheight"] == config["height"] ||
+ Stage["displayState"] == "fullScreen") {
+ Animations.fadeIn(config['clip'].controlbar);
+ clearInterval(hideInt);
+ if(!config["clip"].controlbar.hitTest(_root._xmouse,_root._ymouse)) {
+ hideInt = setInterval(this,"hideBar",500);
+ }
+ }
+ };
+
+
+ public function onFeedUpdate(typ:String) {
+ setDimensions();
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/DisplayView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/DisplayView.as
new file mode 100755
index 0000000..14732cf
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/DisplayView.as
@@ -0,0 +1,267 @@
+/**
+* Display user interface management of the players MCV pattern.
+*
+* @author Jeroen Wijering
+* @version 1.8
+**/
+
+
+import com.jeroenwijering.players.*;
+import com.jeroenwijering.utils.*;
+
+
+class com.jeroenwijering.players.DisplayView extends AbstractView {
+
+
+ /** reference to the imageloader object **/
+ private var imageLoader:ImageLoader;
+ /** Reference to the currently active item **/
+ private var currentItem;
+ /** Reference to the currently active item **/
+ private var itemSize:Array;
+ /** Reference to the currently active item **/
+ private var thumbSize:Array;
+ /** Starting position of the players **/
+ private var startPos:Array;
+
+
+ /** Constructor **/
+ function DisplayView(ctr:AbstractController,cfg:Object,fed:Object) {
+ super(ctr,cfg,fed);
+ Stage.addListener(this);
+ itemSize = new Array(config['displaywidth'],config['displayheight']);
+ thumbSize = new Array(config['displaywidth'],config['displayheight']);
+ var ref = this;
+ var tgt = config["clip"];
+ imageLoader = new ImageLoader(tgt.display.thumb);
+ imageLoader.onLoadFinished = function() {
+ ref.thumbSize = new Array(this.targetClip._width,
+ this.targetClip._height);
+ ref.scaleClip(tgt.display.thumb,this.targetClip._width,
+ this.targetClip._height);
+ }
+ startPos = new Array(tgt._x,tgt._y);
+ setColorsClicks();
+ setDimensions();
+ };
+
+
+ /** Sets up colors and clicks of all display items. **/
+ private function setColorsClicks() {
+ var ref = this;
+ // background
+ var tgt = config["clip"].back;
+ tgt.col = new Color(tgt);
+ tgt.col.setRGB(config["backcolor"]);
+ // display items
+ tgt = config["clip"].display;
+ tgt.col = new Color(tgt.back);
+ tgt.col.setRGB(config["screencolor"]);
+ tgt.setMask(config["clip"].mask);
+ if(config["showicons"] == "false") {
+ tgt.playicon._visible = false;
+ tgt.muteicon._visible = false;
+ }
+ tgt.activity._visible = false;
+ tgt.back.tabEnabled = false;
+ if(config["autostart"] == "muted") {
+ tgt.back.onRelease = function() {
+ ref.sendEvent("volume",80);
+ ref.firstClick();
+ };
+ } else if (config["autostart"] == "false") {
+ tgt.muteicon._visible = false;
+ tgt.back.onRelease = function() {
+ ref.sendEvent("playpause");
+ ref.firstClick();
+ };
+ } else {
+ ref.firstClick();
+ }
+ if(config["logo"] != "undefined") {
+ var lll = new ImageLoader(tgt.logo,"none");
+ lll.onLoadFinished = function() {
+ tgt.logo._x = ref.config["displaywidth"] -
+ tgt.logo._width - 10;
+ tgt.logo._y = 10;
+ };
+ lll.loadImage(config["logo"]);
+ tgt.logo.onRelease = function() {
+ ref.sendEvent("getlink",ref.currentItem);
+ };
+ }
+ };
+
+
+ /** Sets up dimensions of all controlbar items. **/
+ private function setDimensions() {
+ var tgt = config["clip"].back;
+ if(Stage["displayState"] == "fullScreen") {
+ config["clip"]._x = config["clip"]._y = 0;
+ tgt._width = Stage.width;
+ tgt._height = Stage.height;
+ } else {
+ config["clip"]._x = startPos[0];
+ config["clip"]._y = startPos[1];
+ tgt._width = config["width"];
+ tgt._height = config["height"];
+ if(config["displayheight"] >= config["height"] -
+ config['controlbar']) { tgt._height--; }
+ }
+ tgt = config["clip"].display;
+ scaleClip(tgt.thumb,thumbSize[0],thumbSize[1]);
+ scaleClip(tgt.image,itemSize[0],itemSize[1]);
+ scaleClip(tgt.video,itemSize[0],itemSize[1]);
+ if(Stage["displayState"] == "fullScreen") {
+ config["clip"].mask._width =
+ tgt.back._width = Stage.width;
+ config["clip"].mask._height =
+ tgt.back._height = Stage.height;
+ } else {
+ config["clip"].mask._width =
+ tgt.back._width = config["displaywidth"];
+ config["clip"].mask._height =
+ tgt.back._height = config["displayheight"];
+ }
+ tgt.playicon._x = tgt.activity._x = tgt.muteicon._x =
+ Math.round(tgt.back._width/2);
+ tgt.playicon._y = tgt.activity._y = tgt.muteicon._y =
+ Math.round(tgt.back._height/2);
+ if(Stage["displayState"] == "fullScreen") {
+ tgt.playicon._xscale = tgt.playicon._yscale =
+ tgt.muteicon._xscale = tgt.muteicon._yscale =
+ tgt.activity._xscale = tgt.activity._yscale =
+ tgt.logo._xscale = tgt.logo._yscale = 200;
+ tgt.logo._x = Stage.width - tgt.logo._width - 20;
+ tgt.logo._y = 20;
+ } else {
+ tgt.playicon._xscale = tgt.playicon._yscale =
+ tgt.muteicon._xscale = tgt.muteicon._yscale =
+ tgt.activity._xscale = tgt.activity._yscale =
+ tgt.logo._xscale = tgt.logo._yscale = 100;
+ if(tgt.logo._height > 1) {
+ tgt.logo._x= config["displaywidth"]-tgt.logo._width -10;
+ tgt.logo._y = 10;
+ }
+ }
+ };
+
+
+ /** Show and hide the play/pause button and show activity icon **/
+ private function setState(stt:Number) {
+ var tgt = config["clip"].display;
+ switch(stt) {
+ case 0:
+ if (config["linkfromdisplay"] == "false" &&
+ config["showicons"] == "true") {
+ tgt.playicon._visible = true;
+ }
+ tgt.activity._visible = false;
+ break;
+ case 1:
+ tgt.playicon._visible = false;
+ if (config["showicons"] == "true") {
+ tgt.activity._visible = true;
+ }
+ break;
+ case 2:
+ tgt.playicon._visible = false;
+ tgt.activity._visible = false;
+ break;
+ }
+ };
+
+
+ /** save size information and rescale accordingly **/
+ private function setSize(wid:Number,hei:Number) {
+ itemSize = new Array (wid,hei);
+ var tgt = config["clip"].display;
+ scaleClip(tgt.image,itemSize[0],itemSize[1]);
+ scaleClip(tgt.video,itemSize[0],itemSize[1]);
+ };
+
+
+ /** Scale movie according to overstretch setting **/
+ private function scaleClip(tgt:MovieClip,wid:Number,hei:Number):Void {
+ var tcf = tgt.mc._currentframe;
+ tgt.mc.gotoAndStop(1);
+ var stw = config["displaywidth"];
+ var sth = config["displayheight"];
+ if(Stage["displayState"] == "fullScreen") {
+ stw = Stage.width;
+ sth = Stage.height;
+ }
+ var xsr = stw/wid;
+ var ysr = sth/hei;
+ var mxm = Math.max(xsr,ysr);
+ if ((Math.abs(xsr-ysr)/mxm < 0.1 && config["overstretch"] != "none")
+ || config["overstretch"] == "fit") {
+ tgt._width = stw;
+ tgt._height = sth;
+ } else if (xsr < ysr && config["overstretch"] == "false" ||
+ ysr < xsr && config["overstretch"] == "true") {
+ tgt._width = wid*xsr;
+ tgt._height = hei*xsr;
+ } else if(config["overstretch"] == "none") {
+ tgt._width = wid;
+ tgt._height = hei;
+ } else {
+ tgt._width = wid*ysr;
+ tgt._height = hei*ysr;
+ }
+ tgt._x = stw/2 - tgt._width/2;
+ tgt._y = sth/2 - tgt._height/2;
+ tgt.mc.gotoAndPlay(tcf);
+ };
+
+
+ /** Load Thumbnail image if available. **/
+ private function setItem(idx:Number) {
+ currentItem = idx;
+ var tgt = config["clip"].display;
+ if(feeder.feed[idx]["image"] == "undefined") {
+ tgt.thumb.clear();
+ tgt.thumb._visible = false;
+ } else {
+ imageLoader.loadImage(feeder.feed[idx]["image"]);
+ tgt.thumb._visible = true;
+ }
+ };
+
+
+ /** OnResize Handler: catches stage resizing **/
+ public function onResize() {
+ if(config['displayheight'] >= config["height"]) {
+ config["height"] = config["displayheight"] = Stage.height;
+ config["width"] = config["displaywidth"] = Stage.width;
+ }
+ setDimensions();
+ };
+
+
+ /** Catches fullscreen escape **/
+ public function onFullScreen(fs:Boolean) {
+ if(fs == false) { setDimensions(); }
+ };
+
+
+ /** Catches the first display click to reset unmute / displayclick **/
+ private function firstClick() {
+ var ref = this;
+ var tgt = config["clip"].display;
+ tgt.playicon._visible = false;
+ tgt.muteicon._visible = false;
+ if(config["linkfromdisplay"] == "true") {
+ tgt.back.onRelease = function() {
+ ref.sendEvent("getlink",ref.currentItem);
+ };
+ } else {
+ tgt.back.onRelease = function() {
+ ref.sendEvent("playpause",1);
+ };
+ }
+
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/EqualizerView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/EqualizerView.as
new file mode 100755
index 0000000..2fd2e5d
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/EqualizerView.as
@@ -0,0 +1,98 @@
+/**
+* View for an actionscript-drawn equalizer (thanks to Brewer).
+* The eq. is fake, but it considers playstate and volume.
+*
+* @author Jeroen Wijering
+* @version 1.1
+**/
+
+
+import com.jeroenwijering.players.*;
+
+
+class com.jeroenwijering.players.EqualizerView extends AbstractView {
+
+
+ /** EQ movieclip reference **/
+ private var eqClip:MovieClip;
+ /** current volume **/
+ private var currentVolume:Number;
+ /** number of stripes to display in the EQ **/
+ private var eqStripes:Number;
+
+
+ /** Constructor; just inheriting. **/
+ function EqualizerView(ctr:AbstractController,cfg:Object,fed:Object) {
+ super(ctr,cfg,fed);
+ setupEQ();
+ Stage.addListener(this);
+ };
+
+
+ /** setup EQ **/
+ private function setupEQ() {
+ eqClip = config["clip"].equalizer;
+ eqClip._y = config["displayheight"] - 50;
+ eqStripes = Math.floor((config['displaywidth'] - 20)/6);
+ eqClip.stripes.duplicateMovieClip("stripes2",1);
+ eqClip.mask.duplicateMovieClip("mask2",3);
+ eqClip.stripes._width = eqClip.stripes2._width =
+ config['displaywidth']-20;
+ eqClip.stripes.top.col = new Color(eqClip.stripes.top);
+ eqClip.stripes.top.col.setRGB(config['lightcolor']);
+ eqClip.stripes.bottom.col = new Color(eqClip.stripes.bottom);
+ eqClip.stripes.bottom.col.setRGB(0xFFFFFF);
+ eqClip.stripes2.top.col = new Color(eqClip.stripes2.top);
+ eqClip.stripes2.top.col.setRGB(config['lightcolor']);
+ eqClip.stripes2.bottom.col = new Color(eqClip.stripes2.bottom);
+ eqClip.stripes2.bottom.col.setRGB(0xFFFFFF);
+ eqClip.stripes.setMask(eqClip.mask);
+ eqClip.stripes2.setMask(eqClip.mask2);
+ eqClip.stripes._alpha = eqClip.stripes2._alpha = 50;
+ setInterval(this,"drawEqualizer",100,eqClip.mask);
+ setInterval(this,"drawEqualizer",100,eqClip.mask2);
+ };
+
+
+ /** Draw a random frame for the equalizer **/
+ private function drawEqualizer(tgt:MovieClip) {
+ tgt.clear();
+ tgt.beginFill(0x000000, 100);
+ tgt.moveTo(0,0);
+ var h = Math.round(currentVolume/4);
+ for (var j=0; j< eqStripes; j++) {
+ var z = random(h)+h/2 + 2;
+ if(j == Math.floor(eqStripes/2)) { z = 0; }
+ tgt.lineTo(j*6,-1);
+ tgt.lineTo(j*6,-z);
+ tgt.lineTo(j*6+4,-z);
+ tgt.lineTo(j*6+4,-1);
+ tgt.lineTo(j*6,-1);
+ }
+ tgt.lineTo(eqStripes*6,0);
+ tgt.lineTo(0,0);
+ tgt.endFill();
+ };
+
+
+ /** Change the height to reflect the volume **/
+ private function setVolume(vol:Number) { currentVolume = vol; };
+
+
+ /** Only display the eq if a song is playing **/
+ private function setState(stt:Number) {
+ stt == 2 ? eqClip._visible = true: eqClip._visible = false;
+ };
+
+
+ /** Hide the EQ on fullscreen view **/
+ public function onFullScreen(fs:Boolean) {
+ if(fs == true) {
+ eqClip._visible = false;
+ } else {
+ eqClip._visible = true;
+ }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/FLVModel.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/FLVModel.as
new file mode 100755
index 0000000..5ac8249
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/FLVModel.as
@@ -0,0 +1,329 @@
+/**
+* FLV model class of the players MCV pattern.
+* Handles playback of FLV files, HTTP streams and RTMP streams.
+*
+* @author Jeroen Wijering
+* @version 1.13
+**/
+
+
+import com.jeroenwijering.players.*;
+
+
+class com.jeroenwijering.players.FLVModel extends AbstractModel {
+
+
+ /** array with extensions used by this model **/
+ private var mediatypes:Array = new Array(
+ "flv","rtmp","mp4","m4v","m4a","mov","3gp","3g2");
+ /** NetConnection object reference **/
+ private var connectObject:NetConnection;
+ /** NetStream object reference **/
+ private var streamObject:NetStream;
+ /** Sound object reference **/
+ private var soundObject:Sound;
+ /** interval ID of the buffer update function **/
+ private var loadedInterval:Number;
+ /** current percentage of the video that's loaded **/
+ private var currentLoaded:Number = 0;
+ /** interval ID of the position update function **/
+ private var positionInterval:Number;
+ /** current state of the video that is playing **/
+ private var currentState:Number;
+ /** Current volume **/
+ private var currentVolume:Number;
+ /** MovieClip with "display" video Object **/
+ private var videoClip:MovieClip;
+ /** object with keyframe times and positions, saved for PHP streaming **/
+ private var metaKeyframes:Object = new Object();
+ /** Boolean to check whether a stop event is fired **/
+ private var stopFired:Boolean = false;
+ /** Boolean to check whether a flusk event is fired **/
+ private var flushFired:Boolean = false;
+ /** Switch for FLV type currently played **/
+ private var flvType:String;
+ /** check h264 for time offset **/
+ private var isH264:Boolean;
+ /** check h264 for time offset **/
+ private var timeOffset:Number = 0;
+ /** reference to the captions object for parsing captionate data **/
+ public var capView:Object;
+ /** buffer iterator (prevents buffericon showing on slow PC's) **/
+ public var bufferCount:Number = 0;
+
+
+
+ /** Constructor **/
+ function FLVModel(vws:Array,ctr:AbstractController,cfg:Object,
+ fed:Object,fcl:MovieClip) {
+ super(vws,ctr,cfg,fed);
+ connectObject = new NetConnection();
+ videoClip = fcl;
+ if(config["smoothing"] == "false") {
+ videoClip.display.smoothing = false;
+ } else {
+ videoClip.display.smoothing = true;
+ }
+ videoClip.display.deblocking = config["deblocking"];
+ videoClip.createEmptyMovieClip("snd",videoClip.getNextHighestDepth());
+ soundObject = new Sound(videoClip.snd);
+ };
+
+
+ /** Check which FLV type we use **/
+ private function setItem(idx:Number) {
+ super.setItem(idx);
+ if(isActive == true) {
+ if(config["streamscript"] != undefined) {
+ flvType = "HTTP";
+ } else if(feeder.feed[currentItem]["type"] == "rtmp") {
+ flvType = "RTMP";
+ } else {
+ flvType = "FLV";
+ }
+ }
+ };
+
+
+ /** Start a specific video **/
+ private function setStart(pos:Number) {
+ stopFired = false;
+ flushFired = false;
+ if (pos != undefined) { currentPosition = pos; }
+ if(pos < 1) {
+ pos = 0;
+ } else if (pos > feeder.feed[currentItem]["duration"] - 1) {
+ pos = feeder.feed[currentItem]["duration"] - 1;
+ }
+ if (flvType=="RTMP" && feeder.feed[currentItem]["id"] != currentURL) {
+ connectObject.connect(feeder.feed[currentItem]["file"]);
+ currentURL = feeder.feed[currentItem]["id"];
+ setStreamObject(connectObject);
+ streamObject.play(currentURL);
+ } else if(flvType != "RTMP" &&
+ feeder.feed[currentItem]["file"] != currentURL) {
+ connectObject.connect(null);
+ currentURL = feeder.feed[currentItem]["file"];
+ if(flvType == "HTTP" ) {
+ setStreamObject(connectObject);
+ if(config["streamscript"] == "lighttpd") {
+ streamObject.play(currentURL);
+ } else {
+ streamObject.play(config["streamscript"] +
+ "?file=" + currentURL);
+ }
+ } else {
+ setStreamObject(connectObject);
+ streamObject.play(currentURL);
+ }
+ } else {
+ if(flvType == "HTTP" && pos != undefined) {
+ playKeyframe(currentPosition);
+ } else if (flvType != "HTTP" && pos != undefined) {
+ streamObject.seek(currentPosition);
+ } else if(flvType == "RTMP" && currentPosition > 0 &&
+ feeder.feed[currentItem]["duration"] == 0) {
+ connectObject.connect(feeder.feed[currentItem]["file"]);
+ setStreamObject(connectObject);
+ streamObject.play(currentURL);
+ } else {
+ streamObject.pause(false);
+ }
+ }
+ videoClip._visible = true;
+ videoClip._parent.thumb._visible = false;
+ clearInterval(positionInterval);
+ positionInterval = setInterval(this,"updatePosition",100);
+ clearInterval(loadedInterval);
+ loadedInterval = setInterval(this,"updateLoaded",100);
+ };
+
+
+ /** Read and broadcast the amount of the flv that's currently loaded **/
+ private function updateLoaded() {
+ var pct:Number = Math.round(streamObject.bufferLength/
+ streamObject.bufferTime*100);
+ if(flvType == "FLV") {
+ pct = Math.round(streamObject.bytesLoaded/
+ streamObject.bytesTotal*100);
+ }
+ if(isNaN(pct)) {
+ currentLoaded = 0;
+ sendUpdate("load",0);
+ } else if (pct > 95) {
+ clearInterval(loadedInterval);
+ currentLoaded = 100;
+ sendUpdate("load",100);
+ } else if (pct != currentLoaded) {
+ currentLoaded= pct;
+ sendUpdate("load",currentLoaded);
+ }
+ };
+
+
+ /** Read and broadcast the current position of the song **/
+ private function updatePosition() {
+ var pos = streamObject.time + timeOffset;
+ if(pos == currentPosition && currentState != 1 && stopFired != true) {
+ if(bufferCount == 5) {
+ currentState = 1;
+ sendUpdate("state",1);
+ bufferCount = 0;
+ } else {
+ bufferCount++;
+ }
+ } else if (pos != currentPosition && currentState != 2) {
+ bufferCount = 0;
+ currentState = 2;
+ sendUpdate("state",2);
+ } else {
+ bufferCount = 0;
+ }
+ if (pos != currentPosition) {
+ currentPosition = pos;
+ sendUpdate("time",currentPosition,
+ Math.max(feeder.feed[currentItem]["duration"]-currentPosition,0));
+ } else if (stopFired == true ||
+ (flushFired == true && flvType != "RTMP" && bufferCount == 5)) {
+ currentState = 3;
+ videoClip._visible = false;
+ videoClip._parent.thumb._visible = true;
+ sendUpdate("state",3);
+ sendCompleteEvent();
+ stopFired = false;
+ flushFired = false;
+ }
+ };
+
+
+ /** Pause the video that's currently playing. **/
+ private function setPause(pos:Number) {
+ if(pos < 1) { pos = 0; }
+ clearInterval(positionInterval);
+ if(pos != undefined) {
+ currentPosition = pos;
+ sendUpdate("time",currentPosition,
+ Math.abs(feeder.feed[currentItem]["duration"]-currentPosition));
+ streamObject.seek(currentPosition);
+ }
+ streamObject.pause(true);
+ currentState = 0;
+ sendUpdate("state",0);
+ };
+
+
+ /** Stop video and clear data. **/
+ private function setStop(pos:Number) {
+ clearInterval(loadedInterval);
+ clearInterval(positionInterval);
+ videoClip._visible = false;
+ delete currentURL;
+ delete currentLoaded;
+ delete currentPosition;
+ delete metaKeyframes;
+ currentLoaded = 0;
+ stopFired = false;
+ timeOffset = 0;
+ streamObject.close();
+ delete streamObject;
+ };
+
+
+ /** Set volume of the sound object. **/
+ private function setVolume(vol:Number) {
+ super.setVolume(vol);
+ currentVolume = vol;
+ soundObject.setVolume(vol);
+ };
+
+
+ /** Connect a new stream object to video/audio/callbacks **/
+ private function setStreamObject(cnt:NetConnection) {
+ _root.tf.text = 'metadata!';
+ var ref = this;
+ currentLoaded = 0;
+ sendUpdate("load",0);
+ streamObject = new NetStream(cnt);
+ streamObject.setBufferTime(config["bufferlength"]);
+ streamObject.onMetaData = function(obj) {
+ if(obj.duration > 1) {
+ ref.feeder.feed[ref.currentItem]["duration"] = obj.duration;
+ }
+ if(obj.width > 10) {
+ ref.sendUpdate("size",obj.width,obj.height);
+ }
+ if(obj.seekpoints != undefined) {
+ ref.isH264 = true;
+ ref.metaKeyframes = new Object();
+ ref.metaKeyframes.times = new Array();
+ ref.metaKeyframes.filepositions = new Array();
+ for (var j in obj.seekpoints) {
+ ref.metaKeyframes.times.unshift(
+ Number(obj.seekpoints[j]['time']));
+ ref.metaKeyframes.filepositions.unshift(
+ Number(obj.seekpoints[j]['time']));
+ }
+ } else {
+ ref.metaKeyframes = obj.keyframes;
+ }
+ if(ref.feeder.feed[ref.currentItem]['start'] > 0) {
+ if(ref.flvType == "HTTP") {
+ ref.playKeyframe(ref.feeder.feed[ref.currentItem]['start']);
+ } else if (ref.flvType == "RTMP") {
+ ref.setStart(ref.feeder.feed[ref.currentItem]['start']);
+ }
+ }
+ delete obj;
+ delete this.onMetaData;
+ };
+ streamObject.onStatus = function(object) {
+ trace("status: "+object.code);
+ if(object.code == "NetStream.Play.Stop" && ref.flvType!='RTMP') {
+ ref.stopFired = true;
+ } else if (object.code == "NetStream.Play.StreamNotFound") {
+ ref.currentState = 3;
+ ref.videoClip._visible = false;
+ ref.sendUpdate("state",3);
+ ref.sendCompleteEvent();
+ ref.stopFired = false;
+ ref.flushFired = false;
+ } else if (object.code == "NetStream.Buffer.Flush") {
+ ref.flushFired = true;
+ }
+ };
+ streamObject.onPlayStatus = function(object) {
+ if( object.code == "NetStream.Play.Complete" ||
+ object.code == "NetStream.Play.Stop") {
+ ref.stopFired = true;
+ }
+ };
+ streamObject.onCaption = function(cap:Array) {
+ ref.capView.onCaptionate(cap);
+ };
+ videoClip.display.attachVideo(streamObject);
+ videoClip.snd.attachAudio(streamObject);
+ };
+
+
+ /** Play from keyframe position from metadata **/
+ private function playKeyframe(pos:Number) {
+ for (var i=0; i< metaKeyframes.times.length; i++) {
+ if((metaKeyframes.times[i] <= pos) &&
+ (metaKeyframes.times[i+1] >= pos)) {
+ if(config["streamscript"] == "lighttpd") {
+ streamObject.play(currentURL+"?start="+
+ metaKeyframes.filepositions[i]);
+ if(isH264 == true) {
+ timeOffset = metaKeyframes.filepositions[i];
+ }
+ } else {
+ streamObject.play(config["streamscript"]+"?file="+
+ currentURL+"&pos="+metaKeyframes.filepositions[i]);
+ }
+ break;
+ }
+ }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/ImageModel.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/ImageModel.as
new file mode 100755
index 0000000..73bb61a
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/ImageModel.as
@@ -0,0 +1,151 @@
+/**
+* Image model class of the players MCV pattern.
+*
+* @author Jeroen Wijering
+* @version 1.5
+**/
+
+
+import com.jeroenwijering.players.*;
+import com.jeroenwijering.utils.ImageLoader;
+
+
+class com.jeroenwijering.players.ImageModel extends AbstractModel {
+
+
+ /** array with extensions used by this model **/
+ private var mediatypes:Array = new Array("jpg","gif","png","swf");
+ /** ImageLoader instance **/
+ private var imageLoader:ImageLoader;
+ /** Clip to load the image into **/
+ private var imageClip:MovieClip;
+ /** interval ID of image duration function **/
+ private var positionInterval:Number;
+ /** current state **/
+ private var currentState:Number;
+ /** boolean to check for current SWF **/
+ private var isSWF:Boolean;
+
+
+ /** Constructor **/
+ function ImageModel(vws:Array,ctr:AbstractController,cfg:Object,
+ fed:Object,imc:MovieClip,scl:Boolean) {
+ super(vws,ctr,cfg,fed);
+ imageClip = imc;
+ var ref = this;
+ if(arguments[5] == true) {
+ imageLoader = new ImageLoader(imageClip,config["overstretch"],
+ config["width"],config["height"]);
+ } else {
+ imageLoader = new ImageLoader(imageClip);
+ }
+ imageLoader.onLoadFinished = function() {
+ ref.currentState = 2;
+ ref.sendUpdate("state",2);
+ ref.sendUpdate("load",100);
+ };
+ imageLoader.onLoadProgress = function(tgt,btl,btt) {
+ ref.sendUpdate("load",Math.round(btl/btt*100));
+ };
+ imageLoader.onMetaData = function() {
+ ref.sendUpdate("size",this.sourceWidth,this.sourceHeight);
+ if(this.sourceLength > ref.feeder.feed[ref.currentItem]["duration"]) {
+ ref.feeder.feed[ref.currentItem]["duration"] = this.sourceLength;
+ }
+ };
+ };
+
+
+ /** Start display interval for a specific image **/
+ private function setStart(pos:Number) {
+ if(pos < 1 ) {
+ pos = 0;
+ } else if (pos > feeder.feed[currentItem]["duration"] - 1) {
+ pos = feeder.feed[currentItem]["duration"] - 1;
+ }
+ clearInterval(positionInterval);
+ if(feeder.feed[currentItem]["file"] != currentURL) {
+ imageClip._visible = true;
+ currentURL = feeder.feed[currentItem]["file"];
+ if(feeder.feed[currentItem]["file"].indexOf(".swf") == -1) {
+ isSWF = false;
+ } else {
+ isSWF = true;
+ }
+ imageLoader.loadImage(feeder.feed[currentItem]["file"]);
+ currentState = 1;
+ sendUpdate("state",1);
+ sendUpdate("load",0);
+ } else {
+ currentState = 2;
+ sendUpdate("state",2);
+ }
+ if (pos != undefined) {
+ currentPosition = pos;
+ isSWF == true ? imageClip.mc.gotoAndPlay(pos*20): null;
+ if(pos == 0) {sendUpdate("time",0,feeder.feed[currentItem]["duration"]); }
+ } else {
+ isSWF == true ? imageClip.mc.play(): null;
+ }
+ positionInterval = setInterval(this,"updatePosition",100);
+ };
+
+
+ /** Read and broadcast the current position of the song **/
+ private function updatePosition() {
+ if(currentState == 2) {
+ currentPosition += 0.1;
+ if(currentPosition >= feeder.feed[currentItem]["duration"]) {
+ currentState = 3;
+ sendUpdate("state",3);
+ sendCompleteEvent();
+ } else {
+ sendUpdate("time",currentPosition,feeder.feed[currentItem]["duration"]-currentPosition);
+ }
+ }
+ };
+
+
+ /** stop the image display interval **/
+ private function setPause(pos:Number) {
+ if(pos < 1 ) {
+ pos = 0;
+ } else if (pos > feeder.feed[currentItem]["duration"] - 1) {
+ pos = feeder.feed[currentItem]["duration"] - 1;
+ }
+ clearInterval(positionInterval);
+ currentState = 0;
+ sendUpdate("state",0);
+ if(pos != undefined) {
+ currentPosition = pos;
+ sendUpdate("time",currentPosition,feeder.feed[currentItem]["duration"]-currentPosition);
+ isSWF == true ? imageClip.mc.gotoAndStop(pos*20+1): null;
+ } else {
+ isSWF == true ? imageClip.mc.stop(): null;
+ }
+ };
+
+
+ /** stop display of the item altogether **/
+ private function setStop() {
+ delete currentURL;
+ clearInterval(positionInterval);
+ currentPosition = 0;
+ isSWF == true ? imageClip.mc.gotoAndStop(1): null;
+ if (imageClip.bg == undefined) {
+ imageClip.mc.removeMovieClip();
+ imageClip.smc.removeMovieClip();
+ imageClip._visible = false;
+ }
+ };
+
+
+ /** set duration to rotatetime for images **/
+ private function setItem(idx:Number) {
+ super.setItem(idx);
+ if(feeder.feed[currentItem]["duration"] == 0 && isActive == true) {
+ feeder.feed[currentItem]["duration"] = config['rotatetime'];
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/ImageRotator.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/ImageRotator.as
new file mode 100755
index 0000000..b63feb4
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/ImageRotator.as
@@ -0,0 +1,82 @@
+/**
+* Manages startup and overall control of the Flash Image Rotator
+*
+* @author Jeroen Wijering
+* @version 1.7
+**/
+
+
+import com.jeroenwijering.players.*;
+
+
+class com.jeroenwijering.players.ImageRotator extends AbstractPlayer {
+
+
+ /** Array with all config values **/
+ public var config:Object = {
+ clip:undefined,
+ file:"playlist.xml",
+ height:200,
+ width:400,
+ transition:"random",
+ backcolor:0x000000,
+ frontcolor:0xffffff,
+ lightcolor:0xffffff,
+ screencolor:0x000000,
+ kenburns:"false",
+ logo:undefined,
+ overstretch:"false",
+ showicons:"true",
+ shownavigation:"true",
+ autostart:"true",
+ repeat:"true",
+ rotatetime:5,
+ shuffle:"true",
+ volume:80,
+ enablejs:"false",
+ javascriptid:undefined,
+ linkfromdisplay:"false",
+ linktarget:"_self",
+ useaudio:"true",
+ abouttxt:"JW Image Rotator 3.15",
+ aboutlnk:"http://www.jeroenwijering.com/?about=JW_Image_Rotator"
+ };
+
+
+ /** Constructor **/
+ function ImageRotator(tgt:MovieClip) {
+ super(tgt);
+ };
+
+
+ /** Setup all necessary MCV blocks. **/
+ private function setupMCV():Void {
+ controller = new RotatorController(config,feeder);
+ var rov = new RotatorView(controller,config,feeder);
+ var ipv = new InputView(controller,config,feeder);
+ var vws:Array = new Array(rov,ipv);
+ if(config["enablejs"] == "true") {
+ var jsv = new JavascriptView(controller,config,feeder);
+ vws.push(jsv);
+ }
+ if(feeder.audio == true) {
+ var bav = new AudioView(controller,config,feeder,false);
+ vws.push(bav);
+ }
+ config["displayheight"] = config["height"];
+ var im1=new ImageModel(vws,controller,config,feeder,
+ config["clip"].img1,true);
+ var im2=new ImageModel(vws,controller,config,feeder,
+ config["clip"].img2,true);
+ var mds:Array = new Array(im1,im2);
+ controller.startMCV(mds);
+ };
+
+
+ /** Application startup, used for MTASC compilation **/
+ public static function main() {
+ var irt = new ImageRotator(_root.rotator);
+ }
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/InputView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/InputView.as
new file mode 100755
index 0000000..735697f
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/InputView.as
@@ -0,0 +1,63 @@
+/**
+* Keyboard input management of the players MCV pattern.
+* SPACE: playpause,UP:prev,DOWN:next,LEFT:volume-10,RIGHT:volume+10
+*
+* @author Jeroen Wijering
+* @version 1.3
+**/
+
+
+import com.jeroenwijering.players.*;
+
+
+class com.jeroenwijering.players.InputView extends AbstractView {
+
+
+ /** The current volume **/
+ private var currentVolume:Number;
+ /** The current elapsed time **/
+ private var currentTime:Number;
+
+
+ /** Constructor **/
+ function InputView(ctr:AbstractController,cfg:Object,fed:Object) {
+ super(ctr,cfg,fed);
+ Key.addListener(this);
+ };
+
+
+ /** Save current elapsed time **/
+ private function setTime(elp:Number,rem:Number) { currentTime = elp; };
+
+
+ /** Save current volume **/
+ private function setVolume(vol:Number) { currentVolume = vol; };
+
+
+ /** KeyDown handler, forwarded by Key object **/
+ public function onKeyDown() {
+ if (Key.getCode() == 32) {
+ sendEvent("playpause");
+ } else if (Key.getCode() == 37) {
+ if(feeder.feed.length == 1) {
+ sendEvent("scrub",currentTime-15);
+ } else {
+ sendEvent("prev");
+ }
+ } else if (Key.getCode() == 39) {
+ if(feeder.feed.length == 1) {
+ sendEvent("scrub",currentTime+15);
+ } else {
+ sendEvent("next");
+ }
+ } else if (Key.getCode() == 38) {
+ sendEvent("volume",currentVolume+10);
+ } else if (Key.getCode() == 40) {
+ sendEvent("volume",currentVolume-10);
+ } else if (Key.getCode() == 77) {
+ sendEvent("volume",0);
+ }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/JavascriptView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/JavascriptView.as
new file mode 100755
index 0000000..7214ecf
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/JavascriptView.as
@@ -0,0 +1,90 @@
+/**
+* Javascript user interface management of the players MCV pattern.
+*
+* @author Jeroen Wijering
+* @version 1.5
+**/
+
+
+import com.jeroenwijering.players.*;
+import flash.external.ExternalInterface;
+
+
+class com.jeroenwijering.players.JavascriptView extends AbstractView {
+
+
+ /** Previous loading value **/
+ private var loads:Number;
+ /** Previous elapsed value **/
+ private var elaps:Number;
+ /** Previous remaining value **/
+ private var remain:Number;
+ /** Previous state value **/
+ private var state:Number = 4;
+ /** Status change abbreviations **/
+ private var statuses:Array = new Array(
+ 'PAUSED',
+ 'BUFFERING',
+ 'PLAYING',
+ 'COMPLETE',
+ 'NOT STARTED'
+ );
+
+
+ /** Constructor **/
+ function JavascriptView(ctr:AbstractController,cfg:Object,fed:Object) {
+ super(ctr,cfg,fed);
+ if(ExternalInterface.available) {
+ ExternalInterface.addCallback("sendEvent",this,sendEvent);
+ }
+ };
+
+
+ /** Override of the update receiver; forwarding all to javascript **/
+ public function getUpdate(typ:String,pr1:Number,pr2:Number) {
+ if(ExternalInterface.available) {
+ switch(typ) {
+ case "load":
+ if(Math.round(pr1) != loads) {
+ loads = Math.round(pr1);
+ ExternalInterface.call("getUpdate",typ,loads,pr2,
+ config["javascriptid"]);
+ }
+ break;
+ case "time":
+ if(Math.round(pr1)!=elaps || Math.round(pr2)!=remain) {
+ elaps = Math.round(pr1);
+ remain = Math.round(pr2);
+ ExternalInterface.call("getUpdate",typ,elaps,remain,
+ config["javascriptid"]);
+ }
+ break;
+ case "item":
+ ExternalInterface.call("getUpdate",typ,pr1,pr2,
+ config["javascriptid"]);
+ break;
+ case "state":
+ sendStatusChange(pr1);
+ ExternalInterface.call("getUpdate",typ,pr1,pr2,
+ config["javascriptid"]);
+ break;
+ default:
+ ExternalInterface.call("getUpdate",typ,pr1,pr2,
+ config["javascriptid"]);
+ break;
+ }
+ }
+ };
+
+
+ /** state change function for longtail **/
+ private function sendStatusChange(stt) {
+ if(!(state == 3 && stt == 0)) {
+ ExternalInterface.call("playerStatusChange",
+ statuses[state],statuses[stt]);
+ }
+ state = stt;
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/MP3Model.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/MP3Model.as
new file mode 100755
index 0000000..1e53b2c
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/MP3Model.as
@@ -0,0 +1,154 @@
+/**
+* MP3 model class of the players MCV pattern.
+*
+* @author Jeroen Wijering
+* @version 1.4
+**/
+
+
+import com.jeroenwijering.players.*;
+
+
+class com.jeroenwijering.players.MP3Model extends AbstractModel {
+
+
+ /** array with extensions used by this model **/
+ private var mediatypes:Array = new Array("mp3","rbs");
+ /** Sound instance **/
+ private var soundObject:Sound;
+ /** MovieClip to apply the sound object to **/
+ private var soundClip:MovieClip;
+ /** interval ID of the buffer update function **/
+ private var loadedInterval:Number;
+ /** currently loaded percentage **/
+ private var currentLoaded:Number = 0;
+ /** interval ID of the position update function **/
+ private var positionInterval:Number;
+ /** current state of the sound that is playing **/
+ private var currentState:Number;
+ /** Current volume **/
+ private var currentVolume:Number;
+
+
+ /** Constructor **/
+ function MP3Model(vws:Array,ctr:AbstractController,
+ cfg:Object,fed:Object,scl:MovieClip) {
+ super(vws,ctr,cfg,fed);
+ soundClip = scl;
+ };
+
+
+ /** Start a specific sound **/
+ private function setStart(pos:Number) {
+ if(pos < 1 ) {
+ pos = 0;
+ } else if (pos > feeder.feed[currentItem]["duration"] - 1) {
+ pos = feeder.feed[currentItem]["duration"] - 1;
+ }
+ clearInterval(positionInterval);
+ if(feeder.feed[currentItem]["file"] != currentURL) {
+ var ref = this;
+ currentURL = feeder.feed[currentItem]["file"];
+ soundObject = new Sound(soundClip);
+ soundObject.onSoundComplete = function() {
+ ref.currentState = 3;
+ ref.sendUpdate("state",3);
+ ref.sendCompleteEvent();
+ };
+ soundObject.onLoad = function(scs:Boolean) {
+ if(scs == false) {
+ ref.currentState = 3;
+ ref.sendUpdate("state",3);
+ ref.sendCompleteEvent();
+ }
+ };
+ soundObject.loadSound(currentURL,true);
+ soundObject.setVolume(currentVolume);
+ sendUpdate("load",0);
+ loadedInterval = setInterval(this,"updateLoaded",100);
+ }
+ if(pos != undefined) {
+ currentPosition = pos;
+ if(pos == 0) { sendUpdate("time",0,feeder.feed[currentItem]["duration"]); }
+ }
+ soundObject.start(currentPosition);
+ updatePosition();
+ sendUpdate("size",0,0);
+ positionInterval = setInterval(this,"updatePosition",100);
+ };
+
+
+ /** Read and broadcast the amount of the mp3 that's currently loaded **/
+ private function updateLoaded() {
+ var pct:Number = Math.round(soundObject.getBytesLoaded() /
+ soundObject.getBytesTotal()*100);
+ if(isNaN(pct)) {
+ currentLoaded = 0;
+ sendUpdate("load",0);
+ } else if (pct != currentLoaded) {
+ sendUpdate("load",pct);
+ currentLoaded = pct;
+ } else if(pct >= 100) {
+ clearInterval(loadedInterval);
+ currentLoaded = 100;
+ sendUpdate("load",100);
+ }
+ };
+
+
+ /** Read and broadcast the current position of the song **/
+ private function updatePosition() {
+ var pos = soundObject.position/1000;
+ feeder.feed[currentItem]["duration"] = soundObject.duration/(10*currentLoaded);
+ if(pos == currentPosition && currentState != 1) {
+ currentState = 1;
+ sendUpdate("state",1);
+ } else if (pos != currentPosition && currentState != 2) {
+ currentState = 2;
+ sendUpdate("state",2);
+ }
+ if (pos != currentPosition) {
+ currentPosition = pos;
+ sendUpdate("time",currentPosition,feeder.feed[currentItem]["duration"]-currentPosition);
+ }
+ };
+
+
+ /** Pause the sound that's currently playing. **/
+ private function setPause(pos:Number) {
+ if(pos < 1) {
+ pos = 0;
+ } else if (pos > feeder.feed[currentItem]["duration"] - 1) {
+ pos = feeder.feed[currentItem]["duration"] - 1;
+ }
+ soundObject.stop();
+ clearInterval(positionInterval);
+ currentState = 0;
+ sendUpdate("state",0);
+ if(pos != undefined) {
+ currentPosition = pos;
+ sendUpdate("time",currentPosition,feeder.feed[currentItem]["duration"]-currentPosition);
+ }
+ };
+
+
+ /** stop and unload the sound **/
+ private function setStop() {
+ soundObject.stop();
+ clearInterval(positionInterval);
+ clearInterval(loadedInterval);
+ delete currentURL;
+ delete soundObject;
+ currentLoaded = 0;
+ };
+
+
+ /** Set volume of the sound object. **/
+ private function setVolume(vol:Number) {
+ super.setVolume(vol);
+ currentVolume = vol;
+ soundObject.setVolume(vol);
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/MediaPlayer.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/MediaPlayer.as
new file mode 100755
index 0000000..cdf0013
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/MediaPlayer.as
@@ -0,0 +1,177 @@
+/**
+* Player that reads all media formats Flash can read.
+*
+* @author Jeroen Wijering
+* @version 1.10
+**/
+
+
+import com.jeroenwijering.players.*;
+import com.jeroenwijering.utils.BandwidthCheck;
+
+
+class com.jeroenwijering.players.MediaPlayer extends AbstractPlayer {
+
+
+ /** Array with all config values **/
+ private var config:Object = {
+ clip:undefined,
+ file:"video.flv",
+ height:260,
+ width:320,
+ controlbar:20,
+ displayheight:undefined,
+ frontcolor:0x000000,
+ backcolor:0xffffff,
+ lightcolor:0x000000,
+ screencolor:0x000000,
+ autoscroll:"false",
+ displaywidth:undefined,
+ largecontrols:"false",
+ logo:undefined,
+ showdigits:"true",
+ showdownload:"false",
+ showeq:"false",
+ showicons:"true",
+ shownavigation:"true",
+ showstop:"false",
+ thumbsinplaylist:"true",
+ usefullscreen:"true",
+ fsbuttonlink:undefined,
+ autostart:"false",
+ bufferlength:3,
+ deblocking:4,
+ overstretch:"false",
+ repeat:"false",
+ rotatetime:5,
+ shuffle:"true",
+ smoothing:"true",
+ volume:80,
+ bwfile:"100k.jpg",
+ bwstreams:undefined,
+ callback:undefined,
+ enablejs:"false",
+ javascriptid:"",
+ linkfromdisplay:"false",
+ linktarget:'_self',
+ prefix:"",
+ recommendations:undefined,
+ streamscript:undefined,
+ useaudio:"true",
+ usecaptions:"true",
+ usemute:"false",
+ usekeys:"true",
+ abouttxt:"JW FLV Media Player 3.15",
+ aboutlnk:"http://www.jeroenwijering.com/?about=JW_FLV_Media_Player"
+ };
+
+
+ /** Constructor **/
+ public function MediaPlayer(tgt:MovieClip) {
+ super(tgt);
+ };
+
+
+ /** check bandwidth for streaming **/
+ private function checkStream() {
+ var ref = this;
+ var str = config["bwstreams"].split(",");
+ var bwc = new BandwidthCheck(config["bwfile"]);
+ bwc.onComplete = function(kbps) {
+ trace("bandwidth: "+kbps);
+ var bwm = new ContextMenuItem("Detected bandwidth: "+kbps+" kbps");
+ bwm.separatorBefore = true;
+ ref.manager.context.customItems.push(bwm);
+ if(ref.config['enablejs'] == "true" &&
+ flash.external.ExternalInterface.available) {
+ flash.external.ExternalInterface.call("getBandwidth",kbps);
+ }
+ for (var i=1; i feeder.feed.length-1 ? itm = feeder.feed.length-1: null;
+ if(feeder.feed[currentItem]['file'] != feeder.feed[itm]['file']) {
+ sendChange("stop");
+ }
+ currentItem = itm;
+ sendChange("item",itm);
+
+ }
+ sendChange("start",feeder.feed[itm]["start"]);
+ currentURL = feeder.feed[itm]['file'];
+ isPlaying = true;
+ };
+
+
+ /** Get url from an item if link exists, else playpause. **/
+ private function setGetlink(idx:Number) {
+ if(feeder.feed[idx]["link"] == undefined) {
+ setPlaypause();
+ } else {
+ getURL(feeder.feed[idx]["link"],config["linktarget"]);
+ }
+ };
+
+
+ /** Determine what to do if an item is completed. **/
+ private function setComplete() {
+ itemsPlayed++;
+ if(feeder.feed[currentItem]['type'] == "rtmp" ||
+ config["streamscript"] != undefined) {
+ sendChange("stop");
+ }
+ if(config["repeat"] == "false" || (config["repeat"] == "list"
+ && itemsPlayed >= feeder.feed.length)) {
+ sendChange("pause",0);
+ isPlaying = false;
+ itemsPlayed = 0;
+ } else {
+ var itm;
+ if(config["shuffle"] == "true") {
+ itm = randomizer.pick();
+ } else if(currentItem == feeder.feed.length - 1) {
+ itm = 0;
+ } else {
+ itm = currentItem+1;
+ }
+ setPlayitem(itm);
+ }
+ };
+
+
+ /** Fullscreen switch function. **/
+ private function setFullscreen() {
+ if(Stage["displayState"] == "normal" &&
+ config["usefullscreen"] == "true") {
+ Stage["displayState"] = "fullScreen";
+ } else if (Stage["displayState"] == "fullScreen" &&
+ config["usefullscreen"] == "true") {
+ Stage["displayState"] = "normal";
+ } else if (config["fsbuttonlink"] != undefined) {
+ sendChange("stop");
+ getURL(config["fsbuttonlink"],config["linktarget"]);
+ }
+ };
+
+
+ /** Captions toggle **/
+ private function setCaptions() {
+ if(config["usecaptions"] == "true") {
+ config["usecaptions"] = "false";
+ config["clip"].captions._visible = false;
+ config["clip"].controlbar.cc.icn._alpha = 40;
+ } else {
+ config["usecaptions"] = "true";
+ config["clip"].captions._visible = true;
+ config["clip"].controlbar.cc.icn._alpha = 100;
+ }
+ playerSO.data.usecaptions = config["usecaptions"];
+ playerSO.flush();
+ };
+
+
+ /** Audiotrack toggle **/
+ private function setAudio() {
+ if(config["useaudio"] == "true") {
+ config["useaudio"] = "false";
+ config["clip"].audio.setStop();
+ config["clip"].controlbar.au.icn._alpha = 40;
+ } else {
+ config["useaudio"] = "true";
+ config["clip"].audio.setStart();
+ config["clip"].controlbar.au.icn._alpha = 100;
+ }
+ playerSO.data.useaudio = config["useaudio"];
+ playerSO.flush();
+ };
+
+
+ /** Check volume percentage and forward to models. **/
+ private function setVolume(prm) {
+ if (prm < 0 ) { prm = 0; } else if (prm > 100) { prm = 100; }
+ if(prm == 0) {
+ if(muted == true) {
+ muted = false;
+ sendChange("volume",config['volume']);
+ } else {
+ muted = true;
+ sendChange("volume",0);
+ }
+ } else {
+ sendChange("volume",prm);
+ config['volume'] = prm;
+ playerSO.data.volume = config["volume"];
+ playerSO.flush();
+ muted = false;
+ }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/PlaylistView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/PlaylistView.as
new file mode 100755
index 0000000..fe69a0a
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/PlaylistView.as
@@ -0,0 +1,239 @@
+/**
+* Playlist view management of the players MCV pattern.
+*
+* @author Jeroen Wijering
+* @version 1.9
+**/
+
+
+import com.jeroenwijering.players.*;
+import com.jeroenwijering.utils.*;
+import com.jeroenwijering.feeds.FeedListener;
+
+
+class com.jeroenwijering.players.PlaylistView extends AbstractView
+ implements FeedListener {
+
+
+ /** ImageLoader **/
+ private var thumbLoader:ImageLoader;
+ /** Scroller instance **/
+ private var listScroller:Scroller;
+ /** Position of the playlist **/
+ private var listRight:Boolean;
+ /** Position of the playlist **/
+ private var listWidth:Number;
+ /** number of items in the playlist **/
+ private var listLength:Number;
+ /** Currently highlighted playlist item **/
+ private var currentItem:Number;
+ /** Save the current time **/
+ private var currentTime:Number = -10;
+
+
+
+ /** Constructor **/
+ function PlaylistView(ctr:AbstractController,cfg:Object,fed:Object) {
+ super(ctr,cfg,fed);
+ if(config["displaywidth"] < config["width"]) {
+ listRight = true;
+ listWidth = config["width"]-config["displaywidth"]-1;
+ } else {
+ listRight = false;
+ listWidth = config["width"];
+ }
+ setButtons();
+ Stage.addListener(this);
+ feeder.addListener(this);
+ };
+
+
+ /** OnLoad event handler; sets up the playlist sizes and colors. **/
+ private function setButtons() {
+ var ref = this;
+ var tgt = config["clip"].playlist;
+ tgt.btn._visible = false;
+ // iterate playlist and setup each button
+ listLength = feeder.feed.length;
+ var num = 0;
+ for(var i=0; i"+(i+1)+":
"+
+ feeder.feed[i]["title"];
+ } else {
+ tgt["btn"+i].txt.htmlText = "" +
+ feeder.feed[i]["author"] + ":
" +
+ feeder.feed[i]["title"];
+ }
+ if(feeder.feed[i]["image"] != undefined) {
+ tgt["btn"+i].txt._x += 60;
+ tgt["btn"+i].txt._width -= 60;
+ thumbLoader =
+ new ImageLoader(tgt["btn"+i].img,"true",60,40);
+ thumbLoader.loadImage(feeder.feed[i]["image"]);
+ tgt["btn"+i].img.setMask(tgt["btn"+i].msk);
+ } else {
+ tgt["btn"+i].msk._height = 10;
+ tgt["btn"+i].img._visible = false;
+ tgt["btn"+i].msk._visible = false;
+ }
+ } else {
+ tgt["btn"+i]._y = num*23;
+ if(feeder.feed[i]["author"] == undefined) {
+ tgt["btn"+i].txt.htmlText = feeder.feed[i]["title"];
+ } else {
+ tgt["btn"+i].txt.htmlText = feeder.feed[i]["author"] +
+ " - " + feeder.feed[i]["title"];
+ }
+ tgt["btn"+i].msk._height = 10;
+ tgt["btn"+i].img._visible =
+ tgt["btn"+i].msk._visible = false;
+ }
+ tgt["btn"+i].txt.textColor = config["frontcolor"];
+ // set link icon
+ if(feeder.feed[i]["link"] != undefined) {
+ tgt["btn"+i].txt._width -= 20;
+ tgt["btn"+i].icn._x = listWidth - 24;
+ tgt["btn"+i].icn.onRollOver = function() {
+ this._parent.col2.setRGB(ref.config["lightcolor"]);
+ };
+ tgt["btn"+i].icn.onRollOut = function() {
+ if(ref.currentItem == this._parent.getDepth()) {
+ this._parent.col2.setRGB(ref.config["backcolor"]);
+ } else {
+ this._parent.col2.setRGB(ref.config["frontcolor"]);
+ }
+ };
+ tgt["btn"+i].icn.onRelease = function() {
+ ref.sendEvent("getlink",this._parent.getDepth());
+ };
+ } else {
+ tgt["btn"+i].icn._visible = false;
+ }
+ num++;
+ }
+ }
+ // setup mask and scrollbar if needed
+ var msk = config["clip"].playlistmask;
+ if(listRight == true) {
+ msk._x = tgt._x = Number(config["displaywidth"]) + 1;
+ msk._y = tgt._y = 0;
+ msk._height = config["displayheight"];
+ } else {
+ msk._y = tgt._y = Number(config["displayheight"]) +
+ Number(config["controlbar"]) - 1;
+ msk._height = Number(config["height"]) + 1 -
+ Number(config["controlbar"])-Number(config["displayheight"]);
+ }
+ msk._width = listWidth;
+ tgt.setMask(msk);
+ if(tgt._height > msk._height + 2 && feeder.feed.length > 1) {
+ if(config["autoscroll"] == "false") {
+ msk._width -= 10;
+ for(var i=0; i 5) {
+ currentTime = elp;
+ for (var i=0; i currentTime) {
+ if(i != currentItem+1) { setItem(i-1); }
+ break;
+ }
+ }
+ }
+ };
+
+
+ /** Hide the scrollbar on fullscreen **/
+ public function onFullScreen(fs:Boolean) {
+ if(listScroller == undefined) {
+ break;
+ } else if(fs == true) {
+ config["clip"].scrollbar._visible = false;
+ } else {
+ config["clip"].scrollbar._visible = true;
+ }
+ };
+
+
+ /** Render a new playlist when the feed updates **/
+ public function onFeedUpdate(typ:String) {
+ listScroller.purgeScrollbar();
+ delete listScroller;
+ var tgt = config["clip"].playlist;
+ for(var i=0; i<999; i++) {
+ tgt["btn"+i].removeMovieClip();
+ }
+ setButtons();
+ setItem(currentItem);
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/RecommendationsView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/RecommendationsView.as
new file mode 100644
index 0000000..eac7b81
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/RecommendationsView.as
@@ -0,0 +1,204 @@
+/**
+* Thumbnailbar with recommended videos.
+*
+* @author Jeroen Wijering
+* @version 1.0
+**/
+
+
+import com.jeroenwijering.utils.ImageLoader;
+import com.jeroenwijering.utils.Animations;
+import com.jeroenwijering.utils.XMLParser;
+import com.jeroenwijering.players.AbstractController;
+import com.jeroenwijering.players.AbstractView;
+
+
+class com.jeroenwijering.players.RecommendationsView extends AbstractView {
+
+
+ /** reference to config Array **/
+ private var config:Object;
+ /** reference to feed Array **/
+ private var feeder:Object;
+ /** Reference to the movieclip **/
+ private var clip:MovieClip;
+ /** XML parser reference **/
+ private var parser:XMLParser;
+ /** Recommendations array **/
+ private var recommendations:Array;
+ /** Current show offset **/
+ private var offset:Number = 0;
+ /** Number of thumbs maximum on screen **/
+ private var maximum:Number;
+
+
+
+ /** Constructor **/
+ function RecommendationsView(ctr:AbstractController,
+ cfg:Object,fed:Object) {
+ config = cfg;
+ feeder = fed;
+ clip = config["clip"].recommendations;
+ var ref = this;
+ parser = new XMLParser();
+ parser.onComplete = function() {
+ ref.loadRecommendations(this.output);
+ };
+ Stage.addListener(this);
+ setButtons();
+ };
+
+
+ /** Set the colors, clicks and dimensions of the buttons. **/
+ private function setButtons() {
+ var ref = this;
+ maximum = Math.floor((config['displaywidth']-44)/70);
+ clip._visible = false;
+ clip.txt._x = 10;
+ clip.txt._width = config['displaywidth'] -20;
+ clip.txt.textColor = config['backcolor'];
+ clip.prv._x = config['displaywidth']/2 - maximum*35;
+ clip.nxt._x = config['displaywidth']/2 + maximum*35;
+ clip.prv.col = new Color(clip.prv);
+ clip.prv.col.setRGB(config['backcolor']);
+ clip.prv.onRelease = function() {
+ this.col.setRGB(ref.config['backcolor']);
+ ref.showRecommendations(ref.offset - ref.maximum);
+ };
+ clip.prv._visible = false;
+ clip.nxt.col = new Color(clip.nxt);
+ clip.nxt.col.setRGB(config['backcolor']);
+ clip.nxt.onRelease = function() {
+ this.col.setRGB(ref.config['backcolor']);
+ ref.showRecommendations(ref.offset + ref.maximum);
+ };
+ clip.nxt._visible = false;
+ clip.itm._visible = false;
+ for(var i=0; i= recommendations.length-maximum ? clip.nxt._visible = false: clip.nxt._visible = true;
+ for(var i=0; i= config["height"]) {
+ config["height"] = config["displayheight"] = Stage.height;
+ config["width"] = config["displaywidth"] = Stage.width;
+ }
+ showRecommendations();
+ };
+
+
+ /** Catches fullscreen escape. **/
+ public function onFullScreen(fs:Boolean) {
+ showRecommendations();
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/RotatorController.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/RotatorController.as
new file mode 100755
index 0000000..b5cb4ab
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/RotatorController.as
@@ -0,0 +1,180 @@
+/**
+* Rotator extension of the controller.
+*
+* @author Jeroen Wijering
+* @version 1.6
+**/
+
+
+import com.jeroenwijering.players.AbstractController;
+import com.jeroenwijering.utils.Randomizer;
+
+
+class com.jeroenwijering.players.RotatorController extends AbstractController{
+
+
+ /** Which one of the models to send the changes to **/
+ private var currentModel:Number;
+ /** use SharedObject to save current file, item and volume **/
+ private var playerSO:SharedObject;
+
+
+ /** Constructor, inherited from super **/
+ function RotatorController(car:Object,ply:Object) {
+ super(car,ply);
+ playerSO = SharedObject.getLocal("com.jeroenwijerin.players", "/");
+ if(playerSO.data.volume != undefined && _root.volume == undefined) {
+ config["volume"] = playerSO.data.volume;
+ }
+ if(playerSO.data.useaudio != undefined &&
+ _root.useaudio == undefined) {
+ config["useaudio"] = playerSO.data.useaudio;
+ }
+ };
+
+
+ /** Complete the build of the MCV cycle and start flow of events. **/
+ public function startMCV(mar:Array) {
+ if(mar != undefined) { registeredModels = mar; }
+ itemsPlayed = 0;
+ if(config["shuffle"] == "true") {
+ randomizer = new Randomizer(feeder.feed);
+ currentItem = randomizer.pick();
+ } else {
+ currentItem = 0;
+ }
+ sendChange("item",currentItem);
+ if(config["autostart"] == "false") {
+ sendChange("start",0);
+ sendChange("pause",0);
+ isPlaying = false;
+ } else {
+ sendChange("start",0);
+ isPlaying = true;
+ }
+ };
+
+
+ /** PlayPause switch **/
+ private function setPlaypause() {
+ if(isPlaying == true) {
+ isPlaying = false;
+ sendChange("pause");
+ } else {
+ isPlaying = true;
+ sendChange("start");
+ }
+ };
+
+
+ /** Play previous item. **/
+ private function setPrev() {
+ if(currentItem == 0) {
+ setPlayitem(feeder.feed.length - 1);
+ } else {
+ setPlayitem(currentItem-1);
+ }
+ };
+
+
+ /** Play next item. **/
+ private function setNext() {
+ if(currentItem == feeder.feed.length - 1) {
+ setPlayitem(0);
+ } else {
+ setPlayitem(currentItem+1);
+ }
+ };
+
+
+ /** Stop and clear item. **/
+ private function setStop() {
+ sendChange("pause",0);
+ sendChange("stop");
+ sendChange("item",currentItem);
+ isPlaying = false;
+ };
+
+
+ /** Forward scrub number to model. **/
+ private function setScrub(prm) {
+ isPlaying == true ? sendChange("start",prm): sendChange("pause",prm);
+ };
+
+
+ /** Play a new item. **/
+ private function setPlayitem(itm:Number) {
+ if(itm != currentItem) {
+ sendChange("stop");
+ itm > feeder.feed.length-1 ? itm = feeder.feed.length-1: null;
+ currentItem = itm;
+ sendChange("item",itm);
+ }
+ if(feeder.feed[itm]["start"] == undefined) {
+ sendChange("start",0);
+ } else {
+ sendChange("start",feeder.feed[itm]["start"]);
+ }
+ currentURL = feeder.feed[itm]['file'];
+ isPlaying = true;
+ };
+
+
+ /** Get url from an item if link exists, else playpause. **/
+ private function setGetlink(idx:Number) {
+ if(feeder.feed[idx]["link"] == undefined) {
+ setPlaypause();
+ } else {
+ getURL(feeder.feed[idx]["link"],config["linktarget"]);
+ }
+ };
+
+
+ /** Determine what to do if an item is completed. **/
+ private function setComplete() {
+ itemsPlayed++;
+ if(config["repeat"]=="false" || (config["repeat"] == "list"
+ && itemsPlayed >= feeder.feed.length)) {
+ sendChange("pause",0);
+ isPlaying = false;
+ itemsPlayed = 0;
+ } else {
+ if(config["shuffle"] == "true") {
+ setPlayitem(randomizer.pick());
+ } else if(currentItem == feeder.feed.length - 1) {
+ setPlayitem(0);
+ } else {
+ setPlayitem(currentItem+1);
+ }
+ }
+ };
+
+
+ /** Audiotrack toggle **/
+ private function setAudio() {
+ if(config["useaudio"] == "true") {
+ config["useaudio"] = "false";
+ config["clip"].audio.setStop();
+ config["clip"].navigation.audioBtn.icnOff._visible = true;
+ config["clip"].navigation.audioBtn.icnOn._visible = false;
+ } else {
+ config["useaudio"] = "true";
+ config["clip"].audio.setStart();
+ config["clip"].navigation.audioBtn.icnOff._visible = false;
+ config["clip"].navigation.audioBtn.icnOn._visible = true;
+ }
+ playerSO.data.useaudio = config["useaudio"];
+ playerSO.flush();
+ };
+
+
+ /** Switch active model and send changes. **/
+ private function sendChange(typ:String,prm:Number):Void {
+ if(typ == "item") {
+ currentModel == 0 ? currentModel = 1: currentModel = 0;
+ }
+ registeredModels[currentModel].getChange(typ,prm);
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/RotatorView.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/RotatorView.as
new file mode 100755
index 0000000..6a8048a
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/players/RotatorView.as
@@ -0,0 +1,521 @@
+/**
+* Rotator user interface View of the MCV cycle.
+*
+* @author Jeroen Wijering
+* @version 1.5
+**/
+
+
+import com.jeroenwijering.players.*;
+import com.jeroenwijering.utils.ImageLoader;
+import com.jeroenwijering.utils.Animations;
+import flash.geom.Transform;
+import flash.geom.ColorTransform;
+
+class com.jeroenwijering.players.RotatorView extends AbstractView {
+
+
+ /** full width of the scrubbars **/
+ private var currentItem:Number;
+ /** clip that's currently active **/
+ private var upClip:MovieClip;
+ /** clip that's currently inactive **/
+ private var downClip:MovieClip;
+ /** boolean for whether to use the title display **/
+ private var useTitle:Boolean;
+ /** boolean to see if the transition is done **/
+ private var transitionDone:Boolean = false;
+ /** boolean to detect first run **/
+ private var firstRun:Boolean = true;
+ /** interval for hiding the display **/
+ private var hideInt:Number;
+ /** array with all transitions **/
+ private var allTransitions:Array = new Array(
+ "bgfade",
+ "blocks",
+ "bubbles",
+ "circles",
+ "fade",
+ "flash",
+ "fluids",
+ "lines",
+ "slowfade"
+ );
+
+
+ /** Constructor **/
+ function RotatorView(ctr:AbstractController,cfg:Object,fed:Object) {
+ super(ctr,cfg,fed);
+ setColorsClicks();
+ if(config["shownavigation"] == "true") {
+ Mouse.addListener(this);
+ }
+ };
+
+
+ /** Sets up visibility, sizes and colors of all display items **/
+ private function setColorsClicks() {
+ var ref = this;
+ var tgt:MovieClip = config["clip"];
+ tgt.button._width = config["width"];
+ tgt.button._height = config["height"];
+ if(config['overstretch']=='true' || config['overstretch']=='fit') {
+ tgt.img1.bg._visible = tgt.img2.bg._visible = false;
+ } else {
+ tgt.img1.bg._width = tgt.img2.bg._width = config["width"];
+ tgt.img1.bg._height = tgt.img2.bg._height = config["height"];
+ tgt.img1.col = new Color(tgt.img1.bg);
+ tgt.img1.col.setRGB(config["screencolor"]);
+ tgt.img2.col = new Color(tgt.img2.bg);
+ tgt.img2.col.setRGB(config["screencolor"]);
+ }
+ if(config["linkfromdisplay"] == "true") {
+ tgt.button.onRelease = function() {
+ ref.sendEvent("getlink",ref.currentItem);
+ };
+ tgt.playicon._visible = false;
+ } else {
+ tgt.button.onRelease = function() {
+ ref.sendEvent("next");
+ };
+ }
+ tgt.img1.swapDepths(1);
+ tgt.img2.swapDepths(2);
+ tgt.playicon.swapDepths(4);
+ tgt.activity.swapDepths(5);
+ tgt.navigation.swapDepths(6);
+ tgt.logo.swapDepths(7);
+ tgt.playicon._x=tgt.activity._x = Math.round(config["width"]/2);
+ tgt.playicon._y=tgt.activity._y = Math.round(config["height"]/2);
+ if(config["logo"] != undefined) {
+ var lll = new ImageLoader(tgt.logo,"none");
+ lll.onLoadFinished = function() {
+ ref.config['clip'].logo._x = ref.config["displaywidth"] -
+ ref.config['clip'].logo._width -10;
+ ref.config['clip'].logo._y = 10;
+ };
+ lll.loadImage(config["logo"]);
+ tgt.logo.onRelease = function() {
+ ref.sendEvent("getlink",ref.currentItem);
+ };
+ }
+ tgt = config["clip"].navigation;
+ if (config["shownavigation"] == "true") {
+ tgt._y = config["height"] - 40;
+ tgt._x = config["width"]/2 - 50;
+ tgt.prevBtn.col1 = new Color(tgt.prevBtn.bck);
+ tgt.prevBtn.col1.setRGB(config["backcolor"]);
+ tgt.prevBtn.col2 = new Color(tgt.prevBtn.icn);
+ tgt.prevBtn.col2.setRGB(config["frontcolor"]);
+ tgt.itmBtn.col1 = new Color(tgt.itmBtn.bck);
+ tgt.itmBtn.col1.setRGB(config["backcolor"]);
+ tgt.itmBtn.txt.textColor = config["frontcolor"];
+ tgt.nextBtn.col1 = new Color(tgt.nextBtn.bck);
+ tgt.nextBtn.col1.setRGB(config["backcolor"]);
+ tgt.nextBtn.col2 = new Color(tgt.nextBtn.icn);
+ tgt.nextBtn.col2.setRGB(config["frontcolor"]);
+ tgt.prevBtn.onRollOver = tgt.nextBtn.onRollOver = function() {
+ this.col2.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.prevBtn.onRollOut = tgt.nextBtn.onRollOut = function() {
+ this.col2.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.itmBtn.onRollOver = function() {
+ this.txt.textColor = ref.config["lightcolor"];
+ };
+ tgt.itmBtn.onRollOut = function() {
+ this.txt.textColor = ref.config["frontcolor"];
+ };
+ tgt.prevBtn.onRelease = function() {
+ ref.sendEvent("prev");
+ this.col2.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.itmBtn.onRelease = function() { ref.sendEvent("playpause"); };
+ tgt.nextBtn.onRelease = function() {
+ ref.sendEvent("next");
+ this.col2.setRGB(ref.config["frontcolor"]);
+ };
+ // set sizes, colors and buttons for image title
+ var len = 0;
+ for(var i=0; i len) {
+ len = feeder.feed[i]['title'].length;
+ }
+ }
+ if(len == 0) {
+ useTitle = false;
+ tgt.titleBtn._visible = false;
+ } else {
+ useTitle = true;
+ tgt.titleBtn._x = 74;
+ tgt.titleBtn.col1 = new Color(tgt.titleBtn.left);
+ tgt.titleBtn.col1.setRGB(config["backcolor"]);
+ tgt.titleBtn.col2 = new Color(tgt.titleBtn.mid);
+ tgt.titleBtn.col2.setRGB(config["backcolor"]);
+ tgt.titleBtn.col3 = new Color(tgt.titleBtn.right);
+ tgt.titleBtn.col3.setRGB(config["backcolor"]);
+ tgt.titleBtn.tf._width = len*6;
+ tgt.titleBtn.tf.textColor = config["frontcolor"];
+ if(feeder.feed[0]["link"] != undefined) {
+ tgt.titleBtn.onRollOver = function() {
+ this.tf.textColor = ref.config["lightcolor"];
+ };
+ tgt.titleBtn.onRollOut = function() {
+ this.tf.textColor = ref.config["frontcolor"];
+ };
+ tgt.titleBtn.onRelease = function() {
+ ref.sendEvent("getlink",ref.currentItem);
+ };
+ };
+ tgt.titleBtn.mid._width = len*6;
+ tgt.titleBtn.right._x = len*6+4;
+ tgt.nextBtn._x = len*6 + 79;
+ }
+ if(feeder.audio == true) {
+ tgt.audioBtn.col1 = new Color(tgt.audioBtn.bck);
+ tgt.audioBtn.col2 = new Color(tgt.audioBtn.icnOn);
+ tgt.audioBtn.col3 = new Color(tgt.audioBtn.icnOff);
+ tgt.audioBtn.col1.setRGB(config["backcolor"]);
+ tgt.audioBtn.col2.setRGB(config["frontcolor"]);
+ tgt.audioBtn.col3.setRGB(config["frontcolor"]);
+ tgt.audioBtn.onRollOver = function() {
+ this.col2.setRGB(ref.config["lightcolor"]);
+ this.col3.setRGB(ref.config["lightcolor"]);
+ };
+ tgt.audioBtn.onRollOut = function() {
+ this.col2.setRGB(ref.config["frontcolor"]);
+ this.col3.setRGB(ref.config["frontcolor"]);
+ };
+ tgt.audioBtn.onRelease = function() {
+ ref.sendEvent("audio");
+ this.col2.setRGB(ref.config["frontcolor"]);
+ this.col3.setRGB(ref.config["frontcolor"]);
+ };
+ if(config['useaudio'] == "true") {
+ tgt.audioBtn.icnOff._visible = false;
+ } else {
+ tgt.audioBtn.icnOn._visible = false;
+ }
+ tgt.audioBtn._x = len*6 + 104;
+ } else {
+ tgt.audioBtn._x = 0;
+ tgt.audioBtn._visible = false;
+ }
+ tgt._x = Math.round(config["width"]/2 - tgt._width/2);
+ } else {
+ tgt._visible = false;
+ }
+ };
+
+
+ /** New item: switch clips and ready transition **/
+ private function setItem(pr1) {
+ currentItem = pr1;
+ transitionDone = false;
+ var tgt = config["clip"];
+ tgt.navigation.itmBtn.txt.text = (currentItem+1) + " / " +
+ feeder.feed.length;
+ if (useTitle == true) {
+ tgt.navigation.titleBtn.tf.text=feeder.feed[currentItem]["title"];
+ }
+ tgt.img1.swapDepths(tgt.img2);
+ downClip = upClip;
+ if (upClip == tgt.img1) {
+ upClip = tgt.img2;
+ } else {
+ upClip = tgt.img1;
+ }
+ };
+
+
+ /** State switch; start the transition **/
+ private function setState(stt:Number) {
+ switch(stt) {
+ case 0:
+ if(config["showicons"] == "true") {
+ config["clip"].playicon._visible = true;
+ }
+ config["clip"].activity._visible = false;
+ break;
+ case 1:
+ config["clip"].playicon._visible = false;
+ if(config["showicons"] == "true") {
+ config["clip"].activity._visible = true;
+ }
+ break;
+ case 2:
+ config["clip"].playicon._visible = false;
+ config["clip"].activity._visible = false;
+ if(transitionDone == false) {
+ doTransition();
+ if(config["kenburns"] == "true") {
+ moveClip();
+ }
+ }
+ break;
+ }
+ };
+
+
+ /** (Re)set the ken burns fade **/
+ private function moveClip() {
+ var dir = random(4);
+ var clp = upClip.smc;
+ if(upClip.smc == undefined) { clp = upClip.mc; }
+ clp._xscale *= config['rotatetime']/20 + 1;
+ clp._yscale *= config['rotatetime']/20 + 1;
+ if(dir == 0) {
+ clp._x = 0;
+ } else if (dir == 1) {
+ clp._y = 0;
+ } else if (dir == 2) {
+ clp._x = config['width'] - upClip._width;
+ } else {
+ clp._y = config['height'] - upClip._height;
+ }
+ clp.onEnterFrame = function() {
+ if(dir == 0) {
+ this._x -= 0.3;
+ } else if (dir == 1) {
+ this._y -= 0.3;
+ } else if (dir == 2) {
+ this._x += 0.3;
+ } else {
+ this._y += 0.3;
+ }
+ };
+ };
+
+
+ /** Start a transition **/
+ private function doTransition() {
+ transitionDone = true;
+ if(firstRun == true) {
+ config["clip"].img1._alpha = 100;
+ config["clip"].img2._alpha = 0;
+ firstRun = false;
+ } else {
+ var trs = config["transition"];
+ if(trs == "random") {
+ trs = allTransitions[random(allTransitions.length)];
+ }
+ switch (trs) {
+ case "bgfade":
+ doBGFade();
+ break;
+ case "blocks":
+ doBlocks();
+ break;
+ case "bubbles":
+ doBubbles();
+ break;
+ case "circles":
+ doCircles();
+ break;
+ case "fade":
+ doFade();
+ break;
+ case "flash":
+ doFlash();
+ break;
+ case "fluids":
+ doFluids();
+ break;
+ case "lines":
+ doLines();
+ break;
+ case "slowfade":
+ doSlowfade();
+ break;
+ default:
+ doFade();
+ break;
+ }
+ }
+ };
+
+
+ /** Function for the fade transition **/
+ private function doFade() {
+ upClip.ref = this;
+ upClip._alpha = 0;
+ upClip.onEnterFrame = function() {
+ this._alpha +=5;
+ if(this._alpha >= 100) {
+ delete this.onEnterFrame;
+ this.ref.downClip._alpha = 0;
+ }
+ };
+ };
+
+
+ /** Function for the bgfade transition **/
+ private function doBGFade() {
+ downClip.ref = upClip.ref = this;
+ downClip.onEnterFrame = function() {
+ this._alpha -=5;
+ if(this._alpha <= 0) {
+ delete this.onEnterFrame;
+ this.ref.upClip.onEnterFrame = function() {
+ if(this._alpha >= 100) {
+ delete this.onEnterFrame;
+ } else {
+ this._alpha +=5;
+ }
+ };
+ }
+ };
+ };
+
+
+ /** Function for the blocks transition **/
+ private function doBlocks() {
+ upClip._alpha = 100;
+ config["clip"].attachMovie("blocksMask","mask",3);
+ var msk:MovieClip = config["clip"].mask;
+ if (config["width"] > config["height"]) {
+ msk._width = msk._height = config["width"];
+ } else {
+ msk._width = msk._height = config["height"];
+ }
+ msk._rotation = random(4)*90;
+ msk._rotation == 90 ? msk._x = config["width"]: null;
+ msk._rotation == 180 ? msk._x = config["width"]: null;
+ msk._rotation == 180 ? msk._y = config["height"]: null;
+ msk._rotation == -90 ? msk._y = config["height"]: null;
+ upClip.setMask(msk);
+ playClip(msk);
+ };
+
+
+ /** Function for the bubbles transition **/
+ private function doBubbles() {
+ upClip._alpha = 100;
+ config["clip"].attachMovie("bubblesMask","mask",3);
+ var msk:MovieClip = config["clip"].mask;
+ upClip.setMask(msk);
+ if (config["width"] > config["height"]) {
+ msk._width = msk._height = config["width"];
+ msk._y = config["height"]/2 - msk._height/2;
+ } else {
+ msk._width = msk._height = config["height"];
+ msk._x = config["width"]/2- msk._width/2;
+ }
+ if(random(2) == 1) {
+ msk._xscale = -msk._xscale;
+ msk._x += config['width'];
+ }
+ playClip(msk);
+ };
+
+
+ /** Function for the circles transition **/
+ private function doCircles() {
+ upClip._alpha = 100;
+ config["clip"].attachMovie("circlesMask","mask",3);
+ var msk:MovieClip = config["clip"].mask;
+ upClip.setMask(msk);
+ if (config["width"] > config["height"]) {
+ msk._width = msk._height = config["width"];
+ } else {
+ msk._width = msk._height = config["height"];
+ }
+ msk._x = config["width"]/2;
+ msk._y = config["height"]/2;
+ playClip(msk,10);
+ };
+
+
+ /** Function for the flash transition **/
+ private function doFlash() {
+ upClip._alpha = 100;
+ upClip.col = new Color(upClip);
+ upClip.ctf = new Object({rb:255,gb:255,bb:255});
+ upClip.col.setTransform(upClip.ctf);
+ upClip.onEnterFrame = function() {
+ if(this.ctf.rb < 1) {
+ this.ctf = new Object({rb:0,gb:0,bb:0});
+ this.col.setTransform(this.ctf);
+ delete this.onEnterFrame;
+ } else {
+ this.ctf.rb /= 1.05;
+ this.ctf.gb /= 1.05;
+ this.ctf.bb /= 1.05;
+ this.col.setTransform(this.ctf);
+ }
+ };
+ };
+
+ /** Function for the fluids transition **/
+ private function doFluids() {
+ upClip._alpha = 100;
+ config["clip"].attachMovie("fluidsMask","mask",3);
+ var msk:MovieClip = config["clip"].mask;
+ upClip.setMask(msk);
+ msk._width = config["width"];
+ msk._height = config["height"];
+ playClip(msk);
+ };
+
+
+ /** Function for the lines transition **/
+ private function doLines() {
+ upClip._alpha = 100;
+ config["clip"].attachMovie("linesMask","mask",3);
+ var msk:MovieClip = config["clip"].mask;
+ upClip.setMask(msk);
+ msk._width = config["width"];
+ msk._height = config["height"];
+ playClip(msk);
+ };
+
+
+ /** Function for the fade transition **/
+ private function doSlowfade() {
+ upClip.ref = this;
+ upClip._alpha = 0;
+ upClip.onEnterFrame = function() {
+ this._alpha+=2;
+ if(this._alpha >= 100) {
+ delete this.onEnterFrame;
+ this.ref.downClip._alpha = 0;
+ }
+ };
+ };
+
+
+ /** Play a specific Movieclip and remove it once it's finished **/
+ private function playClip(tgt:MovieClip,rot:Number) {
+ tgt.ref = this;
+ tgt.onEnterFrame = function() {
+ this.nextFrame();
+ rot == undefined ? null: this._rotation +=rot;
+ if(this._currentframe == this._totalframes) {
+ this.ref.downClip._alpha = 0;
+ this.clear();
+ this.unloadMovie();
+ this.removeMovieClip();
+ }
+ };
+ };
+
+
+ /** after a delay, the controlbar is hidden **/
+ private function hideBar() {
+ Animations.fadeOut(config['clip'].navigation);
+ clearInterval(hideInt);
+ }
+
+
+ /** Mouse move shows controlbar **/
+ public function onMouseMove() {
+ Animations.fadeIn(config['clip'].navigation);
+ clearInterval(hideInt);
+ if(!config["clip"].navigation.hitTest(_root._xmouse,_root._ymouse)) {
+ hideInt = setInterval(this,"hideBar",500);
+ }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/Animations.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/Animations.as
new file mode 100755
index 0000000..eb832e2
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/Animations.as
@@ -0,0 +1,134 @@
+/**
+* A couple of commonly used animation functions.
+*
+* @author Jeroen Wijering
+* @version 1.12
+**/
+
+
+class com.jeroenwijering.utils.Animations {
+
+
+ /**
+ * Fadein function for MovieClip.
+ *
+ * @param tgt The Movieclip to fade in.
+ * @param end The final alpha value.
+ * @param spd The amount of alpha change per frame.
+ **/
+ public static function fadeIn(tgt:MovieClip,end:Number,spd:Number) {
+ arguments.length < 3 ? spd = 20: null;
+ arguments.length < 2 ? end = 100: null;
+ tgt._visible = true;
+ tgt.onEnterFrame = function() {
+ if(this._alpha > end-spd) {
+ delete this.onEnterFrame;
+ this._alpha = end;
+ } else {
+ this._alpha += spd;
+ }
+ };
+ };
+
+
+ /**
+ * Fadeout function for MovieClip.
+ *
+ * @param tgt The Movieclip to fade out.
+ * @param end The final alpha value.
+ * @param spd The amount of alpha change per frame.
+ * @param rmv Removing the clip off stage switch.
+ **/
+ public static function fadeOut(tgt:MovieClip,end:Number,
+ spd:Number,rmv:Boolean) {
+ arguments.length < 4 ? rmv = false: null;
+ arguments.length < 3 ? spd = 20: null;
+ arguments.length < 2 ? end = 0: null;
+ tgt.onEnterFrame = function() {
+ if(this._alpha < end+spd) {
+ delete this.onEnterFrame;
+ this._alpha = end;
+ end == 0 ? this._visible = false: null;
+ rmv == true ? this.removeMovieClip(): null;
+ } else {
+ this._alpha -= spd;
+ }
+ };
+ };
+
+
+ /**
+ * Crossfade a given MovieClip through 0.
+ *
+ * @param tgt The Movieclip to crossfade.
+ * @param alp The final alpha value.
+ **/
+ public static function crossfade(tgt:MovieClip, alp:Number) {
+ var phs = "out";
+ var pct = alp/5;
+ tgt.onEnterFrame = function() {
+ if(phs == "out") {
+ this._alpha -= pct;
+ if (this._alpha < 1) { phs = "in"; }
+ } else {
+ this._alpha += pct;
+ this._alpha >= alp ? delete this.onEnterFrame : null;
+ }
+ };
+ };
+
+
+ /**
+ * Smoothly move a Movielip to a certain position.
+ *
+ * @param tgt The Movielip to move.
+ * @param xps The x destination.
+ * @param yps The y destination.
+ * @param spd The movement speed (1 - 2).
+ **/
+ public static function easeTo(tgt:MovieClip,xps:Number,yps:Number,
+ spd:Number) {
+ arguments.length < 4 ? spd = 1.3: null;
+ tgt.onEnterFrame = function() {
+ this._x = xps-(xps-this._x)/(1+1/spd);
+ this._y = yps-(yps-this._y)/(1+1/spd);
+ if (this._x>xps-1 && this._xyps-1 && this._y 1) {
+ config['width'] = Stage.width;
+ config['height'] = Stage.height;
+ config["clip"]._parent.activity._x = Stage.width/2;
+ config["clip"]._parent.activity._y = Stage.height/2;
+ config["clip"]._parent.activity._alpha = 100;
+ }
+ _root['config'] == undefined ? loadCookies(): loadFile();
+ };
+
+
+ /** Load configuration data from external XML file **/
+ private function loadFile() {
+ var ref = this;
+ parser = new XMLParser();
+ parser.onComplete = function(obj) {
+ var ret = new Object();
+ for(var i=0; i 1 ? overStretch = String(ost): null;
+ if(arguments.length > 2) {
+ targetWidth = wid;
+ targetHeight = hei;
+ }
+ mcLoader = new MovieClipLoader();
+ mcLoader.addListener(this);
+ };
+
+
+ /** Switch image with bitmaparray if possible. **/
+ public function onLoadInit(inTarget:MovieClip):Void {
+ if(useSmoothing == 'true') {
+ var bmp = new flash.display.BitmapData(targetClip.mc._width,
+ targetClip.mc._height, true, 0x000000);
+ bmp.draw(targetClip.mc);
+ var bmc:MovieClip = targetClip.createEmptyMovieClip("smc",
+ targetClip.getNextHighestDepth());
+ bmc.attachBitmap(bmp, bmc.getNextHighestDepth(),"auto",true);
+ targetClip.mc.unloadMovie();
+ targetClip.mc.removeMovieClip();
+ delete targetClip.mc;
+ scaleImage(targetClip.smc);
+ onLoadFinished();
+ } else {
+ targetClip.mc.forceSmoothing = true;
+ if(sourceURL.toLowerCase().indexOf(".swf") == -1) {
+ scaleImage(targetClip.mc);
+ }
+ onLoadFinished();
+ }
+ };
+
+
+ /** Scale the image while maintaining aspectratio **/
+ private function scaleImage(tgt:MovieClip):Void {
+ targetClip._xscale = targetClip._yscale = 100;
+ var tcf = tgt._currentframe;
+ tgt.gotoAndStop(1);
+ sourceWidth = tgt._width;
+ sourceHeight = tgt._height;
+ sourceLength = tgt._totalframes/20;
+ var xsr = targetWidth/sourceWidth;
+ var ysr = targetHeight/sourceHeight;
+ if (overStretch == "fit" || Math.abs(xsr-ysr) < 0.1) {
+ tgt._width = targetWidth;
+ tgt._height = targetHeight;
+ } else if ((overStretch == "true" && xsr > ysr) ||
+ (overStretch == "false" && xsr < ysr)) {
+ tgt._xscale = tgt._yscale = xsr*100;
+ } else if(overStretch == "none") {
+ tgt._xscale = tgt._yscale = 100;
+ } else {
+ tgt._xscale = tgt._yscale = ysr*100;
+ }
+ if(targetWidth != undefined) {
+ tgt._x = targetWidth/2 - tgt._width/2;
+ tgt._y = targetHeight/2 - tgt._height/2;
+ }
+ tgt.gotoAndPlay(tcf);
+ onMetaData();
+ };
+
+
+ /** Start loading an image. **/
+ public function loadImage(img:String):Void {
+ sourceURL = img;
+ targetClip.mc.clear();
+ targetClip.smc.unloadMovie();
+ targetClip.smc.removeMovieClip();
+ delete targetClip.smc;
+ checkSmoothing(img);
+ var raw:MovieClip = targetClip.createEmptyMovieClip("mc",1);
+ mcLoader.loadClip(img,raw);
+ if(img.toLowerCase().indexOf(".swf") > -1) {
+ metaInt = setInterval(this,"setSWFMeta",200);
+ }
+ };
+
+
+ /** Check whether smoothing can be enabled. **/
+ private function checkSmoothing(img:String):Void {
+ var idx:Number = _root._url.indexOf("/",8);
+ var rot:String = _root._url.substring(0,idx);
+ if(System.capabilities.version.indexOf("7,0,") > -1 ||
+ img.toLowerCase().indexOf(".swf") > -1 ||
+ _root._url.indexOf("file://") > -1 ||
+ (img.indexOf(rot) == -1 && img.indexOf('http://') == 0)) {
+ useSmoothing = false;
+ } else {
+ useSmoothing = true;
+ }
+ };
+
+
+ /** Check when to set the SWF metadata **/
+ private function setSWFMeta() {
+ if(targetClip.mc._currentframe > 0) {
+ clearInterval(metaInt);
+ scaleImage(targetClip.mc);
+ }
+ };
+
+
+ /** Event handler; invoked when loading. **/
+ public function onLoadProgress(tgt:MovieClip,btl:Number,btt:Number) {};
+
+
+ /** Event handler; invoked when image is completely loaded. **/
+ public function onLoadFinished() {};
+
+
+ /** Event handler; invoked when metadata is received. **/
+ public function onMetaData() {};
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/Randomizer.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/Randomizer.as
new file mode 100755
index 0000000..a8446aa
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/Randomizer.as
@@ -0,0 +1,43 @@
+/**
+* Pick random array indexes without having the same picked twice times.
+*
+* @author Jeroen Wijering
+* @version 1.2
+**/
+
+
+class com.jeroenwijering.utils.Randomizer {
+
+
+ /** a reference of the original array **/
+ private var originalArray:Array;
+ /** a copy of the original array **/
+ private var bufferArray:Array;
+
+
+ /**
+ * Constructor.
+ *
+ * @param arr Array to randomize.
+ **/
+ public function Randomizer(arr:Array) {
+ originalArray = arr;
+ bufferArray = new Array();
+ };
+
+
+ /** Randomly pick an index from the array given. **/
+ public function pick():Number {
+ if(bufferArray.length == 0) {
+ for(var k=0; k 2 ? autoScroll = asc: null;
+ arguments.length > 3 ? frontColor = fcl: null;
+ arguments.length > 4 ? lightColor = hcl: null;
+ sizeRatio = maskClip._height/targetClip._height;
+ if(autoScroll == false) {
+ drawScrollbar();
+ } else {
+ scrollInterval = setInterval(this,"doAutoscroll",50);
+ }
+ if(System.capabilities.os.toLowerCase().indexOf("mac") == -1) {
+ Mouse.addListener(this);
+ }
+ };
+
+
+ /** Draw the scrollbar. **/
+ private function drawScrollbar() {
+ targetClip._parent.createEmptyMovieClip("scrollbar",
+ targetClip._parent.getNextHighestDepth());
+ SCROLLER_CLIP = targetClip._parent.scrollbar;
+ SCROLLER_CLIP._x = maskClip._x+maskClip._width - 1;
+ SCROLLER_CLIP._y = maskClip._y+3;
+ SCROLLER_CLIP.createEmptyMovieClip("back",0);
+ SCROLLER_CLIP.back._alpha = 0;
+ SCROLLER_CLIP.back._y = -3;
+ drawSquare(SCROLLER_CLIP.back,12,maskClip._height,frontColor);
+ SCROLLER_CLIP.createEmptyMovieClip("bar",1);
+ SCROLLER_CLIP.bar._x = 4;
+ SCROLLER_CLIP.bar._alpha = 50;
+ drawSquare(SCROLLER_CLIP.bar,4,maskClip._height-5,frontColor);
+ SCROLLER_CLIP.createEmptyMovieClip("front",2);
+ SCROLLER_CLIP.front._x = 3;
+ drawSquare(SCROLLER_CLIP.front,6,
+ SCROLLER_CLIP.bar._height*sizeRatio,frontColor);
+ SCROLLER_CLIP.front.createEmptyMovieClip("bg",1);
+ SCROLLER_CLIP.front.bg._x = -3;
+ SCROLLER_CLIP.front.bg._alpha = 0;
+ drawSquare(SCROLLER_CLIP.front.bg,12,
+ SCROLLER_CLIP.front._height,frontColor);
+ SCROLLER_FRONT_COLOR = new Color(SCROLLER_CLIP.front);
+ setScrollbarEvents();
+ };
+
+
+ /** Set use of mousewheel to scroll playlist. **/
+ public function onMouseWheel(dta:Number) {
+ scrollTo(currentScroll-dta*20);
+ };
+
+
+ /** Set autoscroll events. **/
+ private function doAutoscroll() {
+ if (maskClip._xmouse>0 && maskClip._xmouse0 &&
+ maskClip._ymouse this._parent.front._y +
+ this._parent.front._height) {
+ instance.scrollTo(instance.currentScroll +
+ instance.maskClip._height/2);
+ } else if (this._ymouse < this._parent.front._y) {
+ instance.scrollTo(instance.currentScroll -
+ instance.maskClip._height/2);
+ }
+ };
+ SCROLLER_CLIP.front.onPress = function() {
+ this.startDrag(false,3,0,3,instance.SCROLLER_CLIP.bar._height -
+ this._height);
+ instance.scrollInterval = setInterval(instance,"scrollTo",100);
+ };
+ SCROLLER_CLIP.front.onRelease =
+ SCROLLER_CLIP.front.onReleaseOutside = function() {
+ this.stopDrag();
+ clearInterval(instance.scrollInterval);
+ };
+ scrollTo(maskClip._y - targetClip._y);
+ };
+
+
+ /** Scroll the MovieClip to a given Y position. **/
+ public function scrollTo(yps:Number):Void {
+ if(arguments.length == 0 && autoScroll == false) {
+ yps = SCROLLER_CLIP.front._y*maskClip._height /
+ SCROLLER_CLIP.front._height;
+ }
+ if(yps<5) {
+ yps=0;
+ } else if (yps>targetClip._height-maskClip._height-5) {
+ yps = targetClip._height - maskClip._height;
+ }
+ Animations.easeTo(targetClip,targetClip._x,maskClip._y - yps);
+ SCROLLER_CLIP.front._y = yps*SCROLLER_CLIP.front._height /
+ maskClip._height;
+ currentScroll = yps;
+ };
+
+
+ /** Remove the scrollbar from stage **/
+ public function purgeScrollbar() {
+ clearInterval(scrollInterval);
+ Mouse.removeListener(this);
+ scrollTo(0);
+ SCROLLER_CLIP.removeMovieClip();
+ };
+
+
+ /** Draw a square in a given movieclip. **/
+ private function drawSquare(tgt:MovieClip,wth:Number,hei:Number,
+ clr:Number) {
+ tgt.clear();
+ tgt.beginFill(clr,100);
+ tgt.moveTo(0,0);
+ tgt.lineTo(wth,0);
+ tgt.lineTo(wth,hei);
+ tgt.lineTo(0,hei);
+ tgt.lineTo(0,0);
+ tgt.endFill();
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/StringMagic.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/StringMagic.as
new file mode 100755
index 0000000..29221ee
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/StringMagic.as
@@ -0,0 +1,92 @@
+/**
+* A couple of commonly used string operations.
+*
+* @author Jeroen Wijering
+* @version 1.3
+**/
+
+
+class com.jeroenwijering.utils.StringMagic {
+
+
+ /** Strip tags and breaks from a string. **/
+ static function stripTagsBreaks(str:String):String {
+ if(str.length == 0 || str == undefined) { return ""; }
+ var tmp:Array = str.split("\n");
+ str = tmp.join("");
+ tmp = str.split("\r");
+ str = tmp.join("");
+ var i:Number = str.indexOf("<");
+ while(i != -1) {
+ var j = str.indexOf(">",i+1);
+ j == -1 ? j = str.length-1: null;
+ str = str.substr(0,i) + str.substr(j+1,str.length);
+ i = str.indexOf("<",i);
+ }
+ return str;
+ };
+
+
+ /**
+ * Chop string into a number of lines.
+ *
+ * @param str The string to chop.
+ * @param cap The maximum number of characters per line.
+ * @param nbr The maximum number of lines.
+ **/
+ static function chopString(str:String,cap:Number,nbr:Number):String {
+ for(var i=cap; i 0) {
+ str = str.substr(0,str.indexOf(" ",i-3)) + "\n" +
+ str.substr(str.indexOf(" ",i-3)+1);
+ }
+ }
+ return str;
+ };
+
+
+ /** Add a leading zero and convert number to string. **/
+ static function addLeading(nbr:Number):String {
+ if(nbr < 10) {
+ return "0"+Math.floor(nbr);
+ } else {
+ return Math.floor(nbr).toString();
+ }
+ };
+
+
+ /**
+ * Convert a string to seconds, with these formats supported:
+ * 00:03:00.1 / 03:00.1 / 180.1s / 3.2m / 3.2h
+ **/
+ static function toSeconds(str:String):Number {
+ var arr = str.split(':');
+ var sec;
+ if (str.substr(-1) == 's') {
+ sec = Number(str.substr(0,str.length-2));
+ } else if (str.substr(-1) == 'm') {
+ sec = Number(str.substr(0,str.length-2))*60;
+ } else if(str.substr(-1) == 'h') {
+ sec = Number(str.substr(0,str.length-2))*3600;
+ } else if(arr.length > 1) {
+ sec = Number(arr[arr.length-1]);
+ sec += Number(arr[arr.length-2])*60;
+ sec += Number(arr[arr.length-3])*3600;
+ } else {
+ sec = Number(str);
+ }
+ if(isNaN(sec)) {
+ return 0;
+ } else {
+ return sec;
+ }
+ };
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/XMLParser.as b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/XMLParser.as
new file mode 100755
index 0000000..e87fba1
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/com/jeroenwijering/utils/XMLParser.as
@@ -0,0 +1,84 @@
+/**
+* Parse XML file and return a simple, associative array.
+*
+* @author Jeroen Wijering
+* @version 1.2
+**/
+
+
+class com.jeroenwijering.utils.XMLParser {
+
+
+ /** Flash XML object the file is loaded into. **/
+ private var input:XML;
+ /** The object the XML is parsed into **/
+ private var output:Object;
+
+
+ /** Constructor, sets up XML object **/
+ function XMLParser() {};
+
+
+ /** Start parsing **/
+ public function parse(lnk:String) {
+ var ref = this;
+ input = new XML();
+ output = new Object();
+ input.ignoreWhite = true;
+ input.onLoad = function(scs:Boolean) {
+ if(scs) {
+ ref.processRoot();
+ } else {
+ ref.onError();
+ }
+ };
+ if(_root._url.indexOf("file://") > -1) {
+ input.load(lnk);
+ } else if(lnk.indexOf('?') > -1) {
+ input.load(lnk+'&'+random(999));
+ } else {
+ input.load(lnk+'?'+random(999));
+ }
+ };
+
+
+ /** Process the root XML node **/
+ private function processRoot() {
+ processNode(input.firstChild,output);
+ delete input;
+ onComplete(output);
+ };
+
+
+ /** Process a specific node **/
+ private function processNode(nod:XMLNode,obj:Object) {
+ obj['name'] = nod.nodeName;
+ for(var att in nod.attributes) {
+ obj[att] = nod.attributes[att];
+ }
+ if(nod.childNodes.length < 2 && nod.firstChild.nodeName == null) {
+ obj['value'] = nod.firstChild.nodeValue;
+ } else {
+ obj['childs'] = new Array();
+ var chn = nod.firstChild;
+ var i = 0;
+ while(chn != undefined) {
+ var cob = new Object();
+ processNode(chn,cob);
+ obj['childs'].push(cob);
+ chn = chn.nextSibling;
+ i++;
+ }
+ }
+ };
+
+
+ /** Invoked when parsing is completed. **/
+ public function onComplete(obj:Object) {};
+
+
+ /** Invoked when parsing is completed. **/
+ public function onError() {};
+
+
+}
\ No newline at end of file
diff --git a/static/contrib/mediaplayer-3.15/source/mediaplayer.fla b/static/contrib/mediaplayer-3.15/source/mediaplayer.fla
new file mode 100755
index 0000000..9b5c9af
Binary files /dev/null and b/static/contrib/mediaplayer-3.15/source/mediaplayer.fla differ
diff --git a/static/contrib/mediaplayer-3.15/source/mediaplayer.pdf b/static/contrib/mediaplayer-3.15/source/mediaplayer.pdf
new file mode 100644
index 0000000..34a1f44
--- /dev/null
+++ b/static/contrib/mediaplayer-3.15/source/mediaplayer.pdf
@@ -0,0 +1,1679 @@
+%PDF-1.4
%
+1 0 obj
<>
endobj
1129 0 obj
<>stream
+
+
+
+
+ 2006-07-12T13:07:58Z
+ 2008-01-11T16:36:17+01:00
+ Adobe Illustrator CS3
+ 2008-01-11T16:36:17+01:00
+
+
+
+ 256
+ 172
+ JPEG
+ /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA
AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK
DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f
Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgArAEAAwER
AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA
AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB
UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE
1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ
qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy
obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp
0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo
+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A6db/AJIa9babY6VbebJI
rGzube+dhA6zyzxwLBMC8c8XGOQeodviq1SxIqVUun/5x41qajDzfNExiSFlSBlVUS2aLigSZNvW
EclD/LTbFU28t/klqWiazYaj/iaW7FrJaSTJJE4Mn1WJ4mO0xWsqsoLFSwFRXiaYq9WxV2KuxV2K
uxV2KuxV2KuxVjP5heVNU8z6Cmm6bqp0e4S5iuhdrGZDyt6yRDirxbCYIx36CnfFWDW35CXun2bx
6b5mnFxNA9rJLcRlkCTWMlrI6pE8PxrJMZI6tRBsBXkzKqw/JHVX1C2nuPMXrWcAWOWye3d0lX60
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
+
+
+
+
+
+ application/pdf
+
+
+ uuid:424ad26a-0391-3e47-a0ac-110085b31b58
+ uuid:a1ec6a83-7e4f-654b-b671-93a86e5b3c39
+
+
+ 1
+ False
+ False
+
+ 841.889771
+ 595.275574
+ Points
+
+
+
+
+ HelveticaNeue
+ Helvetica Neue
+ Regular
+ TrueType
+ 5.0d1
+ False
+ HelveticaNeue.dfont
+
+
+ HelveticaNeue-CondensedBold
+ Helvetica Neue
+ Condensed Bold
+ TrueType
+ 5.01d
+ False
+ HelveticaNeue.dfont
+
+
+ HelveticaNeue-Bold
+ Helvetica Neue
+ Bold
+ TrueType
+ 5.0d1
+ False
+ HelveticaNeue.dfont
+
+
+ MyriadPro-Bold
+ Myriad Pro
+ Bold
+ Open Type
+ Version 2.007;PS 002.000;Core 1.0.38;makeotf.lib1.7.9032
+ False
+ MyriadPro-Bold.otf
+
+
+ MyriadPro-Regular
+ Myriad Pro
+ Regular
+ Open Type
+ Version 2.007;PS 002.000;Core 1.0.38;makeotf.lib1.7.9032
+ False
+ MyriadPro-Regular.otf
+
+
+
+
+
+ Cyan
+ Magenta
+ Yellow
+ Black
+ grey
+ New Color Swatch 2
+ New Color Swatch 1
+
+
+
+
+
+ Default Swatch Group
+ 0
+
+
+
+ New Color Swatch 1
+ SPOT
+ 100.000000
+ RGB
+ 203
+ 0
+ 0
+
+
+ New Color Swatch 2
+ SPOT
+ 100.000000
+ RGB
+ 0
+ 0
+ 0
+
+
+ grey
+ SPOT
+ 100.000000
+ RGB
+ 102
+ 102
+ 102
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
endstream
endobj
2 0 obj
<>
endobj
5 0 obj
<>/ArtBox[52.1289 57.0234 796.124 551.148]/MediaBox[0.0 0.0 841.89 595.276]/TrimBox[0.0 0.0 841.89 595.276]/Resources<>/Font<>/ProcSet[/PDF/Text]/Properties<>>>/ExtGState<>>>/Type/Page/LastModified(D:20080111163617+01'00')>>
endobj
1122 0 obj
<>stream
+HW[8~WG˾%d7SLf2Ԕ팱 6=mMRՀtwM-zv}ыWhDz7 qt
[U5R&rDLhJ(F4
+nHi(
+M9㉔r/}a$HHs773w-q/}6a>[Gҫ%I֣߾z>{;t3췏&)% 6[Ư>ϧo2mW4/$'鯞2[!'u0z0b/]ˬ/1Zww6[p8ѱe@V![w8$I])wb,PJ'R"eD7OYU'OWfsݜӕ=b |ABS*DXb8ItcS@ M&=ww_:]1Tv2eQr= X'Ex肿cA%01^q`^5Y[\`8YD y*21P#a{ƴz~w,
+ ]ye Y|ȠV1#^