feat: 添加自动播放
This commit is contained in:
parent
983b35f914
commit
74b52562f4
@ -1,4 +1,4 @@
|
|||||||
import React, {useEffect, useRef, useState} from "react";
|
import React, {useEffect, useMemo, useRef, useState} from "react";
|
||||||
import {Button, Modal} from "antd";
|
import {Button, Modal} from "antd";
|
||||||
import {SortableContext, arrayMove} from '@dnd-kit/sortable';
|
import {SortableContext, arrayMove} from '@dnd-kit/sortable';
|
||||||
import {DndContext} from "@dnd-kit/core";
|
import {DndContext} from "@dnd-kit/core";
|
||||||
@ -9,8 +9,11 @@ import {deleteByIds, getList, modifyOrder, playState} from "@/service/api/live.t
|
|||||||
import {showErrorToast, showToast} from "@/components/message.ts";
|
import {showErrorToast, showToast} from "@/components/message.ts";
|
||||||
import ButtonBatch from "@/components/button-batch.tsx";
|
import ButtonBatch from "@/components/button-batch.tsx";
|
||||||
import FlvJs from "flv.js";
|
import FlvJs from "flv.js";
|
||||||
|
import {formatDuration} from "@/util/strings.ts";
|
||||||
|
import {useSetState} from "ahooks";
|
||||||
|
import {set} from "lodash";
|
||||||
|
|
||||||
const cache: { flvPlayer?: FlvJs.Player } = {}
|
const cache: { flvPlayer?: FlvJs.Player,timerPlayNext?:any,timerLoadState?:any } = {}
|
||||||
export default function LiveIndex() {
|
export default function LiveIndex() {
|
||||||
const videoRef = useRef<HTMLVideoElement | null>(null)
|
const videoRef = useRef<HTMLVideoElement | null>(null)
|
||||||
const [videoData, setVideoData] = useState<LiveVideoInfo[]>([])
|
const [videoData, setVideoData] = useState<LiveVideoInfo[]>([])
|
||||||
@ -18,9 +21,14 @@ export default function LiveIndex() {
|
|||||||
const [checkedIdArray, setCheckedIdArray] = useState<number[]>([])
|
const [checkedIdArray, setCheckedIdArray] = useState<number[]>([])
|
||||||
const [editable, setEditable] = useState<boolean>(false)
|
const [editable, setEditable] = useState<boolean>(false)
|
||||||
|
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useSetState({
|
||||||
activeIndex: -1,
|
activeIndex: -1,
|
||||||
|
muted: true,
|
||||||
})
|
})
|
||||||
|
const activeIndex = useRef(state.activeIndex)
|
||||||
|
useEffect(()=>{
|
||||||
|
activeIndex.current = state.activeIndex
|
||||||
|
},[state.activeIndex])
|
||||||
|
|
||||||
const showVideoItem = (index: number) => {
|
const showVideoItem = (index: number) => {
|
||||||
// 找到对应video item 并显示在视图可见区域
|
// 找到对应video item 并显示在视图可见区域
|
||||||
@ -42,29 +50,28 @@ export default function LiveIndex() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const activeToNext = (index?: number) => {
|
const activeToNext = (index?: number) => {
|
||||||
const endToFirst = index != undefined && index > -1 ? false : state.activeIndex >= videoData.length - 1
|
const endToFirst = index != undefined && index > -1 ? false : activeIndex.current >= videoData.length - 1
|
||||||
const activeIndex = index != undefined && index > -1 ? index : (endToFirst ? 0 : state.activeIndex + 1)
|
const _activeIndex = index != undefined && index > -1 ? index : (endToFirst ? 0 : activeIndex.current + 1)
|
||||||
setState(() => {
|
setState({activeIndex:_activeIndex})
|
||||||
return {
|
|
||||||
activeIndex
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if (endToFirst) {
|
if (endToFirst) {
|
||||||
showToast('即将播放第一条视频');
|
showToast('即将播放第一条视频');
|
||||||
}
|
}
|
||||||
// 找到对应video item 并显示在视图可见区域
|
// 找到对应video item 并显示在视图可见区域
|
||||||
showVideoItem(activeIndex)
|
showVideoItem(_activeIndex)
|
||||||
|
return _activeIndex;
|
||||||
}
|
}
|
||||||
const playVideo = (video: LiveVideoInfo, state: LiveState) => {
|
const playVideo = (video: LiveVideoInfo, liveState: LiveState) => {
|
||||||
if (videoRef.current && video.video_oss_url) {
|
if (videoRef.current && video.video_oss_url) {
|
||||||
const playedTime = Date.now() / 1000 >> 0 - state.start_time
|
if(cache.timerPlayNext) clearTimeout(cache.timerPlayNext)
|
||||||
if (playedTime < 0 || playedTime > video.video_duration) { // 已播放时间大于总时长了
|
const duration = Math.ceil(video.video_duration / 1000)
|
||||||
initPlayingState() // 重新获取播放状态
|
const playedTime =( Date.now() / 1000 >> 0) - liveState.live_start_time
|
||||||
|
if (playedTime < 0 || playedTime > duration) { // 已播放时间大于总时长了
|
||||||
|
//initPlayingState() // 重新获取播放状态
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (/mp4$/i.test(video.video_oss_url)) {
|
if (/mp4$/i.test(video.video_oss_url)) {
|
||||||
videoRef.current!.src = video.video_oss_url
|
videoRef.current!.src = video.video_oss_url
|
||||||
videoRef.current!.currentTime = playedTime
|
if(liveState.live_start_time > 0 && playedTime > 0) videoRef.current!.currentTime = playedTime
|
||||||
videoRef.current!.play()
|
videoRef.current!.play()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -80,44 +87,56 @@ export default function LiveIndex() {
|
|||||||
url: video.video_oss_url
|
url: video.video_oss_url
|
||||||
})
|
})
|
||||||
|
|
||||||
cache.flvPlayer.on('ended', () => {
|
|
||||||
//activeToNext()
|
|
||||||
initPlayingState()
|
|
||||||
})
|
|
||||||
cache.flvPlayer.attachMediaElement(videoRef.current!)
|
cache.flvPlayer.attachMediaElement(videoRef.current!)
|
||||||
cache.flvPlayer.load()
|
cache.flvPlayer.load()
|
||||||
cache.flvPlayer.currentTime = playedTime
|
|
||||||
|
if(liveState.live_start_time > 0 && playedTime > 0) videoRef.current!.currentTime = playedTime
|
||||||
|
|
||||||
cache.flvPlayer.play()
|
cache.flvPlayer.play()
|
||||||
|
cache.timerPlayNext = setTimeout(()=>{
|
||||||
|
const index = activeToNext(),nextVideo = videoData[index]
|
||||||
|
playVideo(nextVideo,{live_start_time:(Date.now() / 1000 >> 0),id:nextVideo.id})
|
||||||
|
},(duration - playedTime) * 1000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const initPlayingState = (videoList?: LiveVideoInfo[] | null) => {
|
const initPlayingState = () => {
|
||||||
const list = videoList || videoData || []
|
if(cache.timerLoadState) clearTimeout(cache.timerLoadState)
|
||||||
playState().then(state => {
|
if(videoData.length == 0) {
|
||||||
const video = list.find(v => v.id === state.id)
|
cache.timerLoadState = setTimeout(initPlayingState, 1000)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
playState().then(liveState => {
|
||||||
|
const video = videoData.find(v => v.id === liveState.id)
|
||||||
if (video) {
|
if (video) {
|
||||||
activeToNext(list.findIndex(v => v.id === state.id))
|
activeToNext(videoData.findIndex(v => v.id === liveState.id))
|
||||||
playVideo(video, state)
|
playVideo(video, liveState)
|
||||||
} else {
|
} else {
|
||||||
setState({activeIndex: -1})
|
setState({activeIndex: -1})
|
||||||
setTimeout(() => {
|
cache.timerLoadState = setTimeout(initPlayingState, 5000)
|
||||||
initPlayingState()
|
|
||||||
}, 5000)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const clearAllTimer = ()=>{
|
||||||
|
|
||||||
|
if(cache.timerPlayNext) clearTimeout(cache.timerPlayNext)
|
||||||
|
if(cache.timerLoadState) clearTimeout(cache.timerLoadState)
|
||||||
|
}
|
||||||
|
|
||||||
const loadList = () => {
|
const loadList = () => {
|
||||||
|
clearAllTimer();
|
||||||
getList().then(res => {
|
getList().then(res => {
|
||||||
console.log('origin list', res.list.map(s => s.id))
|
// console.log('origin list', res.list.map(s => s.id))
|
||||||
setVideoData(res.list || [])
|
setVideoData(()=>(res.list || []))
|
||||||
setCheckedIdArray([])
|
setCheckedIdArray([])
|
||||||
initPlayingState(res.list)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(loadList, [])
|
useEffect(()=>{
|
||||||
|
loadList()
|
||||||
|
initPlayingState();
|
||||||
|
return clearAllTimer;
|
||||||
|
}, [])
|
||||||
|
|
||||||
const processDeleteVideo = async (ids: number[]) => {
|
const processDeleteVideo = async (ids: number[]) => {
|
||||||
deleteByIds(ids).then(() => {
|
deleteByIds(ids).then(() => {
|
||||||
@ -154,18 +173,32 @@ export default function LiveIndex() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const totalDuration = useMemo(() => {
|
||||||
|
if (!videoData || videoData.length == 0) return 0;
|
||||||
|
// 计算总时长
|
||||||
|
return videoData.reduce((sum, v) => sum + v.video_duration, 0);
|
||||||
|
}, [videoData])
|
||||||
|
|
||||||
return (<div className="container py-10 page-live">
|
return (<div className="container py-10 page-live">
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="video-player-container mr-8 flex flex-col">
|
<div className="video-player-container mr-8 flex flex-col">
|
||||||
<div className="text-center text-base">数字人直播间</div>
|
<div className="text-center text-base">数字人直播间</div>
|
||||||
<div className="video-player flex justify-center flex-1 mt-5">
|
<div className="video-player flex justify-center flex-1 mt-5">
|
||||||
<div className="live-player rounded overflow-hidden w-[360px] h-[700px]">
|
<div className="live-player relative rounded overflow-hidden w-[360px] h-[636px]" style={{backgroundColor:'hsl(210, 100%, 48%)'}}>
|
||||||
<video ref={videoRef} controls autoPlay
|
<video ref={videoRef} autoPlay muted={state.muted}
|
||||||
className="w-[360px] rounded overflow-hidden h-full object-contain"></video>
|
className="w-[360px] rounded overflow-hidden h-full object-contain"></video>
|
||||||
{/*<iframe src="https://fm.gachafun.com/" className="border-0 w-full h-full max-h-full"></iframe>*/}
|
{state.muted && state.activeIndex != -1 && <div className="absolute inset-0 flex items-center justify-center">
|
||||||
|
<Button onClick={()=>{
|
||||||
|
setState({muted: false})
|
||||||
|
videoRef.current!.muted= false;
|
||||||
|
}}>开启声音</Button>
|
||||||
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mt-4 text-center text-sm">
|
||||||
|
<span>视频时长: {formatDuration(totalDuration)}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="video-list-container flex-1">
|
<div className="video-list-container flex-1">
|
||||||
<div className=" bg-white py-8 px-6 rounded">
|
<div className=" bg-white py-8 px-6 rounded">
|
||||||
|
2
src/types/api.d.ts
vendored
2
src/types/api.d.ts
vendored
@ -103,5 +103,5 @@ declare interface LiveVideoInfo {
|
|||||||
|
|
||||||
declare interface LiveState{
|
declare interface LiveState{
|
||||||
id: number;
|
id: number;
|
||||||
start_time?: number;
|
live_start_time?: number;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user