mardi 29 septembre 2015

JW Player - Amazon Web Services CDN and Advanced Javascript Debugging

I have a customized JW Player 7 Pro embedded on the following page: http://ift.tt/1h6QrvA.

The embed code is as follows:

<!--Course Video, Scripts and Style-->
<div id="visualSPPlayer">Loading the player...</div>
<script type="text/javascript">
var playerInstance = jwplayer("visualSPPlayer");
playerInstance.setup({
file: "http://ift.tt/1iYHeHv",
primary: "HTML5",
image: "http://ift.tt/1h6QrLO",
   width: "100%",
aspectratio: "16:9",
       tracks :[{
file: "http://ift.tt/1iYHciL", 
            label: "English",
            kind: "captions",
        },{
              file:'http://ift.tt/1h6QrLT',
               kind:'chapters'

},
{ 
            file: "http://ift.tt/1iYHeHx", 
            kind: "thumbnails"
        }],
skin: {
  name: "vapor",
active: "#E16933",
inactive: "#E16933",
background: "#333333"
}

});
</script>
<script type="application/javascript" src="http://ift.tt/1h6QrLV"></script>
<link rel="stylesheet" href="http://ift.tt/1iYHciN" type="text/css" media="screen" />

The player.js file contents:

jQuery(document).ready(function() {

jQuery(function($){

var playerInstance = jwplayer();

var chapters = [];
var captions = [];
var toc = [];
var caption = -1;
var matches = [];
var seekArr = [];
 var seekPos = [];
var seePos;
var query = "";
var cycle = -1;

var transcript = document.getElementById('courseTranscript');
var search = document.getElementById('courseSearch');
var match = document.getElementById('courseMatch');


var caption_file;
var chapter_file;


playerInstance.onReady(function(){
        
//Self-Hosted
caption_file = playerInstance.getPlaylist()[0].tracks[0].file;
chapter_file = playerInstance.getPlaylist()[0].tracks[1].file;

    if (playerInstance.getRenderingMode() == "flash") {
        return;
      }

      tag = document.querySelector('video');
      tag.defaultPlaybackRate = 1.0;
      tag.playbackRate = 1.0;

      playerInstance.addButton("http://ift.tt/1h6QtU5", "1.5x", function() {
        playerInstance.seek(playerInstance.getPosition());
        tag.playbackRate = 1.5;
      },"playerHighSpeed");

      playerInstance.addButton("http://ift.tt/1iYHciP", "1.0x", function() {
        playerInstance.seek(playerInstance.getPosition());
        tag.playbackRate = 1.0;
      },"playerNormalSpeed");

    playerInstance.addButton("http://ift.tt/1h6QtU8", "0.5x", function(){
        playerInstance.seek(playerInstance.getPosition());
        tag.playbackRate = 0.5;
      },"playerSlowSpeed");


     
 });

   

 //Adds Player Focus on Playing
playerInstance.on('play', function() {

         $('html, body').animate({
        scrollTop: $(".jwplayer").offset().top - 190
    }, 1000);

});


playerInstance.onReady(function(){

 $.get( caption_file , function( data ) {
                 data = data.trim();
                     var t = data.split("\n\r\n");
             
                      for(var i=0; i<t.length; i++) {
                        var c = parse(t[i]);
                        chapters.push(c);

                      }
                      loadCaptions();
          loadChapters();
          
                    });

        //

 });



// Load chapters / captions


  function loadCaptions(){
       
     $.get(caption_file, function( data ) {
  
        data = data.trim();

      var t = data.split("\n\r\n");
      t.pop();
      var h = "<p>";
      var s = 0;
      for(var i=0; i<t.length; i++) {
        var c = parse(t[i]);
        if(s < chapters.length && c.begin > chapters[s].begin) {
           s++;
        }
        h += "<span id='caption"+i+"'>"+c.text+"</span>";
        captions.push(c);
      }
      transcript.innerHTML = h + "</p>";


    });

};



function parse(d) {
    var a = d.split("\n");
   
    //console.log(a[1]);
    var i = a[1].indexOf(' --> ');

    var t = a[2]; //Caption text
 

    if (a[3]) {  t += " " + a[3]; }
    t = t.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    return {
      begin: seconds(a[1].substr(0,i)),
      btext: a[1].substr(3,i-7),
      end: seconds(a[1].substr(i+5)),
      text: t
    }
};

function seconds(s) {
  var a = s.split(':');
 
  secs = a[2].substring(0, a[2].indexOf(','));

    var r = Number(secs) + Number(a[a.length-2]) * 60;


  if(a.length > 2) { r+= Number(a[a.length-3]) * 3600; }
  return r;

};

function toc_seconds(s) {
  var a = s.split(':');
 
secs = a[2].substring(0, a[2].indexOf('.'));
  
   var r = Number(secs) + Number(a[a.length-2]) * 60;

  if(a.length > 2) { r+= Number(a[a.length-3]) * 3600; }
  return r;

};

function toc_time(s) {
  var a = s.split(':');
   var ms = a[2].split(".");

   var h = a[0];
  
   if (h != "00") {
        var r = a[0] + ":"+ a[1] + ":" + ms[0]; 
   } else {
        var r = a[1] + ":" + ms[0];     
   }

  
   return r;

};



// Highlight current caption and chapter
playerInstance.onTime(function(e){
  var p = e.position;
  for(var j=0; j<captions.length; j++) {
    if(captions[j].begin < p && captions[j].end > p) {
      if(j != caption) {
        var c = document.getElementById('caption'+j);
        if(caption > -1) {
          document.getElementById('caption'+caption).className = "";
        }
        c.className = "current";
        if(query == "") {
          transcript.scrollTop = c.offsetTop - transcript.offsetTop - 40;
        }
        caption = j;
      }
      break; 
    }
  }
});



// Hook up interactivity
transcript.addEventListener("click",function(e) {
  if(e.target.id.indexOf("caption") == 0) { 
    var i = Number(e.target.id.replace("caption",""));
    playerInstance.seek(captions[i].begin);
  }
});

/**/

search.addEventListener('focus',function(e){
  setTimeout(function(){search.select();},100);
resetSearch();
  $("#prevMatchLink").hide();
    $("#nextMatchLink").hide();
});
search.addEventListener('keydown',function(e) {
  if(e.keyCode == 27) {
    resetSearch();
    $("#prevMatchLink").hide();
    $("#nextMatchLink").hide();
  } else if (e.keyCode == 13) {
    $("#prevMatchLink").show();
    $("#nextMatchLink").show();
    var q = this.value.toLowerCase();
    if(q.length > 0) {
      if (q == query) {
        if(cycle >= matches.length - 1) {
          cycleSearch(0);

          } else { 

          cycleSearch(cycle + 1);
        }
      } else {
        resetSearch();
        searchTranscript(q);
      }
    } else {
      resetSearch();
    }
  } else if (e.keyCode == 37) {
    cycleSearch(cycle - 1);
  }
  else if (e.keyCode == 39) {
    cycleSearch(cycle + 1);
  }
});

$("#prevMatchLink").click(function(e) {
e.preventDefault();
cycleSearch(cycle - 1);
});

$("#nextMatchLink").click(function(e) {
e.preventDefault();
cycleSearch(cycle + 1);
});



// Execute search
function searchTranscript(q) {
  matches = [];
  query = q;
  for(var i=0; i<captions.length; i++) {
    var m = captions[i].text.toLowerCase().indexOf(q);
    if( m > -1) {
      document.getElementById('caption'+i).innerHTML = 
        captions[i].text.substr(0,m) + "<em>" + 
        captions[i].text.substr(m,q.length) + "</em>" + 
        captions[i].text.substr(m+q.length);
      matches.push(i);
    }
  }
  if(matches.length) {
    cycleSearch(0);
  } else {
    resetSearch();
  }
};

function cycleSearch(i) {
  if(cycle > -1) {
    var o = document.getElementById('caption'+matches[cycle]);
    o.getElementsByTagName("em")[0].className = "";
  }
  var c = document.getElementById('caption'+matches[i]);
  c.getElementsByTagName("em")[0].className = "current";
  match.innerHTML = (i+1) + " of " + matches.length;
  transcript.scrollTop = c.offsetTop - transcript.offsetTop - 40;
  cycle = i;
};

function resetSearch() {
  if(matches.length) {
    for(var i=0; i<captions.length; i++) {
      document.getElementById('caption'+i).innerHTML = captions[i].text;
    }
  }
  query = "";
  matches = [];
  match.innerHTML = "0 of 0";
  cycle = -1;
  transcript.scrollTop = 0;
};


var videoTitle = $(".videoTitle").text();


        var hasPlayed = false;

        playerInstance.onBeforePlay(function(event) {
                if(hasPlayed == false){
                        ga('send', 'event', 'Video', 'Play', videoTitle);
                        hasPlayed = true;
                }
        });


    //Can be used to trigger the Course to Marked Completed so the user doesn't have to
    playerInstance.on('complete', function() {

    });


     function loadChapters(){
       
     $.get(chapter_file, function( data ) {
  
        data = data.trim();
               
      var c = data.split("\n\r\n");
      
      var d;

      for (var i = 0; i < c.length; i++) {
      
        d = c[i].split("\n");
        //pushes in Title for each chapter
        toc.push(d[0]);
        //pushes in the time intervals for each chapter
        seekArr.push(d[1]);
        
      };

       

      for (var a = 0; a < seekArr.length; a++) {
        //Splits the time interval and pushes the start interval for each chapter
        var tempPos = seekArr[a].split(" --> ");
        seekPos.push(tempPos[0]);
      };

      runTOC(seekPos);

      var toc_output = "";
      $.each(toc, function(i, v) {
       
        toc_output += "<li class=ch"+i+"><a href='#' onclick='jwplayer().seek("+toc_seconds(seekPos[i])+");'>"+v+"</a> ("+toc_time(seekPos[i])+")</li>"
      
      });

      if (toc.length < 7) {
      toc_output += " <li class='blank'> </li><li class='blank'> </li>";
      }

      $(".courseTitles ul").html(toc_output);
    
    });

         

};
     
      function runTOC(x) {
     
          playerInstance.onTime(function(event){
          
          for (var i = 0; i < x.length; i++) {
           
           if (event.position >  toc_seconds(x[i]) ) {
            $(".courseTitles ul li").removeClass("active");
            $(".courseTitles ul li.ch"+i).addClass('active');
          
          }


          };

         


        });

      
      }

     
});

});

We are hosting the video and Chapter/Captions VTT files using Amazon Web Services with Cloudfront.

We have included the interactive transcript from the captions as well as dynamic video chapters to be loaded once the video is ready to be played.

One thing I have noticed is that the chapters and the transcript do not always load and require the page to be refreshed several times so I was thinking that maybe it was a caching issue on the AWS side of the equation.

I have used Google Chrome and there are no errors in the developers console when the chapters and transcript do not load.

It should be noted that this functionality was working flawlessly when were using the JW Platform cloud hosted solution so it seems to be a factor of the AWS/Cloudfront CDN.




Aucun commentaire:

Enregistrer un commentaire