javascript - 如何最好地跟踪视频的播放时长?

标签 javascript html video

当用户观看视频时,我想进行2次AJAX调用。一种是当用户看完视频并且播放的时间等于或大于视频的持续时间时(因为用户也可以倒带)。 timePlayed>=duration && event.type==“已结束”。我成功地调用了电话。

我遇到困难的是,我还想在视频观看超过 80% 并且视频播放时间超过 80% 时调用电话,以防止用户快进。

为了使其正常工作,我必须修改我的 videoStartedPlaying() 方法,这就是我在尝试设置时间间隔时遇到问题的地方。现在,设置了一个间隔,就像一个无限循环。

var video_data = document.getElementById("video");

var timeStarted = -1;
var timePlayed = 0;
var duration = 0;

// If video metadata is loaded get duration
if(video_data.readyState > 0)
    getDuration.call(video_data);
//If metadata not loaded, use event to get it
else {
    video_data.addEventListener('loadedmetadata', getDuration);
}

// remember time user started the video
function videoStartedPlaying() {
    timeStarted = new Date().getTime()/1000;
    setInterval(function(){
        playedFor = new Date().getTime()/1000 - timeStarted;
        checkpoint = playedFor / duration;
        percentComplete = video_data.currentTime/video_data.duration;

        // here I need help of how to best accomplish this
        if (percentComplete >= 0.8 && checkpoint >= 0.8) {
            // AJAX call here
        }
    }, 2000);
}

function videoStoppedPlaying(event) {
    // Start time less then zero means stop event was fired vidout start event
    if(timeStarted>0) {
        var playedFor = new Date().getTime()/1000 - timeStarted;
        timeStarted = -1;
        // add the new amount of seconds played
        timePlayed+=playedFor;
    }

    // Count as complete only if end of video was reached
    if(timePlayed>=duration && event.type=="ended") {
        // AJAX call here
    }
}

function getDuration() {
    duration = video_data.duration;
}

video_data.addEventListener("play", videoStartedPlaying);
video_data.addEventListener("playing", videoStartedPlaying);
video_data.addEventListener("ended", videoStoppedPlaying);
video_data.addEventListener("pause", videoStoppedPlaying);

我真的很感激任何有关这方面的帮助,因为我似乎已经束手无策了。

非常感谢!

编辑: 感谢评论,我想出了这个:

const video = document.getElementById("video");
const set = new Set();
const percent = .8;
let toWatch;

function mediaWatched (curr) {
  alert(`${curr}% of media watched`)
}

function handleMetadata(e) {
  toWatch = Math.ceil(video.duration * percent);
  console.log(toWatch, video.duration);
}

function handleTimeupdate (e) {
  set.add(Math.ceil(video.currentTime));
  let watched = Array.from(set).pop();
  if (set.has(toWatch) && watched === toWatch) {
    video.removeEventListener("timeupdate", handleTimeupdate);
    console.log(watched);
    mediaWatched(
      Math.round(watched / Math.ceil(video.duration) * 100)
    );
  }
}

video.addEventListener("loadedmetadata", handleMetadata);

video.addEventListener("timeupdate", handleTimeupdate);
<video width="400" height="300" controls="true" poster="" id="video">
    <source type="video/mp4" src="http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_2mb.mp4" />
</video>

现在,例如,如果我快进到大约 50% 的长度,然后让它播放,那么只要达到电影的 80%,它就会触发,但它不应该,因为我快进到 50% 并且本质上只看了30%。

这有道理吗?我怎样才能实现这样的行为?

最佳答案

根据评论中的讨论,这里有一个工作示例。

它包含几个处理程序,只是为了让设置数组和对内容求和变得更容易,以便您知道何时达到 80% 标记(尽管如果您想强制它们,您可能需要更改该逻辑) ,比如说,明确观看前 80%,而不仅仅是整个视频的总共 80%)。

其中有许多 console.log(...) 语句,因此您可以在浏览器控制台窗口中观察它在做什么...您可能想将它们删除在真正部署之前。

我已经在 timeupdate 事件中放置了在何处进行 ajax 调用的钩子(Hook),但您也可以始终在主循环中使用常规 setInterval 计时器检查 80% 并在那里进行调用,但这看起来更干净

大部分内容应该是不言自明的,但如果有任何不清楚的地方,请在评论中询问......

<video controls preload="auto" id="video" width="640" height="365" muted>
      <source src="http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_2mb.mp4" type="video/mp4">
    </video>

<script>

 // handler to let me resize the array once we know the length
 Array.prototype.resize = function(newSize, defaultValue) {
    while(newSize > this.length)
        this.push(defaultValue);
    this.length = newSize;
}

// function to round up a number
function roundUp(num, precision) {
  return Math.ceil(num * precision) / precision
} 

var vid = document.getElementById("video")
var duration = 0; // will hold length of the video in seconds
var watched = new Array(0);
var reported80percent = false;

vid.addEventListener('loadedmetadata', getDuration, false);
vid.addEventListener('timeupdate',timeupdate,false)

function timeupdate() {
    currentTime = parseInt(vid.currentTime);
    // set the current second to "1" to flag it as watched
    watched[currentTime] = 1;

    // show the array of seconds so you can track what has been watched
    // you'll note that simply looping over the same few seconds never gets
    // the user closer to the magic 80%...
    console.log(watched);

    // sum the value of the array (add up the "watched" seconds)
    var sum = watched.reduce(function(acc, val) {return acc + val;}, 0);
    // take your desired action on the ?80% completion
    if ((sum >= (duration * .8)) && !reported80percent) {
        // set reported80percent to true so that the action is triggered once and only once
        // could also unregister the timeupdate event to avoid calling unneeded code at this point
        // vid.removeEventListener('timeupdate',timeupdate)
        reported80percent = true;
        console.log("80% watched...")
        // your ajax call to report progress could go here...   
    }
}

function getDuration() {
    console.log("duration:" + vid.duration)
    // get the duration in seconds, rounding up, to size the array
    duration = parseInt(roundUp(vid.duration,1));
    // resize the array, defaulting entries to zero
    console.log("resizing arrary to " + duration + " seconds.");
    watched.resize(duration,0)
}

</script> 

关于javascript - 如何最好地跟踪视频的播放时长?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42310019/

相关文章:

javascript - 使用插值标记分割字符串

html - <元字符集 ="UTF-8"> 未验证

php - Moov原子重定位

image - Qt jpg图像显示

javascript - IE 中关于 ZK 和 JavaScript 集成的一些错误

javascript - 如何等待回调为不支持 promise 和/或异步等待的旧浏览器运行?

javascript - MongoDb 中的自动增量字段与异步批量插入

javascript - HTML5 Canvas 删除线条

javascript - 如何在不使用井号 (#) 的情况下通过 url 打开新页面并滚动到新页面的 div?

html - iframe 视频与 ios 上的填充容器重叠