'./component.js'에서 컴포넌트 가져오기;
'./utils/merge-options.js'에서 mergeOptions 가져오기;
'글로벌/문서'에서 문서 가져오기;
* './utils/browser.js'에서 브라우저로 가져오기;
'글로벌/창'에서 창 가져오기;
import * as Fn from './utils/fn.js';
const 기본값 = {
추적 임계값: 20,
liveTolerance: 15
};
/*
라이브 에지에 있을 때 추적 및 라이브 재생을 위한 기타 도우미 */
/**
* 라이브 현재 시간을 확인하고 플레이어가
* 라이브 에지 또는 그 뒤에 있습니다.
*/
클래스 LiveTracker 확장 구성 요소 {
/**
* 이 클래스의 인스턴스를 만듭니다.
*
* @param {플레이어} 플레이어
* 이 클래스가 연결되어야 하는 `Player`.
*
* @param {객체} [옵션]
* 플레이어 옵션의 키/값 저장소.
*
* @param {숫자} [options.trackingThreshold=20]
* 라이브 창(seekableEnd - seekableStart)의 초 수
* 미디어가 있어야 라이브 UI가 표시됩니다.
*
* @param {숫자} [options.liveTolerance=15]
* 우리가 있어야 하는 생방송보다 몇 초 뒤에
* 라이브가 아닌 것으로 간주되기 전에. 이것은 단지
* 라이브 에지에서 플레이할 때 사용합니다. 이것은 큰 탐색 가능한 끝을 허용합니다
* 라이브 여부에 영향을 주지 않도록 변경합니다.
*/
생성자(플레이어, 옵션) {
// LiveTracker에는 요소가 필요하지 않습니다.
const options_ = mergeOptions(defaults, options, {createEl: false});
슈퍼(플레이어, 옵션_);
this.handleVisibilityChange_ = (e) => this.handleVisibilityChange(e);
this.trackLiveHandler_ = () => this.trackLive_();
this.handlePlay_ = (e) => this.handlePlay(e);
this.handleFirstTimeupdate_ = (e) => this.handleFirstTimeupdate(e);
this.handleSeeked_ = (e) => this.handleSeeked(e);
this.seekToLiveEdge_ = (e) => this.seekToLiveEdge(e);
this.reset_();
this.on(this.player_, 'durationchange', (e) => this.handleDurationchange(e));
// Safari와 같은 기본 재생 엔진으로 canplay에서 추적을 토글해야 합니다.
// 그때까지 seekableEnd와 같은 항목에 대한 적절한 값이 없을 수 있습니다.
this.on(this.player_, 'canplay', () => this.toggleTracking());
// 문서가 숨겨져 있으면 실시간 재생을 추적할 필요가 없습니다.
// 또한 문서가 숨겨져 있을 때 추적할 수 있습니다.
// CPU가 급증하고 결국 IE11에서 페이지가 충돌합니다.
경우 (browser.IE_VERSION && 문서에 '숨겨진' && 문서의 'visibilityState') {
this.on(문서, 'visibilitychange', this.handleVisibilityChange_);
}
}
/**
* 문서 가시성에 따라 추적 토글
*/
handleVisibilityChange() {
if (this.player_.duration() !== Infinity) {
반품;
}
if (문서.숨김) {
this.stopTracking();
} else {
this.startTracking();
}
}
/**
* 탐색 종료 변경 시 추적을 위한 모든 기능
* 탐색 끝을 지나 얼마나 멀리 있어야 하는지 추적하기 위해
*/
trackLive_() {
const seekable = this.player_.seekable();
// 정의되지 않은 검색 가능 항목 건너뛰기
if (!탐색가능 || !탐색가능.길이) {
반품;
}
const newTime = Number(window.performance.now().toFixed(4));
const deltaTime = this.lastTime_ === -1 ? 0 : (newTime - this.lastTime_) / 1000;
this.lastTime_ = newTime;
this.pastSeekEnd_ = this.pastSeekEnd() + deltaTime;
const liveCurrentTime = this.liveCurrentTime();
const currentTime = this.player_.currentTime();
// true인 경우 live 뒤에 있습니다.
// 1. 플레이어가 일시중지됨
// 2. 사용자는 라이브에서 2초 떨어진 위치를 찾았습니다.
// 3. 라이브 시간과 현재 시간의 차이가 더 큽니다.
// 기본값이 15초인 liveTolerance
let isBehind = this.player_.paused() || this.seekedBehindLive_ ||
Math.abs(liveCurrentTime - 현재시간) > this.options_.liveTolerance;
// 우리는 뒤에 있을 수 없는 경우
// 1. 아직 timeupdate를 보지 않을 때까지
// 2. liveCurrentTime은 Android 및 기본 Safari에서 발생하는 Infinity입니다.
if (!this.timeupdateSeen_ || liveCurrentTime === Infinity) {
isBehind = 거짓;
}
if (isBehind !== this.behindLiveEdge_) {
this.behindLiveEdge_ = isBehind;
this.trigger('liveedgechange');
}
}
/**
* 플레이어에서 durationchange 이벤트 처리
* 그에 따라 추적을 시작/중지합니다.
*/
handleDurationchange() {
this.toggleTracking();
}
/**
* 추적 시작/중지
*/
토글트래킹() {
if (this.player_.duration() === 무한대 && this.liveWindow() > = this.options_.trackingThreshold) {
if (this.player_.options_.liveui) {
this.player_.addClass('vjs-liveui');
}
this.startTracking();
} else {
this.player_.removeClass('vjs-liveui');
this.stopTracking();
}
}
/**
* 실시간 재생 추적 시작
*/
시작 추적() {
if (this.isTracking()) {
반품;
}
// timeupdate를 보지 못한 경우 재생 여부를 확인해야 합니다.
// 이 구성 요소가 추적을 시작하기 전에 시작되었습니다. 이것은 일반적으로 발생할 수 있습니다
// 자동 재생을 사용할 때.
if (!this.timeupdateSeen_) {
this.timeupdateSeen_ = this.player_.hasStarted();
}
this.trackingInterval_ = this.setInterval(this.trackLiveHandler_, Fn.UPDATE_REFRESH_INTERVAL);
this.trackLive_();
this.on(this.player_, ['재생', '일시중지'], this.trackLiveHandler_);
if (!this.timeupdateSeen_) {
this.one(this.player_, '플레이', this.handlePlay_);
this.one(this.player_, 'timeupdate', this.handleFirstTimeupdate_);
} else {
this.on(this.player_, '검색', this.handleSeeked_);
}
}
/**
* 플레이어가 아직 재생되지 않은 경우 플레이어에서 첫 번째 업데이트를 처리합니다.
* 라이브 트래커가 트래킹을 시작했을 때.
*/
handleFirstTimeupdate() {
this.timeupdateSeen_ = 참;
this.on(this.player_, '검색', this.handleSeeked_);
}
/**
* 탐색이 시작되는 시간을 추적하고 탐색을 듣습니다.
* 찾기가 끝나는 곳을 찾기 위해.
*/
handleSeeked() {
const timeDiff = Math.abs(this.liveCurrentTime() - this.player_.currentTime());
this.seekedBehindLive_ = this.nextSeekedFromUser_ && 시간 차이 > 2;
this.nextSeekedFromUser_ = 거짓;
this.trackLive_();
}
/**
* 플레이어의 첫 번째 플레이를 처리하고 우리가 찾는지 확인합니다.
* 라이브 엣지 바로.
*/
핸들플레이() {
this.one(this.player_, 'timeupdate', this.seekToLiveEdge_);
}
/**
* 추적을 중지하고 모든 내부 변수를
* 초기 값.
*/
초기화_() {
this.lastTime_ = -1;
this.pastSeekEnd_ = 0;
this.lastSeekEnd_ = -1;
this.behindLiveEdge_ = 참;
this.timeupdateSeen_ = 거짓;
this.seekedBehindLive_ = 거짓;
this.nextSeekedFromUser_ = 거짓;
this.clearInterval(this.trackingInterval_);
this.trackingInterval_ = null;
this.off(this.player_, ['재생', '일시정지'], this.trackLiveHandler_);
this.off(this.player_, '검색', this.handleSeeked_);
this.off(this.player_, '플레이', this.handlePlay_);
this.off(this.player_, 'timeupdate', this.handleFirstTimeupdate_);
this.off(this.player_, 'timeupdate', this.seekToLiveEdge_);
}
/**
* 다음으로 찾는 이벤트는 사용자가 보낸 이벤트입니다. 모든 추구를 의미
* > 라이브 비하인드 2는 실제 라이브 비하인드로 간주되며
* liveTolerance는 무시됩니다.
*/
nextSeekedFromUser() {
this.nextSeekedFromUser_ = 참;
}
/**
* 실시간 재생 추적 중지
*/
stopTracking() {
if (!this.isTracking()) {
반품;
}
this.reset_();
this.trigger('liveedgechange');
}
/**
* 플레이어가 찾는 끝을 얻는 도우미
* 모든 곳에서 null 검사를 할 필요가 없도록
*
* @return {숫자}
* 가장 멀리 찾을 수 있는 끝 또는 무한대.
*/
탐색 가능한 종료() {
const seekable = this.player_.seekable();
const seekableEnds = [];
i = 탐색 가능 합니까? 검색 가능 길이 : 0;
동안 (i--) {
seekableEnds.push(seekable.end(i));
}
// 정렬 후 검색 가능한 가장 먼 끝을 잡거나 없는 경우
// 기본값은 무한대로
seekableEnds.length를 반환합니까? seekableEnds.sort()[seekableEnds.length - 1] : 무한대;
}
/**
* 플레이어가 탐색 가능한 시작을 할 수 있도록 도와주는 도우미
* 모든 곳에서 null 검사를 할 필요가 없도록
*
* @return {숫자}
* 검색 가능한 가장 빠른 시작 또는 0.
*/
탐색 가능한 시작() {
const seekable = this.player_.seekable();
const seekableStarts = [];
i = 탐색 가능 합니까? 검색 가능 길이 : 0;
동안 (i--) {
seekableStarts.push(seekable.start(i));
}
// 정렬 후 첫 번째 검색 가능한 시작을 가져오거나 없는 경우
// 기본값은 0
seekableStarts.length를 반환합니까? seekableStarts.sort()[0] : 0;
}
/**
* 라이브 시간 창 일명 받기
* 검색 가능한 시작과
* 라이브 현재 시간.
*
* @return {숫자}
* 탐색 가능한 시간(초)
* 라이브 영상.
*/
라이브윈도우() {
const liveCurrentTime = this.liveCurrentTime();
// liveCurrenTime이 Infinity이면 liveWindow가 전혀 없습니다.
if (liveCurrentTime === Infinity) {
0을 반환합니다.
}
return liveCurrentTime - this.seekableStart();
}
/**
* 플레이어가 라이브인지 확인하고 이 구성 요소가 있는지 확인합니다.
* 라이브 재생을 추적하는지 여부
*
* @return {부울}
* Wether liveTracker가 추적 중입니다.
*/
라이브() {
return this.isTracking();
}
/**
* currentTime이 라이브 에지에 있고 뒤쳐지지 않을지 여부를 결정합니다.
* 각 검색 가능한 변경 사항
*
* @return {부울}
* Wether 재생은 라이브 에지에 있습니다.
*/
atLiveEdge() {
return !this.behindLiveEdge();
}
/**
* 라이브 현재 시간이 예상되는 것을 얻습니다.
*
* @return {숫자}
* 예상 라이브 현재 시간
*/
liveCurrentTime() {
return this.pastSeekEnd() + this.seekableEnd();
}
/**
* 검색 가능한 종료 후 발생한 초 수
* 변경되었습니다. 검색 가능한 끝이 변경되면 0으로 재설정됩니다.
*
* @return {숫자}
* 현재 검색 가능한 끝을 지난 초
*/
과거탐색종료() {
const seekableEnd = this.seekableEnd();
if (this.lastSeekEnd_ !== -1 && seekableEnd !== this.lastSeekEnd_) {
this.pastSeekEnd_ = 0;
}
this.lastSeekEnd_ = seekableEnd;
this.pastSeekEnd_를 반환합니다.
}
/**
* 현재 라이브 에지 뒤에 있는 경우 일명 currentTime은
* seekableendchange 뒤에
*
* @return {부울}
* 우리가 라이브 엣지 뒤에 있는 경우
*/
비하인드엣지() {
this.behindLiveEdge_를 반환합니다.
}
/**
* Wether 라이브 추적기가 현재 추적 중인지 아닌지.
*/
isTracking() {
return typeof this.trackingInterval_ === '숫자';
}
/**
* 우리가 라이브 에지 뒤에 있다면 라이브 에지를 찾으십시오.
*/
seekToLiveEdge() {
this.seekedBehindLive_ = 거짓;
if (this.atLiveEdge()) {
반품;
}
this.nextSeekedFromUser_ = 거짓;
this.player_.currentTime(this.liveCurrentTime());
}
/**
* liveTracker 폐기
*/
폐기() {
this.off(문서, 'visibilitychange', this.handleVisibilityChange_);
this.stopTracking();
super.dispose();
}
}
Component.registerComponent('LiveTracker', LiveTracker);
기본 LiveTracker 내보내기;