'./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 내보내기;