You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
educoder/public/react/src/modules/courses/Video/video-play/index.jsx

192 lines
5.0 KiB

import React, { useRef, useEffect, useCallback } from 'react'
Object.defineProperty(HTMLMediaElement.prototype, 'playing', {
get: function () {
return !!(this.currentTime > 0 && !this.paused && !this.ended && this.readyState > 2)
}
})
function compareNumbers(a, b) {
return a - b;
}
function getTotalEffectTime(pos) {
pos.sort(compareNumbers)
let sum = 0
for (let i = 0; i < pos.length - 1; i++) {
let v = pos[i + 1] - pos[i]
if (v < 21) {
sum += v
}
}
return sum
}
const regex = /(android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini)/i
//接口文档 https://www.showdoc.cc/educoder?page_id=4029884447803706
export default ({ src, videoId, logWatchHistory, courseId = null }) => {
const suf = src.split('.').pop()
const isFlv = suf === 'flv'
const el = useRef()
const deviceMatch = navigator.userAgent.toLowerCase().match(regex)
const device = deviceMatch ? deviceMatch[0] : 'pc'
let totalDuration = 0
let sumTimePlayed = 0
let lastUpdatedTime = 0
let logId = null
let initLog = false
let timeTick = 20 //记录频率 默认20s
let logCount = 1
let isLoging = false
let isSeeking = false
let pos = []//播放时间点集
const log = useCallback((callback, isEnd = false) => {
let params = {
point: el.current.currentTime
}
if (logId) {
params['log_id'] = logId
params['watch_duration'] = getTotalEffectTime(pos) //当前观看视频时长,拖放进度条,重复的视频片段观看时,不会把重复的时长累积进来,最大时长是视频的总时长
params['total_duration'] = sumTimePlayed //累计观看视频时长,拖放进度条,重复的视频片段观看时,重复观看时长要累积进来
} else {
if (courseId) {
params['video_id'] = parseInt(videoId, 10)
params['course_id'] = parseInt(courseId, 10)
} else {
params['video_id'] = videoId
}
params['duration'] = totalDuration
params['device'] = device
}
if (isEnd) {
params['ed'] = "1"
}
async function getLogId() {
isLoging = true
let id = await logWatchHistory(params)
logId = id
isLoging = false
if (callback) {
callback()
}
}
getLogId()
}, [videoId, courseId])
useEffect(() => {
let player = null
if (window.flvjs.isSupported && isFlv) {
player = window.flvjs.createPlayer({
type: 'flv',
volume: 0.8,
cors: true,
url: src,
muted: false
})
if (el.current) {
player.attachMediaElement(el.current)
player.load()
}
} else {
el.current.setAttribute('src', src)
}
return () => {
if (player) {
player.unload()
player.pause()
player.destroy()
player = null
}
}
}, [el, isFlv, src])
useEffect(() => {
function onPlay() {
pos.push(el.current.currentTime)
if (!initLog) {
initLog = true
log()
}
}
//循环播放, 累计时长不能清空
async function onEnded() {
log(() => {
logId = null
lastUpdatedTime = 0
initLog = false
isLoging = false
isSeeking = false
}, true)
}
function onTimeupdate() {
if (!isSeeking) {
let newTime = el.current.currentTime
let timeDiff = newTime - lastUpdatedTime
//currenttime update before Seeking & Seeked fired
if (Math.abs(timeDiff) < 0.5) {
sumTimePlayed += Math.abs(timeDiff)
lastUpdatedTime = newTime
if (!isLoging) {
if (sumTimePlayed - logCount * timeTick >= 0) {
logCount++
pos.push(lastUpdatedTime)
log()
}
}
} else {
lastUpdatedTime = newTime
}
}
}
function onSeeking() {
isSeeking = true
}
function onSeeked() {
if (el.current.playing) {
pos.push(el.current.currentTime, lastUpdatedTime)
}
lastUpdatedTime = el.current.currentTime
isSeeking = false
}
function onCanPlay() {
totalDuration = el.current.duration
if (totalDuration <= 20) {
timeTick = totalDuration / 3
}
el.current.addEventListener('play', onPlay)
}
el.current.addEventListener('canplay', onCanPlay)
el.current.addEventListener('ended', onEnded)
el.current.addEventListener('seeking', onSeeking)
el.current.addEventListener('seeked', onSeeked)
el.current.addEventListener('timeupdate', onTimeupdate)
return () => {
el.current.removeEventListener('canplay', onCanPlay)
el.current.removeEventListener('play', onPlay)
el.current.removeEventListener('ended', onEnded)
el.current.removeEventListener('seeking', onSeeking)
el.current.removeEventListener('seeked', onSeeked)
el.current.removeEventListener('timeupdate', onTimeupdate)
if (el.current.playing) {
log()
}
}
}, [el, src])
return (
<video ref={el} controls autoPlay={false} controlsList="nodownload" muted={false} />
)
}