/**
 * @file video.js
 * @module videojs
 */
'../../package.json'에서 {버전} 가져오기;
'글로벌/창'에서 창 가져오기;
가져오기 {
  후크_,
  후크,
  훅,
  hookOnce,
  removeHook
} './utils/hooks'에서;
import * as setup from './setup';
import * as stylesheet from './utils/stylesheet.js';
'./component'에서 컴포넌트 가져오기;
'./event-target'에서 EventTarget 가져오기;
import * as Events from './utils/events.js';
'./player'에서 플레이어 가져오기;
'./plugin'에서 플러그인 가져오기;
'./utils/merge-options.js'에서 mergeOptions 가져오기;
import * as Fn from './utils/fn.js';
'./tracks/text-track.js'에서 TextTrack 가져오기;
'./tracks/audio-track.js'에서 AudioTrack 가져오기;
'./tracks/video-track.js'에서 VideoTrack 가져오기;

import { createTimeRanges } from './utils/time-ranges.js';
import formatTime, { setFormatTime, resetFormatTime } from './utils/format-time.js';
로그 가져오기, './utils/log.js'에서 { createLogger };
import * as Dom from './utils/dom.js';
* './utils/browser.js'에서 브라우저로 가져오기;
import * as Url from './utils/url.js';
'./utils/obj'에서 {isObject} 가져오기;
import computedStyle from './utils/computed-style.js';
import extend from './extend.js';
'@videojs/xhr'에서 xhr 가져오기;

// 내장 기술 포함
'./tech/tech.js'에서 기술 가져오기;
import { 미들웨어 사용으로 사용, TERMINATOR } from './tech/middleware.js';
import defineLazyProperty from './utils/define-lazy-property.js';

/**
 * 선행 `#`을 잘라내어 `id` 값을 정규화합니다.
 *
 * @사적인
 * @param {문자열} 아이디
 * 문자열, 아마도 앞에 `#`이 있을 것입니다.
 *
 * @return {문자열}
 * 앞에 `#`이 없는 문자열입니다.
 */
const normalizeId = (ID) => id.indexOf('#') === 0 ? id.slice(1) : id;

/**
 * `videojs()` 함수는 사용자가
 * {@link Player} 인스턴스 및 기본 라이브러리 네임스페이스.
 *
 * 기존 {@link Player} 인스턴스의 getter로도 사용할 수 있습니다.
 * 그러나 이를 위해 `videojs.getPlayer()`를 사용하는 것이 _강력하게_ 권장됩니다.
 * 의도하지 않은 초기화의 가능성을 피하기 때문에 목적.
 *
 * [제한 사항](https://github.com/jsdoc3/jsdoc/issues/955#issuecomment-313829149)으로 인해
 * JSDoc 템플릿의 경우 이를 둘 다 함수로 제대로 문서화할 수 없습니다.
 * 및 네임스페이스이므로 함수 서명은 여기에 문서화되어 있습니다.
 *
 * #### 인수
 * ##### ID
 * string|요소, **필수**
 *
 * 동영상 요소 또는 동영상 요소 ID.
 *
 * ##### 옵션
 * 개체, 선택 사항
 *
 * 설정을 제공하기 위한 옵션 개체.
 * 참조: [옵션 가이드](https://docs.videojs.com/tutorial-options.html).
 *
 * ##### 준비가 된
 * {@link Component~ReadyCallback}, 선택 사항
 *
 * {@link Player} 및 {@link Tech}가 준비되면 호출되는 함수입니다.
 *
 * #### 반환 값
 *
 * `videojs()` 함수는 {@link Player} 인스턴스를 반환합니다.
 *
 * @네임스페이스
 *
 * @Borrows AudioTrack as AudioTrack
 * @borrows Component.getComponent를 getComponent로 사용
 * @borrows 모듈:computed-style~computedStyle as computedStyle
 * @borrows 모듈:events.on as on
 * @borrows 모듈:events.one을 하나로
 * @borrows 모듈:events.off를 꺼짐으로
 * @borrows 모듈:events.trigger를 트리거로 사용
 * @borrows EventTarget을 EventTarget으로 사용
 * @borrows 모듈:extend~extend as extend
 * @borrows 모듈:바인드로 fn.bind
 * @borrows 모듈:format-time.formatTime as formatTime
 * @borrows 모듈: format-time.resetFormatTime as resetFormatTime
 * @borrows 모듈:format-time.setFormatTime as setFormatTime
 * @borrows 모듈: mergeOptions로 병합 옵션.mergeOptions
 * @borrows 모듈:middleware.use as use
 * @borrows Player.players를 플레이어로 사용
 * @borrows Plugin.registerPlugin as registerPlugin
 * @borrows Plugin.deregisterPlugin as deregisterPlugin
 * @borrows Plugin.getPlugins as getPlugins
 * @borrows Plugin.getPlugin as getPlugin
 * @borrows Plugin.getPluginVersion as getPluginVersion
 * @borrows Tech.getTech를 getTech로 사용
 * @borrows Tech.registerTech as registerTech
 * @borrows TextTrack을 TextTrack으로
 * @borrows 모듈: time-ranges.createTimeRanges as createTimeRange
 * @borrows 모듈: time-ranges.createTimeRanges as createTimeRanges
 * @borrows 모듈: url.isCrossOrigin as isCrossOrigin
 * @borrows 모듈:url.parseUrl as parseUrl
 * @borrows VideoTrack as VideoTrack
 *
 * @param {문자열|요소} id
 * 동영상 요소 또는 동영상 요소 ID.
 *
 * @param {객체} [옵션]
 * 설정을 제공하기 위한 옵션 개체.
 * 참조: [옵션 가이드](https://docs.videojs.com/tutorial-options.html).
 *
 * @param {Component~ReadyCallback} [준비]
 * {@link Player}와 {@link Tech}가 연결될 때 호출되는 함수
 * 준비가 된.
 *
 * @return {플레이어}
 * `videojs()` 함수는 {@link Player|Player} 인스턴스를 반환합니다.
 */
함수 videojs(ID, 옵션, 준비) {
  let player = videojs.getPlayer(id);

  if (플레이어) {
    if (옵션) {
      log.warn(`플레이어 "${id}"는 이미 초기화되었습니다. 옵션이 적용되지 않습니다.`);
    }
    경우 (준비) {
      player.ready(준비);
    }
    리턴 플레이어;
  }

  const el = (typeof id === '문자열') ? Dom.$('#' + normalizeId(id)) : id;

  if (!Dom.isEl(el)) {
    throw new TypeError('제공된 요소 또는 ID가 유효하지 않습니다. (videojs)');
  }

  // document.body.contains(el)는 el이 해당 문서 내에 포함되어 있는지 확인합니다.
  // 이로 인해 iframe의 요소에 문제가 발생합니다.
  // 대신 전역 문서 대신 요소의 ownerDocument를 사용합니다.
  // 이렇게 하면 해당 요소가 실제로 해당 문서의 dom에 있는지 확인합니다.
  // 또한 해당 문서에 기본 보기가 있는지 확인합니다.
  // 문서가 더 이상 dom에 연결되지 않으면 문서의 defaultView는 null이 됩니다.
  if (!el.ownerDocument.defaultView || !el.ownerDocument.body.contains(el)) {
    log.warn('제공된 요소는 DOM에 포함되어 있지 않습니다.');
  }

  옵션 = 옵션 || {};

  // destroy()에서 복원하려는 경우 수정 전에 el의 복사본을 저장합니다.
  // div가 수집되면 상위 div를 저장합니다.
  if (options.restoreEl === 참) {
    options.restoreEl = (el.parentNode && el.parentNode.hasAttribute('data-vjs-player') ? el.parentNode : el).cloneNode(참);
  }

  hooks('beforesetup').forEach((hookFunction) => {
    const opts = hookFunction(el, mergeOptions(options));

    if (!isObject(opts) || Array.isArray(opts)) {
      log.error('beforesetup hooks에서 객체를 반환하십시오.');
      반품;
    }

    options = mergeOptions(옵션, 옵션);
  });

  // 통합이 완료된 경우 현재 "Player" 구성 요소를 여기에서 얻습니다.
  // 커스텀 플레이어로 교체했습니다.
  const PlayerComponent = Component.getComponent('플레이어');

  player = new PlayerComponent(el, options, ready);

  hooks('설정').forEach((hookFunction) => hookFunction(플레이어));

  리턴 플레이어;
}

videojs.hooks_ = 후크_;
videojs.hooks = 후크;
videojs.hook = 후크;
videojs.hookOnce = hookOnce;
videojs.removeHook = removeHook;

// 기본 스타일 추가
if (window.VIDEOJS_NO_DYNAMIC_STYLE !== 참 && Dom.isReal()) {
  let style = Dom.$('.vjs-styles-defaults');

  if (! 스타일) {
    style = stylesheet.createStyleElement('vjs-styles-defaults');
    const 머리 = Dom.$('머리');

    만약 (머리) {
      head.insertBefore(스타일, head.firstChild);
    }
    stylesheet.setTextContent(스타일, `
      .비디오 JS {
        폭: 300px;
        높이: 150픽셀;
      }

      .vjs-fluid:not(.vjs-오디오 전용 모드) {
        패딩 탑: 56.25 %
      }
    `);
  }
}

// 자동 로드 플레이어 실행
// 이 스크립트가 로드된 후에 적어도 한 번은 기다려야 합니다.
// DOM의 비디오(축소된 버전에서만 이상한 동작)
setup.autoSetupTimeout(1, videojs);

/**
 * 현재 Video.js 버전. [시맨틱 버전 관리](https://semver.org/)를 따릅니다.
 *
 * @유형 {문자열}
 */
videojs.VERSION = 버전;

/**
 * 전역 옵션 개체입니다. 적용되는 설정입니다
 * 플레이어가 생성될 때 재정의가 지정되지 않은 경우.
 *
 * @type {객체}
 */
videojs.options = Player.prototype.options_;

/**
 * 플레이어 ID로 키가 지정된 현재 생성된 플레이어로 개체 가져오기
 *
 * @return {객체}
 * 생성된 플레이어
 */
videojs.getPlayers = () => 플레이어.플레이어;

/**
 * ID 또는 DOM 요소를 기반으로 단일 플레이어를 가져옵니다.
 *
 * 이것은 요소 또는 ID에 연결된 요소가 있는지 확인하려는 경우에 유용합니다.
 * Video.js 플레이어, 하지만 없으면 생성하지 않습니다.
 *
 * @param {문자열|요소} id
 * HTML 요소 - `< 동영상> `, `< 오디오> `, 또는 `< 비디오 js> ` -
 * 또는 그러한 요소의 `id`와 일치하는 문자열.
 *
 * @return {플레이어|정의되지 않음}
 * 플레이어 인스턴스 또는 플레이어 인스턴스가 없는 경우 '정의되지 않음'
 * 인수 일치.
 */
videojs.getPlayer = (id) => {
  const 플레이어 = Player.players;
  태그하자;

  if (ID 유형 === '문자열') {
    const nId = normalizeId(id);
    const player = 플레이어[nId];

    if (플레이어) {
      리턴 플레이어;
    }

    태그 = Dom.$('#' + nId);
  } else {
    태그 = 아이디;
  }

  if (Dom.isEl(태그)) {
    const {플레이어, 플레이어 ID} = 태그;

    // 요소에는 이미 생성된 플레이어를 참조하는 `player` 속성이 있을 수 있습니다.
    // 플레이어 인스턴스. 그렇다면 반환하십시오.
    if (플레이어 || 플레이어[플레이어Id]) {
      복귀 플레이어 || 플레이어[플레이어Id];
    }
  }
};

/**
 * 현재 모든 플레이어의 배열을 반환합니다.
 *
 * @return {배열}
 * 모든 플레이어의 배열. 배열은
 * `Object.keys`가 제공하며 잠재적으로
 * 자바스크립트 엔진.
 *
 */
videojs.getAllPlayers = () =>

  // 폐기된 플레이어는 `null` 값이 있는 키를 남기므로 우리는 다음을 확인해야 합니다.
  // 우리는 그것들을 걸러냅니다.
  Object.keys(Player.players).map(k => Player.players[k]).filter(Boolean);

videojs.players = 플레이어.플레이어;
videojs.getComponent = Component.getComponent;

/**
 * 이름으로 참조할 수 있도록 구성 요소를 등록합니다. 다른 것을 추가할 때 사용
 * 컴포넌트, addChild `component.addChild('myComponent')` 또는
 * 기본 자식 옵션 `{ children: ['myComponent'] }`.
 *
 * > 메모: 추가하기 전에 구성 요소를 초기화할 수도 있습니다.
 * `component.addChild(new MyComponent());`
 *
 * @param {문자열} 이름
 * 컴포넌트의 클래스 이름
 *
 * @param {구성 요소} 광고
 * 컴포넌트 클래스
 *
 * @return {구성 요소}
 * 새로 등록된 컴포넌트
 */
videojs.registerComponent = (이름, 광고) => {
  if (Tech.isTech(comp)) {
    log.warn(`${name} 기술이 구성 요소로 등록되었습니다. 대신 videojs.registerTech(name, tech)`);를 사용하여 등록해야 합니다.
  }

  Component.registerComponent.call(구성 요소, 이름, 구성 요소);
};

videojs.getTech = Tech.getTech;
videojs.registerTech = Tech.registerTech;
videojs.use = 미들웨어사용;

/**
 * 미들웨어가 반환할 수 있는 객체
 * 미들웨어가 종료되고 있음.
 *
 * @type {객체}
 * @property {객체} 미들웨어.TERMINATOR
 */
Object.defineProperty(videojs, '미들웨어', {
  값: {},
  쓰기 가능: 거짓,
  열거 가능: 참
});

Object.defineProperty(videojs.middleware, '종료자', {
  값: 터미네이터,
  쓰기 가능: 거짓,
  열거 가능: 참
});

/**
 * 객체로서의 {@link module:browser|browser utility module}에 대한 참조.
 *
 * @type {객체}
 * @see {@link module:browser|브라우저}
 */
videojs.browser = 브라우저;

/**
 * {@link module:browser.TOUCH_ENABLED|browser.TOUCH_ENABLED}를 대신 사용하세요. 오직
 * 4.x와의 하위 호환성을 위해 포함되었습니다.
 *
 * @deprecated 버전 5.0부터 {@link module:browser.TOUCH_ENABLED|browser.TOUCH_ENABLED를 대신 사용하세요.
 * @유형 {부울}
 */
videojs.TOUCH_ENABLED = 브라우저.TOUCH_ENABLED;

videojs.extend = 확장;
videojs.mergeOptions = mergeOptions;
videojs.bind = Fn.bind;
videojs.registerPlugin = Plugin.registerPlugin;
videojs.deregisterPlugin = Plugin.deregisterPlugin;

/**
 * Video.js에 플러그인을 등록하는 더 이상 사용되지 않는 방법
 *
 * @deprecated videojs.plugin()은 더 이상 사용되지 않습니다. 대신 videojs.registerPlugin() 사용
 *
 * @param {문자열} 이름
 * 플러그인 이름
 *
 * @param {플러그인|함수} 플러그인
 * 플러그인 하위 클래스 또는 기능
 */
videojs.plugin = (이름, 플러그인) => {
  log.warn('videojs.plugin()은 더 이상 사용되지 않습니다. 대신 videojs.registerPlugin()을 사용하세요.');
  return Plugin.registerPlugin(이름, 플러그인);
};

videojs.getPlugins = Plugin.getPlugins;
videojs.getPlugin = Plugin.getPlugin;
videojs.getPluginVersion = Plugin.getPluginVersion;

/**
 * 모든 플레이어가 사용할 수 있도록 언어를 추가합니다.
 * 예: `videojs.addLanguage('es', { 'Hello': '안녕' });`
 *
 * @param {문자열} 코드
 * 언어 코드 또는 사전 속성
 *
 * @param {객체} 데이터
 * 변환할 데이터 값
 *
 * @return {객체}
 * 결과 언어 사전 객체
 */
videojs.addLanguage = 함수(코드, 데이터) {
  코드 = ('' + 코드).toLowerCase();

  videojs.options.languages = mergeOptions(
    videojs.options.languages,
    {[코드]: 데이터}
  );

  return videojs.options.languages[코드];
};

/**
 * 객체로서의 {@link module:log|log utility module}에 대한 참조.
 *
 * @type {함수}
 * @see {@link module:log|log}
 */
videojs.log = 로그;
videojs.createLogger = createLogger;

videojs.createTimeRange = videojs.createTimeRanges = createTimeRanges;
videojs.formatTime = formatTime;
videojs.setFormatTime = setFormatTime;
videojs.resetFormatTime = resetFormatTime;
videojs.parseUrl = Url.parseUrl;
videojs.isCrossOrigin = Url.isCrossOrigin;
videojs.EventTarget = EventTarget;
videojs.on = 이벤트.온;
videojs.one = 이벤트.one;
videojs.off = 이벤트.오프;
videojs.trigger = 이벤트.트리거;

/**
 * 크로스 브라우저 XMLHttpRequest 래퍼.
 *
 * @기능
 * @param {객체} 옵션
 * 요청에 대한 설정.
 *
 * @return {XMLHttpRequest|XDomainRequest}
 * 요청 개체입니다.
 *
 * @see https://github.com/Raynos/xhr
 */
videojs.xhr = xhr;

videojs.TextTrack = TextTrack;
videojs.AudioTrack = 오디오트랙;
videojs.VideoTrack = 비디오트랙;

[
  '이엘',
  'isTextNode',
  '만들다',
  '하스클래스',
  '추가 클래스',
  '제거 클래스',
  '토글클래스',
  '세트속성',
  'getAttributes',
  '빈 엘',
  '추가 콘텐츠',
  '삽입 콘텐츠'
].forEach(k => {
  videojs[k] = 함수() {
    log.warn(`videojs.${k}()는 더 이상 사용되지 않습니다. 대신 videojs.dom.${k}()를 사용하세요.`);
    return Dom[k].apply(null, arguments);
  };
});

videojs.computedStyle = computedStyle;

/**
 * 객체로서의 {@link module:dom|DOM utility module}에 대한 참조.
 *
 * @type {객체}
 * @see {@link module:dom|dom}
 */
videojs.dom = 돔;

/**
 * 객체로서의 {@link module:url|URL 유틸리티 모듈}에 대한 참조.
 *
 * @type {객체}
 * @see {@링크 모듈:url|url}
 */
videojs.url = URL;

videojs.defineLazyProperty = defineLazyProperty;

// 전체 화면 버튼에 덜 모호한 텍스트를 추가합니다.
// 주요 업데이트에서 이것이 기본 텍스트 및 키가 될 수 있습니다.
videojs.addLanguage('en', {'전체화면 아님': '전체화면 종료'});

기본 videojs 내보내기;