feat: update video player
This commit is contained in:
parent
74f37055bc
commit
0ccbfb5f5a
@ -1,10 +1,13 @@
|
||||
import AppRouter from "@/routes";
|
||||
import {ConfigProvider} from "@/contexts/config";
|
||||
import {AuthProvider} from "@/contexts/auth";
|
||||
import LivePlayer from "@/pages/live-player";
|
||||
import React from 'react';
|
||||
// import LivePlayer from "@/pages/live-player";
|
||||
|
||||
console.log(`APP-BUILD-AT: ${AppBuildVersion}`)
|
||||
|
||||
const LivePlayer = React.lazy(() => import('@/pages/live-player'));
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<ConfigProvider>
|
||||
|
131
src/components/video/Mp4Player.tsx
Normal file
131
src/components/video/Mp4Player.tsx
Normal file
@ -0,0 +1,131 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
// import TCPlayer from 'tcplayer.js';
|
||||
|
||||
import flvPlayer, { VideoPlayer } from '@/components/video/VideoPlayer.ts';
|
||||
import {PlayerInstance} from "@/hooks/useCache.ts";
|
||||
|
||||
// import 'tcplayer.js/dist/tcplayer.min.css';
|
||||
|
||||
type State = {
|
||||
playing: boolean
|
||||
muted: boolean
|
||||
end?: boolean
|
||||
error?: boolean
|
||||
fullscreen: boolean
|
||||
progress: number
|
||||
playedSeconds: number
|
||||
duration: number
|
||||
}
|
||||
type StateUpdate = Partial<State> | ((prev: State) => Partial<State>)
|
||||
|
||||
type Props = {
|
||||
url?: string; cover?: string; showControls?: boolean; className?: string;
|
||||
poster?: string;
|
||||
onChange?: (state: State) => void;
|
||||
onProgress?: (current:number,duration:number) => void;
|
||||
muted?: boolean;
|
||||
autoPlay?: boolean;
|
||||
}
|
||||
export type PlayerInstance = {
|
||||
play: (url: string, currentTime: number) => void;
|
||||
pause: () => void;
|
||||
getState: () => State;
|
||||
}
|
||||
|
||||
export const Mp4Player = React.forwardRef<PlayerInstance, Props>((props, ref) => {
|
||||
const [tcPlayer, setTcPlayer] = useState<VideoPlayer | null>(null)
|
||||
const [prevUrl, setPrevUrl] = useState<string | undefined>();
|
||||
const [state, _setState] = useState<State>({
|
||||
playing: false,
|
||||
muted: false,
|
||||
// 是否全屏
|
||||
fullscreen: false,
|
||||
progress: 0,
|
||||
playedSeconds: 0,
|
||||
duration: 0
|
||||
})
|
||||
|
||||
const setState = (data: StateUpdate) => {
|
||||
console.log('playstate change', data)
|
||||
_setState(prev => {
|
||||
const _state = typeof (data) === 'function' ? {...prev, ...data(prev)} : {...prev, ...data}
|
||||
props.onChange?.(_state)
|
||||
return _state
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
if(props.url && tcPlayer){
|
||||
tcPlayer.src(props.url)
|
||||
}
|
||||
},[props.url, tcPlayer])
|
||||
|
||||
useEffect(() => {
|
||||
const player = flvPlayer.newInstance({className:props.className});
|
||||
document.querySelector('.video-player-container-inner')!.appendChild(player.getVideo())
|
||||
// const player = TCPlayer(playerVideo, {
|
||||
// controls: props.showControls,
|
||||
// poster: props.poster,
|
||||
// autoplay: typeof(props.autoPlay) != 'undefined' ? props.autoPlay : true,
|
||||
// licenseUrl: AppConfig.TCPlayerLicense
|
||||
// }
|
||||
// ) as TCPlayerInstance;
|
||||
|
||||
player.on('pause', () => {
|
||||
setState({playing: false, end: false, error: false})
|
||||
})
|
||||
player.on('playing', () => {
|
||||
setState({playing: true, end: false, error: false})
|
||||
})
|
||||
player.on('ended', () => {
|
||||
setState({end: true, playing: false, error: false})
|
||||
})
|
||||
player.on('timeupdate', () => {
|
||||
props.onProgress?.(player.currentTime(), player.duration())
|
||||
})
|
||||
player.on('error', () => {
|
||||
setState({end: false, playing: false, error: true})
|
||||
})
|
||||
setTcPlayer(() => player)
|
||||
return () => {
|
||||
console.log('destroy video')
|
||||
try{
|
||||
// player.unload();
|
||||
player.dispose();
|
||||
setTcPlayer(() => null)
|
||||
//Array.from(document.querySelectorAll('video')).forEach(v => v.pause())
|
||||
}catch (e){
|
||||
console.log(e)
|
||||
}
|
||||
//playerVideo.parentElement?.removeChild(playerVideo)
|
||||
}
|
||||
}, [])
|
||||
React.useImperativeHandle(ref, () => {
|
||||
return {
|
||||
pause(){
|
||||
if (!tcPlayer) return;
|
||||
tcPlayer.pause()
|
||||
},
|
||||
play: (url, currentTime = 0) => {
|
||||
// console.log('play', url, currentTime)
|
||||
url = url.replace('.flv','.mp4');
|
||||
if (!tcPlayer) return;
|
||||
const player = tcPlayer
|
||||
if (prevUrl == url) {
|
||||
player.currentTime(0)
|
||||
} else {
|
||||
player.src(url)
|
||||
}
|
||||
player.play()
|
||||
setPrevUrl(url)
|
||||
if (currentTime > 0) {
|
||||
player.currentTime(currentTime)
|
||||
}
|
||||
},
|
||||
getState: () => state
|
||||
}
|
||||
})
|
||||
|
||||
return <div className={`video-player relative ${props.className} video-player-container-inner`}>
|
||||
</div>
|
||||
})
|
165
src/components/video/VideoPlayer.ts
Normal file
165
src/components/video/VideoPlayer.ts
Normal file
@ -0,0 +1,165 @@
|
||||
type VideoPlayerEvents =
|
||||
'playing'
|
||||
| 'pause'
|
||||
| 'ended'
|
||||
| 'timeupdate'
|
||||
| 'error'
|
||||
| 'canplay'
|
||||
| 'durationchange'
|
||||
| 'progress'
|
||||
|
||||
type PlayerOptions = {
|
||||
enableLog?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
enum PlayState {
|
||||
playing = 'playing',
|
||||
pause = 'pause',
|
||||
ended = 'ended',
|
||||
error = 'error',
|
||||
}
|
||||
|
||||
export class VideoPlayer {
|
||||
private video?: HTMLVideoElement;
|
||||
private State: PlayState = PlayState.pause;
|
||||
private enable_log = true;
|
||||
private currentDuration = 0;
|
||||
|
||||
|
||||
newInstance(options?: PlayerOptions) {
|
||||
const { className, enableLog=true } = options || {};
|
||||
this.enable_log = enableLog || false;
|
||||
|
||||
if (this.video) {
|
||||
this.video.remove();
|
||||
}
|
||||
if (this.video) {
|
||||
this.video.pause();
|
||||
}
|
||||
// Create video element
|
||||
const playerVideo = document.createElement('video');
|
||||
const playerId = `player-container-${Date.now().toString(16)}`;
|
||||
playerVideo.setAttribute('id', playerId);
|
||||
playerVideo.setAttribute('preload', 'auto');
|
||||
playerVideo.setAttribute('playsInline', 'true');
|
||||
playerVideo.setAttribute('webkit-playsinline', 'true');
|
||||
if (className) playerVideo.setAttribute('className', className);
|
||||
playerVideo.classList.add('digital-video-player');
|
||||
playerVideo.addEventListener('durationchange', (e) => {
|
||||
this.currentDuration = Math.floor(this.video?.duration || 0);
|
||||
this.log('video duration change',e)
|
||||
});
|
||||
playerVideo.addEventListener('error', (e) => {
|
||||
this.log('video error:',e)
|
||||
});
|
||||
this.video = playerVideo;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志
|
||||
* @param args
|
||||
*/
|
||||
log(...args: any[]) {
|
||||
if (this.enable_log) {
|
||||
console.log(...args);
|
||||
}
|
||||
}
|
||||
|
||||
getVideo() {
|
||||
return this.video!;
|
||||
}
|
||||
|
||||
// 暂停视频
|
||||
pause() {
|
||||
this.video?.pause();
|
||||
// 更新状态
|
||||
this.State = PlayState.pause;
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听视频事件
|
||||
* @param event
|
||||
* @param callback
|
||||
*/
|
||||
on(event: VideoPlayerEvents, callback: () => void) {
|
||||
this.video?.addEventListener(event, callback);
|
||||
|
||||
}
|
||||
|
||||
off(event: VideoPlayerEvents, callback: () => void) {
|
||||
this.video?.removeEventListener(event, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取或这是当前播放时间点
|
||||
* @param time
|
||||
*/
|
||||
currentTime(time?: number) {
|
||||
if (!this.video) return 0;
|
||||
if (typeof time === 'number' && this.video.currentTime !== time) {
|
||||
try {
|
||||
this.video.currentTime = time;
|
||||
} catch (err) {
|
||||
this.log('Failed to set currentTime', err);
|
||||
}
|
||||
}
|
||||
return this.video.currentTime || 0;
|
||||
}
|
||||
|
||||
src(url: string) {
|
||||
if (!this.video) return;
|
||||
this.video.src = url;
|
||||
this.video.load();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放
|
||||
*/
|
||||
play() {
|
||||
if (!this.video) return;
|
||||
this.video.play().then(() => {
|
||||
this.State = PlayState.playing;
|
||||
}).catch((err) => {
|
||||
this.State = PlayState.error;
|
||||
this.log('play error', err);
|
||||
});
|
||||
}
|
||||
|
||||
duration() {
|
||||
return this.currentDuration || this.video?.duration || 0;
|
||||
}
|
||||
dispose(){
|
||||
if(!this.video){
|
||||
return;
|
||||
}
|
||||
// 暂停
|
||||
this.pause();
|
||||
// 移除
|
||||
this.video.parentNode?.removeChild(this.video);
|
||||
this.video = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* player.on('pause', () => {
|
||||
* setState({playing: false, end: false, error: false})
|
||||
* })
|
||||
* player.on('playing', () => {
|
||||
* setState({playing: true, end: false, error: false})
|
||||
* })
|
||||
* player.on('ended', () => {
|
||||
* setState({end: true, playing: false, error: false})
|
||||
* })
|
||||
* player.on('timeupdate', () => {
|
||||
* props.onProgress?.(player.currentTime(), player.duration())
|
||||
* })
|
||||
* player.on('error', () => {
|
||||
* setState({end: false, playing: false, error: true})
|
||||
* })
|
||||
*/
|
||||
|
||||
const videoPlayer = new VideoPlayer();
|
||||
export default videoPlayer;
|
@ -1,11 +1,10 @@
|
||||
// import ReactPlayer from 'react-player'
|
||||
// import {PauseOutlined, PlayCircleOutlined, FullscreenOutlined, FullscreenExitOutlined} from "@ant-design/icons"
|
||||
// import {Progress} from "antd";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {PlayerInstance} from "@/hooks/useCache.ts";
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import TCPlayer from 'tcplayer.js';
|
||||
import 'tcplayer.js/dist/tcplayer.min.css';
|
||||
|
||||
import { PlayerInstance } from '@/hooks/useCache.ts';
|
||||
import videoPlayer from '@/components/video/VideoPlayer.ts';
|
||||
|
||||
type State = {
|
||||
playing: boolean
|
||||
muted: boolean
|
||||
@ -22,7 +21,7 @@ type Props = {
|
||||
url?: string; cover?: string; showControls?: boolean; className?: string;
|
||||
poster?: string;
|
||||
onChange?: (state: State) => void;
|
||||
onProgress?: (current:number,duration:number) => void;
|
||||
onProgress?: (current: number, duration: number) => void;
|
||||
muted?: boolean;
|
||||
autoPlay?: boolean;
|
||||
}
|
||||
@ -32,8 +31,9 @@ export type PlayerInstance = {
|
||||
getState: () => State;
|
||||
}
|
||||
export const Player = React.forwardRef<PlayerInstance, Props>((props, ref) => {
|
||||
const [tcPlayer, setTcPlayer] = useState<TCPlayer | null>(null)
|
||||
const [prevUrl, setPrevUrl] = useState<string | undefined>();
|
||||
const [tcPlayer, setTcPlayer] = useState<TCPlayerInstance | null>(null);
|
||||
|
||||
const [state, _setState] = useState<State>({
|
||||
playing: false,
|
||||
muted: false,
|
||||
@ -42,105 +42,85 @@ export const Player = React.forwardRef<PlayerInstance, Props>((props, ref) => {
|
||||
progress: 0,
|
||||
playedSeconds: 0,
|
||||
duration: 0
|
||||
})
|
||||
});
|
||||
|
||||
const setState = (data: StateUpdate) => {
|
||||
console.log('playstate change', data)
|
||||
console.log('playstate change', data);
|
||||
_setState(prev => {
|
||||
const _state = typeof (data) === 'function' ? {...prev, ...data(prev)} : {...prev, ...data}
|
||||
props.onChange?.(_state)
|
||||
return _state
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
if(props.url && tcPlayer){
|
||||
tcPlayer.src(props.url)
|
||||
}
|
||||
},[props.url, tcPlayer])
|
||||
const _state = typeof (data) === 'function' ? { ...prev, ...data(prev) } : { ...prev, ...data };
|
||||
props.onChange?.(_state);
|
||||
return _state;
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if(PlayerInstance.length != 0){
|
||||
PlayerInstance.forEach(player => player.pause())
|
||||
PlayerInstance.length = 0
|
||||
if (props.url && tcPlayer) {
|
||||
tcPlayer.src(props.url);
|
||||
}
|
||||
const playerVideo = document.createElement('video');
|
||||
const playerId = `player-container-${Date.now().toString(16)}`;
|
||||
playerVideo.setAttribute('id', playerId)
|
||||
playerVideo.setAttribute('preload', 'auto')
|
||||
playerVideo.setAttribute('playsInline', 'true')
|
||||
playerVideo.setAttribute('webkit-playsinline', 'true')
|
||||
if(props.className) playerVideo.setAttribute('className', props.className)
|
||||
playerVideo.classList.add('digital-video-player')
|
||||
PlayerInstance.push(playerVideo)
|
||||
document.querySelector('.video-player-container-inner')!.appendChild(playerVideo)
|
||||
}, [props.url, tcPlayer]);
|
||||
|
||||
const player = TCPlayer(playerId, {
|
||||
useEffect(() => {
|
||||
const playerVideo = videoPlayer.newInstance().getVideo();
|
||||
document.querySelector('.video-player-container-inner')!.appendChild(playerVideo);
|
||||
|
||||
const flvPlayer = TCPlayer(playerVideo, {
|
||||
//sources: [{src: props.url}],
|
||||
controls: props.showControls,
|
||||
// muted:props.muted,
|
||||
poster: props.poster,
|
||||
autoplay: typeof(props.autoPlay) != 'undefined' ? props.autoPlay : true,
|
||||
autoplay: typeof (props.autoPlay) != 'undefined' ? props.autoPlay : true,
|
||||
licenseUrl: 'https://license.vod2.myqcloud.com/license/v2/1328581896_1/v_cube.license'
|
||||
}
|
||||
)
|
||||
player.on('pause', () => {
|
||||
setState({playing: false, end: false, error: false})
|
||||
})
|
||||
player.on('playing', () => {
|
||||
setState({playing: true, end: false, error: false})
|
||||
})
|
||||
player.on('ended', () => {
|
||||
setState({end: true, playing: false, error: false})
|
||||
})
|
||||
player.on('timeupdate', () => {
|
||||
props.onProgress?.(player.currentTime(), player.duration())
|
||||
})
|
||||
player.on('error', () => {
|
||||
setState({end: false, playing: false, error: true})
|
||||
})
|
||||
setTcPlayer(() => player)
|
||||
);
|
||||
|
||||
flvPlayer.on('pause', () => {
|
||||
setState({ playing: false, end: false, error: false });
|
||||
});
|
||||
flvPlayer.on('playing', () => {
|
||||
setState({ playing: true, end: false, error: false });
|
||||
});
|
||||
flvPlayer.on('ended', () => {
|
||||
setState({ end: true, playing: false, error: false });
|
||||
});
|
||||
flvPlayer.on('timeupdate', () => {
|
||||
props.onProgress?.(flvPlayer.currentTime(), flvPlayer.duration());
|
||||
});
|
||||
flvPlayer.on('error', () => {
|
||||
setState({ end: false, playing: false, error: true });
|
||||
});
|
||||
setTcPlayer(() => flvPlayer);
|
||||
return () => {
|
||||
// if (tcPlayer) {
|
||||
// tcPlayer.pause()
|
||||
// tcPlayer.unload()
|
||||
// }else{
|
||||
// playerVideo.pause()
|
||||
// }
|
||||
console.log('destroy video')
|
||||
try{
|
||||
Array.from(document.querySelectorAll('video')).forEach(v => v.pause())
|
||||
}catch (e){
|
||||
console.log(e)
|
||||
}
|
||||
playerVideo.parentElement?.removeChild(playerVideo)
|
||||
}
|
||||
}, [])
|
||||
tcPlayer?.pause();
|
||||
console.log('destroy video');
|
||||
tcPlayer?.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
React.useImperativeHandle(ref, () => {
|
||||
return {
|
||||
pause(){
|
||||
pause() {
|
||||
if (!tcPlayer) return;
|
||||
tcPlayer.pause()
|
||||
tcPlayer.pause();
|
||||
},
|
||||
play: (url, currentTime = 0) => {
|
||||
console.log('play', url, currentTime)
|
||||
console.log('play', url, currentTime);
|
||||
if (!tcPlayer) return;
|
||||
const player = tcPlayer
|
||||
const player = tcPlayer;
|
||||
if (prevUrl == url) {
|
||||
player.currentTime(0)
|
||||
player.currentTime(0);
|
||||
} else {
|
||||
player.src(url)
|
||||
player.src(url);
|
||||
}
|
||||
player.play()
|
||||
setPrevUrl(url)
|
||||
player.play();
|
||||
setPrevUrl(url);
|
||||
if (currentTime > 0) {
|
||||
player.currentTime(currentTime)
|
||||
player.currentTime(currentTime);
|
||||
}
|
||||
},
|
||||
getState: () => state
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
return <div className={`video-player relative ${props.className} video-player-container-inner`}>
|
||||
</div>
|
||||
})
|
||||
</div>;
|
||||
});
|
@ -89,7 +89,7 @@ export const VideoListItem = (
|
||||
>{index}</div>
|
||||
<div className="col cover cursor-pointer" onClick={onItemClick}>
|
||||
<div className="relative">
|
||||
<img className="w-[100px] h-[56px] object-cover" src={video.cover || ImageCover}/>
|
||||
<img className="w-[100px] h-[56px] object-cover border border-gray-200" src={video.cover || ImageCover}/>
|
||||
{generating &&
|
||||
<div
|
||||
className={'absolute rounded inset-0 bg-black/40 backdrop-blur-[1px] text-white flex items-center justify-center'}>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {useMount} from "ahooks";
|
||||
import {getLiveUrl} from "@/service/api/live.ts";
|
||||
import React, {useState} from "react";
|
||||
|
||||
import {getLiveUrl} from "@/service/api/live.ts";
|
||||
import {Player} from "@/components/video/player.tsx";
|
||||
import './style.scss'
|
||||
|
||||
|
@ -76,7 +76,7 @@ export default function VideoIndex() {
|
||||
|
||||
// 播放视频
|
||||
const playVideo = (video: VideoInfo) => {
|
||||
console.log('play video',video)
|
||||
|
||||
if (state.playingId == video.id) {
|
||||
player.current?.pause();
|
||||
setState({playingId: -1})
|
||||
@ -86,9 +86,9 @@ export default function VideoIndex() {
|
||||
// setState({playingIndex})
|
||||
// player.current?.play('https://staticplus.gachafun.com/ai-collect/composite_video/2024-12-17/1186196465916190720.flv', 30)
|
||||
//
|
||||
if (video.oss_video_url && video.status !== 1) {
|
||||
if (video.oss_video_mp4_url && video.status !== 1) {
|
||||
setState({playingId: video.id})
|
||||
player.current?.play(video.oss_video_url, 0)
|
||||
player.current?.play(video.oss_video_mp4_url, 0)
|
||||
}
|
||||
}
|
||||
// 处理全选
|
||||
@ -227,14 +227,6 @@ export default function VideoIndex() {
|
||||
handleModifySort(newSorts)
|
||||
return newSorts;
|
||||
});
|
||||
// modal.confirm({
|
||||
// title: '提示',
|
||||
// content: '是否要移动到指定位置',
|
||||
// onOk: handleModifySort,
|
||||
// onCancel: () => {
|
||||
// setVideoData(originArr);
|
||||
// }
|
||||
// })
|
||||
}
|
||||
}}>
|
||||
<SortableContext items={videoData}>
|
||||
|
61
src/types/tcplayer.d.ts
vendored
Normal file
61
src/types/tcplayer.d.ts
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
|
||||
|
||||
type TCPlayerEvents = 'play' // 已经开始播放,调用 play() 方法或者设置了 autoplay 为 true 且生效时触发,这时 paused 属性为 false。
|
||||
| 'playing' // 因缓冲而暂停或停止后恢复播放时触发,paused 属性为 false 。通常用这个事件来标记视频真正播放,play 事件只是开始播放,画面并没有开始渲染。
|
||||
| 'loadstart' // 开始加载数据时触发。
|
||||
| 'durationchange' // 视频的时长数据发生变化时触发。
|
||||
| 'loadedmetadata' // 已加载视频的 metadata。
|
||||
| 'loadeddata' // 当前帧的数据已加载,但没有足够的数据来播放视频的下一帧时,触发该事件。
|
||||
| 'progress' // 在获取到媒体数据时触发。
|
||||
| 'canplay' // 当播放器能够开始播放视频时触发。
|
||||
| 'canplaythrough' // 当播放器预计能够在不停下来进行缓冲的情况下持续播放指定的视频时触发。
|
||||
| 'error' // 视频播放出现错误时触发。
|
||||
| 'pause' // 暂停时触发。
|
||||
| 'blocked' // 自动播放被浏览器阻止时触发。(原 2005 回调事件统一合并到 blocked 事件中)。
|
||||
| 'ratechange' // 播放速率变更时触发。
|
||||
| 'seeked' // 搜寻指定播放位置结束时触发。
|
||||
| 'seeking' // 搜寻指定播放位置开始时触发。
|
||||
| 'timeupdate' // 当前播放位置有变更,可以理解为 currentTime 有变更。
|
||||
| 'volumechange' // 设置音量或者 muted 属性值变更时触发。
|
||||
| 'waiting' // 播放停止,下一帧内容不可用时触发。
|
||||
| 'ended' // 视频播放已结束时触发。此时 currentTime 值等于媒体资源最大值。
|
||||
| 'resolutionswitching' // 清晰度切换进行中。
|
||||
| 'resolutionswitched' // 清晰度切换完毕。
|
||||
| 'fullscreenchange' //全屏状态切换时触发。
|
||||
| 'webrtcevent' // 播放 webrtc 时的事件集合。
|
||||
| 'webrtcstats' // 播放 webrtc 时的统计数据。
|
||||
| 'webrtcfallback' // 播放 webrtc 时触发降级。
|
||||
|
||||
declare type TCPlayerInstance = {
|
||||
//监听事件。
|
||||
on: (event: TCPlayerEvents, callback: () => void) => void;
|
||||
// 取消监听事件。
|
||||
off: (event: TCPlayerEvents, callback: () => void) => void;
|
||||
// 监听事件,事件处理函数最多只执行1次。
|
||||
one: (event: TCPlayerEvents, callback: () => void) => void;
|
||||
// 设置播放地址。
|
||||
src: (url: string) => void;
|
||||
// 设置播放器初始化完成后的回调。
|
||||
ready: (callback: () => void) => void;
|
||||
play: () => void;
|
||||
pause: () => void;
|
||||
unload: () => void;
|
||||
//获取或设置播放器是否静音。
|
||||
muted: (mute: boolean) => boolean | void;
|
||||
//获取或设置播放器音量。
|
||||
volume: (percent: number) => number | void;
|
||||
// 获取或设置播放倍速。
|
||||
playbackRate: (percent: number) => number | void;
|
||||
//获取当前播放时间点,或者设置播放时间点,该时间点不能超过视频时长。
|
||||
currentTime: (seconds?: number) => number;
|
||||
//获取视频时长。
|
||||
duration: () => number;
|
||||
// 销毁播放器。
|
||||
dispose: () => number;
|
||||
};
|
||||
|
||||
declare function TCPlayer(container: HTMLVideoElement | string, options: any): TCPlayerInstance;
|
||||
|
||||
declare module 'tcplayer.js' {
|
||||
export default TCPlayer;
|
||||
}
|
2
src/vite-env.d.ts
vendored
2
src/vite-env.d.ts
vendored
@ -14,6 +14,8 @@ declare const AppConfig: {
|
||||
API_PREFIX: string;
|
||||
ONLY_LIVE: string;
|
||||
APP_LANG: string;
|
||||
// 腾讯播放器
|
||||
TCPlayerLicense: string;
|
||||
};
|
||||
declare const AppMode: 'test' | 'production' | 'development';
|
||||
|
||||
|
@ -4,6 +4,10 @@ import {resolve} from "path";
|
||||
import AppPackage from './package.json'
|
||||
import dayjs from "dayjs";
|
||||
|
||||
// 播放器 SDK Web 端(TCPlayer)自 5.0.0 版本起需获取 License 授权后方可使用。
|
||||
// <p>https://cloud.tencent.com/document/product/881/77877#.E5.87.86.E5.A4.87.E5.B7.A5.E4.BD.9C</p>
|
||||
const TCPlayerLicense = 'https://license.vod2.myqcloud.com/license/v2/1328581896_1/v_cube.license'
|
||||
|
||||
const DevServerList:{
|
||||
[key:string]:string
|
||||
} = {
|
||||
@ -30,7 +34,8 @@ export default defineConfig(({mode}) => {
|
||||
AUTH_TOKEN_KEY: process.env.AUTH_TOKEN_KEY || AUTH_TOKEN_KEY,
|
||||
AUTHED_PERSON_DATA_KEY: process.env.AUTHED_PERSON_DATA_KEY || 'digital-person-user-info',
|
||||
ONLY_LIVE: process.env.ONLY_LIVE || 'no',
|
||||
APP_LANG: process.env.APP_LANGUAGE
|
||||
APP_LANG: process.env.APP_LANGUAGE,
|
||||
TCPlayerLicense
|
||||
}),
|
||||
AppMode: JSON.stringify(mode),
|
||||
AppBuildVersion: JSON.stringify(AppPackage.name + '-' + AppPackage.version + '-' + dayjs().format('YYYYMMDDHH_mmss'))
|
||||
|
Loading…
x
Reference in New Issue
Block a user