function IncPlayer()
{
// --------------------------------------------------------------------------------------------------------------------
// Members
// --------------------------------------------------------------------------------------------------------------------
// Global
this.initDone = false;
this.playerIsReady = false;
this.playerWaitForBeingReady = false; // used on ipad
this.mobile;
this.ipad;
this.nextPage;
this.reloadPage;
// Sequences
this.allSequencesData = [];
this.sequences = [];
this.singleVideo;
// Popcorn objects
this.videoDivId = "";
this.videoExt = "";
this.popSeq = null;
// Controls
this.playButton = null;
this.hdSdButton = null
this.progressCurrent = null;
this.progressDuration = null;
this.progressCursor = null;
this.progressBar = null;
this.progressCursorX = 0;
this.progressCursorDrag;
this.hd;
this.seekTime = -1;
// Tools
this.logiEnable = true;
this.jsonData = [];
// --------------------------------------------------------------------------------------------------------------------
// Functions
// --------------------------------------------------------------------------------------------------------------------
this.init = function(nextPage, videoDivId, playButtonId, hdSdButtonId, progressCurrentId, progressDurationId, progressCursorId, progressBarId, jsonFile)
{
this.nextPage = nextPage;
this.videoDivId = videoDivId;
// Control
this.playButton = $("#" + playButtonId).get(0);
this.hdSdButton = $("#" + hdSdButtonId).get(0);
this.progressCurrent = $("#" + progressCurrentId);
this.progressDuration = $("#" + progressDurationId);
this.progressCursor = $("#" + progressCursorId);
this.progressBar = $("#" + progressBarId);
this.ctrlSetCursorDragFunction();
this.setCursorPosition(0);
// HD ?
this.hd = incChoice.getHD();
$(this.hdSdButton).css({"background-position" : this.hd ? '0 -12px' : '0 0'});
// Video extention
this.videoExt = this.getSupportedVideoExt();
if (this.videoExt === "") {
this.loge("your browser don't support HTML5 videos");
return false;
}
if (jsonFile !== null & jsonFile !== undefined) {
// Load all sequences data
this.allSequencesData = this.loadJson(jsonFile);
// Add index to the videos
for (var i = 0; i < this.allSequencesData.videos.length; ++i) {
this.allSequencesData.videos[i].index = i;
}
}
this.initDone = true;
this.mobile = IsSmartphone();
this.ipad = !this.mobile && IsIpad();
return true;
};
this.destroySequence = function()
{
if (this.popSeq !== null) {
for (var i = 0; i < this.sequences.length; ++i) {
this.popSeq.eq(i).destroy();
}
this.sequences = [];
this.popSeq.remove();
}
};
this.createPopSequence = function(words, videosIndex, paramIndex)
{
if (!this.initDone) {
this.loge("incplayer not initialized");
return;
}
// Delete previous popcorn objects
this.destroySequence();
// Choose the 3 videos
this.choosePopSequence(words, videosIndex, paramIndex);
// And init the popcorn sequence
this.initPopSequence();
};
this.playSingleVideo = function(videoUrl)
{
this.sequences = [];
this.singleVideo = true;
var video = { name : "xxx", src: videoUrl, in: 0, out: "1.44" };
this.sequences.push(video);
this.formatPopSequence();
this.initPopSequence();
}
this.choosePopSequence = function(wordsIndex, videosIndex, paramIndex)
{
this.sequences = [];
if (paramIndex.length == 3) {
// This is a shared link, we get the videos index from the url
for (var i = 0; i < paramIndex.length; ++i) {
this.sequences.push(this.allSequencesData.videos[paramIndex[i]]);
}
} else if (videosIndex.length == 3) {
// The player got reloded, we use the previously choosen videos
for (var i = 0; i < videosIndex.length; ++i) {
this.sequences.push(this.allSequencesData.videos[videosIndex[i]]);
}
} else if (wordsIndex[0] == null) {
// No reason to be here, redirection
location.href = "index.html";
} else {
// We choose new videos
// Get previous used videos
var var32bits = incChoice.getChoosenVideosFlags();
// Choose videos according to the chosen words
for (var i = 0; i < wordsIndex.length; ++i) {
var v = this.getRandomVideos(wordsIndex[i], var32bits, this.sequences);
if (v == null) {
// We didn't find free video
// So we mark some as unplayed, we must get flags again and retry
var32bits = incChoice.getChoosenVideosFlags();
v = this.getRandomVideos(wordsIndex[i], var32bits, this.sequences);
if (v == null) {
this.loge("We didn't find a free video");
}
}
this.sequences.push(v);
}
// Save played videos with cookies
this.savePlayedVideos(this.sequences, true);
// Save chosen video with cookies
this.saveChosenVideos(this.sequences);
}
// Format pop sequence
this.formatPopSequence();
// Debug
this.logi("choosed sequences:");
for (i = 0; i < this.sequences.length; ++i) {
this.logi(this.sequenceToString(i));
}
};
this.formatPopSequence = function()
{
// Set the video file name
var i;
for (i = 0; i < this.sequences.length; ++i) {
var v = this.sequences[i];
// HD
if(!this.hd) {
v.src = v.src.replace("HD", "SD");
}
// Extention
v.src += "." + this.videoExt;
// Set the final file
this.sequences[i] = v;
}
for (i = 0; i < this.sequences.length; ++i) {
// Get the sequence
var seq = this.sequences[i];
// Compute time in seconds
var integer = Math.floor(seq.duration);
var decimal = Math.floor((seq.duration - integer) * 100);
var duration = integer * 60 + decimal;
this.sequences[i] = { src: seq.src, in: 0, out: duration };
}
}
this.getRandomVideos = function(wordIndex, var32bits, otherVideos)
{
var i;
var index = parseInt(wordIndex);
var videos = [];
var allVideosPlayed = true;
var videosMatchWord = [];
// Debug
var freeVideosCount = 0;
var wordScoreAllVideos = 0;
// Get all videos affected by this word
for (i = 0; i < this.allSequencesData.videos.length; ++i) {
var video = this.allSequencesData.videos[i];
var wordScore = video.scoreWord[index];
if (wordScore <= 0) {
// This video can't be choosen with this word
continue;
}
videosMatchWord.push(video); // Debug
video.choosen = incChoice.IsThisVideoWasPlayed(var32bits, video.index);
if (video.choosen) {
// This video was already played in an another session
continue;
}
allVideosPlayed = false;
// Compare categories
video.samecat = false;
for (var j = 0; j < otherVideos.length; ++j) {
if (video.cat == otherVideos[j].cat) {
video.samecat = true;
break;
}
}
if (video.samecat == true) {
// This video have the same cat that an other selected video
continue;
}
// We push has many time the video that the score for the word
for (var j = 0; j < wordScore; ++j) {
videos.push(video);
}
// Debug
wordScoreAllVideos += wordScore;
++freeVideosCount;
}
if (allVideosPlayed || !videos.length) {
// All the videos asociated with the word have been played
// or there is no videos to choose because we skipped the one with the same cat
// We must mark the videos asociated with the word as unplayed
this.savePlayedVideos(videosMatchWord, false);
return null;
}
// Choose random video
var v = videos[this.random(0, videos.length)];
// Debug
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
this.logi("---------------------------------------------------------------------");
this.logi("The word " + this.allSequencesData.mots[index] + "(" + index + ")" +" give us " + videosMatchWord.length + " videos, we can choose " + freeVideosCount);
this.logi("---------------------------------------------------------------------");
for (i = 0; i < videosMatchWord.length; ++i) {
var video = videosMatchWord[i];
var message = this.resizeString(video.name, 15) + this.resizeString(" cat:" + video.cat, 15);
if (video.choosen) {
message += this.resizeString("played", 15);
} else if (video.samecat) {
message += this.resizeString("same cat", 15);
} else {
message += this.resizeString("OK", 15) + this.resizeString("proba:" + video.scoreWord[index] + "/" + wordScoreAllVideos, 15);
}
this.logi(message);
}
this.logi("");
this.logi("We choose " + v.name + "(" + v.index + ")" + " cat:" + v.cat + " proba: " + v.scoreWord[index] + "/" + wordScoreAllVideos + "\n\n");
return v;
}
this.savePlayedVideos = function(videos, markPlayed)
{
var indexs = [];
for (var i = 0; i < videos.length; ++i) {
indexs.push(videos[i].index);
}
incChoice.savePlayedVideos(indexs, markPlayed);
};
this.saveChosenVideos = function(videos)
{
var indexs = [];
for (var i = 0; i < videos.length; ++i) {
indexs.push(videos[i].index);
}
incChoice.saveChosenVideos(indexs);
};
this.resizeString = function (str, size)
{
while (str.length < size) {
str += " ";
}
return str;
};
this.getWordIndex = function(word)
{
var words = this.allSequencesData.mots;
for (var i = 0; i < words.length; ++i) {
if (words[i] == word) {
return i;
}
}
this.loge("getWordIndex erreur");
return -1;
};
this.debugDisplayWordsIndex = function()
{
var words = this.allSequencesData.mots;
for (var i = 0; i < words.length; ++i) {
this.logi(words[i] + " -> " + i);
}
};
this.initPopSequence = function()
{
var self = this;
// Create the popcorn sequencer
self.popSeq = Popcorn.sequence(self.videoDivId, self.sequences);
for (var i = 0; i < self.sequences.length; ++i) {
var pop = self.popSeq.eq(i);
// Hide controls
pop.controls(false);
// Add poster on ipad
if (self.ipad && !this.singleVideo) {
$(pop.media).attr('poster', 'static/res/img/poster' + (i + 1) + '_video.png');
}
// Play event
self.listenEvent(pop, "playing", false, i, function(index) {
self.displayPlayButton(false);
self.logi("play sequence: " + self.sequenceToString(self.popSeq.active));
});
// Pause event
self.listenEvent(pop, "pause", false, i, function(index) {
self.displayPlayButton(true);
self.logi("pause sequence: " + self.sequenceToString(self.popSeq.active));
});
// Ended event
self.listenEvent(pop, "ended", false, i, function(index) {
self.logi("ended sequence: " + self.sequenceToString(self.popSeq.active));
});
// Timeupdate event
self.listenEvent(pop, "timeupdate", false, i, function(index) {
var currentTime = self.popSeq.currentTime();
if (!self.progressCursorDrag) {
// Move timeline and display the time
self.progressCursorX = self.setCursorPosition(currentTime);
}
// Detect the sequence end
if (self.popSeq.active == self.sequences.length-1 && currentTime >= self.popSeq.duration() - 1) {
setTimeout(function() {
location.href = self.nextPage;
}, 1500);
}
});
/*
// Canplaythrough event
self.listenEvent(pop, "canplaythrough", true, i, function(index) {
});
*/
}
if (!this.ipad) {
self.popSeq.on("canplaythrough", function() {
self.playerIsReady = true;
// Recompute Duration
self.recomputeDuration();
// Automatic play
self.ctrlPlay();
// Unlisten event
self.popSeq.off("canplaythrough");
self.logi("the player is ready");
});
}
self.popSeq.on("cycle", function() {
console.log("CYCLE");
});
self.popSeq.on("ended", function() {
});
};
this.listenEvent = function(pop, event, unlisten, index, func)
{
pop.on(event, function() {
// Execute the function
func(index);
if (unlisten) {
// Unlisten event
pop.off(event);
}
});
};
this.recomputeDuration = function()
{
// Recompute duration
var totalDuration = 0;
for (var j = 0; j < this.sequences.length; ++j) {
var duration = this.popSeq.eq(j).duration();
// ofVideos
this.popSeq.inOuts.ofVideos[j].out = duration;
// ofClips
this.popSeq.inOuts.ofClips[j].in = totalDuration;
totalDuration += duration;
this.popSeq.inOuts.ofClips[j].out = totalDuration;
}
// Set total duration
$(this.progressDuration).html(this.secondsToTime(this.popSeq.duration()));
};
this.recomputeDurationNoAutoPlay = function()
{
// Recompute duration
var totalDuration = 0;
for (var j = 0; j <= this.popSeq.active; ++j) {
var duration = this.popSeq.eq(j).duration();
// ofVideos
this.popSeq.inOuts.ofVideos[j].out = duration;
// ofClips
this.popSeq.inOuts.ofClips[j].in = totalDuration;
totalDuration += duration;
this.popSeq.inOuts.ofClips[j].out = totalDuration;
}
// Set total duration
$(this.progressDuration).html(this.secondsToTime(this.popSeq.duration()));
if (incHideBar !== undefined) {
incHideBar.showBarPointerOnAction(6000);
}
};
this.getCurrentPop = function()
{
var index = this.popSeq.active;
if (index >= this.sequences.length) {
index = this.sequences.length-1;
}
return this.popSeq.eq(index);
};
this.setCursorPosition = function(time)
{
// Display time
$(this.progressCurrent).html(this.secondsToTime(time));
// Move cursor timeline
var progressCursorX = time ? ((time / this.popSeq.duration()) * (240 - 16)) : 0;
$(this.progressCursor).css({"left" : progressCursorX });
$("#progress").css({"width" : progressCursorX + 8});
return progressCursorX;
}
this.forceCheckPlayerIsReady = function()
{
this.playerIsReady = false;
this.playerWaitForBeingReady = false;
this.checkPlayerIsReady();
}
this.checkPlayerIsReady = function()
{
if (this.playerIsReady) {
return true;
}
if (this.ipad) {
// We "manualy" play the video (we are in a click event handler)
var media = this.popSeq.eq(this.popSeq.active).media;
media.play();
if (media.readystate === 4) {
this.playerIsReady = true;
this.recomputeDurationNoAutoPlay();
return false; // Ready but we don't want to do anything after
}
if (this.playerWaitForBeingReady) {
return false;
}
this.playerWaitForBeingReady = true;
var self = this;
var mediaCanPlay = function () {
// Remove event
media.removeEventListener('canplaythrough', mediaCanPlay, false);
media.removeEventListener('load', mediaCanPlay, false);
// The video is ready, play
media.play();
self.playerIsReady = true;
self.recomputeDurationNoAutoPlay();
console.log("ipad play event");
}
media.addEventListener('canplaythrough', mediaCanPlay, false);
media.addEventListener('load', mediaCanPlay, false);
setTimeout(function() {
media.pause(); // Block play so it buffers before playing
}, 1);
}
this.logi("can't play, the player is not ready");
return false;
}
this.ctrlSetCursorDragFunction = function()
{
var self = this;
var origineX = null;
var posX;
var maxX = 240 - 16;
var setCursorPositionX = function (x) {
if (x < 0) {
x = 0;
} else if (x > maxX) {
x = maxX;
}
var time = self.popSeq.duration() * x / maxX;
self.setCursorPosition(time);
return x;
}
var setCursorPosition = function (x) {
self.progressCursorDrag = true;
if (origineX == null) {
origineX = x;
} else {
posX = self.progressCursorX + x - origineX;
posX = setCursorPositionX(posX);
}
}
this.progressCursor.on({
mousedown: function() {
if (!self.checkPlayerIsReady()) {
return;
}
$(document).on(
self.ipad ? {
touchmove: function (e) {
e.preventDefault();
var touches = ( typeof( event.touches ) != "undefined" ) ? event.touches : event.changedTouches;
setCursorPosition(touches[0].pageX);
}
} : {
mousemove: function (e) {
self.progressCursorDrag = true;
setCursorPosition(e.pageX);
}
}
);
}
});
var progressBarX = $(self.progressBar).position().left;
if (self.ipad) {
this.progressBar.on({
touchdown: function(e) {
if (!self.checkPlayerIsReady()) {
return;
}
e.preventDefault();
var touches = ( typeof( event.touches ) != "undefined" ) ? event.touches : event.changedTouches;
PosX = touches[0].pageX - progressBarX - 8;
PosX = setCursorPositionX(PosX);
// Seek time
var jumpTime = self.popSeq.duration() * PosX / maxX;
self.popSeq.jumpTo(jumpTime);
}
});
} else {
this.progressBar.on({
mousedown: function(e) {
if (!self.checkPlayerIsReady()) {
return;
}
PosX = e.pageX - progressBarX - 8;
PosX = setCursorPositionX(PosX);
// Seek time
var jumpTime = self.popSeq.duration() * PosX / maxX;
self.popSeq.jumpTo(jumpTime);
}
});
}
$(document).mouseup(function(){
if (self.progressCursorDrag) {
self.progressCursorDrag = false;
origineX = null;
// Remove event
$(document).off(self.ipad ? "touchmove" : "mousemove");
// Seek time
var jumpTime = self.popSeq.duration() * posX / maxX;
self.popSeq.jumpTo(jumpTime);
}
});
}
this.ctrlPlay = function()
{
if (!this.checkPlayerIsReady()) {
return;
}
if (this.getCurrentPop().paused()) {
// Play
this.popSeq.play();
} else {
// Pause
this.popSeq.pause();
}
};
this.ctrlNext = function()
{
if (!this.checkPlayerIsReady()) {
return;
}
if (this.popSeq.active == this.sequences.length - 1) {
// We are at the last video
location.href = this.nextPage;
return;
}
if (this.ipad) {
this.playerIsReady = false;
this.playerWaitForBeingReady = false;
}
// Go to the next video
var jumpTime = this.popSeq.durationSeqs(this.popSeq.active + 1) + 0.001;
this.popSeq.jumpTo(jumpTime);
};
this.ctrlPrev = function()
{
if (!this.checkPlayerIsReady()) {
return;
}
var videoIndex = this.popSeq.active;
if (videoIndex === 0) {
// We jump to the start
this.popSeq.jumpTo(0);
} else {
// If we are a less than 1 sec from the sequence start, we jump to the prev sequence
// else we jump to the start of the current sequence
var jumpTime = this.popSeq.durationSeqs(videoIndex);
if (this.popSeq.currentTime() - jumpTime < 1) {
jumpTime = this.popSeq.durationSeqs(videoIndex-1);
}
this.popSeq.jumpTo(jumpTime + 0.001);
}
};
this.ctrlHdSd = function()
{
// We swape between hd/sd
incChoice.setHD(this.hd ? 0 : 1);
// We record the current time
// Reload
location.href = document.URL;
};
this.displayPlayButton = function(playIcon)
{
$(this.playButton).css({"background-position" : playIcon ? '-77px 0' : '-77px -17px'});
};
// --------------------------------------------------------------------------------------------------------------------
// Tools Functions
// --------------------------------------------------------------------------------------------------------------------
this.logi = function(txt)
{
if (this.logiEnable) {
console.log("info: " + txt);
}
};
this.loge = function(txt)
{
console.log("error: " + txt);
};
this.loadJson = function(jsonFile)
{
var txt = this.loadTxtFile(jsonFile);
var obj = null;
$.ajax({
url: jsonFile,
async: false,
success: function (data){
obj = data;
}
});
return obj;
};
this.loadTxtFile = function(jsonFile)
{
var xhr = new XMLHttpRequest();
xhr.open("GET", jsonFile, false);
if (xhr.overrideMimeType) {
xhr.overrideMimeType('text/plain; charset=x-user-defined');
}
try {
xhr.send(null);
} catch(e) {
return "";
}
if (xhr.status == 404) {
return "";
}
var buffer;
if (xhr.responseType == "arraybuffer") {
buffer = xhr.response;
} else if (xhr.mozResponseArrayBuffer === null) {
buffer = xhr.mozResponseArrayBuffer;
} else {
buffer = xhr.response;
}
return buffer;
};
this.random = function(min, max)
{
return Math.floor((Math.random()*(max-min))+min);
};
this.secondsToTime = function(sec)
{
var minutes = Math.floor(sec / 60);
var seconds = Math.floor(sec - minutes * 60);
if (seconds < 10) {
seconds = "0" + seconds;
}
return "" + minutes + "'" + seconds + "''";
};
this.sequenceToString = function(index)
{
return JSON.stringify(this.sequences[index]);
};
this.getSupportedVideoExt = function()
{
var v = document.createElement("video");
if (v.canPlayType) {
// Check for Webm support
if (v.canPlayType('video/webm; codecs="vp8, vorbis"') !== "") {
return "webm";
}
// Check for MPEG-4 support
if (v.canPlayType('video/mp4; codecs="mp4v.20.8"' ) !== "") {
return "mp4";
}
// Check for h264 support
if ((v.canPlayType('video/mp4; codecs="avc1.42E01E"' ) !== "" || v.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'))) {
return "mp4";
}
}
return "";
};
}
var incPlayer = new IncPlayer();