Changeset 1973


Ignore:
Timestamp:
08/23/11 04:49:08 (21 months ago)
Author:
jeroen
Message:

added overall logic and srt parsing to html5 captions

Location:
plugins/captions
Files:
6 added
3 deleted
24 edited

Legend:

Unmodified
Added
Removed
  • plugins/captions/captions.js

    r1964 r1973  
    1 (function(a){var b=function(g,e,d){function f(){if(g.getRenderingMode()=="flash"){return}}g.onReady(f);this.resize=function(i,h){if(g.getRenderingMode()=="flash"){return}};function c(h,i){for(var j in i){h.style[j]=i[j]}}};a().registerPlugin("captions",b,"./captions.swf")})(jwplayer); 
     1(function(a){var b=function(d,h,r){var o={back:false,color:"#FFFFFF",fontFamily:"Arial,sans-serif",fontSize:15,fontStyle:"normal",fontWeight:"normal",state:true,textDecoration:"none"};var m=["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA6ZJREFUeNrsWM9LVFEUfm8cU7NsxkwU+zGhRQWB1aY29RYtXIVRUO1mKW1qE/inCG2ENq0qCMJFCxcupBYFQQxSYog1CPkDC8ccnb5D37XD5YmPeU9fxD3wcd67c+be85177r3nPs9z4sSJEydOnPw/4kcxqtVqYrcPaCZagENAm2proo3oLNBIbcsvoEq9RlSIH8Ay8BNYZdua7/ubO/mYjUj4HtBDR7NRAxBTNoB1YA54khSRDqB1m98kiiVgnoML2aNAL2fKdu4LMM2IS0DywGngiGXbQOSjOJiNGbUp4DmmfjUkHQ9D3SQpj2nyDLZTIbavoa4BQb2OZGKQWAFeGhJwJgM0cz15aP8O9Qow+T2uScCuCcjStgaM4/FDGkQ+YfAV9X4deASc3dpJfP8rVJmv04pEN9QD4JbdZxpEFq3348zpcyFrqMoZNHIM2C/rCKTaVPtqvc7EWSOb22zlB+FcJ/uucsFXLfuMWtA9sG/h7+1pENlOTgD3Q9ZTmAiRO0kMmkmQwF6cLXtCJFXS2V1wbgF4wyDJAXiRpUxo9QNMsizxeCheSo2IOTsoy9h2J9VvPSGL2FdE3sF+nrYn6yUSJ7Ua1HlRo1OmKLTHyFhj1VTJUk0i5eLMSIf1/pH9vbXa8ySdU+fEZxaDcwjCgrJtS4NIH1Kh3TgCPQE1YaVcL6tmkVPAN9pKKj22bGXGzqexa8khNggH8mFrBpBSZVA1X0XbhW3WmNxtbrNiTmXXkrJkCI7MsoyvMoW6mXq+NdYN2F6BnmXpIqd+p7rr7Pr2u8jaqFEvcorcCPuIKFt0JxH1YrWY5FU3Q4dbGMUDjHyrddU119us2ql81lFmZ9tQu9V6UlddJ06cOIlVROaAwQT6OQNcTvxkR6ddAqtNvpwURKvmHBHWR5i9IV+wzLtCvo3VfyBigCI7lH1dyLzA3l6SiLEMKbP9Kdpn8Fzk/wJ+5tkKBNRdYAkQMqNiD93Pb1pLQgh6lIEI+L8Z9ht7iovilJpu4+iQiSKjPKSeiyH9BCbl2E+OM/TQzJCkEjCg7IPEZoRiIlLRU28ixch27dDHe5kt2A17fz6zlpk+Ev1htNtj7VnRWJFIgkSFEa3sZA+MqLSRyEvqldHHiFlDaXx8KLGUL3CtlNRvzcx3LQO0M6QrIFCmbcB+JCX1TpWLQi4qkbKKdsX7+xl0jM8B9ZiylwXdb/Uzxv8H6t2zFndJbRAlthfcoebEiRMn/6T8FmAAOmqqRlH6QggAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09JREFUeNrsmEtIVFEYx+fOjI1WNmkUPUxDjR4USZIUFANBtigoqn1R0Np9C1u2y0XQKrCNKwmJoLDAhOhBhEG1U9Qg7YHNlJaPKaf/B/+Rj8O9Oc29M2N1Pvhx7jn3u/ee/3l+54ZC1qxZs2bNmrV/x5xcnDKZTBjJCrAaVIFqUAs2MR8Hq8BKpuVgOVP9jQz4BqbBFPhKvoAk+ADeMk2SScdxfixWx2iOgm+DFoqpyLUBfNoc+A6eg9aghGwHaz3uvQc94DU/Lr2yHxxlT2lLg37wAHwGEVAPjoMdhu8yUh9Y02BoDWbc7Q6o9nhmK3iqfJPgmNfQBe0e3xgstJAxsEH5REAcOKqsGaTp32a8sxKUG2Vd+QoJ+9B3F5NwXOWvgE/g9MJK4jgvkLxk9r6q8F4kw6DLeOe9fCvjR8iwkT8IysAZo1xWoBkwpsoOgDXgCETVqPKJfCsT9SEkbeQjTDeicruQxihAluxZ8NPluzKZ93GeyRLbWAohXkvwIfDKKBv38BUht4KYx+FQcOYUyPf/EhItgJAhcI3vlg3yAtjs4SshSwfDErneCS4WW0hGLaeOqtwolt0Oda/FZRJnfWUBuAH/N/Q9nK8QP0MrpvYLETXP7JTLalZmNNq8Wvlmghhyfnpkm5HvZrR73ShvoJA6xlfZzVGCwWdohCHlW1PQMNQjRJkADYs816r8Ly3iKyFObyliLbFHoN7F3wGnwDvlOw3Oe7y/FnT7CRpzPVgNcoi42SR4zE1wlkOomUMv7LJAyMR+wvBfwvzdsrsz/HezIQy/xqCE9PJgVcHduBi2cLCCkNaghER5hK0i69ny65iXeKqSJ8gYBUe4mIQZR2VXtjn23AwrKkfdFJEAcxR8/NOjrjVr1gq3Se6RM3pA70mY18UUclU+7PMdJ/h3pU9fl7qHEqDuN/fj9ImrMvkF1G5eF7vifdmKgQHmk26VMVo+yecSKgzpU9ftpRKSoJC41xjn/YTquYGge8T3URe7br/amS97uDXRL+vftFTP7OfAFv6M63G5n8rODaapJScEFTvLyjepnjFN7ndyeHV6iC3Zzwdp/RSGyk1UUHqjjSJOuvi2ERl6D/nDQWxE+YzY3dmaNWvW/jr7JcAAj0e1BA7EkwQAAAAASUVORK5CYII=","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA0tJREFUeNrsmM9LVFEUx30zY2pl/oiiH6YxGv2gUJKkoFCCbFFgVH9AFLSefQtdtpxF0CqalSuJiKCwwIToBxEK1U4Rg7QfmFNajlpO3wPfkcPlPZ3mvXHM7oEPZ+6d89475917zz33FRVZsWLFihUrVtaOONkYpdPpENQGUAmqQDWoBTvZrgCbwEbqUrCeWj8jDX6AGTANvpNvYBJ8Au+pJ8mU4zi/lvMxkmXA90ALgynL9gX4lDnwE7wC7UEFsg9s8fjvI7gL3vLhMipHwWmOlJZ50A8eg68gDKLgLNhv2K4j0cBeDabWUNpd7oNqj2v2gBfKdhKc8Zq6oNPjGUP5DmQMbFc2YVABHNXXDOZpHzPuWQ5Kjb7uXAMJ+YjvARbhuGpfB1/AhcVM4jivoQbZfKQcPgw1ArqNez7M1Rk/gYwY7eOgGFw0+iUDpcCY6jsGNoNTCKpG9U/k6kzERyDzRjtMvQPOHYQuYQCSsmfBb5fnymI+wnUmKbahEIF4peAT4I3RN+5hK4HcCWIdh4qCEydPtv9XIJE8BDIMbvDeskFeAbs8bKVkibMskd8HwNWVDiSt0qmjnBtF2o2r/1pcFnHGVhLALdi/o+3JXAPxM7VK1H4hQS2wOe2SzYqNl7agMl8qiCnnZ0T2Gu0eVrs3jf56BlLH+iqzOUox+BIvYVjZ1uS1DPUoUSZA/TLXtSv7a8vYSonTW4haS+QpiLrYO+A8+KBsZ8Blj/vXgh4/RWO2B6shThE3mQLPuAnOcgo1c+qFXBKELOznLP+lzD8kuzvLfzcZxvRrCCqQXh6syrgbr4QsHqwQSHtQgUR4hK0i2/jmt7It9VQ5T5AlDDjMZBJiHZXJbHMcuRQdlaNukkiBOQo+/+1R14oVK/nbJBvljL5a/PFTa10Cu9fa6MjXk9alRmgpG45uY6Gc76Nj4sQI2yKtLrYd/K7VR92q7jGg+jsKGYh8WLutHK5zsR1Qzss1A+oeneravkIedROgTd4o9DkPmybszv08u4huUv89oU4W+syepGNtLFXibjaZtUGdXE1ZKyNxjkqlqplMkY/cCU6vBNurJpBBOh2j7mJ/zMU2Rvsu6phxj8zIDtod2ooVK1b+KfkjwAC9JXx/mwsoAgAAAABJRU5ErkJggg=="];var v;var x;var i;var f=[];var u;function k(z,C){z="jwplayercaptions"+z;if(C!==undefined){var D=z+"="+C+"; expires=Wed, 1 Jan 2020 00:00:00 UTC; path=/";document.cookie=D}else{var B=document.cookie.split(";");for(var A=0;A<B.length;A++){var D=B[A];while(D.charAt(0)==" "){D=D.substring(1,D.length)}if(D.indexOf(z)==0){return D.substring(z.length+1,D.length)}}}return null}var w=function(){if(f.length>1){x.show();try{d.getPlugin("display").hide();d.getPlugin("dock").hide()}catch(z){}}else{if(f.length==1){o.state=!o.state;k("state",o.state);e()}}};function p(z){console.log("CAPTIONS("+z+")")}function n(z){u="idle";e()}function q(z){i=0;f=[];v.update(0);x.hide();try{d.getPlugin("display").show();d.getPlugin("dock").show()}catch(E){}var G=d.getPlaylist()[z.index];if(G["captions.files"]){var I=false;var A=G["captions.files"].split(",");if(G["captions.labels"]){var D=G["captions.labels"].split(",")}for(var C=0;C<A.length;C++){var F={file:A[C]};if(D&&D[C]){F.label=D[C]}else{F.label=A[C].substring(A[C].lastIndexOf("/")+1,A[C].indexOf(".")-1)}if(o.label==F.label){I=true;i=f.length;y(F.file)}f.push(F)}if(I==false){o.state=false}var H=[{label:"(Off)"}];for(var B=0;B<f.length;B++){H.push({label:f[B].label})}if(o.state){x.populate(H,i+1)}else{x.populate(H,0)}}else{if(G["captions.file"]){f.push({file:G["captions.file"]});y(f[0].file)}}e()}function y(A){var z=new a.captions.srt(t,p);z.load(A)}function t(z){v.populate(z);f[i].data=z;e()}function j(z){u="playing";e()}function s(z){if(o.file){d.getPlaylist()[0]["captions.file"]=o.file}if(o.files){d.getPlaylist()[0]["captions.files"]=o.files}if(o.labels){d.getPlaylist()[0]["captions.labels"]=o.labels}}function e(){if(!f.length){d.getPlugin("dock").setButton("captions",w,m[0]);v.hide()}else{if(o.state){d.getPlugin("dock").setButton("captions",w,m[2]);if(u=="playing"){v.show()}else{v.hide()}}else{d.getPlugin("dock").setButton("captions",w,m[1]);v.hide()}}}this.resize=function(A,z){if(d.getRenderingMode()=="flash"){return}v.resize(A,z);x.resize(A,z)};function g(){if(d.getRenderingMode()=="flash"){return}d.onPlaylist(s);d.onPlaylistItem(q);d.onIdle(n);d.onPlay(j);d.onTime(c);if(k("state")!==null){if(k("state")=="true"){o.state=true}else{o.state=false}}if(k("label")!==null){o.label=k("label")}for(var z in h){o[z]=h[z]}v=new a.captions.renderer(o,r);x=new a.captions.selector(l,r);e()}d.onReady(g);function l(A){x.hide();try{d.getPlugin("display").show();d.getPlugin("dock").show()}catch(z){}if(A>0){o.state=true;i=A-1;o.label=f[i].label}else{_config.state=false}k("label",o.label);k("state",o.state);if(f[i].data){v.populate(f[i].data)}else{y(f[i].file)}e()}function c(z){v.update(z.position)}};a.captions={};a().registerPlugin("captions",b,"./captions.swf")})(jwplayer);(function(a){a.captions.renderer=function(k,e){var j;var d;var h;var g;this.hide=function(){b({display:"none"})};this.populate=function(l){g=-1;j=l;c()};function i(l){d.innerHTML=l}this.resize=function(m,l){};function c(){var m=-1;for(var l=0;l<j.length;l++){if(j[l]["begin"]<=h&&(l==j.length-1||j[l+1]["begin"]>=h)){m=l;break}}if(m==-1){i("")}else{if(m!=g){g=m;i(j[l]["text"])}}}function f(){d=document.createElement("p");e.appendChild(d);b({color:k.color,fontFamily:k.fontFamily,fontSize:k.fontSize+"px",fontStyle:k.fontStyle,fontWeight:k.fontWeight,lineHeight:Math.round(k.fontSize*1.4)+"px",textAlign:"center",textDecoration:k.textDecoration});if(k.back){b({textShadow:"#000 1px 1px 0"})}else{b({background:"#000"})}}f();this.show=function(){b({display:"block"})};function b(l){for(var m in l){d.style[m]=l[m]}}this.update=function(l){h=l;if(j){c()}}}})(jwplayer);(function(a){a.captions.selector=function(d,c){this.hide=function(){};this.populate=function(e,f){};this.resize=function(f,e){};this.show=function(){};function b(e,f){for(var g in f){e.style[g]=f[g]}}}})(jwplayer);(function(a){a.captions.srt=function(g,b){var d;var c;function h(k){if(k==0){b("Crossdomain loading denied: "+c)}else{if(k==404){b("SRT File not found: "+c)}else{b("Error "+k+" loading SRT file: "+c)}}}this.load=function(l){c=l;try{d.open("GET",l,true);d.send(null)}catch(k){b("Error loading SRT File: "+l)}};function f(n){_captions=[{begin:0,text:""}];n=n.replace(/^\s+/,"").replace(/\s+$/,"");var m=n.split("\r\n\r\n");if(m.length==1){m=n.split("\n\n")}for(var k=0;k<m.length;k++){var l=j(m[k]);if(l.begin&&l.text){_captions.push(l);if(l.end){_captions.push({begin:l.end,text:""});delete l.end}}}if(_captions.length>1){g(_captions)}else{b("Invalid SRT file: "+c)}}function j(o){var n={};var p=o.split("\r\n");if(p.length==1){p=o.split("\n")}try{var l=p[1].indexOf(" --> ");if(l>0){n.begin=i(p[1].substr(0,l));n.end=i(p[1].substr(l+5))}if(p[2]){n.text=p[2];for(var m=3;m<p.length;m++){n.text+="<br/>"+p[m]}}}catch(k){}return n}function i(k){k=k.replace(",",".");var m=k.split(":");var l=0;if(k.substr(-1)=="s"){l=Number(k.substr(0,k.length-1))}else{if(k.substr(-1)=="m"){l=Number(k.substr(0,k.length-1))*60}else{if(k.substr(-1)=="h"){l=Number(k.substr(0,k.length-1))*3600}else{if(m.length>1){l=Number(m[m.length-1]);l+=Number(m[m.length-2])*60;if(m.length==3){l+=Number(m[m.length-3])*3600}}else{l=Number(k)}}}}return l}function e(){d=new XMLHttpRequest();d.onreadystatechange=function(){if(d.readyState===4){if(d.status===200){f(d.responseText)}else{h(d.status)}}}}e()}})(jwplayer); 
  • plugins/captions/doc/guide.html

    r1964 r1973  
    2626<h2>Introduction</h2> 
    2727 
    28 <p>The Captions plugin for JW Player supports the display of closed captions or subtitles at the bottom of a video. More creative use cases are karaoke, or the displaying of timed comments with the video. Captions can be shown or hidden with a toggle:</p> 
     28<p>The Captions plugin for JW Player supports the display of closed captions or subtitles at the bottom of a video. Captions can be shown or hidden with a toggle:</p> 
    2929 
    3030<p><img src="assets/captions_example.png" alt="A screenshot of example captions implementation" style="margin-left:15px"/></p> 
     
    4646<dd>Location of the captions file to display. Should be the URL to a valid <a href="#dfxp">DFXP</a> or <a href="#srt">SRT</a> captions file. If your captions are embedded in your MP4 videos, or if you use a playlist, this option is not needed.</dd> 
    4747<dt><b>state</b> (<em>true</em>)</dt> 
    48 <dd>Describes whether to show the captions on startup or not. The default is <b>true</b> (captions are shown). When changed, the value is saved in a cookie, so users won't have to disable the captions on every video again if they don't want them.</dd> 
     48<dd>Describes whether to show the captions on startup or not. The default is <b>true</b> (captions are shown). When a viewer changes the state, the value is saved in a cookie, so users won't have to disable the captions on every video again if they don't want them.</dd> 
    4949</dl> 
    5050 
     
    159159<dd>Set this value to a second comma-separated list, defining the labels for each language that should pop up in the selection menu (e.g. <em>English,Deutsch,Francais</em>). The amount and order of these labels should be the same as the amount and order of entries in the <b>files</b> option.</dd> 
    160160</dl> 
     161 
     162<p>When a viewer changes the captions track, the value is saved in a cookie. That way the viewer won't have to re-set the track with every new video or page reload.<p> 
    161163 
    162164<h3>Example</h3> 
     
    306308</ul> 
    307309<ul> 
    308 <li>Enhanced support for dock button language shortcode in multitrack setups. The first three characters of labels are now used.</li> 
     310<li>Enhanced support for dock button language shortcode in multitrack setups. The full label is simply shown.</li> 
    309311<li>Made captions aware of controlbar in the "over" state. For player 5.7+, the captions will now scroll up if the controlbar shows and scroll down again if the controlbar hides.</li> 
    310312<li>Added a timed transition to showing/hiding of the language selector.</li> 
    311313<li>Added a close button to the language selector menu.</li> 
     314<li>Added support for displaying filenames in language selector if labels are not shown.</li> 
     315</ul> 
     316<ul> 
     317<li>Fixed an issue with language selector tabbing that required two tabs for advancing one entry.</li> 
    312318<li>Fixed an issue with OVA advertising that caused displaying captions on the preroll.</li> 
    313319</ul> 
  • plugins/captions/src/as/com/longtailvideo/plugins/captions/Captions.as

    r1964 r1973  
    2929        private var _config:Object = { 
    3030            back: false, 
    31             code: undefined, 
     31            label: undefined, 
    3232            file: undefined, 
    3333            state: true 
     
    189189                } 
    190190                for(var i:Number = 0; i < files.length; i++) { 
    191                     var entry:Object = { 
    192                         file: files[i], 
    193                         code: files[i].substr(files[i].indexOf('.')-3,3) 
    194                     }; 
     191                    var entry:Object = { file: files[i] }; 
    195192                    // Set label. 
    196193                    if(labels && labels[i]) { 
    197194                        entry.label = labels[i]; 
    198                         entry.code = labels[i].substr(0,3).toLowerCase(); 
    199                     } else {  
    200                         entry.label = ISO639.label(entry.code); 
    201                     } 
    202                     if(_config.code == entry.code) { 
     195                    } else { 
     196                        var slash:Number = files[i].lastIndexOf('/'); 
     197                        var dot:Number = files[i].indexOf('.'); 
     198                        entry.label = files[i].substr(slash+1,1).toUpperCase()+files[i].substr(slash+2,dot-slash-2); 
     199                    } 
     200                    if(_config.label == entry.label) { 
    203201                        _track = _tracks.length; 
    204202                        found = true; 
     
    256254            for(var i:Number = 0; i < info.length; i++) { 
    257255                if(info[i].sampledescription[0].sampletype == 'tx3g') { 
    258                     if(_config.code == info[i].language) { 
     256                    if(_config.label == ISO639.label(info[i].language)) { 
    259257                        _track = _tracks.length; 
    260258                        found = true; 
    261259                    } 
    262260                    _tracks.push({ 
    263                         code: info[i].language, 
    264261                        data: undefined, 
    265262                        file: undefined, 
     
    297294        /** Populate the selector. **/ 
    298295        private function _populateSelector():void {  
    299             var options:Array = new Array({label:'Captions Off'}); 
     296            var options:Array = new Array({label:'(Off)'}); 
    300297            for(var j:Number=0; j<_tracks.length; j++) { 
    301298                options.push({label:_tracks[j].label}); 
     
    336333                    _button.field.alpha = 1; 
    337334                    if(_tracks.length > 1) {  
    338                         _button.field.text = '('+_tracks[_track].code+')'; 
     335                        _button.field.text = _tracks[_track].label.toLowerCase(); 
    339336                    } else {  
    340337                        _button.field.text = 'is on'; 
     
    354351        // Resize the captions, a bit smaller in fullscreen 
    355352            if(_player.config.fullscreen) { 
    356                 _renderer.x = width / 6; 
    357                 _renderer.width = width * 2/3; 
     353                _renderer.x = width / 8; 
     354                _renderer.width = width * 3 / 4; 
    358355            } else { 
    359356                _renderer.x = width / 24; 
     
    381378                (_player.controls.dock as Object).show(); 
    382379            } catch (error:Error) {} 
    383             // Set and cookie state/code 
     380            // Set and cookie state/label 
    384381            if(index > 0) { 
    385382                _config.state = true; 
    386383                _track = index - 1; 
    387                 _config.code = _tracks[_track].code; 
     384                _config.label = _tracks[_track].label; 
    388385            } else { 
    389386                _config.state = false; 
    390387            } 
    391388            _cookie.data['captions.state'] = _config.state; 
    392             _cookie.data['captions.code'] = _config.code; 
     389            _cookie.data['captions.label'] = _config.label; 
    393390            _cookie.flush(); 
    394391            // Update UI 
  • plugins/captions/src/as/com/longtailvideo/plugins/captions/ISO639.as

    r1813 r1973  
    2727            fin: 'Finnish', 
    2828            fra: 'Français', 
    29             fre: 'Français', 
     29            fre: 'French', 
    3030            geo: 'Georgian', 
    3131            ger: 'Deutsch', 
  • plugins/captions/src/as/com/longtailvideo/plugins/captions/Renderer.as

    r1964 r1973  
    126126        public function setPosition(position:Number):void { 
    127127            _position = position; 
    128             if(_captions) {  
     128            if(_captions) { 
    129129                _selectCaption(); 
    130130            } 
  • plugins/captions/src/as/com/longtailvideo/plugins/captions/Selector.as

    r1964 r1973  
    3131        /** Function to call when a selection is made. **/ 
    3232        private var _callback:Function; 
    33         /** Reference to the page down button. **/ 
    34         private var _down:SelectorUpDown; 
    35         /** Offset of the visible entries. **/ 
    36         private var _offset:Number; 
    3733        /** List with options from the selector. **/ 
    3834        private var _options:Array; 
    39         /** Reference to the page up button. **/ 
    40         private var _up:SelectorUpDown; 
    4135 
    4236 
     
    5650            addChild(_container); 
    5751            _container.buttonMode = true; 
    58             _down = new SelectorUpDown(false,_downHandler); 
    59             _up = new SelectorUpDown(true,_upHandler); 
    6052        }; 
    6153 
     
    7668 
    7769 
    78         /** The down button was clicked. **/ 
    79         private function _downHandler():void { 
    80             _offset++; 
    81             _redraw(); 
    82         }; 
    83  
    84  
    85         /** Return the max number of buttons that fit in the screen. **/ 
    86         private function _max():Number {  
    87             return Math.floor(_back.height/27) - 2; 
    88         }; 
    89  
    90  
    9170        /** Populate the selector with a number of items. **/ 
    9271        public function populate(options:Array,active:Number=0):void { 
    9372            _options = options; 
    9473            _active = active; 
    95             // Build all the buttons. 
    96             for(var i:Number=0; i < _options.length; i++) { 
    97                 _options[i].button = new SelectorButton(_buttonHandler,i,_options[i].label); 
    98             } 
    99             _options[_active].button.activate(true); 
    100             // Redraw the menu. 
    101             _reoffset(); 
    102             _redraw(); 
    103         }; 
    104  
    105  
    106         /** Draw visible portion of the options. **/ 
    107         private function _redraw():void { 
    108             var button:SelectorButton; 
    109             var height:Number = 0; 
    110             var end:Number; 
    111             var scroll:Boolean; 
    112             // clear existing buttons. 
     74            // Remove existing buttons. 
    11375            while(_container.numChildren > 0) { 
    11476                _container.removeChildAt(0); 
    11577            } 
    116             // Check if scrollbars are needed and if offset needs correcting. 
    117             if(_options.length > _max()) { 
    118                 scroll = true; 
    119                 end = _max(); 
    120             } else { 
    121                 end = _options.length; 
    122             } 
    123             if(_offset < 0) { 
    124                 _offset = 0; 
    125             } else if (scroll && _offset > _options.length - _max()) { 
    126                 _offset = _options.length - _max(); 
    127             } 
    128             // Draw prev button if needed. 
    129             if(scroll) { 
    130                 _container.addChild(_up); 
    131                 _up.y = height; 
    132                 _offset == 0 ? _up.alpha = 0: _up.alpha = 1; 
    133                 height += 26; 
    134                 height = _redrawDivider(height); 
    135             } 
    136             // Draw new buttons and dividers 
    137             for(var i:Number = _offset; i < _offset + end; i++) { 
     78            // Draw new buttons. 
     79            for(var i:Number = 0; i<_options.length; i++) { 
     80                _options[i].button = new SelectorButton(_buttonHandler,i,_options[i].label); 
    13881                _container.addChild(_options[i].button); 
    139                 _options[i].button.y = height; 
    140                 height += 26; 
    141                 if(i < _offset + end - 1) { 
    142                     height = _redrawDivider(height); 
     82                _options[i].button.y = i*25; 
     83                if(i < _options.length - 1) { 
     84                    var divider:DisplayObject = new DividerRow(); 
     85                    divider.y = i*25 + 24; 
     86                    _container.addChild(divider); 
    14387                } 
    14488            } 
    145             //draw next button if needed 
    146             if(scroll) { 
    147                 height = _redrawDivider(height); 
    148                 _container.addChild(_down); 
    149                 _down.y = height; 
    150                 _offset == _options.length - _max() ? _down.alpha = 0: _down.alpha = 1; 
    151                 height += 26; 
    152             } 
    153             // Rescale button list. 
    154             _container.x = Math.round(_back.width/2 - _container.width/2); 
    155             _container.y = Math.round(_back.height/2 - height/2); 
    156         }; 
    157  
    158  
    159         private function _redrawDivider(height:Number):Number { 
    160             var divider:DisplayObject = new DividerRow(); 
    161             _container.addChild(divider); 
    162             divider.y = height; 
    163             return height + 1; 
    164         }; 
    165  
    166  
    167         /** If scrolling, set offset such that active track is visible. **/ 
    168         private function _reoffset():void { 
    169             if(_active < _max()) { 
    170                 _offset = 0; 
    171             } else if(_options.length > _max() && _active > _options.length - _max()) { 
    172                 _offset = _options.length - _max(); 
    173             } else {  
    174                 _offset = _active; 
    175             } 
     89            // Set active button and center the list 
     90            _options[_active].button.activate(true); 
     91            resize(_back.width,_back.height); 
    17692        }; 
    17793 
     
    18399            _close.x = width - 50; 
    184100            if(_options) { 
    185                 _reoffset(); 
    186                 _redraw(); 
     101                _container.x = Math.round(_back.width/2 - _container.width/2); 
     102                _container.y = Math.round(_back.height/2 - _container.height/2); 
    187103            } 
    188         }; 
    189  
    190  
    191         /** The up button was clicked. **/ 
    192         private function _upHandler():void { 
    193             _offset--; 
    194             _redraw(); 
    195104        }; 
    196105 
  • plugins/captions/src/as/com/longtailvideo/plugins/captions/SelectorButton.as

    r1964 r1973  
    5959            _field.height = 20; 
    6060            _field.width = 180; 
    61             _field.y = 3; 
     61            _field.y = 2; 
    6262            _field.text = _label; 
    63             buttonMode = true; 
    64             mouseChildren = false; 
    65             // Insert accessibility options (tabbing / screenreader label). 
    66             var acs:AccessibilityProperties = new AccessibilityProperties(); 
    67             acs.name = label; 
    68             accessibilityProperties = acs; 
    69             tabEnabled = true; 
    70             tabChildren = false; 
    71             tabIndex = index + 501; 
    7263            // Add active indicator (small dot). 
    7364            _active = new ActiveIcon(); 
     
    7667            _active.visible = false; 
    7768            addChild(_active); 
    78             _active.x = 90 - _field.getLineMetrics(0).width/2 - 26; 
     69            // Insert accessibility options (tabbing / screenreader label). 
     70            var acs:AccessibilityProperties = new AccessibilityProperties(); 
     71            acs.name = label; 
     72            accessibilityProperties = acs; 
     73            buttonMode = true; 
     74            mouseChildren = false; 
     75            tabEnabled = true; 
     76            tabChildren = false; 
     77            tabIndex = index + 501; 
    7978            // Set event handlers. 
    8079            addEventListener(MouseEvent.CLICK,_clickHandler); 
     
    8685        /** (de)activate the button. **/ 
    8786        public function activate(state:Boolean):void { 
    88             if(state) {  
     87            if(state) { 
    8988                _active.visible = true; 
    9089            } else { 
  • plugins/captions/src/js/captions.js

    r1964 r1973  
    22 
    33 
    4 /** Displays closed captions or subtitles on top of the video. **/ 
    5 var template = function(_player, _options, _div) { 
    6  
    7  
    8     /** Set dock buttons when player is ready. **/ 
    9     function _setup() { 
    10         if(_player.getRenderingMode() == 'flash') { return; } 
     4    /** Displays closed captions or subtitles on top of the video. **/ 
     5    var template = function(_player, options, _div) { 
     6 
     7 
     8        /** Default configuration options. **/ 
     9        var _options = { 
     10            back: false, 
     11            color: '#FFFFFF', 
     12            fontFamily: 'Arial,sans-serif', 
     13            fontSize: 15, 
     14            fontStyle: 'normal', 
     15            fontWeight: 'normal', 
     16            state: true, 
     17            textDecoration: 'none' 
     18        }; 
     19        /** Dock icons. **/ 
     20        var _icons = [ 
     21            '../assets/not_set.png', 
     22            '../assets/is_off.png', 
     23            '../assets/is_on.png' 
     24        ]; 
     25        /** Reference to the text renderer. **/ 
     26        var _renderer; 
     27        /** Reference to the language selector. **/ 
     28        var _selector; 
     29        /** Currently active captions track. **/ 
     30        var _track; 
     31        /** List with all tracks. **/ 
     32        var _tracks = []; 
     33        /** Current player state. **/ 
     34        var _state; 
     35 
     36 
     37        /** Read or write a cookie. **/ 
     38        function _cookie(name,value) { 
     39            name = 'jwplayercaptions' + name; 
     40            if(value !== undefined) { 
     41                var c = name+'='+value+'; expires=Wed, 1 Jan 2020 00:00:00 UTC; path=/'; 
     42                document.cookie = c; 
     43            } else { 
     44                // http://www.quirksmode.org/js/cookies.html 
     45                var list = document.cookie.split(';'); 
     46                for(var i=0; i< list.length; i++) { 
     47                    var c = list[i]; 
     48                    while (c.charAt(0) == ' ') { 
     49                        c = c.substring(1,c.length); 
     50                    } 
     51                    if (c.indexOf(name) == 0) { 
     52                        return c.substring(name.length+1, c.length); 
     53                    } 
     54                } 
     55            } 
     56            return null; 
     57        }; 
     58 
     59 
     60        /** Dock button was clicked. **/ 
     61        var dockHandler = function() { 
     62            if(_tracks.length > 1) { 
     63                _selector.show(); 
     64                try { 
     65                    _player.getPlugin('display').hide(); 
     66                    _player.getPlugin('dock').hide(); 
     67                } catch (error) {} 
     68            } else if(_tracks.length == 1) { 
     69                _options.state = !_options.state; 
     70                _cookie('state',_options.state); 
     71                _redraw(); 
     72            } 
     73        }; 
     74 
     75 
     76        /** Error loading/parsing the captions. **/ 
     77        function _errorHandler(error) { 
     78            console.log("CAPTIONS(" + error + ")"); 
     79        }; 
     80 
     81 
     82        /** Player jumped to idle state. **/ 
     83        function _idleHandler(event) { 
     84            _state = 'idle'; 
     85            _redraw(); 
     86        }; 
     87 
     88 
     89        /** Listen to playlist item updates. **/ 
     90        function _itemHandler(event) { 
     91            _track = 0; 
     92            _tracks = []; 
     93            _renderer.update(0); 
     94            _selector.hide(); 
     95            try { 
     96                _player.getPlugin('display').show(); 
     97                _player.getPlugin('dock').show(); 
     98            } catch (error) {} 
     99            var item = _player.getPlaylist()[event.index]; 
     100            // Load multiple captions 
     101            if(item['captions.files']) { 
     102                var found = false; 
     103                var files = item['captions.files'].split(','); 
     104                if(item['captions.labels']) {  
     105                    var labels = item['captions.labels'].split(','); 
     106                } 
     107                for(var i=0; i<files.length; i++) { 
     108                    var entry = { file: files[i] }; 
     109                    // Set label 
     110                    if(labels && labels[i]) { 
     111                        entry.label = labels[i]; 
     112                    } else { 
     113                        entry.label = files[i].substring(files[i].lastIndexOf('/')+1,files[i].indexOf('.')-1); 
     114                    } 
     115                    // Matched label from cookie. 
     116                    if(_options.label == entry.label) { 
     117                        found = true; 
     118                        _track = _tracks.length; 
     119                        _load(entry.file); 
     120                    } 
     121                    _tracks.push(entry); 
     122                } 
     123                if(found == false) { 
     124                    _options.state = false; 
     125                } 
     126                // populate selector 
     127                var options = [{label:'(Off)'}]; 
     128                for(var j=0; j<_tracks.length; j++) { 
     129                    options.push({label:_tracks[j].label}); 
     130                } 
     131                if(_options.state) { 
     132                    _selector.populate(options, _track+1); 
     133                } else { 
     134                    _selector.populate(options, 0); 
     135                } 
     136            // Load single caption 
     137            } else if(item['captions.file']) { 
     138                _tracks.push({file:item['captions.file']}); 
     139                _load(_tracks[0].file); 
     140            } 
     141            _redraw(); 
     142        }; 
     143 
     144 
     145        /** Load captions. **/ 
     146        function _load(file) { 
     147            var loader = new jwplayer.captions.srt(_loadHandler,_errorHandler); 
     148            loader.load(file); 
     149        }; 
     150 
     151 
     152        /** Captions were loaded. **/ 
     153        function _loadHandler(data) { 
     154            _renderer.populate(data); 
     155            _tracks[_track].data = data; 
     156            _redraw(); 
     157        }; 
     158 
     159 
     160        /** Player started playing. **/ 
     161        function _playHandler(event) { 
     162            _state = 'playing'; 
     163            _redraw(); 
     164        }; 
     165 
     166 
     167        /** Insert global file/files on playlist update. **/ 
     168        function _playlistHandler(event) { 
     169            if(_options.file) { 
     170                _player.getPlaylist()[0]['captions.file'] = _options.file; 
     171            } 
     172            if(_options.files) { 
     173                _player.getPlaylist()[0]['captions.files'] = _options.files; 
     174            }  
     175            if(_options.labels) { 
     176                _player.getPlaylist()[0]['captions.labels'] = _options.labels; 
     177            } 
     178        }; 
     179 
     180 
     181        /** Update the interface. **/ 
     182        function _redraw() { 
     183            if(!_tracks.length) { 
     184                _player.getPlugin("dock").setButton('captions',dockHandler,_icons[0]); 
     185                _renderer.hide(); 
     186            } else if (_options.state) { 
     187                _player.getPlugin("dock").setButton('captions',dockHandler,_icons[2]); 
     188                if(_state == 'playing') { 
     189                    _renderer.show(); 
     190                } else { 
     191                    _renderer.hide(); 
     192                } 
     193            } else { 
     194                _player.getPlugin("dock").setButton('captions',dockHandler,_icons[1]); 
     195                _renderer.hide(); 
     196            } 
     197        }; 
     198 
     199        /** Reposition elements upon a resize. **/ 
     200        this.resize = function(width,height) { 
     201            if(_player.getRenderingMode() == 'flash') { return; } 
     202            _renderer.resize(width,height); 
     203            _selector.resize(width,height); 
     204        }; 
     205 
     206 
     207        /** Set dock buttons when player is ready. **/ 
     208        function _setup() { 
     209            if(_player.getRenderingMode() == 'flash') { return; } 
     210            // Listen to player events 
     211            _player.onPlaylist(_playlistHandler); 
     212            _player.onPlaylistItem(_itemHandler); 
     213            _player.onIdle(_idleHandler); 
     214            _player.onPlay(_playHandler); 
     215            _player.onTime(_timeHandler); 
     216            // Grab cookies and config options 
     217            if(_cookie('state') !== null) { 
     218                if(_cookie('state') == 'true') {  
     219                    _options.state = true; 
     220                } else { 
     221                    _options.state = false; 
     222                } 
     223            } 
     224            if(_cookie('label') !== null) { 
     225                _options.label = _cookie('label'); 
     226            } 
     227            for (var option in options) { 
     228                _options[option] = options[option]; 
     229            } 
     230            // Place renderer and selector. 
     231            _renderer = new jwplayer.captions.renderer(_options,_div); 
     232            _selector = new jwplayer.captions.selector(_selectorHandler,_div); 
     233            _redraw(); 
     234        }; 
     235        _player.onReady(_setup); 
     236 
     237 
     238        /** Selection menu was closed. **/ 
     239        function _selectorHandler(index) { 
     240            // Show dock/display for 5.7+ 
     241            _selector.hide(); 
     242            try { 
     243                _player.getPlugin('display').show(); 
     244                _player.getPlugin('dock').show(); 
     245            } catch (error) {} 
     246            // Store new state and track 
     247            if(index > 0) { 
     248                _options.state = true; 
     249                _track = index - 1; 
     250                _options.label = _tracks[_track].label; 
     251            } else { 
     252                _config.state = false; 
     253            } 
     254            _cookie('label',_options.label); 
     255            _cookie('state',_options.state); 
     256            // Load new captions 
     257            if(_tracks[_track].data) { 
     258                _renderer.populate(_tracks[_track].data); 
     259            } else { 
     260                _load(_tracks[_track].file); 
     261            } 
     262            _redraw(); 
     263        }; 
     264 
     265 
     266        /** Listen to player time updates. **/ 
     267        function _timeHandler(event) { 
     268            _renderer.update(event.position); 
     269        }; 
     270 
     271 
    11272    }; 
    12     _player.onReady(_setup); 
    13  
    14  
    15     /** Reposition elements upon a resize. **/ 
    16     this.resize = function(width,height) { 
    17         if(_player.getRenderingMode() == 'flash') { return; } 
    18     }; 
    19  
    20  
    21     /** Apply CSS styles to elements. **/ 
    22     function _style(element,styles) { 
    23         for(var property in styles) { 
    24           element.style[property] = styles[property]; 
    25         } 
    26      }; 
    27  
    28  
    29 }; 
    30  
    31  
    32 /** Register the plugin with JW Player. **/ 
    33 jwplayer().registerPlugin('captions', template,'./captions.swf'); 
     273 
     274 
     275    /** Claim the namespace and register the plugin. **/ 
     276    jwplayer.captions = {}; 
     277    jwplayer().registerPlugin('captions', template,'./captions.swf'); 
    34278 
    35279 
  • plugins/captions/src/js/captions.renderer.js

    r1941 r1973  
     1(function(jwplayer) { 
     2 
     3 
     4    /** Component that renders the actual captions on screen. **/ 
     5    jwplayer.captions.renderer = function(_options,_div) { 
     6 
     7 
     8        /** Current list with captions. **/ 
     9        var _captions; 
     10        /** Container with captions data. **/ 
     11        var _container; 
     12        /** Current video position. **/ 
     13        var _position; 
     14        /** Current actie captions entry. **/ 
     15        var _current; 
     16 
     17 
     18        /** Hide the rendering component. **/ 
     19        this.hide = function() { 
     20            _style({display:'none'}); 
     21        }; 
     22 
     23 
     24        /** Assign list of captions to the renderer. **/ 
     25        this.populate = function(captions) { 
     26            _current = -1; 
     27            _captions = captions; 
     28            _select(); 
     29        }; 
     30 
     31 
     32        /** Render the active caption. **/ 
     33        function _render(html) { 
     34            _container.innerHTML = html; 
     35        }; 
     36 
     37 
     38        /** Resize the captions. **/ 
     39        this.resize = function(width,height) { 
     40            /** 
     41            if(_player.config.fullscreen) { 
     42                _renderer.x = width / 8; 
     43                _renderer.width = width * 3 / 4; 
     44            } else { 
     45                _renderer.x = width / 24; 
     46                _renderer.width = width * 11 / 12; 
     47            } 
     48            _renderer.scaleY = _renderer.scaleX; 
     49            // Position the captions, taking controls into account. 
     50            if (_player.config.fullscreen) { 
     51                _renderer.y = height - 70; 
     52            } else if (_player.config.controlbar == 'over') { 
     53                _renderer.y = height - 50; 
     54            } else { 
     55                _renderer.y = height - 20; 
     56            } 
     57            **/ 
     58        }; 
     59 
     60 
     61        /** Select a caption for rendering. **/ 
     62        function _select() { 
     63            var found = -1; 
     64            for (var i=0; i < _captions.length; i++) { 
     65                if (_captions[i]['begin'] <= _position &&  
     66                    (i == _captions.length-1 || _captions[i+1]['begin'] >= _position)) { 
     67                    found = i; 
     68                    break; 
     69                } 
     70            } 
     71            // If none, empty the text. If not current, re-render. 
     72            if(found == -1) { 
     73                _render(''); 
     74            } else if (found != _current) { 
     75                _current = found; 
     76                _render(_captions[i]['text']); 
     77            } 
     78        }; 
     79 
     80 
     81        /** Constructor for the renderer. **/ 
     82        function _setup() { 
     83            _container = document.createElement("p"); 
     84            _div.appendChild(_container); 
     85            _style({ 
     86                color: _options.color, 
     87                fontFamily: _options.fontFamily, 
     88                fontSize: _options.fontSize+'px', 
     89                fontStyle: _options.fontStyle, 
     90                fontWeight: _options.fontWeight, 
     91                lineHeight: Math.round(_options.fontSize * 1.4)+'px', 
     92                textAlign: 'center', 
     93                textDecoration: _options.textDecoration 
     94            }); 
     95            if(_options.back) {  
     96                _style({textShadow: '#000 1px 1px 0'}); 
     97            } else {  
     98                _style({background:'#000'}); 
     99            } 
     100        }; 
     101        _setup(); 
     102 
     103 
     104        /** Show the rendering component. **/ 
     105        this.show = function() { 
     106            _style({display:'block'}); 
     107        }; 
     108 
     109 
     110        /** Apply CSS styles to elements. **/ 
     111        function _style(styles) { 
     112            for(var property in styles) { 
     113              _container.style[property] = styles[property]; 
     114            } 
     115        }; 
     116 
     117 
     118        /** Update the video position. **/ 
     119        this.update = function(position) { 
     120            _position = position; 
     121            if(_captions) { 
     122                _select(); 
     123            } 
     124        }; 
     125 
     126 
     127    }; 
     128 
     129 
     130})(jwplayer); 
  • plugins/captions/src/js/captions.selector.js

    r1941 r1973  
     1(function(jwplayer) { 
     2 
     3 
     4    /** Component that renders a selection menu. **/ 
     5    jwplayer.captions.selector = function(_callback,_div) { 
     6 
     7 
     8        /** Hide the language selector. **/ 
     9        this.hide = function() {}; 
     10 
     11 
     12        /** Polulate the selector with a list of options. **/ 
     13        this.populate = function(options, active) {}; 
     14 
     15 
     16        /** Resize the selector to fit the display. **/ 
     17        this.resize = function(width,height) {}; 
     18 
     19 
     20        /** Show the language selector. **/ 
     21        this.show = function() {}; 
     22 
     23 
     24        /** Apply CSS styles to elements. **/ 
     25        function _style(element,styles) { 
     26            for(var property in styles) { 
     27              element.style[property] = styles[property]; 
     28            } 
     29        }; 
     30 
     31 
     32    }; 
     33 
     34 
     35})(jwplayer); 
  • plugins/captions/src/js/captions.srt.js

    r1941 r1973  
     1(function(jwplayer) { 
     2 
     3 
     4    /** Component that loads and parses an SRT file. **/ 
     5    jwplayer.captions.srt = function(_success, _failure) { 
     6 
     7 
     8        /** XMLHTTP Object. **/ 
     9        var _request; 
     10        /** URL of the SRT file. **/ 
     11        var _url; 
     12 
     13 
     14        /** Handle errors. **/ 
     15        function _error(status) { 
     16            if(status == 0) { 
     17                _failure("Crossdomain loading denied: "+_url); 
     18            } else if (status == 404) {  
     19                _failure("SRT File not found: "+_url); 
     20            } else {  
     21                _failure("Error "+status+" loading SRT file: "+_url); 
     22            } 
     23        }; 
     24 
     25 
     26        /** Load a new SRT file. **/ 
     27        this.load = function(url) { 
     28            _url = url; 
     29            try { 
     30                _request.open("GET", url, true); 
     31                _request.send(null); 
     32            } catch (error) { 
     33                _failure("Error loading SRT File: "+url); 
     34            } 
     35        }; 
     36 
     37 
     38        /** Proceed from loading to parsing. **/ 
     39        function _parse(data) { 
     40            _captions = [{begin:0,text:''}]; 
     41            // Trim whitespace and split the list by returns. 
     42            data = data.replace(/^\s+/, '').replace(/\s+$/, ''); 
     43            var list = data.split("\r\n\r\n"); 
     44            if(list.length == 1) { list = data.split("\n\n"); } 
     45            for(var i=0; i<list.length; i++) { 
     46                // Parse each entry 
     47                var entry = _entry(list[i]); 
     48                if(entry['begin'] && entry['text']) { 
     49                    _captions.push(entry); 
     50                    // Insert empty caption at the end. 
     51                    if(entry['end']) { 
     52                        _captions.push({begin:entry['end'],text:''}); 
     53                        delete entry['end']; 
     54                    } 
     55                } 
     56            } 
     57            if(_captions.length > 1) { 
     58                _success(_captions); 
     59            } else { 
     60                _failure("Invalid SRT file: "+_url); 
     61            } 
     62        }; 
     63 
     64 
     65        /** Parse a single captions entry. **/ 
     66        function _entry(data) { 
     67            var entry = {}; 
     68            var array = data.split("\r\n"); 
     69            if(array.length == 1) { array = data.split("\n"); } 
     70            try { 
     71                // Second line contains the start and end. 
     72                var index = array[1].indexOf(' --> '); 
     73                if(index > 0) { 
     74                    entry['begin'] = _seconds(array[1].substr(0,index)); 
     75                    entry['end'] = _seconds(array[1].substr(index+5)); 
     76                } 
     77                // Third line starts the text. 
     78                if(array[2]) { 
     79                    entry['text'] = array[2]; 
     80                    // Arbitrary number of additional lines. 
     81                    for (var i=3; i<array.length; i++) { 
     82                        entry['text'] += '<br/>' + array[i]; 
     83                    } 
     84                } 
     85            } catch (error) {} 
     86            return entry; 
     87        }; 
     88 
     89 
     90        /** Convert timecode to seconds. **/ 
     91        function _seconds(string) { 
     92            string = string.replace(',', '.'); 
     93            var array = string.split(':'); 
     94            var number = 0; 
     95            if (string.substr(-1) == 's') { 
     96                number = Number(string.substr(0, string.length - 1)); 
     97            } else if (string.substr(-1) == 'm') { 
     98                number = Number(string.substr(0, string.length - 1)) * 60; 
     99            } else if (string.substr(-1) == 'h') { 
     100                number = Number(string.substr(0, string.length - 1)) * 3600; 
     101            } else if (array.length > 1) { 
     102                number = Number(array[array.length - 1]); 
     103                number += Number(array[array.length - 2]) * 60; 
     104                if (array.length == 3) { 
     105                    number += Number(array[array.length - 3]) * 3600; 
     106                } 
     107            } else { 
     108                number = Number(string); 
     109            } 
     110            return number; 
     111        }; 
     112 
     113 
     114        /** Setup the SRT parser. **/ 
     115        function _setup() { 
     116            _request = new XMLHttpRequest(); 
     117            _request.onreadystatechange = function() { 
     118                if (_request.readyState === 4) { 
     119                    if (_request.status === 200) { 
     120                        _parse(_request.responseText); 
     121                    } else { 
     122                        _error(_request.status); 
     123                    } 
     124                } 
     125            }; 
     126        }; 
     127        _setup(); 
     128 
     129 
     130    }; 
     131 
     132 
     133})(jwplayer); 
  • plugins/captions/test/assets/bunny-ned.txt

    r1964 r1973  
    993 
    101000:00:11,000 --> 00:00:13,000 
    11 Drie knaagdieren 
     11Drie knagers 
    1212 
    13134 
  • plugins/captions/test/assets/playlist.xml

    r1769 r1973  
    66      <title>Coronation Street</title> 
    77      <description>Single, external XML captions.</description> 
    8       <jwplayer:file>http://content.bitsontherun.com/videos/7OCSON1y-393434.flv</jwplayer:file> 
     8      <jwplayer:file>http://content.bitsontherun.com/videos/7OCSON1y.mp4</jwplayer:file> 
    99      <jwplayer:image>http://content.bitsontherun.com/thumbs/7OCSON1y-320.jpg</jwplayer:image> 
    1010      <jwplayer:captions.file>assets/corrie.xml</jwplayer:captions.file> 
  • plugins/captions/test/basic.html

    r1964 r1973  
    55<meta charset="UTF-8"> 
    66<script type="text/javascript" src="assets/jwplayer.min.js"></script> 
    7 <title>Single Track</title> 
     7<title>Basic Setup</title> 
    88<style> 
    99    body { padding: 50px; font: 13px/20px Arial; background: #EEE; } 
    1010    form,p, ul { margin-top: 20px; } 
    11     #player { -webkit-box-shadow: 0 0 5px #999; background: #000; color:#FFF; line-height:270px; text-align: center; } 
     11    #player { -webkit-box-shadow: 0 0 5px #999; } 
    1212</style> 
    1313 
     
    1515<body> 
    1616 
    17 <h2>Single Track</h2> 
     17<h2>Basic Setup</h2> 
    1818 
    1919<div id="player"></div> 
     
    2121function loadPlayer(key,captions) { 
    2222    var options = { 
    23         file: 'http://content.bitsontherun.com/videos/'+key+'-393434.flv', 
     23        file: 'http://content.bitsontherun.com/videos/'+key+'.mp4', 
    2424        height: 270, 
    25         image: 'http://content.bitsontherun.com/thumbs/'+key+'-480.jpg', 
     25        image: 'http://content.bitsontherun.com/thumbs/'+key.substr(0,8)+'-480.jpg', 
    2626        plugins: { 
    2727            '../captions.js': {} 
     
    4242    <li><a href="javascript:loadPlayer('7OCSON1y','assets/corrie.srt')">srt captions</a></li> 
    4343    <li><a href="javascript:loadPlayer('7OCSON1y','assets/corrie.xml')">dfxp captions</a></li> 
    44     <li><a href="javascript:loadPlayer('aytCR4cx')">mp4 captions</a></li> 
    45     <li><a href="javascript:loadPlayer('7OCSON1y','assets/corri.xml')">nonexisting file</a></li> 
     44    <li><a href="javascript:loadPlayer('aytCR4cx-393434')">mp4 captions</a></li> 
    4645</ul> 
    4746 
  • plugins/captions/test/compatibility.html

    r1964 r1973  
    99    body { padding: 50px; font: 13px/20px Arial; background: #EEE; } 
    1010    #player, p, ul { margin-top: 20px; display: block; } 
    11     #player { -webkit-box-shadow: 0 0 5px #999; background: #000; color:#FFF; line-height:270px; text-align: center; } 
     11    #player { -webkit-box-shadow: 0 0 5px #999; } 
    1212</style> 
    1313 
  • plugins/captions/test/index.html

    r1964 r1973  
    2727<ul> 
    2828    <li><a href="compatibility.html">Backward Compatibility</a></li> 
     29    <li><a href="errors.html">Error Handling</a></li> 
    2930    <li><a href="ova.html">OVA Support</a></li> 
    3031</ul> 
  • plugins/captions/test/modes.html

    r1964 r1973  
    99    body { padding: 50px; font: 13px/20px Arial; background: #EEE; } 
    1010    form,p, ul { margin-top: 20px; } 
    11     #player { -webkit-box-shadow: 0 0 5px #999; background: #000; color:#FFF; } 
     11    #player { -webkit-box-shadow: 0 0 5px #999;} 
    1212</style> 
    1313 
  • plugins/captions/test/multiple.html

    r1964 r1973  
    4444 
    4545<ul> 
    46     <li><a href="javascript:loadPlayer({file:'http://content.bitsontherun.com/jwp/aytCR4cx.xml'},{files:'assets/bunny-eng.txt,assets/bunny-ned.txt',labels:'English,Nederlands'})">2 external srt tracks</a></li> 
     46    <li><a href="javascript:loadPlayer({file:'http://content.bitsontherun.com/videos/aytCR4cx.mp4'},{files:'assets/bunny-eng.txt,assets/bunny-ned.txt',labels:'English,Nederlands'})">2 external srt tracks</a></li> 
    4747 
    4848    <li><a href="javascript:loadPlayer({file:'http://content.bitsontherun.com/videos/w5VkaqJ1-393434.mp4',image:'http://content.bitsontherun.com/thumbs/w5VkaqJ1-480.jpg'},{})">6 embedded mp4 tracks</a></li> 
    4949     
    50     <li><a href="javascript:loadPlayer({file:'http://content.bitsontherun.com/jwp/a95zAVN1.xml'},{files:'assets/sintel-chi.txt,assets/sintel-deu.txt,assets/sintel-dut.txt,assets/sintel-eng.txt,assets/sintel-far.txt,assets/sintel-fra.txt,assets/sintel-gre.txt,assets/sintel-ita.txt,assets/sintel-jpn.txt,assets/sintel-kor.txt,assets/sintel-pol.txt,assets/sintel-por.txt,assets/sintel-rus.txt,assets/sintel-spa.txt,assets/sintel-srp.txt,assets/sintel-tur.txt',labels:'Chinese,German,Dutch,English,Farsi,French,Greek,Italian,Japanese,Korean,Polish,Portuguese,Russian,Spanish,Serbian,Turkish'})">16 external srt tracks</a></li> 
     50    <li><a href="javascript:loadPlayer({file:'http://content.bitsontherun.com/videos/a95zAVN1.mp4'},{files:'assets/sintel-chi.txt,assets/sintel-far.txt,assets/sintel-gre.txt,assets/sintel-jpn.txt,assets/sintel-kor.txt,assets/sintel-pol.txt,assets/sintel-rus.txt,assets/sintel-srp.txt,assets/sintel-tur.txt',labels:'Chinese,Farsi,Greek,Japanese,Korean,Polish,Russian,Serbian,Turkish'})">9 external srt tracks</a></li> 
     51     <li><a href="javascript:loadPlayer({file:'http://content.bitsontherun.com/videos/aytCR4cx.mp4'},{files:'assets/bunny-eng.txt,assets/bunny-ned.txt'})">2 srt tracks, no labels</a></li> 
     52 
    5153 
    5254</ul> 
  • plugins/captions/test/options.html

    r1964 r1973  
    1919<div id="player"></div> 
    2020<script type="text/javascript"> 
    21 function loadPlayer(dock,back,state) { 
     21function loadPlayer(back,state) { 
    2222    var options = { 
    2323        controlbar: 'bottom', 
    24         file: 'http://content.bitsontherun.com/videos/aytCR4cx-393434.mp4', 
     24        file: 'http://content.bitsontherun.com/videos/7OCSON1y.mp4', 
    2525        height: 296, 
    26         image: 'http://content.bitsontherun.com/thumbs/aytCR4cx-480.jpg', 
     26        image: 'http://content.bitsontherun.com/thumbs/7OCSON1y-480.jpg', 
    2727        plugins: { 
    28             '../captions.js': {} 
     28            '../captions.js': { 
     29                file: 'assets/corrie.srt' 
     30            } 
    2931        }, 
    3032        flashplayer: 'assets/player.swf', 
    3133        width: 480 
    3234    }; 
    33     if(dock !== undefined) {  
    34         options.dock = dock; 
    35         options.plugins['../captions.swf'].back = back; 
    36         options.plugins['../captions.swf'].state = state; 
     35    if(back !== undefined) {  
     36        options.plugins['../captions.js'].back = back; 
     37        options.plugins['../captions.js'].state = state; 
    3738    } 
    3839    jwplayer("player").setup(options); 
     
    4344<ul> 
    4445    <li><a href="javascript:loadPlayer()">Default options</a></li> 
    45     <li><a href="javascript:loadPlayer(true,true,true)">Dock true, back true, state true</a></li> 
    46     <li><a href="javascript:loadPlayer(false,false,false)">Dock false, back false, state false</a></li> 
     46    <li><a href="javascript:loadPlayer(true,true)">Back true, state true</a></li> 
     47    <li><a href="javascript:loadPlayer(false,false)">Back false, state false</a></li> 
    4748</ul> 
    4849 
  • plugins/captions/test/playlist.html

    r1964 r1973  
    99    body { padding: 50px; font: 13px/20px Arial; background: #EEE; } 
    1010    form,p, ul { margin-top: 20px; } 
    11     #player { -webkit-box-shadow: 0 0 5px #999; background: #000; color:#FFF; line-height:270px; text-align: center; } 
     11    #player { -webkit-box-shadow: 0 0 5px #999; } 
    1212</style> 
    1313 
     
    3232        width: 800 
    3333    } 
    34     if(typeof(list) == 'string') {  
     34    if(typeof(list) == 'string') { 
    3535        options.file = list; 
    3636    } else {  
     
    4343    title: 'Coronation Street', 
    4444    description: 'Single, external XML captions.', 
    45     file: 'http://content.bitsontherun.com/videos/7OCSON1y-393434.flv',  
     45    file: 'http://content.bitsontherun.com/videos/7OCSON1y.mp4',  
    4646    image: 'http://content.bitsontherun.com/thumbs/7OCSON1y-320.jpg', 
    4747    'captions.file': 'assets/corrie.xml' 
     
    4949      title:'Big Buck Bunny', 
    5050      description: 'Single, embedded MP4 captions.', 
    51       file: 'http://content.bitsontherun.com/videos/aytCR4cx-393434.mp4', 
     51      file: 'http://content.bitsontherun.com/videos/aytCR4cx.mp4', 
    5252      image: 'http://content.bitsontherun.com/thumbs/aytCR4cx-320.jpg' 
    5353},{ 
    5454      title: 'Men With Talent', 
    5555      description: 'No captions at all.', 
    56       file: 'http://content.bitsontherun.com/videos/SAs4hE5G-364766.mp4', 
     56      file: 'http://content.bitsontherun.com/videos/SAs4hE5G.mp4', 
    5757      image: 'http://content.bitsontherun.com/thumbs/SAs4hE5G-320.jpg' 
    5858},{ 
    5959      title: 'Global Timoto', 
    6060      description: 'Multiple, embedded MP4 captions.', 
    61       file: 'http://content.bitsontherun.com/videos/w5VkaqJ1-393434.mp4', 
     61      file: 'http://content.bitsontherun.com/videos/w5VkaqJ1.mp4', 
    6262      image: 'http://content.bitsontherun.com/thumbs/w5VkaqJ1-320.jpg' 
    6363},{ 
    6464    title: 'Sintel', 
    6565     description: 'Multiple, external SRT captions.', 
    66       file: 'http://content.bitsontherun.com/videos/q1fx20VZ-364765.mp4', 
     66      file: 'http://content.bitsontherun.com/videos/q1fx20VZ.mp4', 
    6767      image: 'http://content.bitsontherun.com/thumbs/q1fx20VZ-320.jpg', 
    6868      'captions.files': 'assets/sintel-dut.txt,assets/sintel-eng.txt,assets/sintel-fra.txt,assets/sintel-deu.txt,assets/sintel-ita.txt,assets/sintel-pol.txt,assets/sintel-por.txt,assets/sintel-rus.txt,assets/sintel-spa.txt' 
     
    7575</ul> 
    7676<ul> 
    77     <li><a href="javascript:jwplayer().load({file:'http://content.bitsontherun.com/videos/7OCSON1y-393434.flv','captions.file':'assets/corrie.xml',title: 'Coronation Street'})">load() one video</a> 
     77    <li><a href="javascript:jwplayer().load({file:'http://content.bitsontherun.com/videos/7OCSON1y.mp4','captions.file':'assets/corrie.xml',title: 'Coronation Street'})">load() one video</a> 
    7878    <li><a href="javascript:jwplayer().load('assets/playlist.xml')">load() RSS feed</a> 
    7979</ul> 
Note: See TracChangeset for help on using the changeset viewer.