/**
 * @file video.js
 * @module videojs
 */
從'../../package.json'導入{version};
從“全局/窗口”導入窗口;
進口 {
  鉤子_,
  掛鉤,
  鉤,
  鉤一次,
  移除鉤子
} 來自 './utils/hooks';
從“./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;
從 './utils/fn.js' 導入 * 作為 Fn;
從 './tracks/text-track.js' 導入 TextTrack;
從 './tracks/audio-track.js' 導入 AudioTrack;
從 './tracks/video-track.js' 導入 VideoTrack;

從'./utils/time-ranges.js'導入{createTimeRanges};
import formatTime, { setFormatTime, resetFormatTime } from './utils/format-time.js';
從'./utils/log.js'導入日誌,{createLogger};
import * as Dom from './utils/dom.js';
import * as browser from './utils/browser.js';
import * as Url from './utils/url.js';
從 './utils/obj' 導入 {isObject};
從 './utils/computed-style.js' 導入 computedStyle;
從 './extend.js' 導入擴展;
從“@videojs/xhr”導入 xhr;

// 包括內置技術
從 './tech/tech.js' 導入技術;
import { use as middlewareUse, TERMINATOR } from './tech/middleware.js';
從 './utils/define-lazy-property.js' 導入 defineLazyProperty;

/**
 * 通過去除前導的 `#` 來規範化 `id` 值
 *
 * @私人的
 * @param {string} id
 * 一個字符串,可能以“#”開頭。
 *
 * @return {字符串}
 * 字符串,沒有任何前導的“#”。
 */
常量正常標識 =(ID)=> ID 指數('#')=== 0?ID 切片(1):標識;

/**
 * `videojs()` 函數兼作主函數,供用戶創建一個
 * {@link Player} 實例以及主庫命名空間。
 *
 * 它也可以用作預先存在的 {@link Player} 實例的吸氣劑。
 * 但是,我們_強烈_建議為此使用 `videojs.getPlayer()`
 * 目的,因為它避免了任何可能的意外初始化。
 *
 * 由於 [限制](https://github.com/jsdoc3/jsdoc/issues/955#issuecomment-313829149)
 * 我們的 JSDoc 模板,我們不能正確地將其記錄為一個函數
 * 和命名空間,因此其函數簽名記錄在此處。
 *
 * #### 參數
 * ##### ID
 * 字符串|元素,**必填**
 *
 * 視頻元素或視頻元素 ID。
 *
 * ##### 選項
 * 對象,可選
 *
 * 用於提供設置的選項對象。
 * 請參閱:[選項指南](https://docs.videojs.com/tutorial-options.html)。
 *
 * ##### 準備好
 * {@link Component~ReadyCallback},可選
 *
 * {@link Player} 和 {@link Tech} 準備就緒時調用的函數。
 *
 * #### 返回值
 *
 * `videojs()` 函數返回一個 {@link Player} 實例。
 *
 * @命名空間
 *
 * @borrows AudioTrack 作為 AudioTrack
 * @borrows Component.getComponent 作為 getComponent
 * @borrows 模組:計算樣式 ~ 計算風格作為計算樣式
 * @borrows 模組:事件. 在上
 * @borrows 模塊:事件。一為一
 * @borrows 模塊:事件。關閉為關閉
 * @borrows 模組:事件. 觸發作為觸發器
 * @borrows EventTarget 作為 EventTarget
 * @borrows 模塊:擴展~擴展為擴展
 * @borrows 模塊:綁定作為綁定
 * @borrows 模塊:format-time.formatTime as formatTime
 * @borrows 模塊:格式時間。重置格式時間為重置格式時間
 * @borrows 模塊:格式時間. 設置格式時間為設置格式時間
 * @borrows 模塊:合併選項。合併選項作為合併選項
 * @borrows 模組:中介軟體. 使用做為使用
 * @borrows Player.players 作為玩家
 * @borrows Plugin.registerPlugin 作為 registerPlugin
 * @borrows Plugin.deregisterPlugin 作為 deregisterPlugin
 * @borrows Plugin.getPlugins 作為 getPlugins
 * @borrows Plugin.getPlugin 作為 getPlugin
 * @borrows Plugin.getPluginVersion 作為 getPluginVersion
 * @borrows Tech.getTech 作為 getTech
 * @borrows Tech.registerTech 作為 registerTech
 * @borrows TextTrack 作為 TextTrack
 * @borrows 模組:時間範圍。將創建時間範圍創建為創建時間範圍
 * @borrows 模組:時間範圍。將創建時間角創建為創建時間範圍
 * @borrows 模塊:URL。交叉起源作為跨起源
 * @borrows 模塊:url.parseUrl 作為 parseUrl
 * @borrows VideoTrack 作為 VideoTrack
 *
 * @param {string|Element} id
 * 視頻元素或視頻元素 ID。
 *
 * @param {對象} [選項]
 * 用於提供設置的選項對象。
 * 請參閱:[選項指南](https://docs.videojs.com/tutorial-options.html)。
 *
 * @param {Component~ReadyCallback} [就緒]
 * {@link Player} 和 {@link Tech} 時調用的函數
 * 準備好。
 *
 * @return {玩家}
 * `videojs()` 函數返回一個 {@link Player|Player} 實例。
 */
函數 videojs(id,選項,就緒){
  讓播放器 = videojs.getPlayer(id);

  如果(玩家){
    如果(選項){
      log.warn(`Player "${id}" 已經初始化。選項將不會被應用。`);
    }
    如果(準備就緒){
      player.ready(準備就緒);
    }
    回歸球員;
  }

  常量埃爾 =(ID === '字符串' 的類型)?點。$('#' + 正常標識(ID)):ID;

  如果(!多米. 伊塞爾 (埃爾)) {
    throw new TypeError('提供的元素或 ID 無效。(videojs)');
  }

  // document.body.contains(el) 只會檢查 el 是否包含在該文檔中。
  // 這會導致 iframe 中的元素出現問題。
  // 相反,使用元素的 ownerDocument 而不是全局文檔。
  // 這將確保該元素確實在該文檔的 dom 中。
  // 此外,檢查相關文檔是否具有默認視圖。
  // 如果文檔不再附加到 dom,則文檔的 defaultView 將為 null。
  如果(!所有者文檔. 默認視圖 ||!所有者文件. 身體. 包含 (el)) {
    log.warn('提供的元素不包含在 DOM 中');
  }

  選項=選項|| {};

  // 保存一份修改前的el,如果要在destroy()中恢復
  // 如果 div 攝取,存儲父 div
  如果(選項。restoreEl === 真){
    選項還原 =(例如。父節點 && 等。父母節點 .has屬性('數據-vjs-播放器')?父節點:EL)。克隆節點(真);
  }

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

    如果(!isObject(opts)|| Array.isArray(opts)){
      log.error('請在 beforesetup 鉤子中返回一個對象');
      返回;
    }

    options = mergeOptions(options, opts);
  });

  // 我們在這裡獲取當前的“播放器”組件,以防集成有
  // 將其替換為自定義播放器。
  const PlayerComponent = Component.getComponent('Player');

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

  hooks('setup').forEach((hookFunction) => hookFunction(player));

  回歸球員;
}

videojs.hooks_ = hooks_;
videojs.hooks = 掛鉤;
videojs.hook = 掛鉤;
videojs.hookOnce = hookOnce;
videojs.removeHook = removeHook;

// 添加默認樣式
如果(窗口。視頻 _ 動態風格!== 真 && DOM. 真實 ()) {
  let style = Dom.$('.vjs-styles-defaults');

  如果(!樣式){
    style = stylesheet.createStyleElement('vjs-styles-defaults');
    const head = Dom.$('head');

    如果(頭){
      head.insertBefore(style, head.firstChild);
    }
    stylesheet.setTextContent(樣式,`
      .video-js {
        寬度:300像素;
        高度:150像素;
      }

      . VJS-流體:不 (. VJS-音頻僅模式) {
        填充頂部:56.25%
      }
    `);
  }
}

// 運行自動加載播放器
// 你必須至少等待一次,以防這個腳本在你之後加載
// DOM 中的視頻(奇怪的行為只有縮小版)
setup.autoSetupTimeout(1, videojs);

/**
 * 當前 Video.js 版本。遵循 [語義版本控制](https://semver.org/)。
 *
 * @type {字符串}
 */
videojs.VERSION = 版本;

/**
 * 全局選項對象。這些是生效的設置
 * 如果在創建播放器時沒有指定覆蓋。
 *
 * @type {對象}
 */
videojs.options = Player.prototype.options_;

/**
 * 獲取包含當前創建的玩家的對象,以玩家 ID 為鍵
 *
 * @return {對象}
 * 創建的玩家
 */
videojs.getPlayers = () => Player.players;

/**
 * 根據 ID 或 DOM 元素獲取單個玩家。
 *
 * 如果你想檢查一個元素或 ID 是否有關聯,這很有用
 * Video.js 播放器,但如果沒有則不創建。
 *
 * @param {string|Element} id
 * 一個 HTML 元素 - `<video>`、`<audio>` 或 `<video-js>` -
 * 或與此類元素的“id”匹配的字符串。
 *
 * @return {玩家|未定義}
 * 一個玩家實例,如果沒有玩家實例,則為 `undefined`
 * 匹配參數。
 */
videojs.getPlayer = (id) => {
  const players = Player.players;
  讓標籤;

  如果 (typeof id === 'string') {
    const nId = normalizeId(id);
    const player = 玩家[nId];

    如果(玩家){
      回歸球員;
    }

    tag = Dom.$('#' + nId);
  }其他{
    標籤=編號;
  }

  如果(Dom.isEl(標籤)){
    const {player, playerId} = 標籤;

    // 元素可能有一個 `player` 屬性引用一個已經創建的
    // 播放器實例。如果是這樣,請返回。
    如果(玩家 || 玩家[playerId]){
      回歸球員||玩家[玩家ID];
    }
  }
};

/**
 * 返回所有當前玩家的數組。
 *
 * @return {數組}
 * 所有玩家的數組。該數組將按照以下順序排列
 * `Object.keys` 提供,這可能會有所不同
 * JavaScript 引擎。
 *
 */
videojs.getAllPlayers = () =>

  // 被處置的玩家留下一個帶有 `null` 值的鍵,所以我們需要確保
  // 我們過濾掉那些。
  Object.keys(Player.players).map(k => Player.players[k]).filter(布爾值);

videojs.players = Player.players;
videojs.getComponent = Component.getComponent;

/**
 * 註冊一個組件,以便可以通過名稱引用它。添加到其他時使用
 * 組件,通過 addChild `component.addChild('myComponent')` 或通過
 * 默認子項選項`{ children: ['myComponent'] }`。
 *
 * > 注意:您也可以在添加之前只初始化組件。
 * `組件。添加子(新的我的組件());`
 *
 * @param {string} 名稱
 * 組件的類名
 *
 * @param {組件} 組件
 * 組件類
 *
 * @return {組件}
 * 新註冊的組件
 */
videojs.registerComponent = (name, comp) => {
  如果(Tech.isTech(comp)){
    log.warn(`${name} 技術已註冊為組件。它應該使用 videojs.registerTech(name, tech)`);
  }

  Component.registerComponent.call(Component, name, comp);
};

videojs.getTech = Tech.getTech;
videojs.registerTech = Tech.registerTech;
videojs.use = middlewareUse;

/**
 * 一個可以由中間件返回的對象來表示
 * 中間件正在終止。
 *
 * @type {對象}
 * @property {object} 中間件.TERMINATOR
 */
Object.defineProperty(videojs, '中間件', {
  價值: {},
  可寫:假,
  可枚舉:真
});

Object.defineProperty(videojs.middleware, '終結者', {
  價值:終結者,
  可寫:假,
  可枚舉:真
});

/**
 * 將 {@link 模組:瀏覽器 | 瀏覽器公用程式模組} 做為物件的參考。
 *
 * @type {對象}
 * @see {@link 模塊:瀏覽器|瀏覽器}
 */
videojs.browser = 瀏覽器;

/**
 * 使用 {@link 模塊:瀏覽器。觸摸啟用 | 瀏覽器。觸摸啟用}; 僅
 * 包括在內以向後兼容 4.x。
 *
 * @deprecated 自 5.0 版以來,請改用 {@link 模組:瀏覽器。觸控啟用 | 瀏覽器。
 * @type {布爾}
 */
videojs.TOUCH_ENABLED = browser.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 {string} 名稱
 * 插件名稱
 *
 * @param {Plugin|Function} 插件
 * 插件子類或函數
 */
videojs.plugin =(名稱,插件)=> {
  log.warn('videojs.plugin() 已棄用;請改用 videojs.registerPlugin()');
  返回 Plugin.registerPlugin(名稱,插件);
};

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

/**
 * 添加語言以便所有玩家都可以使用。
 * 示例:`videojs.addLanguage('es', { '你好':'霍拉'}); `
 *
 * @param {string} 代碼
 * 語言代碼或字典屬性
 *
 * @param {Object} 數據
 * 要翻譯的數據值
 *
 * @return {對象}
 * 生成的語言字典對象
 */
videojs.addLanguage = 函數(代碼,數據){
  code = ('' + code).toLowerCase();

  videojs.options.languages = mergeOptions(
    videojs.options.languages,
    {[代碼]:數據}
  );

  返回 videojs.options.languages[code];
};

/**
 * 將 {@link 模組:log| 記錄公用程式模組} 做為物件的參考。
 *
 * @type {函數}
 * @see {@link 模塊:日誌|日誌}
 */
videojs.log = 日誌;
videojs.createLogger = createLogger;

videojs.createTimeRange = videojs.createTimeRanges = createTimeRanges;
videojs.formatTime = 格式時間;
videojs.setFormatTime = setFormatTime;
videojs.resetFormatTime = resetFormatTime;
videojs.parseUrl = Url.parseUrl;
videojs.isCrossOrigin = Url.isCrossOrigin;
videojs.EventTarget = EventTarget;
videojs.on = Events.on;
videojs.one = Events.one;
videojs.off = Events.off;
videojs.trigger = Events.trigger;

/**
 * 跨瀏覽器的 XMLHttpRequest 包裝器。
 *
 * @功能
 * @param {Object} 選項
 * 請求的設置。
 *
 * @return {XMLHttpRequest|XDomainRequest}
 * 請求對象。
 *
 * @see https://github.com/Raynos/xhr
 */
videojs.xhr = xhr;

videojs.TextTrack = TextTrack;
videojs.AudioTrack = AudioTrack;
videojs.VideoTrack = VideoTrack;

[
  '是El',
  'isTextNode',
  '創建El',
  '有等級',
  '添加類',
  '刪除類',
  '切換類',
  '設置屬性',
  '獲取屬性',
  '空El',
  '追加內容',
  '插入內容'
].forEach(k => {
  videojs[k] = function() {
    log.warn(`videojs.${k}() 已棄用;請改用 videojs.dom.${k}()`);
    返回 Dom[k].apply(null, arguments);
  };
});

videojs.computedStyle = computedStyle;

/**
 * 將 {@link 模組:DOM|DOM 公用程式模組} 做為物件的參考。
 *
 * @type {對象}
 * @see {@link 模塊:dom|dom}
 */
videojs.dom = Dom;

/**
 * 將 {@link 模組:URL|URL 公用程式模組} 做為物件的參考。
 *
 * @type {對象}
 * @see {@link 模塊:url|url}
 */
videojs.url = 網址;

videojs.defineLazyProperty = defineLazyProperty;

// 為全屏按鈕添加更明確的文本。
// 在主要更新中,這可能成為默認文本和鍵。
videojs.addLanguage('en', {'非全屏':'退出全屏'});

導出默認videojs;