From 48af1f8f22a3f7053416e717fca7596a6ee582d9 Mon Sep 17 00:00:00 2001 From: Daniel Thies Date: Tue, 5 Mar 2024 15:04:40 -0600 Subject: [PATCH] VID-727: Use interval counter --- amd/build/videotime.min.js | 2 +- amd/build/videotime.min.js.map | 2 +- amd/src/videotime.js | 4 +++- version.php | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/amd/build/videotime.min.js b/amd/build/videotime.min.js index 26a305b2..e3ac9fd2 100644 --- a/amd/build/videotime.min.js +++ b/amd/build/videotime.min.js @@ -1,2 +1,2 @@ -define ("mod_videotime/videotime",["jquery","mod_videotime/player","core/ajax","core/log","core/templates","core/notification"],function(a,b,c,d,e,f){var g=function(b,c,d,e){this.elementId=b;this.cmId=c;this.hasPro=d;this.interval=e;this.player=null;this.resumeTime=null;this.session=null;this.instance=null;this.played=!1;this.playing=!1;this.time=0;this.percent=0;this.currentTime=0;this.playbackRate=1;this.plugins=[];if(d&&a("body").hasClass("path-course-view")&&!a("body").hasClass("vtinit")){a("body").addClass("vtinit");a(document).on("focus","body",this.initializeNewInstances.bind(this))}this.modulecount=a("body .activity.videotime").length};g.prototype.getCmId=function(){return this.cmId};g.prototype.registerPlugin=function(a){this.plugins.push(a)};g.prototype.initialize=function(){var a=this;d.debug("Initializing Video Time "+this.elementId);this.getInstance().then(function(c){d.debug("Initializing Vimeo player with options:");d.debug(c);a.player=new b(a.elementId,{autopause:c.autopause,autoplay:c.autoplay,background:c.background,byline:c.byline,color:c.color,controls:c.controls,dnt:c.dnt,height:c.height,maxheight:c.maxheight,maxwidth:c.maxwidth,muted:c.muted,portrait:c.portrait,pip:c.pip,playsinline:c.playsinline,responsive:c.responsive,speed:c.speed,title:c.title,transparent:c.transparent,url:c.vimeo_url,width:c.width});var e=new URL(window.location.href),g=e.searchParams.get("q"),h=(e.searchParams.get("time")||"").match(/^([0-9]+:){0,2}([0-9]+)(\.[0-9]+)$/);if(h){a.setStartTime(h[0]).then(function(){if(g&&window.find){window.find(g)}return!0}).catch(f.exception)}else if(g&&window.find){window.find(g)}a.addListeners();for(var j=0,i;j=a){return!0}b.getPlayer().getDuration().then(function(c){var e=a;if(a+1>=Math.floor(c)){d.debug("VIDEO_TIME video finished, resuming at start of video.");e=0}d.debug("VIDEO_TIME resuming at "+e);b.player.on("loaded",function(){b.player.setCurrentTime(e)});return!0}).catch(f.exception);return!0}).catch(f.exception);this.player.on("play",function(){this.playing=!0;d.debug("VIDEO_TIME play")}.bind(this));this.player.on("playing",function(){this.playing=!0;d.debug("VIDEO_TIME playing")}.bind(this));this.player.on("pause",function(){this.playing=!1;d.debug("VIDEO_TIME pause")}.bind(this));this.player.on("stalled",function(){this.playing=!1;d.debug("VIDEO_TIME stalled")}.bind(this));this.player.on("suspend",function(){this.playing=!1;d.debug("VIDEO_TIME suspend")}.bind(this));this.player.on("abort",function(){this.playing=!1;d.debug("VIDEO_TIME abort")}.bind(this));this.player.getPlaybackRate().then(function(a){this.playbackRate=a||1}.bind(this)).catch(f.exception);this.player.on("playbackratechange",function(a){this.playbackRate=a.playbackRate||1}.bind(this));this.player.on("timeupdate",function(a){this.percent=a.percent;this.currentTime=a.seconds;d.debug("VIDEO_TIME timeupdate. Percent: "+this.percent+". Current time: "+this.currentTime)}.bind(this));this.player.on("ended",function(){this.playing=!1;d.debug("VIDEO_TIME ended");new Promise(function(a){this.getSession().then(function(b){a(b);return!0}).catch(f.exception)}.bind(this)).then(function(a){this.setSessionState(a.id,1);return a}.bind(this)).then(function(a){this.setPercent(a.id,1);return a}.bind(this)).then(function(a){this.setCurrentTime(a.id,this.currentTime);return a}.bind(this)).catch(f.exception).finally(function(){this.getSession().then(function(b){this.getNextActivityButtonData(b.id).then(function(b){var c=JSON.parse(b.data);if(c.instance&&parseInt(c.instance.next_activity_auto)){if(!c.is_restricted&&c.hasnextcm){var d=a(".aalink[href=\""+c.nextcm_url+"\"] img").first();if(a(".path-course-view").length&&d){d.click()}else{window.location.href=c.nextcm_url}}}e.render("videotime/next_activity_button",JSON.parse(b.data)).then(function(b){a("#next-activity-button").html(b);return!0}).fail(f.exception);return!0}).fail(f.exception)}.bind(this)).catch(f.exception)}.bind(this)).fail(f.exception)}.bind(this));a(a("#"+this.elementId).closest(".videotimetabs")).each(function(b,c){a(c).find("[data-action=\"cue\"]").each(function(a,b){var c=b.getAttribute("data-start"),d=c.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\.[0-9]+))/);if(d){this.player.addCuePoint(3600*+(d[3]||0)+60*+(d[5]||0)+ +d[6],{starttime:c}).catch(f.exeception)}}.bind(this));this.player.on("cuepoint",function(b){if(b.data.starttime){a(c).find(".videotime-highlight").removeClass("videotime-highlight");a(c).find("[data-action=\"cue\"][data-start=\""+b.data.starttime+"\"]").closest(".row").addClass("videotime-highlight");a(".videotime-highlight").each(function(){if(this.offsetTop){this.parentNode.scrollTo({top:this.offsetTop-50,left:0,behavior:"smooth"})}})}})}.bind(this))};g.prototype.startWatchInterval=function(){if(this.watchInterval){return}this.watchInterval=setInterval(function(){var a=this;this.getPaused().then(function(b){if(b){return}a.time+=a.playbackRate;a.getSession().then(function(a){if(0==this.time/this.playbackRate%this.interval){d.debug("VIDEO_TIME watch_time: "+this.time+". percent: "+this.percent);this.recordWatchTime(a.id,this.time);this.setPercent(a.id,this.percent);this.setCurrentTime(a.id,this.currentTime)}return!0}.bind(a)).catch(f.exception)})}.bind(this),1e3)};g.prototype.setSessionState=function(a,b){return c.call([{methodname:"videotimeplugin_pro_set_session_state",args:{session_id:a,state:b}}])[0]};g.prototype.setCurrentTime=function(a,b){return c.call([{methodname:"videotimeplugin_pro_set_session_current_time",args:{session_id:a,current_time:b},fail:function fail(a){d.debug(a);document.querySelectorAll(".videotime-server-error").forEach(function(a){a.classList.remove("hidden")})}}])[0]};g.prototype.setPercent=function(a,b){return c.call([{methodname:"videotimeplugin_pro_set_percent",args:{session_id:a,percent:b}}])[0]};g.prototype.recordWatchTime=function(a,b){return c.call([{methodname:"videotimeplugin_pro_record_watch_time",args:{session_id:a,time:b}}])[0]};g.prototype.getNextActivityButtonData=function(a){return c.call([{methodname:"videotimeplugin_pro_get_next_activity_button_data",args:{session_id:a}}])[0]};g.prototype.getInstance=function(){var a=this;if(this.instance){return Promise.resolve(this.instance)}return new Promise(function(b){c.call([{methodname:"mod_videotime_get_videotime",args:{cmid:a.cmId}}])[0].then(function(c){a.instance=c;b(a.instance);return!0}).fail(f.exception)})};g.prototype.getResumeTime=function(){var a=this;if(this.resumeTime){return Promise.resolve(this.resumeTime)}return new Promise(function(b){c.call([{methodname:"videotimeplugin_pro_get_resume_time",args:{cmid:a.cmId}}])[0].then(function(c){a.resumeTime=c.seconds;b(a.resumeTime);return!0}).fail(f.exception)})};g.prototype.getSession=function(){var a=this;if(this.session){return this.session}this.session=c.call([{methodname:"videotimeplugin_pro_get_new_session",args:{cmid:this.cmId}}])[0].fail(function(b){a.session=null;f.exception(b);return b});return this.session};g.prototype.setStartTime=function(a){var b=a.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\.[0-9]+))/);if(b){this.resumeTime=3600*+(b[3]||0)+60*+(b[5]||0)+ +b[6];return this.player.setCurrentTime(this.resumeTime)}return this.player.getCurrentTime()};g.prototype.view=function(){return c.call([{methodname:"mod_videotime_view_videotime",args:{cmid:this.cmId}}])[0]};g.prototype.initializeNewInstances=function(){if(this.modulecount==a("body .activity.videotime").length){return}this.modulecount=a("body .activity.videotime").length;a("body .activity.videotime").each(function(b,c){if(!a(c).find(".instancename").length&&a(c).find(".vimeo-embed").length&&!a(c).find(".vimeo-embed iframe").length){var d={cmid:+a(c).attr("id").replace("module-",""),haspro:!0,interval:this.interval,uniqueid:a(c).find(".vimeo-embed").first().attr("id").replace("vimeo-embed-","")};e.render("mod_videotime/videotime_instance",{instance:d}).then(function(a,b){e.runTemplateJS(b);return!0}).fail(f.exception)}}.bind(this))};return g}); +define ("mod_videotime/videotime",["jquery","mod_videotime/player","core/ajax","core/log","core/templates","core/notification"],function(a,b,c,d,e,f){var g=function(b,c,d,e){this.elementId=b;this.cmId=c;this.hasPro=d;this.interval=e;this.player=null;this.resumeTime=null;this.session=null;this.instance=null;this.played=!1;this.playing=!1;this.intervalcount=0;this.time=0;this.percent=0;this.currentTime=0;this.playbackRate=1;this.plugins=[];if(d&&a("body").hasClass("path-course-view")&&!a("body").hasClass("vtinit")){a("body").addClass("vtinit");a(document).on("focus","body",this.initializeNewInstances.bind(this))}this.modulecount=a("body .activity.videotime").length};g.prototype.getCmId=function(){return this.cmId};g.prototype.registerPlugin=function(a){this.plugins.push(a)};g.prototype.initialize=function(){var a=this;d.debug("Initializing Video Time "+this.elementId);this.getInstance().then(function(c){d.debug("Initializing Vimeo player with options:");d.debug(c);a.player=new b(a.elementId,{autopause:c.autopause,autoplay:c.autoplay,background:c.background,byline:c.byline,color:c.color,controls:c.controls,dnt:c.dnt,height:c.height,maxheight:c.maxheight,maxwidth:c.maxwidth,muted:c.muted,portrait:c.portrait,pip:c.pip,playsinline:c.playsinline,responsive:c.responsive,speed:c.speed,title:c.title,transparent:c.transparent,url:c.vimeo_url,width:c.width});var e=new URL(window.location.href),g=e.searchParams.get("q"),h=(e.searchParams.get("time")||"").match(/^([0-9]+:){0,2}([0-9]+)(\.[0-9]+)$/);if(h){a.setStartTime(h[0]).then(function(){if(g&&window.find){window.find(g)}return!0}).catch(f.exception)}else if(g&&window.find){window.find(g)}a.addListeners();for(var j=0,i;j=a){return!0}b.getPlayer().getDuration().then(function(c){var e=a;if(a+1>=Math.floor(c)){d.debug("VIDEO_TIME video finished, resuming at start of video.");e=0}d.debug("VIDEO_TIME resuming at "+e);b.player.on("loaded",function(){b.player.setCurrentTime(e)});return!0}).catch(f.exception);return!0}).catch(f.exception);this.player.on("play",function(){this.playing=!0;d.debug("VIDEO_TIME play")}.bind(this));this.player.on("playing",function(){this.playing=!0;d.debug("VIDEO_TIME playing")}.bind(this));this.player.on("pause",function(){this.playing=!1;d.debug("VIDEO_TIME pause")}.bind(this));this.player.on("stalled",function(){this.playing=!1;d.debug("VIDEO_TIME stalled")}.bind(this));this.player.on("suspend",function(){this.playing=!1;d.debug("VIDEO_TIME suspend")}.bind(this));this.player.on("abort",function(){this.playing=!1;d.debug("VIDEO_TIME abort")}.bind(this));this.player.getPlaybackRate().then(function(a){this.playbackRate=a||1}.bind(this)).catch(f.exception);this.player.on("playbackratechange",function(a){this.playbackRate=a.playbackRate||1}.bind(this));this.player.on("timeupdate",function(a){this.percent=a.percent;this.currentTime=a.seconds;d.debug("VIDEO_TIME timeupdate. Percent: "+this.percent+". Current time: "+this.currentTime)}.bind(this));this.player.on("ended",function(){this.playing=!1;d.debug("VIDEO_TIME ended");new Promise(function(a){this.getSession().then(function(b){a(b);return!0}).catch(f.exception)}.bind(this)).then(function(a){this.setSessionState(a.id,1);return a}.bind(this)).then(function(a){this.setPercent(a.id,1);return a}.bind(this)).then(function(a){this.setCurrentTime(a.id,this.currentTime);return a}.bind(this)).catch(f.exception).finally(function(){this.getSession().then(function(b){this.getNextActivityButtonData(b.id).then(function(b){var c=JSON.parse(b.data);if(c.instance&&parseInt(c.instance.next_activity_auto)){if(!c.is_restricted&&c.hasnextcm){var d=a(".aalink[href=\""+c.nextcm_url+"\"] img").first();if(a(".path-course-view").length&&d){d.click()}else{window.location.href=c.nextcm_url}}}e.render("videotime/next_activity_button",JSON.parse(b.data)).then(function(b){a("#next-activity-button").html(b);return!0}).fail(f.exception);return!0}).fail(f.exception)}.bind(this)).catch(f.exception)}.bind(this)).fail(f.exception)}.bind(this));a(a("#"+this.elementId).closest(".videotimetabs")).each(function(b,c){a(c).find("[data-action=\"cue\"]").each(function(a,b){var c=b.getAttribute("data-start"),d=c.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\.[0-9]+))/);if(d){this.player.addCuePoint(3600*+(d[3]||0)+60*+(d[5]||0)+ +d[6],{starttime:c}).catch(f.exeception)}}.bind(this));this.player.on("cuepoint",function(b){if(b.data.starttime){a(c).find(".videotime-highlight").removeClass("videotime-highlight");a(c).find("[data-action=\"cue\"][data-start=\""+b.data.starttime+"\"]").closest(".row").addClass("videotime-highlight");a(".videotime-highlight").each(function(){if(this.offsetTop){this.parentNode.scrollTo({top:this.offsetTop-50,left:0,behavior:"smooth"})}})}})}.bind(this))};g.prototype.startWatchInterval=function(){if(this.watchInterval){return}this.watchInterval=setInterval(function(){var a=this;this.getPaused().then(function(b){if(b){return}a.time+=a.playbackRate;a.intervalcount+=1;a.getSession().then(function(a){if(0==this.intervalcount%this.interval){d.debug("VIDEO_TIME watch_time: "+this.time+". percent: "+this.percent);this.recordWatchTime(a.id,this.time);this.setPercent(a.id,this.percent);this.setCurrentTime(a.id,this.currentTime)}return!0}.bind(a)).catch(f.exception)})}.bind(this),1e3)};g.prototype.setSessionState=function(a,b){return c.call([{methodname:"videotimeplugin_pro_set_session_state",args:{session_id:a,state:b}}])[0]};g.prototype.setCurrentTime=function(a,b){return c.call([{methodname:"videotimeplugin_pro_set_session_current_time",args:{session_id:a,current_time:b},fail:function fail(a){d.debug(a);document.querySelectorAll(".videotime-server-error").forEach(function(a){a.classList.remove("hidden")})}}])[0]};g.prototype.setPercent=function(a,b){return c.call([{methodname:"videotimeplugin_pro_set_percent",args:{session_id:a,percent:b}}])[0]};g.prototype.recordWatchTime=function(a,b){return c.call([{methodname:"videotimeplugin_pro_record_watch_time",args:{session_id:a,time:b}}])[0]};g.prototype.getNextActivityButtonData=function(a){return c.call([{methodname:"videotimeplugin_pro_get_next_activity_button_data",args:{session_id:a}}])[0]};g.prototype.getInstance=function(){var a=this;if(this.instance){return Promise.resolve(this.instance)}return new Promise(function(b){c.call([{methodname:"mod_videotime_get_videotime",args:{cmid:a.cmId}}])[0].then(function(c){a.instance=c;b(a.instance);return!0}).fail(f.exception)})};g.prototype.getResumeTime=function(){var a=this;if(this.resumeTime){return Promise.resolve(this.resumeTime)}return new Promise(function(b){c.call([{methodname:"videotimeplugin_pro_get_resume_time",args:{cmid:a.cmId}}])[0].then(function(c){a.resumeTime=c.seconds;b(a.resumeTime);return!0}).fail(f.exception)})};g.prototype.getSession=function(){var a=this;if(this.session){return this.session}this.session=c.call([{methodname:"videotimeplugin_pro_get_new_session",args:{cmid:this.cmId}}])[0].fail(function(b){a.session=null;f.exception(b);return b});return this.session};g.prototype.setStartTime=function(a){var b=a.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\.[0-9]+))/);if(b){this.resumeTime=3600*+(b[3]||0)+60*+(b[5]||0)+ +b[6];return this.player.setCurrentTime(this.resumeTime)}return this.player.getCurrentTime()};g.prototype.view=function(){return c.call([{methodname:"mod_videotime_view_videotime",args:{cmid:this.cmId}}])[0]};g.prototype.initializeNewInstances=function(){if(this.modulecount==a("body .activity.videotime").length){return}this.modulecount=a("body .activity.videotime").length;a("body .activity.videotime").each(function(b,c){if(!a(c).find(".instancename").length&&a(c).find(".vimeo-embed").length&&!a(c).find(".vimeo-embed iframe").length){var d={cmid:+a(c).attr("id").replace("module-",""),haspro:!0,interval:this.interval,uniqueid:a(c).find(".vimeo-embed").first().attr("id").replace("vimeo-embed-","")};e.render("mod_videotime/videotime_instance",{instance:d}).then(function(a,b){e.runTemplateJS(b);return!0}).fail(f.exception)}}.bind(this))};return g}); //# sourceMappingURL=videotime.min.js.map diff --git a/amd/build/videotime.min.js.map b/amd/build/videotime.min.js.map index e0b41bc1..72fbed59 100644 --- a/amd/build/videotime.min.js.map +++ b/amd/build/videotime.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/videotime.js"],"names":["define","$","Vimeo","Ajax","Log","Templates","Notification","VideoTime","elementId","cmId","hasPro","interval","player","resumeTime","session","instance","played","playing","time","percent","currentTime","playbackRate","plugins","hasClass","addClass","document","on","initializeNewInstances","bind","modulecount","length","prototype","getCmId","registerPlugin","plugin","push","initialize","debug","getInstance","then","autopause","autoplay","background","byline","color","controls","dnt","height","maxheight","maxwidth","muted","portrait","pip","playsinline","responsive","speed","title","transparent","url","vimeo_url","width","URL","window","location","href","q","searchParams","get","starttime","match","setStartTime","find","catch","exception","addListeners","i","exeption","getPlayer","getPaused","getSession","startWatchInterval","view","getResumeTime","seconds","getDuration","duration","Math","floor","setCurrentTime","getPlaybackRate","event","Promise","resolve","setSessionState","id","setPercent","finally","getNextActivityButtonData","response","data","JSON","parse","parseInt","next_activity_auto","is_restricted","hasnextcm","link","nextcm_url","first","click","render","html","fail","closest","each","tabs","index","anchor","getAttribute","addCuePoint","exeception","removeClass","offsetTop","parentNode","scrollTo","top","left","behavior","watchInterval","setInterval","paused","recordWatchTime","sessionId","state","call","methodname","args","e","querySelectorAll","forEach","warning","classList","remove","cmid","getCurrentTime","module","attr","replace","haspro","uniqueid","js","runTemplateJS"],"mappings":"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","sourcesContent":["/*\n * @package mod_videotime\n * @copyright 2021 bdecent gmbh \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * @module mod_videotime/videotime\n */\ndefine([\n 'jquery',\n 'mod_videotime/player',\n 'core/ajax',\n 'core/log',\n 'core/templates',\n 'core/notification'\n], function(\n $,\n Vimeo,\n Ajax,\n Log,\n Templates,\n Notification\n) {\n\n let VideoTime = function(elementId, cmId, hasPro, interval) {\n this.elementId = elementId;\n this.cmId = cmId;\n this.hasPro = hasPro;\n this.interval = interval;\n this.player = null;\n this.resumeTime = null;\n this.session = null;\n this.instance = null;\n\n this.played = false;\n\n this.playing = false;\n this.time = 0;\n this.percent = 0;\n this.currentTime = 0;\n this.playbackRate = 1;\n\n this.plugins = [];\n\n if (hasPro && $('body').hasClass('path-course-view') && !$('body').hasClass('vtinit')) {\n $('body').addClass('vtinit');\n $(document).on('focus', 'body', this.initializeNewInstances.bind(this));\n }\n this.modulecount = $('body .activity.videotime').length;\n };\n\n /**\n * Get course module ID of this VideoTime instance.\n *\n * @return {int}\n */\n VideoTime.prototype.getCmId = function() {\n return this.cmId;\n };\n\n /**\n * Register a plugin to hook into VideoTime functionality.\n *\n * @param {VideoTimePlugin} plugin\n */\n VideoTime.prototype.registerPlugin = function(plugin) {\n this.plugins.push(plugin);\n };\n\n VideoTime.prototype.initialize = function() {\n Log.debug('Initializing Video Time ' + this.elementId);\n\n this.getInstance().then((instance) => {\n Log.debug('Initializing Vimeo player with options:');\n Log.debug(instance);\n this.player = new Vimeo(this.elementId, {\n autopause: instance.autopause,\n autoplay: instance.autoplay,\n background: instance.background,\n byline: instance.byline,\n color: instance.color,\n controls: instance.controls,\n dnt: instance.dnt,\n height: instance.height,\n maxheight: instance.maxheight,\n maxwidth: instance.maxwidth,\n muted: instance.muted,\n portrait: instance.portrait,\n pip: instance.pip,\n playsinline: instance.playsinline,\n responsive: instance.responsive,\n speed: instance.speed,\n title: instance.title,\n transparent: instance.transparent,\n url: instance.vimeo_url,\n width: instance.width\n });\n\n let url = new URL(window.location.href),\n q = url.searchParams.get('q'),\n starttime = (url.searchParams.get('time') || '').match(/^([0-9]+:){0,2}([0-9]+)(\\.[0-9]+)$/);\n if (starttime) {\n this.setStartTime(starttime[0]).then(function() {\n if (q && window.find) {\n window.find(q);\n }\n return true;\n }).catch(Notification.exception);\n } else if (q && window.find) {\n window.find(q);\n }\n\n this.addListeners();\n\n for (let i = 0; i < this.plugins.length; i++) {\n const plugin = this.plugins[i];\n plugin.initialize(this, instance);\n }\n\n return true;\n }).catch(Notification.exeption);\n };\n\n /**\n * Get Vimeo player object.\n *\n * @returns {Vimeo}\n */\n VideoTime.prototype.getPlayer = function() {\n return this.player;\n };\n\n /**\n * Get pause state\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getPaused = function() {\n return this.player.getPaused();\n };\n\n\n /**\n * Register player events to respond to user interaction and play progress.\n */\n VideoTime.prototype.addListeners = function() {\n if (!this.player) {\n Log.debug('Player was not properly initialized for course module ' + this.cmId);\n return;\n }\n\n // Fire view event in Moodle on first play only.\n this.player.on('play', () => {\n if (!this.played) {\n if (this.hasPro) {\n // Getting a new session on first play.\n this.getSession();\n this.startWatchInterval();\n }\n this.view();\n this.played = true;\n }\n return true;\n });\n\n // Features beyond this point are for pro only.\n if (!this.hasPro) {\n return;\n }\n\n // If resume is present force seek the player to that point.\n this.getResumeTime().then((seconds) => {\n if (seconds <= 0) {\n return true;\n }\n\n this.getPlayer().getDuration().then((duration) => {\n let resumeTime = seconds;\n // Duration is often a little greater than a resume time at the end of the video.\n // A user may have watched 100 seconds when the video ends, but the duration may be\n // 100.56 seconds. BUT, sometimes the duration is rounded depending on when the\n // video loads, so it may be 101 seconds. Hence the +1 and Math.floor usage.\n if (seconds + 1 >= Math.floor(duration)) {\n Log.debug('VIDEO_TIME video finished, resuming at start of video.');\n resumeTime = 0;\n }\n\n Log.debug('VIDEO_TIME resuming at ' + resumeTime);\n this.player.on('loaded', () => {\n this.player.setCurrentTime(resumeTime);\n });\n return true;\n }).catch(Notification.exception);\n\n return true;\n }).catch(Notification.exception);\n\n // Note: Vimeo player does not support multiple events in a single on() call. Each requires it's own function.\n\n // Catch all events where video plays.\n this.player.on('play', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME play');\n }.bind(this));\n this.player.on('playing', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME playing');\n }.bind(this));\n\n // Catch all events where video stops.\n this.player.on('pause', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME pause');\n }.bind(this));\n this.player.on('stalled', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME stalled');\n }.bind(this));\n this.player.on('suspend', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME suspend');\n }.bind(this));\n this.player.on('abort', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME abort');\n }.bind(this));\n\n this.player.getPlaybackRate().then(function(playbackRate) {\n this.playbackRate = playbackRate || 1;\n }.bind(this)).catch(Notification.exception);\n\n this.player.on('playbackratechange', function(event) {\n this.playbackRate = event.playbackRate || 1;\n }.bind(this));\n\n // Always update internal values for percent and current time watched.\n this.player.on('timeupdate', function(event) {\n this.percent = event.percent;\n this.currentTime = event.seconds;\n Log.debug('VIDEO_TIME timeupdate. Percent: ' + this.percent + '. Current time: ' + this.currentTime);\n }.bind(this));\n\n // Initiate video finish procedure.\n this.player.on('ended', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME ended');\n\n new Promise(function(resolve) {\n this.getSession().then(function(session) {\n resolve(session);\n return true;\n }).catch(Notification.exception);\n }.bind(this)).then(function(session) {\n this.setSessionState(session.id, 1);\n return session;\n }.bind(this)).then(function(session) {\n this.setPercent(session.id, 1);\n return session;\n }.bind(this)).then(function(session) {\n this.setCurrentTime(session.id, this.currentTime);\n return session;\n }.bind(this)).catch(Notification.exception).finally(function() {\n this.getSession().then(function(session) {\n this.getNextActivityButtonData(session.id).then(function(response) {\n let data = JSON.parse(response.data);\n\n if (data.instance && parseInt(data.instance.next_activity_auto)) {\n if (!data.is_restricted && data.hasnextcm) {\n let link = $('.aalink[href=\"' + data.nextcm_url + '\"] img').first();\n if ($('.path-course-view').length && link) {\n link.click();\n } else {\n window.location.href = data.nextcm_url;\n }\n }\n }\n\n Templates.render('videotime/next_activity_button', JSON.parse(response.data))\n .then(function(html) {\n $('#next-activity-button').html(html);\n return true;\n }).fail(Notification.exception);\n return true;\n }).fail(Notification.exception);\n }.bind(this)).catch(Notification.exception);\n }.bind(this)).fail(Notification.exception);\n }.bind(this));\n\n // If this is a tab play set time cues and listener.\n $($('#' + this.elementId).closest('.videotimetabs')).each(function(i, tabs) {\n $(tabs).find('[data-action=\"cue\"]').each(function(index, anchor) {\n let starttime = anchor.getAttribute('data-start'),\n time = starttime.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\\.[0-9]+))/);\n if (time) {\n this.player.addCuePoint(\n 3600 * Number(time[3] || 0) + 60 * Number(time[5] || 0) + Number(time[6]),\n {\n starttime: starttime\n }\n ).catch(Notification.exeception);\n }\n }.bind(this));\n\n this.player.on('cuepoint', function(event) {\n if (event.data.starttime) {\n $(tabs).find('.videotime-highlight').removeClass('videotime-highlight');\n $(tabs).find('[data-action=\"cue\"][data-start=\"' + event.data.starttime + '\"]')\n .closest('.row')\n .addClass('videotime-highlight');\n $('.videotime-highlight').each(function() {\n if (this.offsetTop) {\n this.parentNode.scrollTo({\n top: this.offsetTop - 50,\n left: 0,\n behavior: 'smooth'\n });\n }\n });\n }\n });\n }.bind(this));\n };\n\n /**\n * Start interval that will periodically record user progress via Ajax.\n */\n VideoTime.prototype.startWatchInterval = function() {\n if (this.watchInterval) {\n return;\n }\n\n this.watchInterval = setInterval(function() {\n this.getPaused().then(paused => {\n if (paused) {\n return;\n }\n this.time += this.playbackRate;\n\n this.getSession().then(function(session) {\n if (this.time / this.playbackRate % this.interval === 0) {\n Log.debug('VIDEO_TIME watch_time: ' + this.time + '. percent: ' + this.percent);\n this.recordWatchTime(session.id, this.time);\n this.setPercent(session.id, this.percent);\n this.setCurrentTime(session.id, this.currentTime);\n }\n return true;\n }.bind(this)).catch(Notification.exception);\n });\n }.bind(this), 1000);\n };\n\n /**\n * Set state on session.\n *\n * @param {int} sessionId\n * @param {int} state\n * @returns {Promise}\n */\n VideoTime.prototype.setSessionState = function(sessionId, state) {\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_session_state',\n args: {\"session_id\": sessionId, state: state}\n }])[0];\n };\n\n /**\n * Set current watch time for video. Used for resuming.\n *\n * @param {int} sessionId\n * @param {float} currentTime\n * @returns {Promise}\n */\n VideoTime.prototype.setCurrentTime = function(sessionId, currentTime) {\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_session_current_time',\n args: {\"session_id\": sessionId, \"current_time\": currentTime},\n fail: function(e) {\n Log.debug(e);\n document.querySelectorAll('.videotime-server-error').forEach(warning => {\n warning.classList.remove('hidden');\n });\n }\n }])[0];\n };\n\n /**\n * Set video watch percentage for session.\n *\n * @param {int} sessionId\n * @param {float} percent\n * @returns {Promise}\n */\n VideoTime.prototype.setPercent = function(sessionId, percent) {\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_percent',\n args: {\"session_id\": sessionId, percent: percent}\n }])[0];\n };\n\n /**\n * Record watch time for session.\n *\n * @param {int} sessionId\n * @param {float} time\n * @returns {Promise}\n */\n VideoTime.prototype.recordWatchTime = function(sessionId, time) {\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_record_watch_time',\n args: {\"session_id\": sessionId, time: time}\n }])[0];\n };\n\n /**\n * Get data for next activity button.\n *\n * @param {int} sessionId\n * @returns {Promise}\n */\n VideoTime.prototype.getNextActivityButtonData = function(sessionId) {\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_get_next_activity_button_data',\n args: {\"session_id\": sessionId}\n }])[0];\n };\n\n /**\n * Get VideoTime instance for this course module.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getInstance = function() {\n if (this.instance) {\n return Promise.resolve(this.instance);\n }\n\n return new Promise((resolve) => {\n Ajax.call([{\n methodname: 'mod_videotime_get_videotime',\n args: {cmid: this.cmId}\n }])[0].then((response) => {\n this.instance = response;\n resolve(this.instance);\n return true;\n }).fail(Notification.exception);\n });\n };\n\n /**\n * Get time to resume video as seconds.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getResumeTime = function() {\n if (this.resumeTime) {\n return Promise.resolve(this.resumeTime);\n }\n\n return new Promise((resolve) => {\n Ajax.call([{\n methodname: 'videotimeplugin_pro_get_resume_time',\n args: {cmid: this.cmId}\n }])[0].then((response) => {\n this.resumeTime = response.seconds;\n resolve(this.resumeTime);\n return true;\n }).fail(Notification.exception);\n });\n };\n\n /**\n * Get new or existing video viewing session.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getSession = function() {\n if (this.session) {\n return this.session;\n }\n\n this.session = Ajax.call([{\n methodname: 'videotimeplugin_pro_get_new_session',\n args: {cmid: this.cmId}\n }])[0].fail((e) => {\n this.session = null;\n Notification.exception(e);\n return e;\n });\n\n return this.session;\n };\n\n /**\n * Parse start time and set player\n *\n * @param {string} starttime\n * @returns {Promise}\n */\n VideoTime.prototype.setStartTime = function(starttime) {\n let time = starttime.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\\.[0-9]+))/);\n if (time) {\n this.resumeTime = 3600 * Number(time[3] || 0) + 60 * Number(time[5] || 0) + Number(time[6]);\n return this.player.setCurrentTime(this.resumeTime);\n }\n return this.player.getCurrentTime();\n };\n\n /**\n * Log the user view of video.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.view = function() {\n return Ajax.call([{\n methodname: 'mod_videotime_view_videotime',\n args: {cmid: this.cmId}\n }])[0];\n };\n\n /**\n * Initialize new labels and preview when editing\n */\n VideoTime.prototype.initializeNewInstances = function() {\n if (this.modulecount == $('body .activity.videotime').length) {\n return;\n }\n this.modulecount = $('body .activity.videotime').length;\n $('body .activity.videotime').each(function(index, module) {\n if (\n !$(module).find('.instancename').length\n && $(module).find('.vimeo-embed').length\n && !$(module).find('.vimeo-embed iframe').length\n ) {\n let instance = {\n cmid: Number($(module).attr('id').replace('module-', '')),\n haspro: true,\n interval: this.interval,\n uniqueid: $(module).find('.vimeo-embed').first().attr('id').replace('vimeo-embed-', '')\n };\n Templates.render('mod_videotime/videotime_instance', {\n instance: instance\n }).then(function(html, js) {\n Templates.runTemplateJS(js);\n return true;\n }).fail(Notification.exception);\n }\n }.bind(this));\n };\n\n return VideoTime;\n});\n"],"file":"videotime.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/videotime.js"],"names":["define","$","Vimeo","Ajax","Log","Templates","Notification","VideoTime","elementId","cmId","hasPro","interval","player","resumeTime","session","instance","played","playing","intervalcount","time","percent","currentTime","playbackRate","plugins","hasClass","addClass","document","on","initializeNewInstances","bind","modulecount","length","prototype","getCmId","registerPlugin","plugin","push","initialize","debug","getInstance","then","autopause","autoplay","background","byline","color","controls","dnt","height","maxheight","maxwidth","muted","portrait","pip","playsinline","responsive","speed","title","transparent","url","vimeo_url","width","URL","window","location","href","q","searchParams","get","starttime","match","setStartTime","find","catch","exception","addListeners","i","exeption","getPlayer","getPaused","getSession","startWatchInterval","view","getResumeTime","seconds","getDuration","duration","Math","floor","setCurrentTime","getPlaybackRate","event","Promise","resolve","setSessionState","id","setPercent","finally","getNextActivityButtonData","response","data","JSON","parse","parseInt","next_activity_auto","is_restricted","hasnextcm","link","nextcm_url","first","click","render","html","fail","closest","each","tabs","index","anchor","getAttribute","addCuePoint","exeception","removeClass","offsetTop","parentNode","scrollTo","top","left","behavior","watchInterval","setInterval","paused","recordWatchTime","sessionId","state","call","methodname","args","e","querySelectorAll","forEach","warning","classList","remove","cmid","getCurrentTime","module","attr","replace","haspro","uniqueid","js","runTemplateJS"],"mappings":"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","sourcesContent":["/*\n * @package mod_videotime\n * @copyright 2021 bdecent gmbh \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * @module mod_videotime/videotime\n */\ndefine([\n 'jquery',\n 'mod_videotime/player',\n 'core/ajax',\n 'core/log',\n 'core/templates',\n 'core/notification'\n], function(\n $,\n Vimeo,\n Ajax,\n Log,\n Templates,\n Notification\n) {\n\n let VideoTime = function(elementId, cmId, hasPro, interval) {\n this.elementId = elementId;\n this.cmId = cmId;\n this.hasPro = hasPro;\n this.interval = interval;\n this.player = null;\n this.resumeTime = null;\n this.session = null;\n this.instance = null;\n\n this.played = false;\n\n this.playing = false;\n this.intervalcount = 0;\n this.time = 0;\n this.percent = 0;\n this.currentTime = 0;\n this.playbackRate = 1;\n\n this.plugins = [];\n\n if (hasPro && $('body').hasClass('path-course-view') && !$('body').hasClass('vtinit')) {\n $('body').addClass('vtinit');\n $(document).on('focus', 'body', this.initializeNewInstances.bind(this));\n }\n this.modulecount = $('body .activity.videotime').length;\n };\n\n /**\n * Get course module ID of this VideoTime instance.\n *\n * @return {int}\n */\n VideoTime.prototype.getCmId = function() {\n return this.cmId;\n };\n\n /**\n * Register a plugin to hook into VideoTime functionality.\n *\n * @param {VideoTimePlugin} plugin\n */\n VideoTime.prototype.registerPlugin = function(plugin) {\n this.plugins.push(plugin);\n };\n\n VideoTime.prototype.initialize = function() {\n Log.debug('Initializing Video Time ' + this.elementId);\n\n this.getInstance().then((instance) => {\n Log.debug('Initializing Vimeo player with options:');\n Log.debug(instance);\n this.player = new Vimeo(this.elementId, {\n autopause: instance.autopause,\n autoplay: instance.autoplay,\n background: instance.background,\n byline: instance.byline,\n color: instance.color,\n controls: instance.controls,\n dnt: instance.dnt,\n height: instance.height,\n maxheight: instance.maxheight,\n maxwidth: instance.maxwidth,\n muted: instance.muted,\n portrait: instance.portrait,\n pip: instance.pip,\n playsinline: instance.playsinline,\n responsive: instance.responsive,\n speed: instance.speed,\n title: instance.title,\n transparent: instance.transparent,\n url: instance.vimeo_url,\n width: instance.width\n });\n\n let url = new URL(window.location.href),\n q = url.searchParams.get('q'),\n starttime = (url.searchParams.get('time') || '').match(/^([0-9]+:){0,2}([0-9]+)(\\.[0-9]+)$/);\n if (starttime) {\n this.setStartTime(starttime[0]).then(function() {\n if (q && window.find) {\n window.find(q);\n }\n return true;\n }).catch(Notification.exception);\n } else if (q && window.find) {\n window.find(q);\n }\n\n this.addListeners();\n\n for (let i = 0; i < this.plugins.length; i++) {\n const plugin = this.plugins[i];\n plugin.initialize(this, instance);\n }\n\n return true;\n }).catch(Notification.exeption);\n };\n\n /**\n * Get Vimeo player object.\n *\n * @returns {Vimeo}\n */\n VideoTime.prototype.getPlayer = function() {\n return this.player;\n };\n\n /**\n * Get pause state\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getPaused = function() {\n return this.player.getPaused();\n };\n\n\n /**\n * Register player events to respond to user interaction and play progress.\n */\n VideoTime.prototype.addListeners = function() {\n if (!this.player) {\n Log.debug('Player was not properly initialized for course module ' + this.cmId);\n return;\n }\n\n // Fire view event in Moodle on first play only.\n this.player.on('play', () => {\n if (!this.played) {\n if (this.hasPro) {\n // Getting a new session on first play.\n this.getSession();\n this.startWatchInterval();\n }\n this.view();\n this.played = true;\n }\n return true;\n });\n\n // Features beyond this point are for pro only.\n if (!this.hasPro) {\n return;\n }\n\n // If resume is present force seek the player to that point.\n this.getResumeTime().then((seconds) => {\n if (seconds <= 0) {\n return true;\n }\n\n this.getPlayer().getDuration().then((duration) => {\n let resumeTime = seconds;\n // Duration is often a little greater than a resume time at the end of the video.\n // A user may have watched 100 seconds when the video ends, but the duration may be\n // 100.56 seconds. BUT, sometimes the duration is rounded depending on when the\n // video loads, so it may be 101 seconds. Hence the +1 and Math.floor usage.\n if (seconds + 1 >= Math.floor(duration)) {\n Log.debug('VIDEO_TIME video finished, resuming at start of video.');\n resumeTime = 0;\n }\n\n Log.debug('VIDEO_TIME resuming at ' + resumeTime);\n this.player.on('loaded', () => {\n this.player.setCurrentTime(resumeTime);\n });\n return true;\n }).catch(Notification.exception);\n\n return true;\n }).catch(Notification.exception);\n\n // Note: Vimeo player does not support multiple events in a single on() call. Each requires it's own function.\n\n // Catch all events where video plays.\n this.player.on('play', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME play');\n }.bind(this));\n this.player.on('playing', function() {\n this.playing = true;\n Log.debug('VIDEO_TIME playing');\n }.bind(this));\n\n // Catch all events where video stops.\n this.player.on('pause', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME pause');\n }.bind(this));\n this.player.on('stalled', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME stalled');\n }.bind(this));\n this.player.on('suspend', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME suspend');\n }.bind(this));\n this.player.on('abort', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME abort');\n }.bind(this));\n\n this.player.getPlaybackRate().then(function(playbackRate) {\n this.playbackRate = playbackRate || 1;\n }.bind(this)).catch(Notification.exception);\n\n this.player.on('playbackratechange', function(event) {\n this.playbackRate = event.playbackRate || 1;\n }.bind(this));\n\n // Always update internal values for percent and current time watched.\n this.player.on('timeupdate', function(event) {\n this.percent = event.percent;\n this.currentTime = event.seconds;\n Log.debug('VIDEO_TIME timeupdate. Percent: ' + this.percent + '. Current time: ' + this.currentTime);\n }.bind(this));\n\n // Initiate video finish procedure.\n this.player.on('ended', function() {\n this.playing = false;\n Log.debug('VIDEO_TIME ended');\n\n new Promise(function(resolve) {\n this.getSession().then(function(session) {\n resolve(session);\n return true;\n }).catch(Notification.exception);\n }.bind(this)).then(function(session) {\n this.setSessionState(session.id, 1);\n return session;\n }.bind(this)).then(function(session) {\n this.setPercent(session.id, 1);\n return session;\n }.bind(this)).then(function(session) {\n this.setCurrentTime(session.id, this.currentTime);\n return session;\n }.bind(this)).catch(Notification.exception).finally(function() {\n this.getSession().then(function(session) {\n this.getNextActivityButtonData(session.id).then(function(response) {\n let data = JSON.parse(response.data);\n\n if (data.instance && parseInt(data.instance.next_activity_auto)) {\n if (!data.is_restricted && data.hasnextcm) {\n let link = $('.aalink[href=\"' + data.nextcm_url + '\"] img').first();\n if ($('.path-course-view').length && link) {\n link.click();\n } else {\n window.location.href = data.nextcm_url;\n }\n }\n }\n\n Templates.render('videotime/next_activity_button', JSON.parse(response.data))\n .then(function(html) {\n $('#next-activity-button').html(html);\n return true;\n }).fail(Notification.exception);\n return true;\n }).fail(Notification.exception);\n }.bind(this)).catch(Notification.exception);\n }.bind(this)).fail(Notification.exception);\n }.bind(this));\n\n // If this is a tab play set time cues and listener.\n $($('#' + this.elementId).closest('.videotimetabs')).each(function(i, tabs) {\n $(tabs).find('[data-action=\"cue\"]').each(function(index, anchor) {\n let starttime = anchor.getAttribute('data-start'),\n time = starttime.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\\.[0-9]+))/);\n if (time) {\n this.player.addCuePoint(\n 3600 * Number(time[3] || 0) + 60 * Number(time[5] || 0) + Number(time[6]),\n {\n starttime: starttime\n }\n ).catch(Notification.exeception);\n }\n }.bind(this));\n\n this.player.on('cuepoint', function(event) {\n if (event.data.starttime) {\n $(tabs).find('.videotime-highlight').removeClass('videotime-highlight');\n $(tabs).find('[data-action=\"cue\"][data-start=\"' + event.data.starttime + '\"]')\n .closest('.row')\n .addClass('videotime-highlight');\n $('.videotime-highlight').each(function() {\n if (this.offsetTop) {\n this.parentNode.scrollTo({\n top: this.offsetTop - 50,\n left: 0,\n behavior: 'smooth'\n });\n }\n });\n }\n });\n }.bind(this));\n };\n\n /**\n * Start interval that will periodically record user progress via Ajax.\n */\n VideoTime.prototype.startWatchInterval = function() {\n if (this.watchInterval) {\n return;\n }\n\n this.watchInterval = setInterval(function() {\n this.getPaused().then(paused => {\n if (paused) {\n return;\n }\n this.time += this.playbackRate;\n this.intervalcount += 1;\n\n this.getSession().then(function(session) {\n if (this.intervalcount % this.interval === 0) {\n Log.debug('VIDEO_TIME watch_time: ' + this.time + '. percent: ' + this.percent);\n this.recordWatchTime(session.id, this.time);\n this.setPercent(session.id, this.percent);\n this.setCurrentTime(session.id, this.currentTime);\n }\n return true;\n }.bind(this)).catch(Notification.exception);\n });\n }.bind(this), 1000);\n };\n\n /**\n * Set state on session.\n *\n * @param {int} sessionId\n * @param {int} state\n * @returns {Promise}\n */\n VideoTime.prototype.setSessionState = function(sessionId, state) {\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_session_state',\n args: {\"session_id\": sessionId, state: state}\n }])[0];\n };\n\n /**\n * Set current watch time for video. Used for resuming.\n *\n * @param {int} sessionId\n * @param {float} currentTime\n * @returns {Promise}\n */\n VideoTime.prototype.setCurrentTime = function(sessionId, currentTime) {\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_session_current_time',\n args: {\"session_id\": sessionId, \"current_time\": currentTime},\n fail: function(e) {\n Log.debug(e);\n document.querySelectorAll('.videotime-server-error').forEach(warning => {\n warning.classList.remove('hidden');\n });\n }\n }])[0];\n };\n\n /**\n * Set video watch percentage for session.\n *\n * @param {int} sessionId\n * @param {float} percent\n * @returns {Promise}\n */\n VideoTime.prototype.setPercent = function(sessionId, percent) {\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_set_percent',\n args: {\"session_id\": sessionId, percent: percent}\n }])[0];\n };\n\n /**\n * Record watch time for session.\n *\n * @param {int} sessionId\n * @param {float} time\n * @returns {Promise}\n */\n VideoTime.prototype.recordWatchTime = function(sessionId, time) {\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_record_watch_time',\n args: {\"session_id\": sessionId, time: time}\n }])[0];\n };\n\n /**\n * Get data for next activity button.\n *\n * @param {int} sessionId\n * @returns {Promise}\n */\n VideoTime.prototype.getNextActivityButtonData = function(sessionId) {\n return Ajax.call([{\n methodname: 'videotimeplugin_pro_get_next_activity_button_data',\n args: {\"session_id\": sessionId}\n }])[0];\n };\n\n /**\n * Get VideoTime instance for this course module.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getInstance = function() {\n if (this.instance) {\n return Promise.resolve(this.instance);\n }\n\n return new Promise((resolve) => {\n Ajax.call([{\n methodname: 'mod_videotime_get_videotime',\n args: {cmid: this.cmId}\n }])[0].then((response) => {\n this.instance = response;\n resolve(this.instance);\n return true;\n }).fail(Notification.exception);\n });\n };\n\n /**\n * Get time to resume video as seconds.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getResumeTime = function() {\n if (this.resumeTime) {\n return Promise.resolve(this.resumeTime);\n }\n\n return new Promise((resolve) => {\n Ajax.call([{\n methodname: 'videotimeplugin_pro_get_resume_time',\n args: {cmid: this.cmId}\n }])[0].then((response) => {\n this.resumeTime = response.seconds;\n resolve(this.resumeTime);\n return true;\n }).fail(Notification.exception);\n });\n };\n\n /**\n * Get new or existing video viewing session.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.getSession = function() {\n if (this.session) {\n return this.session;\n }\n\n this.session = Ajax.call([{\n methodname: 'videotimeplugin_pro_get_new_session',\n args: {cmid: this.cmId}\n }])[0].fail((e) => {\n this.session = null;\n Notification.exception(e);\n return e;\n });\n\n return this.session;\n };\n\n /**\n * Parse start time and set player\n *\n * @param {string} starttime\n * @returns {Promise}\n */\n VideoTime.prototype.setStartTime = function(starttime) {\n let time = starttime.match(/((([0-9]+):)?(([0-9]+):))?([0-9]+(\\.[0-9]+))/);\n if (time) {\n this.resumeTime = 3600 * Number(time[3] || 0) + 60 * Number(time[5] || 0) + Number(time[6]);\n return this.player.setCurrentTime(this.resumeTime);\n }\n return this.player.getCurrentTime();\n };\n\n /**\n * Log the user view of video.\n *\n * @returns {Promise}\n */\n VideoTime.prototype.view = function() {\n return Ajax.call([{\n methodname: 'mod_videotime_view_videotime',\n args: {cmid: this.cmId}\n }])[0];\n };\n\n /**\n * Initialize new labels and preview when editing\n */\n VideoTime.prototype.initializeNewInstances = function() {\n if (this.modulecount == $('body .activity.videotime').length) {\n return;\n }\n this.modulecount = $('body .activity.videotime').length;\n $('body .activity.videotime').each(function(index, module) {\n if (\n !$(module).find('.instancename').length\n && $(module).find('.vimeo-embed').length\n && !$(module).find('.vimeo-embed iframe').length\n ) {\n let instance = {\n cmid: Number($(module).attr('id').replace('module-', '')),\n haspro: true,\n interval: this.interval,\n uniqueid: $(module).find('.vimeo-embed').first().attr('id').replace('vimeo-embed-', '')\n };\n Templates.render('mod_videotime/videotime_instance', {\n instance: instance\n }).then(function(html, js) {\n Templates.runTemplateJS(js);\n return true;\n }).fail(Notification.exception);\n }\n }.bind(this));\n };\n\n return VideoTime;\n});\n"],"file":"videotime.min.js"} \ No newline at end of file diff --git a/amd/src/videotime.js b/amd/src/videotime.js index cc06bcca..3c2948db 100644 --- a/amd/src/videotime.js +++ b/amd/src/videotime.js @@ -36,6 +36,7 @@ define([ this.played = false; this.playing = false; + this.intervalcount = 0; this.time = 0; this.percent = 0; this.currentTime = 0; @@ -336,9 +337,10 @@ define([ return; } this.time += this.playbackRate; + this.intervalcount += 1; this.getSession().then(function(session) { - if (this.time / this.playbackRate % this.interval === 0) { + if (this.intervalcount % this.interval === 0) { Log.debug('VIDEO_TIME watch_time: ' + this.time + '. percent: ' + this.percent); this.recordWatchTime(session.id, this.time); this.setPercent(session.id, this.percent); diff --git a/version.php b/version.php index 11d21220..4004129f 100644 --- a/version.php +++ b/version.php @@ -26,6 +26,6 @@ $plugin->component = 'mod_videotime'; $plugin->release = '1.5.7'; -$plugin->version = 2022091406; +$plugin->version = 2022091407; $plugin->requires = 2015111610; $plugin->maturity = MATURITY_STABLE;