From ac671f889b43a4f3802658abc91c5c4aefbfc02c Mon Sep 17 00:00:00 2001 From: harry Date: Thu, 12 Mar 2020 19:55:43 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E8=A7=86=E9=A2=91=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../react/src/modules/courses/Video/Video.js | 48 +++--- .../courses/Video/video-play/flv-player.jsx | 37 ----- .../courses/Video/video-play/index.jsx | 143 ++++++++++++++++-- .../user/usersInfo/common/HeadlessModal.js | 20 +-- .../user/usersInfo/video/InfosVideo.js | 41 ++--- public/react/src/services/video-service.js | 11 ++ 6 files changed, 193 insertions(+), 107 deletions(-) delete mode 100644 public/react/src/modules/courses/Video/video-play/flv-player.jsx create mode 100644 public/react/src/services/video-service.js diff --git a/public/react/src/modules/courses/Video/Video.js b/public/react/src/modules/courses/Video/Video.js index 89c0a0c6f..91d947300 100644 --- a/public/react/src/modules/courses/Video/Video.js +++ b/public/react/src/modules/courses/Video/Video.js @@ -13,6 +13,7 @@ import VideoPanel from './video-play' import './video.css'; import '../../user/usersInfo/video/InfosVideo.css' import axios from 'axios'; +import { logWatchHistory } from "../../../services/video-service"; const DEFAULT_VIDEO_WIDTH_IN_MD = "90%" // 400 const DEFAULT_VIDEO_HEIGHT_IN_MD = "55%" // 400 @@ -31,8 +32,8 @@ class Video extends Component { videoVisible: false, visible: false, - moveVisible:false, - moveVideoId:undefined + moveVisible: false, + moveVideoId: undefined } } @@ -70,7 +71,6 @@ class Video extends Component { } } - // 编辑成功后回调的方法 editSuccess = () => { this.props.showNotification("视频信息修改成功!"); @@ -82,7 +82,7 @@ class Video extends Component { let videoId = { videoId: item.id, title: item.title, - link:item.link + link: item.link } this.setState({ videoId, @@ -118,8 +118,6 @@ class Video extends Component { _clipboard = null; } } else { - // videoEl.current && videoEl.current.play() - setTimeout(() => { if (!_clipboard) { _clipboard = new ClipboardJS('.copybtn'); @@ -148,7 +146,7 @@ class Video extends Component { axios.delete(url, { params: { video_id: item.id, - is_link:item.link ? true : undefined + is_link: item.link ? true : undefined } }).then(result => { if (result) { @@ -168,30 +166,30 @@ class Video extends Component { } // 移动到 - moveVideo=(id,flag)=>{ - if(!flag){ + moveVideo = (id, flag) => { + if (!flag) { this.setState({ - moveVisible:true, - moveVideoId:id + moveVisible: true, + moveVideoId: id }) - }else{ + } else { this.props.define({ - title:'提示', - content:"您不是课堂管理员或者视频发布者,暂不能移动视频。", + title: '提示', + content: "您不是课堂管理员或者视频发布者,暂不能移动视频。", }) } } - setMoveVisible=(flag)=>{ + setMoveVisible = (flag) => { this.setState({ - moveVisible:flag, - moveVideoId:undefined + moveVisible: flag, + moveVideoId: undefined }) } render() { - const { visible, videoVisible, videoId , moveVisible , moveVideoId } = this.state; + const { visible, videoVisible, videoId, moveVisible, moveVideoId } = this.state; const CourseId = this.props.match.params.coursesId; - const VID=this.props.match.params.videoId; + const VID = this.props.match.params.videoId; const login = this.props.user && this.props.user.login; const _inputValue = videoId && this.getCopyText(videoId.file_url, videoId.cover_url); @@ -201,7 +199,7 @@ class Video extends Component { const { videos, upload, uploadVideo, videoData, changePage, pageSize, page } = this.props; const operation = admin || business; - const {course_identity} = this.props.coursedata; + const { course_identity } = this.props.coursedata; const flagMove = parseInt(course_identity) < 5; return ( @@ -214,8 +212,8 @@ class Video extends Component { {...this.props} visible={moveVisible} mainId={videoData && videoData.course_module_id} - setMoveVisible={(flag)=>this.setMoveVisible(flag)} - successFunc={()=>uploadVideo()} + setMoveVisible={(flag) => this.setMoveVisible(flag)} + successFunc={() => uploadVideo()} id={moveVideoId} > - {videoId && } + {videoId && }
0 ? - +

{videoData && videoData.count} 个视频

{ @@ -259,7 +257,7 @@ class Video extends Component { getCopyText={this.getCopyText} operation={operation || item.user_id === user_id} deleteVideo={(admin || item.user_id === user_id) ? this.deleteVideo : undefined} - moveVideo={videoData && videoData.has_category && flagMove ? ()=>this.moveVideo(item.id,(course_identity > 2 && item.user_id !== user_id)):undefined} + moveVideo={videoData && videoData.has_category && flagMove ? () => this.moveVideo(item.id, (course_identity > 2 && item.user_id !== user_id)) : undefined} > ) diff --git a/public/react/src/modules/courses/Video/video-play/flv-player.jsx b/public/react/src/modules/courses/Video/video-play/flv-player.jsx deleted file mode 100644 index 3a36df964..000000000 --- a/public/react/src/modules/courses/Video/video-play/flv-player.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { useEffect, useRef } from 'react' - -export default ({ url }) => { - const ref = useRef() - - useEffect(() => { - let player = null - if (window.flvjs.isSupported) { - player = window.flvjs.createPlayer({ - type: 'flv', - volume: 0.8, - cors: true, - url, - muted: false - }) - - if (ref.current) { - player.attachMediaElement(ref.current) - player.load() - player.play() - } - } - return () => { - if (player) { - player.unload() - player.pause() - player.destroy() - player = null - } - } - - }, [url, ref.current]) - - return ( - - ) -} \ No newline at end of file diff --git a/public/react/src/modules/courses/Video/video-play/index.jsx b/public/react/src/modules/courses/Video/video-play/index.jsx index 61338e202..6cb54fb5b 100644 --- a/public/react/src/modules/courses/Video/video-play/index.jsx +++ b/public/react/src/modules/courses/Video/video-play/index.jsx @@ -1,18 +1,139 @@ -import React, { Fragment } from 'react' -import ReactFlvPlayer from './flv-player' +import React, { useRef, useEffect, useCallback } from 'react' + +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 }) => { -export default ({ src }) => { const suf = src.split('.').pop() const isFlv = suf === 'flv' - return ( - - { - isFlv ? : + const el = useRef() + + const deviceMatch = navigator.userAgent.toLowerCase().match(regex) + const device = deviceMatch ? deviceMatch[0] : 'pc' + + let totalDuration = 0 + let totalTimePlayed = 0 + let sumTimePlayed = 0 + let lastUpdatedTime = 0 + let lastEffectUpdatedTime = 0 + let logId = null + let initLog = false + let timeTick = 20 //记录频率 默认20s + let logCount = 1 + + const log = useCallback((callback) => { + let params = {} + if (logId) { + params['log_id'] = logId + params['watch_duration'] = totalTimePlayed //当前观看视频时长,拖放进度条,重复的视频片段观看时,不会把重复的时长累积进来,最大时长是视频的总时长 + params['total_duration'] = sumTimePlayed //累计观看视频时长,拖放进度条,重复的视频片段观看时,重复观看时长要累积进来 + } else { + if (courseId) { + params['course_video_id'] = videoId + } else { + params['video_id'] = videoId + } + params['duration'] = totalDuration + params['device'] = device + } + async function getLogId() { + let id = await logWatchHistory(params) + logId = id + 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() { + if (!initLog) { + initLog = true + log() + } + } + + async function onEnded() { + log(() => { + logId = null + logCount = 1 + totalTimePlayed = 0 + lastUpdatedTime = 0 + sumTimePlayed = 0 + initLog = false + lastEffectUpdatedTime = 0 + }) + } + + function onTimeupdate() { + let newTime = el.current.currentTime + let timeDiff = newTime - lastUpdatedTime + let effectTimeDiff = newTime - lastEffectUpdatedTime + if (effectTimeDiff > 0) { + totalTimePlayed += effectTimeDiff + lastEffectUpdatedTime = newTime + } + sumTimePlayed += Math.abs(timeDiff) + lastUpdatedTime = newTime + + if (sumTimePlayed - logCount * timeTick >= 0) { + logCount++ + log() } - + } + 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('timeupdate', onTimeupdate) + return () => { + el.current.removeEventListener('canplay', onCanPlay) + el.current.removeEventListener('play', onPlay) + el.current.removeEventListener('ended', onEnded) + el.current.removeEventListener('timeupdate', onTimeupdate) + } + }, [el, src]) + + + return ( +