{"version":3,"file":"524.chunk.js?v=7799","mappings":"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","sources":["webpack://peertube-client/./src/assets/player/shared/upnext/end-card.ts","webpack://peertube-client/./src/assets/player/shared/upnext/upnext-plugin.ts","webpack://peertube-client/../shared/core-utils/common/date.ts","webpack://peertube-client/../shared/core-utils/common/object.ts","webpack://peertube-client/../shared/core-utils/i18n/i18n.ts","webpack://peertube-client/../shared/core-utils/renderer/markdown.ts","webpack://peertube-client/./src/assets/player/shared/common/utils.ts","webpack://peertube-client/./src/assets/player/shared/stats/stats-card.ts","webpack://peertube-client/./src/assets/player/shared/stats/stats-plugin.ts","webpack://peertube-client/./src/root-helpers/web-browser.ts","webpack://peertube-client/./src/assets/player/shared/bezels/pause-bezel.ts","webpack://peertube-client/./src/assets/player/shared/bezels/bezels-plugin.ts","webpack://peertube-client/./src/assets/player/peertube-player-local-storage.ts","webpack://peertube-client/./src/assets/player/shared/peertube/peertube-plugin.ts","webpack://peertube-client/./src/assets/player/shared/resolutions/peertube-resolutions-plugin.ts","webpack://peertube-client/./src/assets/player/shared/control-bar/next-previous-video-button.ts","webpack://peertube-client/./src/assets/player/shared/control-bar/p2p-info-button.ts","webpack://peertube-client/./src/assets/player/shared/control-bar/picture-in-picture-bastyon.ts","webpack://peertube-client/./src/assets/player/shared/control-bar/peertube-load-progress-bar.ts","webpack://peertube-client/./src/assets/player/shared/control-bar/theater-button.ts","webpack://peertube-client/./src/assets/player/shared/settings/resolution-menu-item.ts","webpack://peertube-client/./src/assets/player/shared/settings/resolution-menu-button.ts","webpack://peertube-client/./src/assets/player/shared/settings/settings-dialog.ts","webpack://peertube-client/./src/assets/player/shared/settings/settings-menu-item.ts","webpack://peertube-client/./src/assets/player/shared/settings/settings-menu-button.ts","webpack://peertube-client/./src/assets/player/shared/settings/settings-panel.ts","webpack://peertube-client/./src/assets/player/shared/settings/settings-panel-child.ts","webpack://peertube-client/./src/assets/player/shared/playlist/playlist-button.ts","webpack://peertube-client/./src/assets/player/shared/playlist/playlist-menu-item.ts","webpack://peertube-client/./src/assets/player/shared/playlist/playlist-menu.ts","webpack://peertube-client/./src/assets/player/shared/playlist/playlist-plugin.ts","webpack://peertube-client/./src/assets/player/shared/mobile/peertube-mobile-plugin.ts","webpack://peertube-client/./src/assets/player/shared/mobile/peertube-mobile-buttons.ts","webpack://peertube-client/./src/assets/player/shared/hotkeys/peertube-hotkeys-plugin.ts","webpack://peertube-client/./src/assets/player/shared/manager-options/control-bar-options-builder.ts","webpack://peertube-client/./src/assets/player/shared/p2p-media-loader/redundancy-url-manager.ts","webpack://peertube-client/./src/assets/player/shared/p2p-media-loader/segment-url-builder.ts","webpack://peertube-client/./src/root-helpers/utils.ts","webpack://peertube-client/./src/assets/player/shared/p2p-media-loader/segment-validator.ts","webpack://peertube-client/./src/assets/player/shared/manager-options/hls-options-builder.ts","webpack://peertube-client/./src/assets/player/shared/manager-options/webtorrent-options-builder.ts","webpack://peertube-client/./src/assets/player/shared/manager-options/manager-options-builder.ts","webpack://peertube-client/./src/assets/player/shared/p2p-media-loader/cap-level-controller.ts","webpack://peertube-client/./src/assets/player/shared/p2p-media-loader/abr-controler.ts","webpack://peertube-client/./src/assets/player/shared/p2p-media-loader/hls-plugin.ts","webpack://peertube-client/./src/assets/player/shared/p2p-media-loader/p2p-media-loader-plugin.ts","webpack://peertube-client/./src/assets/player/peertube-player-manager.ts","webpack://peertube-client/./src/shims/path.ts","webpack://peertube-client/./src/assets/player/shared/videojs-helpers/guid.js","webpack://peertube-client/./src/assets/player/shared/videojs-helpers/fn.js","webpack://peertube-client/./src/assets/player/shared/videojs-helpers/hotkeys.js"],"sourcesContent":["import videojs from 'video.js'\r\n\r\nfunction getMainTemplate (options: any) {\r\n return `\r\n
\r\n ${options.headText}\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n \r\n \r\n \r\n \r\n ${options.suspendedText}\r\n \r\n `\r\n}\r\n\r\nexport interface EndCardOptions extends videojs.ComponentOptions {\r\n next: () => void\r\n getTitle: () => string\r\n timeout: number\r\n cancelText: string\r\n headText: string\r\n suspendedText: string\r\n condition: () => boolean\r\n suspended: () => boolean\r\n}\r\n\r\nconst Component = videojs.getComponent('Component')\r\nclass EndCard extends Component {\r\n options_: EndCardOptions\r\n\r\n dashOffsetTotal = 586\r\n dashOffsetStart = 293\r\n interval = 50\r\n upNextEvents = new videojs.EventTarget()\r\n ticks = 0\r\n totalTicks: number\r\n\r\n container: HTMLDivElement\r\n title: HTMLElement\r\n autoplayRing: HTMLElement\r\n cancelButton: HTMLElement\r\n suspendedMessage: HTMLElement\r\n nextButton: HTMLElement\r\n\r\n constructor (player: videojs.Player, options: EndCardOptions) {\r\n super(player, options)\r\n\r\n this.totalTicks = this.options_.timeout / this.interval\r\n\r\n player.on('ended', (_: any) => {\r\n if (!this.options_.condition()) return\r\n\r\n player.addClass('vjs-upnext--showing')\r\n this.showCard((canceled: boolean) => {\r\n player.removeClass('vjs-upnext--showing')\r\n this.container.style.display = 'none'\r\n if (!canceled) {\r\n this.options_.next()\r\n }\r\n })\r\n })\r\n\r\n player.on('playing', () => {\r\n this.upNextEvents.trigger('playing')\r\n })\r\n }\r\n\r\n createEl () {\r\n const container = super.createEl('div', {\r\n className: 'vjs-upnext-content',\r\n innerHTML: getMainTemplate(this.options_)\r\n }) as HTMLDivElement\r\n\r\n this.container = container\r\n container.style.display = 'none'\r\n\r\n this.autoplayRing = container.getElementsByClassName('vjs-upnext-svg-autoplay-ring')[0] as HTMLElement\r\n this.title = container.getElementsByClassName('vjs-upnext-title')[0] as HTMLElement\r\n this.cancelButton = container.getElementsByClassName('vjs-upnext-cancel-button')[0] as HTMLElement\r\n this.suspendedMessage = container.getElementsByClassName('vjs-upnext-suspended')[0] as HTMLElement\r\n this.nextButton = container.getElementsByClassName('vjs-upnext-autoplay-icon')[0] as HTMLElement\r\n\r\n this.cancelButton.onclick = () => {\r\n this.upNextEvents.trigger('cancel')\r\n }\r\n\r\n this.nextButton.onclick = () => {\r\n this.upNextEvents.trigger('next')\r\n }\r\n\r\n return container\r\n }\r\n\r\n showCard (cb: (value: boolean) => void) {\r\n let timeout: any\r\n\r\n this.autoplayRing.setAttribute('stroke-dasharray', `${this.dashOffsetStart}`)\r\n this.autoplayRing.setAttribute('stroke-dashoffset', `${-this.dashOffsetStart}`)\r\n\r\n this.title.innerHTML = this.options_.getTitle()\r\n\r\n this.upNextEvents.one('cancel', () => {\r\n clearTimeout(timeout)\r\n cb(true)\r\n })\r\n\r\n this.upNextEvents.one('playing', () => {\r\n clearTimeout(timeout)\r\n cb(true)\r\n })\r\n\r\n this.upNextEvents.one('next', () => {\r\n clearTimeout(timeout)\r\n cb(false)\r\n })\r\n\r\n const goToPercent = (percent: number) => {\r\n const newOffset = Math.max(-this.dashOffsetTotal, -this.dashOffsetStart - percent * this.dashOffsetTotal / 2 / 100)\r\n this.autoplayRing.setAttribute('stroke-dashoffset', '' + newOffset)\r\n }\r\n\r\n const tick = () => {\r\n goToPercent((this.ticks++) * 100 / this.totalTicks)\r\n }\r\n\r\n const update = () => {\r\n if (this.options_.suspended()) {\r\n this.suspendedMessage.innerText = this.options_.suspendedText\r\n goToPercent(0)\r\n this.ticks = 0\r\n timeout = setTimeout(update.bind(this), 300) // checks once supsended can be a bit longer\r\n } else if (this.ticks >= this.totalTicks) {\r\n clearTimeout(timeout)\r\n cb(false)\r\n } else {\r\n this.suspendedMessage.innerText = ''\r\n tick()\r\n timeout = setTimeout(update.bind(this), this.interval)\r\n }\r\n }\r\n\r\n this.container.style.display = 'block'\r\n timeout = setTimeout(update.bind(this), this.interval)\r\n }\r\n}\r\n\r\nvideojs.registerComponent('EndCard', EndCard)\r\n","import videojs from 'video.js'\r\nimport { EndCardOptions } from './end-card'\r\n\r\nconst Plugin = videojs.getPlugin('plugin')\r\n\r\nclass UpNextPlugin extends Plugin {\r\n\r\n constructor (player: videojs.Player, options: Partial = {}) {\r\n const settings = {\r\n next: options.next,\r\n getTitle: options.getTitle,\r\n timeout: options.timeout || 5000,\r\n cancelText: options.cancelText || 'Cancel',\r\n headText: options.headText || 'Up Next',\r\n suspendedText: options.suspendedText || 'Autoplay is suspended',\r\n condition: options.condition,\r\n suspended: options.suspended\r\n }\r\n\r\n super(player)\r\n\r\n this.player.ready(() => {\r\n player.addClass('vjs-upnext')\r\n })\r\n\r\n player.addChild('EndCard', settings)\r\n }\r\n}\r\n\r\nvideojs.registerPlugin('upnext', UpNextPlugin)\r\nexport { UpNextPlugin }\r\n","function isToday (d: Date) {\r\n const today = new Date()\r\n\r\n return areDatesEqual(d, today)\r\n}\r\n\r\nfunction isYesterday (d: Date) {\r\n const yesterday = new Date()\r\n yesterday.setDate(yesterday.getDate() - 1)\r\n\r\n return areDatesEqual(d, yesterday)\r\n}\r\n\r\nfunction isThisWeek (d: Date) {\r\n const minDateOfThisWeek = new Date()\r\n minDateOfThisWeek.setHours(0, 0, 0)\r\n\r\n // getDay() -> Sunday - Saturday : 0 - 6\r\n // We want to start our week on Monday\r\n let dayOfWeek = minDateOfThisWeek.getDay() - 1\r\n if (dayOfWeek < 0) dayOfWeek = 6 // Sunday\r\n\r\n minDateOfThisWeek.setDate(minDateOfThisWeek.getDate() - dayOfWeek)\r\n\r\n return d >= minDateOfThisWeek\r\n}\r\n\r\nfunction isThisMonth (d: Date) {\r\n const thisMonth = new Date().getMonth()\r\n\r\n return d.getMonth() === thisMonth\r\n}\r\n\r\nfunction isLastMonth (d: Date) {\r\n const now = new Date()\r\n\r\n return getDaysDifferences(now, d) <= 30\r\n}\r\n\r\nfunction isLastWeek (d: Date) {\r\n const now = new Date()\r\n\r\n return getDaysDifferences(now, d) <= 7\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction timeToInt (time: number | string) {\r\n if (!time) return 0\r\n if (typeof time === 'number') return time\r\n\r\n const reg = /^((\\d+)[h:])?((\\d+)[m:])?((\\d+)s?)?$/\r\n const matches = time.match(reg)\r\n\r\n if (!matches) return 0\r\n\r\n const hours = parseInt(matches[2] || '0', 10)\r\n const minutes = parseInt(matches[4] || '0', 10)\r\n const seconds = parseInt(matches[6] || '0', 10)\r\n\r\n return hours * 3600 + minutes * 60 + seconds\r\n}\r\n\r\nfunction secondsToTime (seconds: number, full = false, symbol?: string) {\r\n let time = ''\r\n\r\n if (seconds === 0 && !full) return '0s'\r\n\r\n const hourSymbol = (symbol || 'h')\r\n const minuteSymbol = (symbol || 'm')\r\n const secondsSymbol = full ? '' : 's'\r\n\r\n const hours = Math.floor(seconds / 3600)\r\n if (hours >= 1) time = hours + hourSymbol\r\n else if (full) time = '0' + hourSymbol\r\n\r\n seconds %= 3600\r\n const minutes = Math.floor(seconds / 60)\r\n if (minutes >= 1 && minutes < 10 && full) time += '0' + minutes + minuteSymbol\r\n else if (minutes >= 1) time += minutes + minuteSymbol\r\n else if (full) time += '00' + minuteSymbol\r\n\r\n seconds %= 60\r\n if (seconds >= 1 && seconds < 10 && full) time += '0' + seconds + secondsSymbol\r\n else if (seconds >= 1) time += seconds + secondsSymbol\r\n else if (full) time += '00'\r\n\r\n return time\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n\r\nexport {\r\n isYesterday,\r\n isThisWeek,\r\n isThisMonth,\r\n isToday,\r\n isLastMonth,\r\n isLastWeek,\r\n timeToInt,\r\n secondsToTime\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction areDatesEqual (d1: Date, d2: Date) {\r\n return d1.getFullYear() === d2.getFullYear() &&\r\n d1.getMonth() === d2.getMonth() &&\r\n d1.getDate() === d2.getDate()\r\n}\r\n\r\nfunction getDaysDifferences (d1: Date, d2: Date) {\r\n return (d1.getTime() - d2.getTime()) / (86400000)\r\n}\r\n","function pick (object: O, keys: K[]): Pick {\r\n const result: any = {}\r\n\r\n for (const key of keys) {\r\n if (Object.prototype.hasOwnProperty.call(object, key)) {\r\n result[key] = object[key]\r\n }\r\n }\r\n\r\n return result\r\n}\r\n\r\nfunction getKeys (object: O, keys: K[]): K[] {\r\n return (Object.keys(object) as K[]).filter(k => keys.includes(k))\r\n}\r\n\r\nfunction sortObjectComparator (key: string, order: 'asc' | 'desc') {\r\n return (a: any, b: any) => {\r\n if (a[key] < b[key]) {\r\n return order === 'asc' ? -1 : 1\r\n }\r\n\r\n if (a[key] > b[key]) {\r\n return order === 'asc' ? 1 : -1\r\n }\r\n\r\n return 0\r\n }\r\n}\r\n\r\nexport {\r\n pick,\r\n getKeys,\r\n sortObjectComparator\r\n}\r\n","export const LOCALE_FILES = [ 'player', 'server' ]\r\n\r\nexport const I18N_LOCALES = {\r\n // Always first to avoid issues when using express acceptLanguages function when no accept language header is set\r\n 'en-US': 'English',\r\n\r\n 'ar': 'العربية',\r\n 'ca-ES': 'Català',\r\n 'cs-CZ': 'Čeština',\r\n 'de-DE': 'Deutsch',\r\n 'el-GR': 'ελληνικά',\r\n 'eo': 'Esperanto',\r\n 'es-ES': 'Español',\r\n 'eu-ES': 'Euskara',\r\n 'fi-FI': 'suomi',\r\n 'fr-FR': 'Français',\r\n 'gd': 'Gàidhlig',\r\n 'gl-ES': 'galego',\r\n 'hr': 'hrvatski',\r\n 'hu-HU': 'magyar',\r\n 'fa-IR': 'فارسی',\r\n 'it-IT': 'Italiano',\r\n 'ja-JP': '日本語',\r\n 'kab': 'Taqbaylit',\r\n 'nl-NL': 'Nederlands',\r\n 'oc': 'Occitan',\r\n 'pl-PL': 'Polski',\r\n 'pt-BR': 'Português (Brasil)',\r\n 'pt-PT': 'Português (Portugal)',\r\n 'ru-RU': 'русский',\r\n 'sq': 'Shqip',\r\n 'sv-SE': 'Svenska',\r\n 'nn': 'norsk nynorsk',\r\n 'nb-NO': 'norsk bokmål',\r\n 'th-TH': 'ไทย',\r\n 'vi-VN': 'Tiếng Việt',\r\n 'tok': 'Toki Pona',\r\n 'zh-Hans-CN': '简体中文(中国)',\r\n 'zh-Hant-TW': '繁體中文(台灣)'\r\n}\r\n\r\nconst I18N_LOCALE_ALIAS = {\r\n 'ar-001': 'ar',\r\n 'ca': 'ca-ES',\r\n 'cs': 'cs-CZ',\r\n 'de': 'de-DE',\r\n 'el': 'el-GR',\r\n 'en': 'en-US',\r\n 'es': 'es-ES',\r\n 'eu': 'eu-ES',\r\n 'fi': 'fi-FI',\r\n 'gl': 'gl-ES',\r\n 'fa': 'fa-IR',\r\n 'fr': 'fr-FR',\r\n 'hu': 'hu-HU',\r\n 'it': 'it-IT',\r\n 'ja': 'ja-JP',\r\n 'nl': 'nl-NL',\r\n 'pl': 'pl-PL',\r\n 'pt': 'pt-BR',\r\n 'nb': 'nb-NO',\r\n 'ru': 'ru-RU',\r\n 'sv': 'sv-SE',\r\n 'th': 'th-TH',\r\n 'vi': 'vi-VN',\r\n 'zh-CN': 'zh-Hans-CN',\r\n 'zh-Hans': 'zh-Hans-CN',\r\n 'zh-Hant': 'zh-Hant-TW',\r\n 'zh-TW': 'zh-Hant-TW',\r\n 'zh': 'zh-Hans-CN'\r\n}\r\n\r\nexport const POSSIBLE_LOCALES = Object.keys(I18N_LOCALES)\r\n .concat(Object.keys(I18N_LOCALE_ALIAS))\r\n\r\nexport function getDefaultLocale () {\r\n return 'en-US'\r\n}\r\n\r\nexport function isDefaultLocale (locale: string) {\r\n return getCompleteLocale(locale) === getCompleteLocale(getDefaultLocale())\r\n}\r\n\r\nexport function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) {\r\n if (!translations || !translations[str]) return str\r\n\r\n return translations[str]\r\n}\r\n\r\nconst possiblePaths = POSSIBLE_LOCALES.map(l => '/' + l)\r\nexport function is18nPath (path: string) {\r\n return possiblePaths.includes(path)\r\n}\r\n\r\nexport function is18nLocale (locale: string) {\r\n return POSSIBLE_LOCALES.includes(locale)\r\n}\r\n\r\nexport function getCompleteLocale (locale: string) {\r\n if (!locale) return locale\r\n\r\n if (I18N_LOCALE_ALIAS[locale]) return I18N_LOCALE_ALIAS[locale]\r\n\r\n return locale\r\n}\r\n\r\nexport function getShortLocale (locale: string) {\r\n if (locale.includes('-') === false) return locale\r\n\r\n return locale.split('-')[0]\r\n}\r\n\r\nexport function buildFileLocale (locale: string) {\r\n return getCompleteLocale(locale)\r\n}\r\n","export const TEXT_RULES = [\r\n 'linkify',\r\n 'autolink',\r\n 'emphasis',\r\n 'link',\r\n 'newline',\r\n 'entity',\r\n 'list'\r\n]\r\n\r\nexport const TEXT_WITH_HTML_RULES = TEXT_RULES.concat([\r\n 'html_inline',\r\n 'html_block'\r\n])\r\n\r\nexport const ENHANCED_RULES = TEXT_RULES.concat([ 'image' ])\r\nexport const ENHANCED_WITH_HTML_RULES = TEXT_WITH_HTML_RULES.concat([ 'image' ])\r\n\r\nexport const COMPLETE_RULES = ENHANCED_WITH_HTML_RULES.concat([\r\n 'block',\r\n 'inline',\r\n 'heading',\r\n 'paragraph'\r\n])\r\n","import { VideoFile } from '@shared/models'\r\n\r\nfunction toTitleCase (str: string) {\r\n return str.charAt(0).toUpperCase() + str.slice(1)\r\n}\r\n\r\nconst dictionaryBytes = [\r\n { max: 1024, type: 'B', decimals: 0 },\r\n { max: 1048576, type: 'KB', decimals: 0 },\r\n { max: 1073741824, type: 'MB', decimals: 0 },\r\n { max: 1.0995116e12, type: 'GB', decimals: 1 }\r\n]\r\nfunction bytes (value: number) {\r\n const format = dictionaryBytes.find(d => value < d.max) || dictionaryBytes[dictionaryBytes.length - 1]\r\n const calc = (value / (format.max / 1024)).toFixed(format.decimals)\r\n\r\n return [ calc, format.type ]\r\n}\r\n\r\nfunction videoFileMaxByResolution (files: VideoFile[]) {\r\n let max = files[0]\r\n\r\n for (let i = 1; i < files.length; i++) {\r\n const file = files[i]\r\n if (max.resolution.id < file.resolution.id) max = file\r\n }\r\n\r\n return max\r\n}\r\n\r\nfunction videoFileMinByResolution (files: VideoFile[]) {\r\n let min = files[0]\r\n\r\n for (let i = 1; i < files.length; i++) {\r\n const file = files[i]\r\n if (min.resolution.id > file.resolution.id) min = file\r\n }\r\n\r\n return min\r\n}\r\n\r\nfunction getRtcConfig () {\r\n return {\r\n iceServers: [\r\n {\r\n urls: \"stun:turn.pocketnet.app\",\r\n username: \"stunuser\",\r\n credential: \"q1w2e3r4t5ASD!@#\",\r\n },\r\n {\r\n urls: \"turn:turn.pocketnet.app\",\r\n username: \"stunuser\",\r\n credential: \"q1w2e3r4t5ASD!@#\",\r\n },\r\n ]\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n\r\nexport {\r\n getRtcConfig,\r\n toTitleCase,\r\n\r\n videoFileMaxByResolution,\r\n videoFileMinByResolution,\r\n bytes\r\n}\r\n","import videojs from 'video.js'\r\nimport { logger } from '@root-helpers/logger'\r\nimport { secondsToTime } from '@shared/core-utils'\r\nimport { PlayerNetworkInfo as EventPlayerNetworkInfo } from '../../types'\r\nimport { bytes } from '../common'\r\n\r\ninterface StatsCardOptions extends videojs.ComponentOptions {\r\n videoUUID: string\r\n videoIsLive: boolean\r\n mode: 'webtorrent' | 'p2p-media-loader' | 'localvideo'\r\n p2pEnabled: boolean\r\n}\r\n\r\ninterface PlayerNetworkInfo {\r\n downloadSpeed?: string\r\n uploadSpeed?: string\r\n totalDownloaded?: string\r\n totalUploaded?: string\r\n numPeers?: number\r\n averageBandwidth?: string\r\n\r\n downloadedFromServer?: string\r\n downloadedFromPeers?: string\r\n}\r\n\r\ninterface InfoElement {\r\n root: HTMLElement\r\n value: HTMLElement\r\n}\r\n\r\nconst Component = videojs.getComponent('Component')\r\nclass StatsCard extends Component {\r\n options_: StatsCardOptions\r\n\r\n updateInterval: any\r\n\r\n mode: 'webtorrent' | 'p2p-media-loader'\r\n\r\n metadataStore: any = {}\r\n\r\n intervalMs = 300\r\n playerNetworkInfo: PlayerNetworkInfo = {}\r\n\r\n private containerEl: HTMLDivElement\r\n private infoListEl: HTMLDivElement\r\n\r\n private playerMode: InfoElement\r\n private p2p: InfoElement\r\n private uuid: InfoElement\r\n private viewport: InfoElement\r\n private resolution: InfoElement\r\n private volume: InfoElement\r\n private codecs: InfoElement\r\n private color: InfoElement\r\n private connection: InfoElement\r\n\r\n private network: InfoElement\r\n private transferred: InfoElement\r\n private download: InfoElement\r\n\r\n private bufferProgress: InfoElement\r\n private bufferState: InfoElement\r\n\r\n private liveLatency: InfoElement\r\n\r\n createEl () {\r\n this.containerEl = videojs.dom.createEl('div', {\r\n className: 'vjs-stats-content'\r\n }) as HTMLDivElement\r\n this.containerEl.style.display = 'none'\r\n\r\n this.infoListEl = videojs.dom.createEl('div', {\r\n className: 'vjs-stats-list'\r\n }) as HTMLDivElement\r\n\r\n const closeButton = videojs.dom.createEl('button', {\r\n className: 'vjs-stats-close',\r\n tabindex: '0',\r\n title: 'Close stats',\r\n innerText: '[x]'\r\n }, { 'aria-label': 'Close stats' }) as HTMLElement\r\n closeButton.onclick = () => this.hide()\r\n\r\n this.containerEl.appendChild(closeButton)\r\n this.containerEl.appendChild(this.infoListEl)\r\n\r\n this.populateInfoBlocks()\r\n\r\n this.player_.on('p2pInfo', (event: any, data: EventPlayerNetworkInfo) => {\r\n if (!data) return // HTTP fallback\r\n\r\n this.mode = data.source\r\n\r\n const p2pStats = data.p2p\r\n const httpStats = data.http\r\n\r\n this.playerNetworkInfo.downloadSpeed = bytes(p2pStats.downloadSpeed + httpStats.downloadSpeed).join(' ')\r\n this.playerNetworkInfo.uploadSpeed = bytes(p2pStats.uploadSpeed + httpStats.uploadSpeed).join(' ')\r\n this.playerNetworkInfo.totalDownloaded = bytes(p2pStats.downloaded + httpStats.downloaded).join(' ')\r\n this.playerNetworkInfo.totalUploaded = bytes(p2pStats.uploaded + httpStats.uploaded).join(' ')\r\n this.playerNetworkInfo.numPeers = p2pStats.numPeers\r\n this.playerNetworkInfo.averageBandwidth = bytes(data.bandwidthEstimate).join(' ') + '/s'\r\n\r\n if (data.source === 'p2p-media-loader') {\r\n this.playerNetworkInfo.downloadedFromServer = bytes(httpStats.downloaded).join(' ')\r\n this.playerNetworkInfo.downloadedFromPeers = bytes(p2pStats.downloaded).join(' ')\r\n }\r\n })\r\n\r\n return this.containerEl\r\n }\r\n\r\n toggle () {\r\n if (this.updateInterval) this.hide()\r\n else this.show()\r\n }\r\n\r\n show () {\r\n this.containerEl.style.display = 'block'\r\n\r\n this.updateInterval = setInterval(async () => {\r\n try {\r\n const options = this.buildHLSOptions()\r\n \r\n \r\n /*this.mode === 'p2p-media-loader'\r\n ? this.buildHLSOptions()\r\n : await this.buildWebTorrentOptions();*/\r\n\r\n this.populateInfoValues(options)\r\n \r\n } catch (err) {\r\n logger.error('Cannot update stats.', err)\r\n clearInterval(this.updateInterval)\r\n }\r\n }, this.intervalMs)\r\n }\r\n\r\n hide () {\r\n clearInterval(this.updateInterval)\r\n this.containerEl.style.display = 'none'\r\n }\r\n\r\n private buildHLSOptions () {\r\n const p2pMediaLoader = this.player_.p2pMediaLoader()\r\n const level = p2pMediaLoader.getCurrentLevel()\r\n\r\n const codecs = level?.videoCodec || level?.audioCodec\r\n ? `${level?.videoCodec || ''} / ${level?.audioCodec || ''}`\r\n : undefined\r\n\r\n const resolution = `${level?.height}p${level?.attrs['FRAME-RATE'] || ''}`\r\n const buffer = this.timeRangesToString(this.player().buffered())\r\n\r\n let progress: number\r\n let latency: string\r\n\r\n if (this.options_.videoIsLive) {\r\n latency = secondsToTime(p2pMediaLoader.getLiveLatency())\r\n } else {\r\n progress = this.player().bufferedPercent()\r\n }\r\n\r\n return {\r\n playerNetworkInfo: this.playerNetworkInfo,\r\n resolution,\r\n codecs,\r\n buffer,\r\n latency,\r\n progress\r\n }\r\n }\r\n\r\n /*private async buildWebTorrentOptions () {\r\n const videoFile = this.player_.webtorrent().getCurrentVideoFile()\r\n\r\n if (!this.metadataStore[videoFile.fileUrl]) {\r\n this.metadataStore[videoFile.fileUrl] = await fetch(videoFile.metadataUrl).then(res => res.json())\r\n }\r\n\r\n const metadata = this.metadataStore[videoFile.fileUrl]\r\n\r\n let colorSpace = 'unknown'\r\n let codecs = 'unknown'\r\n\r\n if (metadata?.streams[0]) {\r\n const stream = metadata.streams[0]\r\n\r\n colorSpace = stream['color_space'] !== 'unknown'\r\n ? stream['color_space']\r\n : 'bt709'\r\n\r\n codecs = stream['codec_name'] || 'avc1'\r\n }\r\n\r\n const resolution = videoFile?.resolution.label + videoFile?.fps\r\n const buffer = this.timeRangesToString(this.player().buffered())\r\n const progress = this.player_.webtorrent().getTorrent()?.progress\r\n\r\n return {\r\n playerNetworkInfo: this.playerNetworkInfo,\r\n progress,\r\n colorSpace,\r\n codecs,\r\n resolution,\r\n buffer\r\n }\r\n }*/\r\n\r\n private populateInfoBlocks () {\r\n this.playerMode = this.buildInfoRow(this.player().localize('Player mode'))\r\n this.p2p = this.buildInfoRow(this.player().localize('P2P'))\r\n this.uuid = this.buildInfoRow(this.player().localize('Video UUID'))\r\n this.viewport = this.buildInfoRow(this.player().localize('Viewport / Frames'))\r\n this.resolution = this.buildInfoRow(this.player().localize('Resolution'))\r\n this.volume = this.buildInfoRow(this.player().localize('Volume'))\r\n this.codecs = this.buildInfoRow(this.player().localize('Codecs'))\r\n this.color = this.buildInfoRow(this.player().localize('Color'))\r\n this.connection = this.buildInfoRow(this.player().localize('Connection Speed'))\r\n\r\n this.network = this.buildInfoRow(this.player().localize('Network Activity'))\r\n this.transferred = this.buildInfoRow(this.player().localize('Total Transfered'))\r\n this.download = this.buildInfoRow(this.player().localize('Download Breakdown'))\r\n\r\n this.bufferProgress = this.buildInfoRow(this.player().localize('Buffer Progress'))\r\n this.bufferState = this.buildInfoRow(this.player().localize('Buffer State'))\r\n\r\n this.liveLatency = this.buildInfoRow(this.player().localize('Live Latency'))\r\n\r\n this.infoListEl.appendChild(this.playerMode.root)\r\n this.infoListEl.appendChild(this.p2p.root)\r\n this.infoListEl.appendChild(this.uuid.root)\r\n this.infoListEl.appendChild(this.viewport.root)\r\n this.infoListEl.appendChild(this.resolution.root)\r\n this.infoListEl.appendChild(this.volume.root)\r\n this.infoListEl.appendChild(this.codecs.root)\r\n this.infoListEl.appendChild(this.color.root)\r\n this.infoListEl.appendChild(this.connection.root)\r\n this.infoListEl.appendChild(this.network.root)\r\n this.infoListEl.appendChild(this.transferred.root)\r\n this.infoListEl.appendChild(this.download.root)\r\n this.infoListEl.appendChild(this.bufferProgress.root)\r\n this.infoListEl.appendChild(this.bufferState.root)\r\n this.infoListEl.appendChild(this.liveLatency.root)\r\n }\r\n\r\n private populateInfoValues (options: {\r\n playerNetworkInfo: PlayerNetworkInfo\r\n progress: number\r\n codecs: string\r\n resolution: string\r\n buffer: string\r\n\r\n latency?: string\r\n colorSpace?: string\r\n }) {\r\n const { playerNetworkInfo, progress, colorSpace, codecs, resolution, buffer, latency } = options\r\n const player = this.player()\r\n\r\n const videoQuality: VideoPlaybackQuality = player.getVideoPlaybackQuality()\r\n const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0)\r\n const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0)\r\n const pr = (window.devicePixelRatio || 1).toFixed(2)\r\n const frames = `${vw}x${vh}*${pr} / ${videoQuality.droppedVideoFrames} dropped of ${videoQuality.totalVideoFrames}`\r\n\r\n const duration = player.duration()\r\n\r\n let volume = `${Math.round(player.volume() * 100)}`\r\n if (player.muted()) volume += ' (muted)'\r\n\r\n const networkActivity = playerNetworkInfo.downloadSpeed\r\n ? `${playerNetworkInfo.downloadSpeed} ⇓ / ${playerNetworkInfo.uploadSpeed} ⇑`\r\n : undefined\r\n\r\n const totalTransferred = playerNetworkInfo.totalDownloaded\r\n ? `${playerNetworkInfo.totalDownloaded} ⇓ / ${playerNetworkInfo.totalUploaded} ⇑`\r\n : undefined\r\n const downloadBreakdown = playerNetworkInfo.downloadedFromServer\r\n ? `${playerNetworkInfo.downloadedFromServer} from servers · ${playerNetworkInfo.downloadedFromPeers} from peers`\r\n : undefined\r\n\r\n const bufferProgress = progress !== undefined\r\n ? `${(progress * 100).toFixed(1)}% (${(progress * duration).toFixed(1)}s)`\r\n : undefined\r\n\r\n this.setInfoValue(this.playerMode, this.mode || 'HTTP')\r\n this.setInfoValue(this.p2p, player.localize(this.options_.p2pEnabled ? 'enabled' : 'disabled'))\r\n this.setInfoValue(this.uuid, this.options_.videoUUID)\r\n\r\n this.setInfoValue(this.viewport, frames)\r\n this.setInfoValue(this.resolution, resolution)\r\n this.setInfoValue(this.volume, volume)\r\n this.setInfoValue(this.codecs, codecs)\r\n this.setInfoValue(this.color, colorSpace)\r\n this.setInfoValue(this.connection, playerNetworkInfo.averageBandwidth)\r\n\r\n this.setInfoValue(this.network, networkActivity)\r\n this.setInfoValue(this.transferred, totalTransferred)\r\n this.setInfoValue(this.download, downloadBreakdown)\r\n\r\n this.setInfoValue(this.bufferProgress, bufferProgress)\r\n this.setInfoValue(this.bufferState, buffer)\r\n\r\n this.setInfoValue(this.liveLatency, latency)\r\n }\r\n\r\n private setInfoValue (el: InfoElement, value: string) {\r\n if (!value) {\r\n el.root.style.display = 'none'\r\n return\r\n }\r\n\r\n el.root.style.display = 'block'\r\n\r\n if (el.value.innerHTML === value) return\r\n el.value.innerHTML = value\r\n }\r\n\r\n private buildInfoRow (labelText: string, valueHTML?: string) {\r\n const root = videojs.dom.createEl('div') as HTMLElement\r\n root.style.display = 'none'\r\n\r\n const label = videojs.dom.createEl('div', { innerText: labelText }) as HTMLElement\r\n const value = videojs.dom.createEl('span', { innerHTML: valueHTML }) as HTMLElement\r\n\r\n root.appendChild(label)\r\n root.appendChild(value)\r\n\r\n return { root, value }\r\n }\r\n\r\n private timeRangesToString (r: videojs.TimeRange) {\r\n let result = ''\r\n\r\n for (let i = 0; i < r.length; i++) {\r\n const start = Math.floor(r.start(i))\r\n const end = Math.floor(r.end(i))\r\n\r\n result += `[${secondsToTime(start)}, ${secondsToTime(end)}] `\r\n }\r\n\r\n return result\r\n }\r\n}\r\n\r\nvideojs.registerComponent('StatsCard', StatsCard)\r\n\r\nexport {\r\n StatsCard,\r\n StatsCardOptions\r\n}\r\n","import videojs from 'video.js'\r\nimport { StatsCard, StatsCardOptions } from './stats-card'\r\n\r\nconst Plugin = videojs.getPlugin('plugin')\r\n\r\nclass StatsForNerdsPlugin extends Plugin {\r\n private statsCard: StatsCard\r\n\r\n constructor (player: videojs.Player, options: StatsCardOptions) {\r\n const settings = {\r\n ...options\r\n }\r\n\r\n super(player)\r\n\r\n this.player.ready(() => {\r\n player.addClass('vjs-stats-for-nerds')\r\n })\r\n\r\n this.statsCard = new StatsCard(player, options)\r\n\r\n player.addChild(this.statsCard, settings)\r\n }\r\n\r\n show () {\r\n this.statsCard.show()\r\n }\r\n}\r\n\r\nvideojs.registerPlugin('stats', StatsForNerdsPlugin)\r\nexport { StatsForNerdsPlugin }\r\n","function isIOS () {\r\n if (/iPad|iPhone|iPod/.test(navigator.platform)) {\r\n return true\r\n }\r\n\r\n // Detect iPad Desktop mode\r\n return !!(navigator.maxTouchPoints &&\r\n navigator.maxTouchPoints > 2 &&\r\n navigator.platform.includes('MacIntel'))\r\n}\r\n\r\nfunction isSafari () {\r\n return /^((?!chrome|android).)*safari/i.test(navigator.userAgent)\r\n}\r\n\r\nfunction isMobile () {\r\n return /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)\r\n}\r\n\r\nexport {\r\n isIOS,\r\n isSafari,\r\n isMobile\r\n}\r\n","import videojs from 'video.js'\r\nimport { isMobile } from '@root-helpers/web-browser'\r\n\r\nfunction getPauseBezel () {\r\n return `\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n `\r\n}\r\n\r\nfunction getPlayBezel () {\r\n return `\r\n
\r\n
\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n
\r\n
\r\n `\r\n}\r\n\r\nconst Component = videojs.getComponent('Component')\r\nclass PauseBezel extends Component {\r\n container: HTMLDivElement\r\n\r\n constructor (player: videojs.Player, options?: videojs.ComponentOptions) {\r\n super(player, options)\r\n\r\n // Hide bezels on mobile since we already have our mobile overlay\r\n if (isMobile()) return\r\n\r\n player.on('pause', (_: any) => {\r\n if (player.seeking() || player.ended()) return\r\n this.container.innerHTML = getPauseBezel()\r\n this.showBezel()\r\n })\r\n\r\n player.on('play', (_: any) => {\r\n if (player.seeking()) return\r\n this.container.innerHTML = getPlayBezel()\r\n this.showBezel()\r\n })\r\n }\r\n\r\n createEl () {\r\n this.container = super.createEl('div', {\r\n className: 'vjs-bezels-content'\r\n }) as HTMLDivElement\r\n\r\n this.container.style.display = 'none'\r\n\r\n return this.container\r\n }\r\n\r\n showBezel () {\r\n this.container.style.display = 'inherit'\r\n\r\n setTimeout(() => {\r\n this.container.style.display = 'none'\r\n }, 500) // matching the animation duration\r\n }\r\n}\r\n\r\nvideojs.registerComponent('PauseBezel', PauseBezel)\r\n","import videojs from 'video.js'\r\nimport './pause-bezel'\r\n\r\nconst Plugin = videojs.getPlugin('plugin')\r\n\r\nclass BezelsPlugin extends Plugin {\r\n\r\n constructor (player: videojs.Player, options?: videojs.ComponentOptions) {\r\n super(player)\r\n\r\n this.player.ready(() => {\r\n player.addClass('vjs-bezels')\r\n })\r\n\r\n player.addChild('PauseBezel', options)\r\n }\r\n}\r\n\r\nvideojs.registerPlugin('bezels', BezelsPlugin)\r\n\r\nexport { BezelsPlugin }\r\n","import { logger } from '@root-helpers/logger'\r\n\r\nfunction getStoredVolume () {\r\n const value = getLocalStorage('volume')\r\n if (value !== null && value !== undefined) {\r\n const valueNumber = parseFloat(value)\r\n if (isNaN(valueNumber)) return undefined\r\n\r\n return valueNumber\r\n }\r\n\r\n return undefined\r\n}\r\n\r\nfunction getStoredMute () {\r\n const value = getLocalStorage('mute')\r\n if (value !== null && value !== undefined) return value === 'true'\r\n\r\n return undefined\r\n}\r\n\r\nfunction getStoredTheater () {\r\n const value = getLocalStorage('theater-enabled')\r\n if (value !== null && value !== undefined) return value === 'true'\r\n\r\n return false\r\n}\r\n\r\nfunction saveVolumeInStore (value: number) {\r\n return setLocalStorage('volume', value.toString())\r\n}\r\n\r\nfunction saveMuteInStore (value: boolean) {\r\n return setLocalStorage('mute', value.toString())\r\n}\r\n\r\nfunction saveTheaterInStore (enabled: boolean) {\r\n return setLocalStorage('theater-enabled', enabled.toString())\r\n}\r\n\r\nfunction saveAverageBandwidth (value: number) {\r\n /** used to choose the most fitting resolution */\r\n return setLocalStorage('average-bandwidth', value.toString())\r\n}\r\n\r\nfunction getAverageBandwidthInStore () {\r\n const value = getLocalStorage('average-bandwidth')\r\n if (value !== null && value !== undefined) {\r\n const valueNumber = parseInt(value, 10)\r\n if (isNaN(valueNumber)) return undefined\r\n\r\n return valueNumber\r\n }\r\n\r\n return undefined\r\n}\r\n\r\nfunction saveLastSubtitle (language: string) {\r\n return setLocalStorage('last-subtitle', language)\r\n}\r\n\r\nfunction getStoredLastSubtitle () {\r\n return getLocalStorage('last-subtitle')\r\n}\r\n\r\nfunction saveVideoWatchHistory (videoUUID: string, duration: number) {\r\n return setLocalStorage(`video-watch-history`, JSON.stringify({\r\n ...getStoredVideoWatchHistory(),\r\n\r\n [videoUUID]: {\r\n duration,\r\n date: `${(new Date()).toISOString()}`\r\n }\r\n }))\r\n}\r\n\r\nfunction getStoredVideoWatchHistory (videoUUID?: string) {\r\n let data\r\n\r\n try {\r\n const value = getLocalStorage('video-watch-history')\r\n if (!value) return {}\r\n\r\n data = JSON.parse(value)\r\n } catch (error) {\r\n logger.error('Cannot parse video watch history from local storage/', error)\r\n }\r\n\r\n data = data || {}\r\n\r\n if (videoUUID) return data[videoUUID]\r\n\r\n return data\r\n}\r\n\r\nfunction cleanupVideoWatch () {\r\n const data = getStoredVideoWatchHistory()\r\n if (!data) return\r\n\r\n const newData = Object.keys(data).reduce((acc, videoUUID) => {\r\n const date = Date.parse(data[videoUUID].date)\r\n\r\n const diff = Math.ceil(((new Date()).getTime() - date) / (1000 * 3600 * 24))\r\n\r\n if (diff > 30) return acc\r\n\r\n return {\r\n ...acc,\r\n [videoUUID]: data[videoUUID]\r\n }\r\n }, {})\r\n\r\n setLocalStorage('video-watch-history', JSON.stringify(newData))\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n\r\nexport {\r\n getStoredVolume,\r\n getStoredMute,\r\n getStoredTheater,\r\n saveVolumeInStore,\r\n saveMuteInStore,\r\n saveTheaterInStore,\r\n saveAverageBandwidth,\r\n getAverageBandwidthInStore,\r\n saveLastSubtitle,\r\n getStoredLastSubtitle,\r\n saveVideoWatchHistory,\r\n getStoredVideoWatchHistory,\r\n cleanupVideoWatch\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n\r\nconst KEY_PREFIX = 'peertube-videojs-'\r\n\r\nfunction getLocalStorage (key: string) {\r\n try {\r\n return localStorage.getItem(KEY_PREFIX + key)\r\n } catch {\r\n return undefined\r\n }\r\n}\r\n\r\nfunction setLocalStorage (key: string, value: string) {\r\n try {\r\n localStorage.setItem(KEY_PREFIX + key, value)\r\n } catch { /* empty */\r\n }\r\n}\r\n","import debug from 'debug'\r\nimport videojs from 'video.js'\r\nimport { logger } from '@root-helpers/logger'\r\nimport { isMobile } from '@root-helpers/web-browser'\r\nimport { timeToInt } from '@shared/core-utils'\r\nimport { VideoView, VideoViewEvent } from '@shared/models/videos'\r\nimport {\r\n getStoredLastSubtitle,\r\n getStoredMute,\r\n getStoredVolume,\r\n saveLastSubtitle,\r\n saveMuteInStore,\r\n saveVideoWatchHistory,\r\n saveVolumeInStore\r\n} from '../../peertube-player-local-storage'\r\nimport { PeerTubePluginOptions, VideoJSCaption } from '../../types'\r\nimport { SettingsButton } from '../settings/settings-menu-button'\r\n\r\nconst debugLogger = debug('peertube:player:peertube')\r\n\r\nconst Plugin = videojs.getPlugin('plugin')\r\n\r\nclass PeerTubePlugin extends Plugin {\r\n private readonly videoViewUrl: string\r\n private readonly authorizationHeader: string\r\n\r\n private readonly videoUUID: string\r\n private readonly startTime: number\r\n\r\n private readonly CONSTANTS = {\r\n USER_VIEW_VIDEO_INTERVAL: 30000 // Every 60 seconds, notify the user is watching the video\r\n }\r\n\r\n //private videoCaptions: VideoJSCaption[]\r\n private defaultSubtitle: string\r\n\r\n private videoViewInterval: any\r\n\r\n private menuOpened = false\r\n private mouseInControlBar = false\r\n private mouseInSettings = false\r\n private readonly initialInactivityTimeout: number\r\n\r\n constructor (player: videojs.Player, options?: PeerTubePluginOptions) {\r\n super(player)\r\n\r\n this.videoViewUrl = options.videoViewUrl\r\n this.authorizationHeader = options.authorizationHeader\r\n this.videoUUID = options.videoUUID\r\n this.startTime = timeToInt(options.startTime)\r\n\r\n //this.videoCaptions = options.videoCaptions\r\n this.initialInactivityTimeout = this.player.options_.inactivityTimeout\r\n\r\n if (options.autoplay) this.player.addClass('vjs-has-autoplay')\r\n\r\n this.player.on('autoplay-failure', () => {\r\n this.player.removeClass('vjs-has-autoplay')\r\n })\r\n\r\n this.player.ready(() => {\r\n const playerOptions = this.player.options_\r\n\r\n const volume = getStoredVolume()\r\n if (volume !== undefined) this.player.volume(volume)\r\n\r\n const muted = playerOptions.muted !== undefined ? playerOptions.muted : getStoredMute()\r\n if (muted !== undefined) this.player.muted(muted)\r\n\r\n this.defaultSubtitle = options.subtitle || getStoredLastSubtitle()\r\n\r\n this.player.on('volumechange', () => {\r\n saveVolumeInStore(this.player.volume())\r\n saveMuteInStore(this.player.muted())\r\n })\r\n\r\n if (options.stopTime) {\r\n const stopTime = timeToInt(options.stopTime)\r\n const self = this\r\n\r\n this.player.on('timeupdate', function onTimeUpdate () {\r\n if (self.player.currentTime() > stopTime) {\r\n self.player.pause()\r\n self.player.trigger('stopped')\r\n\r\n self.player.off('timeupdate', onTimeUpdate)\r\n }\r\n })\r\n }\r\n\r\n this.player.textTracks().addEventListener('change', () => {\r\n const showing = this.player.textTracks().tracks_.find(t => {\r\n return t.kind === 'captions' && t.mode === 'showing'\r\n })\r\n\r\n if (!showing) {\r\n saveLastSubtitle('off')\r\n return\r\n }\r\n\r\n saveLastSubtitle(showing.language)\r\n })\r\n\r\n //this.player.on('sourcechange', () => this.initCaptions())\r\n\r\n this.player.duration(options.videoDuration)\r\n\r\n this.initializePlayer()\r\n this.runUserViewing()\r\n })\r\n }\r\n\r\n dispose () {\r\n this.stopListen()\r\n if (this.videoViewInterval) clearInterval(this.videoViewInterval)\r\n }\r\n\r\n onMenuOpened () {\r\n this.menuOpened = true\r\n this.alterInactivity()\r\n }\r\n\r\n onMenuClosed () {\r\n this.menuOpened = false\r\n this.alterInactivity()\r\n }\r\n\r\n displayFatalError () {\r\n this.player.addClass('vjs-error-display-enabled')\r\n }\r\n\r\n hideFatalError () {\r\n this.player.removeClass('vjs-error-display-enabled')\r\n }\r\n\r\n private initializePlayer () {\r\n if (isMobile()) this.player.addClass('vjs-is-mobile')\r\n\r\n //this.initSmoothProgressBar()\r\n\r\n //this.initCaptions()\r\n\r\n this.listenControlBarMouse()\r\n\r\n this.listenFullScreenChange()\r\n }\r\n\r\n private runUserViewing () {\r\n let lastCurrentTime = this.startTime\r\n let lastViewEvent: VideoViewEvent\r\n\r\n this.player.one('play', () => {\r\n this.notifyUserIsWatching(Math.round(this.startTime), lastViewEvent)\r\n })\r\n\r\n this.player.on('seeked', () => {\r\n // Don't take into account small seek events\r\n if (Math.abs(this.player.currentTime() - lastCurrentTime) < 3) return\r\n\r\n lastViewEvent = 'seek'\r\n })\r\n\r\n \r\n\r\n this.player.one('ended', () => {\r\n\r\n const currentTime = Math.round(this.player.duration())\r\n lastCurrentTime = currentTime\r\n\r\n this.notifyUserIsWatching(currentTime, lastViewEvent)\r\n\r\n lastViewEvent = undefined\r\n })\r\n\r\n this.videoViewInterval = setInterval(() => {\r\n const currentTime = Math.round(this.player.currentTime())\r\n\r\n // No need to update\r\n if (currentTime === lastCurrentTime) return\r\n\r\n lastCurrentTime = currentTime\r\n\r\n this.notifyUserIsWatching(currentTime, lastViewEvent)\r\n .catch(err => logger.error('Cannot notify user is watching.', err))\r\n\r\n lastViewEvent = undefined\r\n\r\n // Server won't save history, so save the video position in local storage\r\n if (!this.authorizationHeader) {\r\n saveVideoWatchHistory(this.videoUUID, currentTime)\r\n }\r\n }, this.CONSTANTS.USER_VIEW_VIDEO_INTERVAL)\r\n }\r\n\r\n private notifyUserIsWatching (currentTime: number, viewEvent: VideoViewEvent) {\r\n if (!this.videoViewUrl) return Promise.resolve(undefined)\r\n\r\n const body: VideoView = {\r\n currentTime,\r\n viewEvent\r\n }\r\n\r\n const headers = new Headers({\r\n 'Content-type': 'application/json; charset=UTF-8'\r\n })\r\n\r\n if (this.authorizationHeader) headers.set('Authorization', this.authorizationHeader)\r\n\r\n return fetch(this.videoViewUrl, { method: 'POST', body: JSON.stringify(body), headers }).catch(e => {\r\n return Promise.resolve()\r\n })\r\n }\r\n\r\n private listenFullScreenChange () {\r\n this.player.on('fullscreenchange', () => {\r\n if (this.player.isFullscreen()) this.player.focus()\r\n })\r\n }\r\n\r\n private stopListen(){\r\n const controlBar = this.player.controlBar\r\n const settingsButton: SettingsButton = (controlBar as any).settingsButton\r\n\r\n\r\n if(controlBar){\r\n controlBar.off('mouseenter')\r\n controlBar.off('mouseleave')\r\n }\r\n\r\n if(settingsButton){\r\n settingsButton.dialog.off('mouseenter')\r\n settingsButton.dialog.off('mouseleave')\r\n }\r\n \r\n }\r\n\r\n private listenControlBarMouse () {\r\n const controlBar = this.player.controlBar\r\n const settingsButton: SettingsButton = (controlBar as any).settingsButton\r\n\r\n controlBar.on('mouseenter', () => {\r\n this.mouseInControlBar = true\r\n this.alterInactivity()\r\n })\r\n\r\n controlBar.on('mouseleave', () => {\r\n this.mouseInControlBar = false\r\n this.alterInactivity()\r\n })\r\n\r\n settingsButton.dialog.on('mouseenter', () => {\r\n this.mouseInSettings = true\r\n this.alterInactivity()\r\n })\r\n\r\n settingsButton.dialog.on('mouseleave', () => {\r\n this.mouseInSettings = false\r\n this.alterInactivity()\r\n })\r\n }\r\n\r\n private alterInactivity () {\r\n if (this.menuOpened || this.mouseInSettings || this.mouseInControlBar) {\r\n this.setInactivityTimeout(0)\r\n return\r\n }\r\n\r\n this.setInactivityTimeout(this.initialInactivityTimeout)\r\n this.player.reportUserActivity(true)\r\n }\r\n\r\n private setInactivityTimeout (timeout: number) {\r\n (this.player as any).cache_.inactivityTimeout = timeout\r\n this.player.options_.inactivityTimeout = timeout\r\n\r\n debugLogger('Set player inactivity to ' + timeout)\r\n }\r\n\r\n}\r\n\r\nvideojs.registerPlugin('peertube', PeerTubePlugin)\r\nexport { PeerTubePlugin }\r\n","import videojs from 'video.js'\r\nimport { PeerTubeResolution } from '../../types'\r\n\r\nconst Plugin = videojs.getPlugin('plugin')\r\n\r\nclass PeerTubeResolutionsPlugin extends Plugin {\r\n private currentSelection: PeerTubeResolution\r\n private resolutions: PeerTubeResolution[] = []\r\n\r\n private autoResolutionChosenId: number\r\n private autoResolutionEnabled = true\r\n\r\n add (resolutions: PeerTubeResolution[]) {\r\n for (const r of resolutions) {\r\n this.resolutions.push(r)\r\n }\r\n\r\n this.currentSelection = this.getSelected()\r\n\r\n this.sort()\r\n this.trigger('resolutionsAdded')\r\n }\r\n\r\n getResolutions () {\r\n return this.resolutions\r\n }\r\n\r\n getSelected () {\r\n return this.resolutions.find(r => r.selected)\r\n }\r\n\r\n getAutoResolutionChosen () {\r\n return this.resolutions.find(r => r.id === this.autoResolutionChosenId)\r\n }\r\n\r\n select (options: {\r\n id: number\r\n byEngine: boolean\r\n autoResolutionChosenId?: number\r\n }) {\r\n const { id, autoResolutionChosenId, byEngine } = options\r\n\r\n if (this.currentSelection?.id === id && this.autoResolutionChosenId === autoResolutionChosenId) return\r\n\r\n this.autoResolutionChosenId = autoResolutionChosenId\r\n\r\n for (const r of this.resolutions) {\r\n r.selected = r.id === id\r\n\r\n if (r.selected) {\r\n this.currentSelection = r\r\n\r\n if (!byEngine) r.selectCallback()\r\n }\r\n }\r\n\r\n this.trigger('resolutionChanged')\r\n }\r\n\r\n disableAutoResolution () {\r\n this.autoResolutionEnabled = false\r\n this.trigger('autoResolutionEnabledChanged')\r\n }\r\n\r\n enabledAutoResolution () {\r\n this.autoResolutionEnabled = true\r\n this.trigger('autoResolutionEnabledChanged')\r\n }\r\n\r\n isAutoResolutionEnabeld () {\r\n return this.autoResolutionEnabled\r\n }\r\n\r\n private sort () {\r\n this.resolutions.sort((a, b) => {\r\n if (a.id === -1) return 1\r\n if (b.id === -1) return -1\r\n\r\n if (a.height > b.height) return -1\r\n if (a.height === b.height) return 0\r\n return 1\r\n })\r\n }\r\n\r\n}\r\n\r\nvideojs.registerPlugin('peertubeResolutions', PeerTubeResolutionsPlugin)\r\nexport { PeerTubeResolutionsPlugin }\r\n","import videojs from 'video.js'\r\nimport { NextPreviousVideoButtonOptions } from '../../types'\r\n\r\nconst Button = videojs.getComponent('Button')\r\n\r\nclass NextPreviousVideoButton extends Button {\r\n private readonly nextPreviousVideoButtonOptions: NextPreviousVideoButtonOptions\r\n\r\n constructor (player: videojs.Player, options?: NextPreviousVideoButtonOptions) {\r\n super(player, options as any)\r\n\r\n this.nextPreviousVideoButtonOptions = options\r\n\r\n this.update()\r\n }\r\n\r\n createEl () {\r\n const type = (this.options_ as NextPreviousVideoButtonOptions).type\r\n\r\n const button = videojs.dom.createEl('button', {\r\n className: 'vjs-' + type + '-video'\r\n }) as HTMLButtonElement\r\n const nextIcon = videojs.dom.createEl('span', {\r\n className: 'icon icon-' + type\r\n })\r\n button.appendChild(nextIcon)\r\n\r\n if (type === 'next') {\r\n button.title = this.player_.localize('Next video')\r\n } else {\r\n button.title = this.player_.localize('Previous video')\r\n }\r\n\r\n return button\r\n }\r\n\r\n handleClick () {\r\n this.nextPreviousVideoButtonOptions.handler()\r\n }\r\n\r\n update () {\r\n const disabled = this.nextPreviousVideoButtonOptions.isDisabled()\r\n\r\n if (disabled) this.addClass('vjs-disabled')\r\n else this.removeClass('vjs-disabled')\r\n }\r\n}\r\n\r\nvideojs.registerComponent('NextVideoButton', NextPreviousVideoButton)\r\nvideojs.registerComponent('PreviousVideoButton', NextPreviousVideoButton)\r\n","import videojs from 'video.js'\r\nimport { PeerTubeP2PInfoButtonOptions, PlayerNetworkInfo } from '../../types'\r\nimport { bytes } from '../common'\r\n\r\nconst Button = videojs.getComponent('Button')\r\nclass P2pInfoButton extends Button {\r\n\r\n constructor (player: videojs.Player, options?: PeerTubeP2PInfoButtonOptions) {\r\n super(player, options as any)\r\n }\r\n\r\n createEl () {\r\n const div = videojs.dom.createEl('div', {\r\n className: 'vjs-peertube'\r\n })\r\n const subDivWebtorrent = videojs.dom.createEl('div', {\r\n className: 'vjs-peertube-hidden' // Hide the stats before we get the info\r\n }) as HTMLDivElement\r\n div.appendChild(subDivWebtorrent)\r\n\r\n // Stop here if P2P is not enabled\r\n const p2pEnabled = (this.options_ as PeerTubeP2PInfoButtonOptions).p2pEnabled\r\n if (!p2pEnabled) return div as HTMLButtonElement\r\n\r\n const downloadIcon = videojs.dom.createEl('span', {\r\n className: 'icon icon-download'\r\n })\r\n subDivWebtorrent.appendChild(downloadIcon)\r\n\r\n const downloadSpeedText = videojs.dom.createEl('span', {\r\n className: 'download-speed-text'\r\n })\r\n const downloadSpeedNumber = videojs.dom.createEl('span', {\r\n className: 'download-speed-number'\r\n })\r\n const downloadSpeedUnit = videojs.dom.createEl('span')\r\n downloadSpeedText.appendChild(downloadSpeedNumber)\r\n downloadSpeedText.appendChild(downloadSpeedUnit)\r\n subDivWebtorrent.appendChild(downloadSpeedText)\r\n\r\n const uploadIcon = videojs.dom.createEl('span', {\r\n className: 'icon icon-upload'\r\n })\r\n subDivWebtorrent.appendChild(uploadIcon)\r\n\r\n const uploadSpeedText = videojs.dom.createEl('span', {\r\n className: 'upload-speed-text'\r\n })\r\n const uploadSpeedNumber = videojs.dom.createEl('span', {\r\n className: 'upload-speed-number'\r\n })\r\n const uploadSpeedUnit = videojs.dom.createEl('span')\r\n uploadSpeedText.appendChild(uploadSpeedNumber)\r\n uploadSpeedText.appendChild(uploadSpeedUnit)\r\n subDivWebtorrent.appendChild(uploadSpeedText)\r\n\r\n const peersText = videojs.dom.createEl('span', {\r\n className: 'peers-text'\r\n })\r\n const peersNumber = videojs.dom.createEl('span', {\r\n className: 'peers-number'\r\n })\r\n subDivWebtorrent.appendChild(peersNumber)\r\n subDivWebtorrent.appendChild(peersText)\r\n\r\n const subDivHttp = videojs.dom.createEl('div', {\r\n className: 'vjs-peertube-hidden'\r\n })\r\n const subDivHttpText = videojs.dom.createEl('span', {\r\n className: 'http-fallback',\r\n textContent: 'HTTP'\r\n })\r\n\r\n subDivHttp.appendChild(subDivHttpText)\r\n div.appendChild(subDivHttp)\r\n\r\n this.player_.on('p2pInfo', (event: any, data: PlayerNetworkInfo) => {\r\n // We are in HTTP fallback\r\n if (!data) {\r\n subDivHttp.className = 'vjs-peertube-displayed'\r\n subDivWebtorrent.className = 'vjs-peertube-hidden'\r\n\r\n return\r\n }\r\n\r\n const p2pStats = data.p2p\r\n const httpStats = data.http\r\n\r\n const downloadSpeed = bytes(p2pStats.downloadSpeed + httpStats.downloadSpeed)\r\n const uploadSpeed = bytes(p2pStats.uploadSpeed + httpStats.uploadSpeed)\r\n const totalDownloaded = bytes(p2pStats.downloaded + httpStats.downloaded)\r\n const totalUploaded = bytes(p2pStats.uploaded + httpStats.uploaded)\r\n const numPeers = p2pStats.numPeers\r\n\r\n subDivWebtorrent.title = this.player().localize('Total downloaded: ') + totalDownloaded.join(' ') + '\\n'\r\n\r\n if (data.source === 'p2p-media-loader') {\r\n const downloadedFromServer = bytes(httpStats.downloaded).join(' ')\r\n const downloadedFromPeers = bytes(p2pStats.downloaded).join(' ')\r\n\r\n subDivWebtorrent.title +=\r\n ' * ' + this.player().localize('From servers: ') + downloadedFromServer + '\\n' +\r\n ' * ' + this.player().localize('From peers: ') + downloadedFromPeers + '\\n'\r\n }\r\n subDivWebtorrent.title += this.player().localize('Total uploaded: ') + totalUploaded.join(' ')\r\n\r\n downloadSpeedNumber.textContent = downloadSpeed[0]\r\n downloadSpeedUnit.textContent = ' ' + downloadSpeed[1]\r\n\r\n uploadSpeedNumber.textContent = uploadSpeed[0]\r\n uploadSpeedUnit.textContent = ' ' + uploadSpeed[1]\r\n\r\n peersNumber.textContent = numPeers.toString()\r\n peersText.textContent = ' ' + (numPeers > 1 ? this.player().localize('peers') : this.player_.localize('peer'))\r\n\r\n subDivHttp.className = 'vjs-peertube-hidden'\r\n subDivWebtorrent.className = 'vjs-peertube-displayed'\r\n })\r\n\r\n return div as HTMLButtonElement\r\n }\r\n}\r\n\r\nvideojs.registerComponent('P2PInfoButton', P2pInfoButton)\r\n","/**\r\n * @file picture-in-picture-toggle.js\r\n */\r\n /*import Button from '../button.js';\r\n import Component from '../component.js';\r\n import document from 'global/document';*/\r\n\r\n import videojs from \"video.js\";\r\n\r\n const Button = videojs.getComponent(\"Button\");\r\n const MenuButton = videojs.getComponent(\"MenuButton\");\r\n \r\n /**\r\n * Toggle Picture-in-Picture mode\r\n *\r\n * @extends Button\r\n */\r\n class PictureInPictureBastyon extends MenuButton {\r\n \r\n \r\n constructor(player : any, options : any) {\r\n super(player, options);\r\n \r\n this.controlText('Mini Player')\r\n }\r\n \r\n createEl(){\r\n return this.buildElement();\r\n }\r\n \r\n handleClick(event : any) {\r\n this.player_.trigger('pictureInPictureRequest', event)\r\n }\r\n \r\n private buildElement() {\r\n \r\n const el = super.createEl();\r\n \r\n el.classList.add(\"vjs-picture-in-picture-control\");\r\n \r\n return el as HTMLButtonElement;\r\n }\r\n \r\n }\r\n \r\n videojs.registerComponent(\"PictureInPictureBastyon\", PictureInPictureBastyon);\r\n ","import videojs from 'video.js'\r\n\r\nconst Component = videojs.getComponent('Component')\r\n\r\nclass PeerTubeLoadProgressBar extends Component {\r\n\r\n constructor (player: videojs.Player, options?: videojs.ComponentOptions) {\r\n super(player, options)\r\n\r\n this.on(player, 'progress', this.update)\r\n }\r\n\r\n createEl () {\r\n return super.createEl('div', {\r\n className: 'vjs-load-progress',\r\n innerHTML: `${this.localize('Loaded')}: 0%`\r\n })\r\n }\r\n\r\n dispose () {\r\n super.dispose()\r\n }\r\n\r\n update () {\r\n return\r\n /*const torrent = this.player().webtorrent().getTorrent()\r\n if (!torrent) return\r\n\r\n // @ts-ignore\r\n (this.el() as HTMLElement).style['transform-origin'] = 'left'\r\n (this.el() as HTMLElement).style['transform'] = 'scaleX('+(torrent.progress).toFixed(2)+')'*/\r\n\r\n //(this.el() as HTMLElement).style.width = (torrent.progress * 100) + '%'\r\n }\r\n\r\n}\r\n\r\nComponent.registerComponent('PeerTubeLoadProgressBar', PeerTubeLoadProgressBar)\r\n","import videojs from 'video.js'\r\nimport { getStoredTheater, saveTheaterInStore } from '../../peertube-player-local-storage'\r\n\r\nconst Button = videojs.getComponent('Button')\r\nclass TheaterButton extends Button {\r\n\r\n private static readonly THEATER_MODE_CLASS = 'vjs-theater-enabled'\r\n\r\n constructor (player: videojs.Player, options: videojs.ComponentOptions) {\r\n super(player, options)\r\n\r\n const enabled = getStoredTheater()\r\n if (enabled === true) {\r\n this.player().addClass(TheaterButton.THEATER_MODE_CLASS)\r\n\r\n this.handleTheaterChange()\r\n }\r\n\r\n this.controlText('Theater mode')\r\n\r\n this.player().theaterEnabled = enabled\r\n }\r\n\r\n buildCSSClass () {\r\n return `vjs-theater-control ${super.buildCSSClass()}`\r\n }\r\n\r\n handleTheaterChange () {\r\n const theaterEnabled = this.isTheaterEnabled()\r\n\r\n if (theaterEnabled) {\r\n this.controlText('Normal mode')\r\n } else {\r\n this.controlText('Theater mode')\r\n }\r\n\r\n saveTheaterInStore(theaterEnabled)\r\n\r\n this.player_.trigger('theaterChange', theaterEnabled)\r\n }\r\n\r\n handleClick () {\r\n this.player_.toggleClass(TheaterButton.THEATER_MODE_CLASS)\r\n\r\n this.handleTheaterChange()\r\n }\r\n\r\n private isTheaterEnabled () {\r\n return this.player_.hasClass(TheaterButton.THEATER_MODE_CLASS)\r\n }\r\n}\r\n\r\nvideojs.registerComponent('TheaterButton', TheaterButton)\r\n","import videojs from 'video.js'\r\n\r\nconst MenuItem = videojs.getComponent('MenuItem')\r\n\r\nexport interface ResolutionMenuItemOptions extends videojs.MenuItemOptions {\r\n resolutionId: number\r\n}\r\n\r\nclass ResolutionMenuItem extends MenuItem {\r\n private readonly resolutionId: number\r\n private readonly label: string\r\n\r\n private autoResolutionEnabled: boolean\r\n private autoResolutionChosen: string\r\n\r\n constructor (player: videojs.Player, options?: ResolutionMenuItemOptions) {\r\n options.selectable = true\r\n\r\n super(player, options)\r\n\r\n this.autoResolutionEnabled = true\r\n this.autoResolutionChosen = ''\r\n\r\n this.resolutionId = options.resolutionId\r\n this.label = options.label\r\n\r\n player.peertubeResolutions().on('resolutionChanged', () => this.updateSelection())\r\n\r\n // We only want to disable the \"Auto\" item\r\n if (this.resolutionId === -1) {\r\n player.peertubeResolutions().on('autoResolutionEnabledChanged', () => this.updateAutoResolution())\r\n }\r\n }\r\n\r\n handleClick (event: any) {\r\n // Auto button disabled?\r\n if (this.autoResolutionEnabled === false && this.resolutionId === -1) return\r\n\r\n super.handleClick(event)\r\n\r\n this.player().peertubeResolutions().select({ id: this.resolutionId, byEngine: false })\r\n }\r\n\r\n updateSelection () {\r\n const selectedResolution = this.player().peertubeResolutions().getSelected()\r\n\r\n if (this.resolutionId === -1) {\r\n this.autoResolutionChosen = this.player().peertubeResolutions().getAutoResolutionChosen()?.label\r\n }\r\n\r\n this.selected(this.resolutionId === selectedResolution.id)\r\n }\r\n\r\n updateAutoResolution () {\r\n const enabled = this.player().peertubeResolutions().isAutoResolutionEnabeld()\r\n\r\n // Check if the auto resolution is enabled or not\r\n if (enabled === false) {\r\n this.addClass('disabled')\r\n } else {\r\n this.removeClass('disabled')\r\n }\r\n\r\n this.autoResolutionEnabled = enabled\r\n }\r\n\r\n getLabel () {\r\n if (this.resolutionId === -1) {\r\n return this.label + ' ' + this.autoResolutionChosen + ''\r\n }\r\n\r\n return this.label\r\n }\r\n}\r\nvideojs.registerComponent('ResolutionMenuItem', ResolutionMenuItem)\r\n\r\nexport { ResolutionMenuItem }\r\n","import videojs from 'video.js'\r\nimport { ResolutionMenuItem } from './resolution-menu-item'\r\n\r\nconst Menu = videojs.getComponent('Menu')\r\nconst MenuButton = videojs.getComponent('MenuButton')\r\nclass ResolutionMenuButton extends MenuButton {\r\n labelEl_: HTMLElement\r\n\r\n constructor (player: videojs.Player, options?: videojs.MenuButtonOptions) {\r\n super(player, options)\r\n\r\n this.controlText('Quality')\r\n\r\n player.peertubeResolutions().on('resolutionsAdded', () => this.buildQualities())\r\n\r\n // For parent\r\n player.peertubeResolutions().on('resolutionChanged', () => {\r\n setTimeout(() => this.trigger('labelUpdated'))\r\n })\r\n }\r\n\r\n createEl () {\r\n const el = super.createEl()\r\n\r\n this.labelEl_ = videojs.dom.createEl('div', {\r\n className: 'vjs-resolution-value'\r\n }) as HTMLElement\r\n\r\n el.appendChild(this.labelEl_)\r\n\r\n return el\r\n }\r\n\r\n updateARIAAttributes () {\r\n this.el().setAttribute('aria-label', 'Quality')\r\n }\r\n\r\n createMenu () {\r\n return new Menu(this.player_)\r\n }\r\n\r\n buildCSSClass () {\r\n return super.buildCSSClass() + ' vjs-resolution-button'\r\n }\r\n\r\n buildWrapperCSSClass () {\r\n return 'vjs-resolution-control ' + super.buildWrapperCSSClass()\r\n }\r\n\r\n private addClickListener (component: any) {\r\n component.on('click', () => {\r\n const children = this.menu.children()\r\n\r\n for (const child of children) {\r\n if (component !== child) {\r\n (child as videojs.MenuItem).selected(false)\r\n }\r\n }\r\n })\r\n }\r\n\r\n private buildQualities () {\r\n for (const d of this.player().peertubeResolutions().getResolutions()) {\r\n const label = d.label === '0p'\r\n ? this.player().localize('Audio-only')\r\n : d.label\r\n\r\n this.menu.addChild(new ResolutionMenuItem(\r\n this.player_,\r\n {\r\n id: d.id + '',\r\n resolutionId: d.id,\r\n label,\r\n selected: d.selected\r\n })\r\n )\r\n }\r\n\r\n for (const m of this.menu.children()) {\r\n this.addClickListener(m)\r\n }\r\n\r\n this.trigger('menuChanged')\r\n }\r\n}\r\n\r\nvideojs.registerComponent('ResolutionMenuButton', ResolutionMenuButton)\r\n","import videojs from 'video.js'\r\n\r\nconst Component = videojs.getComponent('Component')\r\n\r\nclass SettingsDialog extends Component {\r\n constructor (player: videojs.Player) {\r\n super(player)\r\n\r\n this.hide()\r\n }\r\n\r\n /**\r\n * Create the component's DOM element\r\n *\r\n */\r\n createEl () {\r\n const uniqueId = this.id()\r\n const dialogLabelId = 'TTsettingsDialogLabel-' + uniqueId\r\n const dialogDescriptionId = 'TTsettingsDialogDescription-' + uniqueId\r\n\r\n return super.createEl('div', {\r\n className: 'vjs-settings-dialog vjs-modal-overlay',\r\n innerHTML: '',\r\n tabIndex: -1\r\n }, {\r\n role: 'dialog',\r\n 'aria-labelledby': dialogLabelId,\r\n 'aria-describedby': dialogDescriptionId\r\n })\r\n }\r\n}\r\n\r\nComponent.registerComponent('SettingsDialog', SettingsDialog)\r\n\r\nexport { SettingsDialog }\r\n","import videojs from 'video.js'\r\nimport { toTitleCase } from '../common'\r\nimport { SettingsDialog } from './settings-dialog'\r\nimport { SettingsButton } from './settings-menu-button'\r\nimport { SettingsPanel } from './settings-panel'\r\nimport { SettingsPanelChild } from './settings-panel-child'\r\n\r\nconst MenuItem = videojs.getComponent('MenuItem')\r\nconst component = videojs.getComponent('Component')\r\n\r\nexport interface SettingsMenuItemOptions extends videojs.MenuItemOptions {\r\n entry: string\r\n menuButton: SettingsButton\r\n}\r\n\r\nclass SettingsMenuItem extends MenuItem {\r\n settingsButton: SettingsButton\r\n dialog: SettingsDialog\r\n mainMenu: videojs.Menu\r\n panel: SettingsPanel\r\n panelChild: SettingsPanelChild\r\n panelChildEl: HTMLElement\r\n size: number[]\r\n menuToLoad: string\r\n subMenu: SettingsButton\r\n\r\n submenuClickHandler: typeof SettingsMenuItem.prototype.onSubmenuClick\r\n transitionEndHandler: typeof SettingsMenuItem.prototype.onTransitionEnd\r\n\r\n settingsSubMenuTitleEl_: HTMLElement\r\n settingsSubMenuValueEl_: HTMLElement\r\n settingsSubMenuEl_: HTMLElement\r\n\r\n constructor (player: videojs.Player, options?: SettingsMenuItemOptions) {\r\n super(player, options)\r\n\r\n this.settingsButton = options.menuButton\r\n this.dialog = this.settingsButton.dialog\r\n this.mainMenu = this.settingsButton.menu\r\n this.panel = this.dialog.getChild('settingsPanel')\r\n this.panelChild = this.panel.getChild('settingsPanelChild')\r\n this.panelChildEl = this.panelChild.el() as HTMLElement\r\n\r\n this.size = null\r\n\r\n // keep state of what menu type is loading next\r\n this.menuToLoad = 'mainmenu'\r\n\r\n const subMenuName = toTitleCase(options.entry)\r\n const SubMenuComponent = videojs.getComponent(subMenuName)\r\n\r\n if (!SubMenuComponent) {\r\n throw new Error(`Component ${subMenuName} does not exist`)\r\n }\r\n\r\n const newOptions = Object.assign({}, options, { entry: options.menuButton, menuButton: this })\r\n\r\n this.subMenu = new SubMenuComponent(this.player(), newOptions) as SettingsButton\r\n const subMenuClass = this.subMenu.buildCSSClass().split(' ')[0]\r\n this.settingsSubMenuEl_.className += ' ' + subMenuClass\r\n\r\n this.eventHandlers()\r\n\r\n player.ready(() => {\r\n // Voodoo magic for IOS\r\n setTimeout(() => {\r\n // Player was destroyed\r\n if (!this.player_) return\r\n\r\n this.build()\r\n\r\n // Update on rate change\r\n player.on('ratechange', this.submenuClickHandler)\r\n\r\n if (subMenuName === 'CaptionsButton') {\r\n // Hack to regenerate captions on HTTP fallback\r\n player.on('captionsChanged', () => {\r\n setTimeout(() => {\r\n this.settingsSubMenuEl_.innerHTML = ''\r\n this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el())\r\n this.update()\r\n this.bindClickEvents()\r\n }, 0)\r\n })\r\n }\r\n\r\n this.reset()\r\n }, 0)\r\n })\r\n }\r\n\r\n eventHandlers () {\r\n this.submenuClickHandler = this.onSubmenuClick.bind(this)\r\n this.transitionEndHandler = this.onTransitionEnd.bind(this)\r\n }\r\n\r\n onSubmenuClick (event: any) {\r\n let target = null\r\n\r\n if (event.type === 'tap') {\r\n target = event.target\r\n } else {\r\n target = event.currentTarget || event.target\r\n }\r\n\r\n if (target?.classList.contains('vjs-back-button')) {\r\n this.loadMainMenu()\r\n return\r\n }\r\n\r\n // To update the sub menu value on click, setTimeout is needed because\r\n // updating the value is not instant\r\n setTimeout(() => this.update(event), 0)\r\n\r\n // Seems like videojs adds a vjs-hidden class on the caption menu after a click\r\n // We don't need it\r\n this.subMenu.menu.removeClass('vjs-hidden')\r\n }\r\n\r\n /**\r\n * Create the component's DOM element\r\n *\r\n */\r\n createEl () {\r\n const el = videojs.dom.createEl('li', {\r\n className: 'vjs-menu-item',\r\n tabIndex: -1\r\n })\r\n\r\n this.settingsSubMenuTitleEl_ = videojs.dom.createEl('div', {\r\n className: 'vjs-settings-sub-menu-title'\r\n }) as HTMLElement\r\n\r\n el.appendChild(this.settingsSubMenuTitleEl_)\r\n\r\n this.settingsSubMenuValueEl_ = videojs.dom.createEl('div', {\r\n className: 'vjs-settings-sub-menu-value'\r\n }) as HTMLElement\r\n\r\n el.appendChild(this.settingsSubMenuValueEl_)\r\n\r\n this.settingsSubMenuEl_ = videojs.dom.createEl('div', {\r\n className: 'vjs-settings-sub-menu'\r\n }) as HTMLElement\r\n\r\n return el as HTMLLIElement\r\n }\r\n\r\n /**\r\n * Handle click on menu item\r\n *\r\n * @method handleClick\r\n */\r\n handleClick (event: videojs.EventTarget.Event) {\r\n this.menuToLoad = 'submenu'\r\n // Remove open class to ensure only the open submenu gets this class\r\n videojs.dom.removeClass(this.el(), 'open')\r\n\r\n super.handleClick(event);\r\n\r\n (this.mainMenu.el() as HTMLElement).style.opacity = '0'\r\n // Whether to add or remove vjs-hidden class on the settingsSubMenuEl element\r\n if (videojs.dom.hasClass(this.settingsSubMenuEl_, 'vjs-hidden')) {\r\n videojs.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden')\r\n\r\n // animation not played without timeout\r\n setTimeout(() => {\r\n this.settingsSubMenuEl_.style.opacity = '1'\r\n this.settingsSubMenuEl_.style.marginRight = '0px'\r\n }, 0)\r\n\r\n this.settingsButton.setDialogSize(this.size)\r\n\r\n const firstChild = this.subMenu.menu.children()[0]\r\n if (firstChild) firstChild.focus()\r\n } else {\r\n videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden')\r\n }\r\n }\r\n\r\n /**\r\n * Create back button\r\n *\r\n * @method createBackButton\r\n */\r\n createBackButton () {\r\n const button = this.subMenu.menu.addChild('MenuItem', {}, 0)\r\n\r\n button.addClass('vjs-back-button');\r\n (button.el() as HTMLElement).innerHTML = this.player().localize(this.subMenu.controlText())\r\n }\r\n\r\n /**\r\n * Add/remove prefixed event listener for CSS Transition\r\n *\r\n * @method PrefixedEvent\r\n */\r\n PrefixedEvent (element: any, type: any, callback: any, action = 'addEvent') {\r\n const prefix = [ 'webkit', 'moz', 'MS', 'o', '' ]\r\n\r\n for (let p = 0; p < prefix.length; p++) {\r\n if (!prefix[p]) {\r\n type = type.toLowerCase()\r\n }\r\n\r\n if (action === 'addEvent') {\r\n element.addEventListener(prefix[p] + type, callback, false)\r\n } else if (action === 'removeEvent') {\r\n element.removeEventListener(prefix[p] + type, callback, false)\r\n }\r\n }\r\n }\r\n\r\n onTransitionEnd (event: any) {\r\n if (event.propertyName !== 'margin-right') {\r\n return\r\n }\r\n\r\n if (this.menuToLoad === 'mainmenu') {\r\n // hide submenu\r\n videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden')\r\n\r\n // reset opacity to 0\r\n this.settingsSubMenuEl_.style.opacity = '0'\r\n }\r\n }\r\n\r\n reset () {\r\n videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden')\r\n this.settingsSubMenuEl_.style.opacity = '0'\r\n this.setMargin()\r\n }\r\n\r\n loadMainMenu () {\r\n const mainMenuEl = this.mainMenu.el() as HTMLElement\r\n this.menuToLoad = 'mainmenu'\r\n this.mainMenu.show()\r\n mainMenuEl.style.opacity = '0'\r\n\r\n // back button will always take you to main menu, so set dialog sizes\r\n const mainMenuAny = this.mainMenu as any\r\n this.settingsButton.setDialogSize([ mainMenuAny.width, mainMenuAny.height ])\r\n\r\n // animation not triggered without timeout (some async stuff ?!?)\r\n setTimeout(() => {\r\n // animate margin and opacity before hiding the submenu\r\n // this triggers CSS Transition event\r\n this.setMargin()\r\n mainMenuEl.style.opacity = '1'\r\n\r\n const firstChild = this.mainMenu.children()[0]\r\n if (firstChild) firstChild.focus()\r\n }, 0)\r\n }\r\n\r\n build () {\r\n this.subMenu.on('labelUpdated', () => {\r\n this.update()\r\n })\r\n this.subMenu.on('menuChanged', () => {\r\n this.bindClickEvents()\r\n this.setSize()\r\n this.update()\r\n })\r\n\r\n this.settingsSubMenuTitleEl_.innerHTML = this.player().localize(this.subMenu.controlText())\r\n this.settingsSubMenuEl_.appendChild(this.subMenu.menu.el())\r\n this.panelChildEl.appendChild(this.settingsSubMenuEl_)\r\n this.update()\r\n\r\n this.createBackButton()\r\n this.setSize()\r\n this.bindClickEvents()\r\n\r\n // prefixed event listeners for CSS TransitionEnd\r\n this.PrefixedEvent(\r\n this.settingsSubMenuEl_,\r\n 'TransitionEnd',\r\n this.transitionEndHandler,\r\n 'addEvent'\r\n )\r\n }\r\n\r\n update (event?: any) {\r\n let target: HTMLElement = null\r\n const subMenu = this.subMenu.name()\r\n\r\n if (event && event.type === 'tap') {\r\n target = event.target\r\n } else if (event) {\r\n target = event.currentTarget\r\n }\r\n\r\n // Playback rate menu button doesn't get a vjs-selected class\r\n // or sets options_['selected'] on the selected playback rate.\r\n // Thus we get the submenu value based on the labelEl of playbackRateMenuButton\r\n if (subMenu === 'PlaybackRateMenuButton') {\r\n const html = (this.subMenu as any).labelEl_.innerHTML\r\n\r\n setTimeout(() => {\r\n this.settingsSubMenuValueEl_.innerHTML = html\r\n }, 250)\r\n } else {\r\n // Loop through the submenu items to find the selected child\r\n for (const subMenuItem of this.subMenu.menu.children_) {\r\n if (!(subMenuItem instanceof component)) {\r\n continue\r\n }\r\n\r\n if (subMenuItem.hasClass('vjs-selected')) {\r\n const subMenuItemUntyped = subMenuItem as any\r\n\r\n // Prefer to use the function\r\n if (typeof subMenuItemUntyped.getLabel === 'function') {\r\n this.settingsSubMenuValueEl_.innerHTML = subMenuItemUntyped.getLabel()\r\n break\r\n }\r\n\r\n this.settingsSubMenuValueEl_.innerHTML = this.player().localize(subMenuItemUntyped.options_.label)\r\n }\r\n }\r\n }\r\n\r\n if (target && !target.classList.contains('vjs-back-button')) {\r\n this.settingsButton.hideDialog()\r\n }\r\n }\r\n\r\n bindClickEvents () {\r\n for (const item of this.subMenu.menu.children()) {\r\n if (!(item instanceof component)) {\r\n continue\r\n }\r\n item.on([ 'tap', 'click' ], this.submenuClickHandler)\r\n }\r\n }\r\n\r\n // save size of submenus on first init\r\n // if number of submenu items change dynamically more logic will be needed\r\n setSize () {\r\n this.dialog.removeClass('vjs-hidden')\r\n videojs.dom.removeClass(this.settingsSubMenuEl_, 'vjs-hidden')\r\n this.size = this.settingsButton.getComponentSize(this.settingsSubMenuEl_)\r\n this.setMargin()\r\n this.dialog.addClass('vjs-hidden')\r\n videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden')\r\n }\r\n\r\n setMargin () {\r\n if (!this.size) return\r\n\r\n const [ width ] = this.size\r\n\r\n this.settingsSubMenuEl_.style.marginRight = `-${width}px`\r\n }\r\n\r\n /**\r\n * Hide the sub menu\r\n */\r\n hideSubMenu () {\r\n // after removing settings item this.el_ === null\r\n if (!this.el()) {\r\n return\r\n }\r\n\r\n if (videojs.dom.hasClass(this.el(), 'open')) {\r\n videojs.dom.addClass(this.settingsSubMenuEl_, 'vjs-hidden')\r\n videojs.dom.removeClass(this.el(), 'open')\r\n }\r\n }\r\n\r\n}\r\n\r\n(SettingsMenuItem as any).prototype.contentElType = 'button'\r\nvideojs.registerComponent('SettingsMenuItem', SettingsMenuItem)\r\n\r\nexport { SettingsMenuItem }\r\n","import videojs from 'video.js'\r\nimport { toTitleCase } from '../common'\r\nimport { SettingsDialog } from './settings-dialog'\r\nimport { SettingsMenuItem } from './settings-menu-item'\r\nimport { SettingsPanel } from './settings-panel'\r\nimport { SettingsPanelChild } from './settings-panel-child'\r\n\r\nconst Button = videojs.getComponent('Button')\r\nconst Menu = videojs.getComponent('Menu')\r\nconst Component = videojs.getComponent('Component')\r\n\r\nexport interface SettingsButtonOptions extends videojs.ComponentOptions {\r\n entries: any[]\r\n setup?: {\r\n maxHeightOffset: number\r\n }\r\n}\r\n\r\nclass SettingsButton extends Button {\r\n dialog: SettingsDialog\r\n dialogEl: HTMLElement\r\n menu: videojs.Menu\r\n panel: SettingsPanel\r\n panelChild: SettingsPanelChild\r\n\r\n addSettingsItemHandler: typeof SettingsButton.prototype.onAddSettingsItem\r\n disposeSettingsItemHandler: typeof SettingsButton.prototype.onDisposeSettingsItem\r\n documentClickHandler: typeof SettingsButton.prototype.onDocumentClick\r\n userInactiveHandler: typeof SettingsButton.prototype.onUserInactive\r\n\r\n private settingsButtonOptions: SettingsButtonOptions\r\n\r\n constructor (player: videojs.Player, options?: SettingsButtonOptions) {\r\n super(player, options)\r\n\r\n this.settingsButtonOptions = options\r\n\r\n this.controlText('Settings')\r\n\r\n this.dialog = this.player().addChild('settingsDialog')\r\n this.dialogEl = this.dialog.el() as HTMLElement\r\n this.menu = null\r\n this.panel = this.dialog.addChild('settingsPanel')\r\n this.panelChild = this.panel.addChild('settingsPanelChild')\r\n\r\n this.addClass('vjs-settings')\r\n this.el().setAttribute('aria-label', 'Settings Button')\r\n\r\n // Event handlers\r\n this.addSettingsItemHandler = this.onAddSettingsItem.bind(this)\r\n this.disposeSettingsItemHandler = this.onDisposeSettingsItem.bind(this)\r\n this.documentClickHandler = this.onDocumentClick.bind(this)\r\n this.userInactiveHandler = this.onUserInactive.bind(this)\r\n\r\n this.buildMenu()\r\n this.bindEvents()\r\n\r\n // Prepare the dialog\r\n this.player().one('play', () => this.hideDialog())\r\n }\r\n\r\n onDocumentClick (event: MouseEvent) {\r\n const element = event.target as HTMLElement\r\n\r\n if (element?.classList?.contains('vjs-settings') || element?.parentElement?.classList?.contains('vjs-settings')) {\r\n return\r\n }\r\n\r\n if (!this.dialog.hasClass('vjs-hidden')) {\r\n this.hideDialog()\r\n }\r\n }\r\n\r\n onDisposeSettingsItem (event: any, name: string) {\r\n if (name === undefined) {\r\n const children = this.menu.children()\r\n\r\n while (children.length > 0) {\r\n children[0].dispose()\r\n this.menu.removeChild(children[0])\r\n }\r\n\r\n this.addClass('vjs-hidden')\r\n } else {\r\n const item = this.menu.getChild(name)\r\n\r\n if (item) {\r\n item.dispose()\r\n this.menu.removeChild(item)\r\n }\r\n }\r\n\r\n this.hideDialog()\r\n\r\n if (this.settingsButtonOptions.entries.length === 0) {\r\n this.addClass('vjs-hidden')\r\n }\r\n }\r\n\r\n dispose () {\r\n document.removeEventListener('click', this.documentClickHandler)\r\n\r\n if (this.isInIframe()) {\r\n window.removeEventListener('blur', this.documentClickHandler)\r\n }\r\n }\r\n\r\n onAddSettingsItem (event: any, data: any) {\r\n const [ entry, options ] = data\r\n\r\n this.addMenuItem(entry, options)\r\n this.removeClass('vjs-hidden')\r\n }\r\n\r\n onUserInactive () {\r\n if (!this.dialog.hasClass('vjs-hidden')) {\r\n this.hideDialog()\r\n }\r\n }\r\n\r\n bindEvents () {\r\n document.addEventListener('click', this.documentClickHandler)\r\n if (this.isInIframe()) {\r\n window.addEventListener('blur', this.documentClickHandler)\r\n }\r\n\r\n this.player().on('addsettingsitem', this.addSettingsItemHandler)\r\n this.player().on('disposesettingsitem', this.disposeSettingsItemHandler)\r\n this.player().on('userinactive', this.userInactiveHandler)\r\n }\r\n\r\n buildCSSClass () {\r\n return `vjs-icon-settings ${super.buildCSSClass()}`\r\n }\r\n\r\n handleClick () {\r\n if (this.dialog.hasClass('vjs-hidden')) {\r\n this.showDialog()\r\n } else {\r\n this.hideDialog()\r\n }\r\n }\r\n\r\n showDialog () {\r\n this.player().peertube().onMenuOpened();\r\n\r\n (this.menu.el() as HTMLElement).style.opacity = '1'\r\n\r\n this.dialog.show()\r\n this.el().setAttribute('aria-expanded', 'true')\r\n\r\n this.setDialogSize(this.getComponentSize(this.menu))\r\n\r\n const firstChild = this.menu.children()[0]\r\n if (firstChild) firstChild.focus()\r\n }\r\n\r\n hideDialog () {\r\n this.player_.peertube().onMenuClosed()\r\n\r\n this.dialog.hide()\r\n this.el().setAttribute('aria-expanded', 'false')\r\n\r\n this.setDialogSize(this.getComponentSize(this.menu));\r\n (this.menu.el() as HTMLElement).style.opacity = '1'\r\n this.resetChildren()\r\n }\r\n\r\n getComponentSize (element: videojs.Component | HTMLElement) {\r\n let width: number = null\r\n let height: number = null\r\n\r\n // Could be component or just DOM element\r\n if (element instanceof Component) {\r\n const el = element.el() as HTMLElement\r\n\r\n width = el.offsetWidth\r\n height = el.offsetHeight;\r\n\r\n (element as any).width = width;\r\n (element as any).height = height\r\n } else {\r\n width = element.offsetWidth\r\n height = element.offsetHeight\r\n }\r\n\r\n return [ width, height ]\r\n }\r\n\r\n setDialogSize ([ width, height ]: number[]) {\r\n if (typeof height !== 'number') {\r\n return\r\n }\r\n\r\n const offset = this.settingsButtonOptions.setup.maxHeightOffset\r\n const maxHeight = (this.player().el() as HTMLElement).offsetHeight - offset\r\n\r\n const panelEl = this.panel.el() as HTMLElement\r\n\r\n if (height > maxHeight) {\r\n height = maxHeight\r\n width += 17\r\n panelEl.style.maxHeight = `${height}px`\r\n } else if (panelEl.style.maxHeight !== '') {\r\n panelEl.style.maxHeight = ''\r\n }\r\n\r\n this.dialogEl.style.width = `${width}px`\r\n this.dialogEl.style.height = `${height}px`\r\n }\r\n\r\n buildMenu () {\r\n this.menu = new Menu(this.player())\r\n this.menu.addClass('vjs-main-menu')\r\n const entries = this.settingsButtonOptions.entries\r\n\r\n if (entries.length === 0) {\r\n this.addClass('vjs-hidden')\r\n this.panelChild.addChild(this.menu)\r\n return\r\n }\r\n\r\n for (const entry of entries) {\r\n this.addMenuItem(entry, this.settingsButtonOptions)\r\n }\r\n\r\n this.panelChild.addChild(this.menu)\r\n }\r\n\r\n addMenuItem (entry: any, options: any) {\r\n const openSubMenu = function (this: any) {\r\n if (videojs.dom.hasClass(this.el_, 'open')) {\r\n videojs.dom.removeClass(this.el_, 'open')\r\n } else {\r\n videojs.dom.addClass(this.el_, 'open')\r\n }\r\n }\r\n\r\n options.name = toTitleCase(entry)\r\n\r\n const newOptions = Object.assign({}, options, { entry, menuButton: this })\r\n const settingsMenuItem = new SettingsMenuItem(this.player(), newOptions)\r\n\r\n this.menu.addChild(settingsMenuItem)\r\n\r\n // Hide children to avoid sub menus stacking on top of each other\r\n // or having multiple menus open\r\n settingsMenuItem.on('click', videojs.bind(this, this.hideChildren))\r\n\r\n // Whether to add or remove selected class on the settings sub menu element\r\n settingsMenuItem.on('click', openSubMenu)\r\n }\r\n\r\n resetChildren () {\r\n for (const menuChild of this.menu.children()) {\r\n (menuChild as SettingsMenuItem).reset()\r\n }\r\n }\r\n\r\n /**\r\n * Hide all the sub menus\r\n */\r\n hideChildren () {\r\n for (const menuChild of this.menu.children()) {\r\n (menuChild as SettingsMenuItem).hideSubMenu()\r\n }\r\n }\r\n\r\n isInIframe () {\r\n return window.self !== window.top\r\n }\r\n\r\n}\r\n\r\nComponent.registerComponent('SettingsButton', SettingsButton)\r\n\r\nexport { SettingsButton }\r\n","import videojs from 'video.js'\r\n\r\nconst Component = videojs.getComponent('Component')\r\n\r\nclass SettingsPanel extends Component {\r\n\r\n createEl () {\r\n return super.createEl('div', {\r\n className: 'vjs-settings-panel',\r\n innerHTML: '',\r\n tabIndex: -1\r\n })\r\n }\r\n}\r\n\r\nComponent.registerComponent('SettingsPanel', SettingsPanel)\r\n\r\nexport { SettingsPanel }\r\n","import videojs from 'video.js'\r\n\r\nconst Component = videojs.getComponent('Component')\r\n\r\nclass SettingsPanelChild extends Component {\r\n\r\n createEl () {\r\n return super.createEl('div', {\r\n className: 'vjs-settings-panel-child',\r\n innerHTML: '',\r\n tabIndex: -1\r\n })\r\n }\r\n}\r\n\r\nComponent.registerComponent('SettingsPanelChild', SettingsPanelChild)\r\n\r\nexport { SettingsPanelChild }\r\n","import videojs from 'video.js'\r\nimport { PlaylistPluginOptions } from '../../types'\r\nimport { PlaylistMenu } from './playlist-menu'\r\n\r\nconst ClickableComponent = videojs.getComponent('ClickableComponent')\r\n\r\nclass PlaylistButton extends ClickableComponent {\r\n private playlistInfoElement: HTMLElement\r\n private wrapper: HTMLElement\r\n\r\n constructor (player: videojs.Player, options?: PlaylistPluginOptions & { playlistMenu: PlaylistMenu }) {\r\n super(player, options as any)\r\n }\r\n\r\n createEl () {\r\n this.wrapper = super.createEl('div', {\r\n className: 'vjs-playlist-button',\r\n innerHTML: '',\r\n tabIndex: -1\r\n }) as HTMLElement\r\n\r\n const icon = super.createEl('div', {\r\n className: 'vjs-playlist-icon',\r\n innerHTML: '',\r\n tabIndex: -1\r\n })\r\n\r\n this.playlistInfoElement = super.createEl('div', {\r\n className: 'vjs-playlist-info',\r\n innerHTML: '',\r\n tabIndex: -1\r\n }) as HTMLElement\r\n\r\n this.wrapper.appendChild(icon)\r\n this.wrapper.appendChild(this.playlistInfoElement)\r\n\r\n this.update()\r\n\r\n return this.wrapper\r\n }\r\n\r\n update () {\r\n const options = this.options_ as PlaylistPluginOptions\r\n\r\n this.playlistInfoElement.innerHTML = options.getCurrentPosition() + '/' + options.playlist.videosLength\r\n this.wrapper.title = this.player().localize('Playlist: {1}', [ options.playlist.displayName ])\r\n }\r\n\r\n handleClick () {\r\n const playlistMenu = this.getPlaylistMenu()\r\n playlistMenu.open()\r\n }\r\n\r\n private getPlaylistMenu () {\r\n return (this.options_ as any).playlistMenu as PlaylistMenu\r\n }\r\n}\r\n\r\nvideojs.registerComponent('PlaylistButton', PlaylistButton)\r\n\r\nexport { PlaylistButton }\r\n","import videojs from 'video.js'\r\nimport { secondsToTime } from '@shared/core-utils'\r\nimport { VideoPlaylistElement } from '@shared/models'\r\nimport { PlaylistItemOptions } from '../../types'\r\n\r\nconst Component = videojs.getComponent('Component')\r\n\r\nclass PlaylistMenuItem extends Component {\r\n private element: VideoPlaylistElement\r\n\r\n constructor (player: videojs.Player, options?: PlaylistItemOptions) {\r\n super(player, options as any)\r\n\r\n this.emitTapEvents()\r\n\r\n this.element = options.element\r\n\r\n this.on([ 'click', 'tap' ], () => this.switchPlaylistItem())\r\n this.on('keydown', event => this.handleKeyDown(event))\r\n }\r\n\r\n createEl () {\r\n const options = this.options_ as PlaylistItemOptions\r\n\r\n const li = super.createEl('li', {\r\n className: 'vjs-playlist-menu-item',\r\n innerHTML: ''\r\n }) as HTMLElement\r\n\r\n if (!options.element.video) {\r\n li.classList.add('vjs-disabled')\r\n }\r\n\r\n const positionBlock = super.createEl('div', {\r\n className: 'item-position-block'\r\n }) as HTMLElement\r\n\r\n const position = super.createEl('div', {\r\n className: 'item-position',\r\n innerHTML: options.element.position\r\n })\r\n\r\n positionBlock.appendChild(position)\r\n li.appendChild(positionBlock)\r\n\r\n if (options.element.video) {\r\n this.buildAvailableVideo(li, positionBlock, options)\r\n } else {\r\n this.buildUnavailableVideo(li)\r\n }\r\n\r\n return li\r\n }\r\n\r\n setSelected (selected: boolean) {\r\n if (selected) this.addClass('vjs-selected')\r\n else this.removeClass('vjs-selected')\r\n }\r\n\r\n getElement () {\r\n return this.element\r\n }\r\n\r\n private buildAvailableVideo (li: HTMLElement, positionBlock: HTMLElement, options: PlaylistItemOptions) {\r\n const videoElement = options.element\r\n\r\n const player = super.createEl('div', {\r\n className: 'item-player'\r\n })\r\n\r\n positionBlock.appendChild(player)\r\n\r\n const thumbnail = super.createEl('img', {\r\n src: window.location.origin + videoElement.video.thumbnailPath\r\n })\r\n\r\n const infoBlock = super.createEl('div', {\r\n className: 'info-block'\r\n })\r\n\r\n const title = super.createEl('div', {\r\n innerHTML: videoElement.video.name,\r\n className: 'title'\r\n })\r\n\r\n const channel = super.createEl('div', {\r\n innerHTML: videoElement.video.channel.displayName,\r\n className: 'channel'\r\n })\r\n\r\n infoBlock.appendChild(title)\r\n infoBlock.appendChild(channel)\r\n\r\n if (videoElement.startTimestamp || videoElement.stopTimestamp) {\r\n let html = ''\r\n\r\n if (videoElement.startTimestamp) html += secondsToTime(videoElement.startTimestamp)\r\n if (videoElement.stopTimestamp) html += ' - ' + secondsToTime(videoElement.stopTimestamp)\r\n\r\n const timestamps = super.createEl('div', {\r\n innerHTML: html,\r\n className: 'timestamps'\r\n })\r\n\r\n infoBlock.append(timestamps)\r\n }\r\n\r\n li.append(thumbnail)\r\n li.append(infoBlock)\r\n }\r\n\r\n private buildUnavailableVideo (li: HTMLElement) {\r\n const block = super.createEl('div', {\r\n className: 'item-unavailable',\r\n innerHTML: this.player().localize('Unavailable video')\r\n })\r\n\r\n li.appendChild(block)\r\n }\r\n\r\n private handleKeyDown (event: KeyboardEvent) {\r\n if (event.code === 'Space' || event.code === 'Enter') {\r\n this.switchPlaylistItem()\r\n }\r\n }\r\n\r\n private switchPlaylistItem () {\r\n const options = this.options_ as PlaylistItemOptions\r\n\r\n options.onClicked()\r\n }\r\n}\r\n\r\nComponent.registerComponent('PlaylistMenuItem', PlaylistMenuItem)\r\n\r\nexport { PlaylistMenuItem }\r\n","import videojs from 'video.js'\r\nimport { VideoPlaylistElement } from '@shared/models'\r\nimport { PlaylistPluginOptions } from '../../types'\r\nimport { PlaylistMenuItem } from './playlist-menu-item'\r\n\r\nconst Component = videojs.getComponent('Component')\r\n\r\nclass PlaylistMenu extends Component {\r\n private menuItems: PlaylistMenuItem[]\r\n\r\n constructor (player: videojs.Player, options?: PlaylistPluginOptions) {\r\n super(player, options as any)\r\n\r\n const self = this\r\n\r\n \r\n this.el().addEventListener('mouseenter', this.mouseenter)\r\n\r\n this.el().addEventListener('mouseleave', this.mouseleave)\r\n\r\n this.player().on('click', event => {\r\n let current = event.target as HTMLElement\r\n\r\n do {\r\n if (\r\n current.classList.contains('vjs-playlist-menu') ||\r\n current.classList.contains('vjs-playlist-button')\r\n ) {\r\n return\r\n }\r\n\r\n current = current.parentElement\r\n } while (current)\r\n\r\n this.close()\r\n })\r\n }\r\n\r\n dispose(): void {\r\n this.el().removeEventListener('mouseenter', this.mouseenter)\r\n\r\n this.el().removeEventListener('mouseleave', this.mouseleave)\r\n }\r\n\r\n private userInactiveHandler(){\r\n self.close()\r\n }\r\n\r\n private mouseenter(){\r\n this.player().off('userinactive', this.userInactiveHandler)\r\n }\r\n private mouseleave(){\r\n this.player().one('userinactive', this.userInactiveHandler)\r\n }\r\n\r\n createEl () {\r\n this.menuItems = []\r\n\r\n const options = this.getOptions()\r\n\r\n const menu = super.createEl('div', {\r\n className: 'vjs-playlist-menu',\r\n innerHTML: '',\r\n tabIndex: -1\r\n })\r\n\r\n const header = super.createEl('div', {\r\n className: 'header'\r\n })\r\n\r\n const headerLeft = super.createEl('div')\r\n\r\n const leftTitle = super.createEl('div', {\r\n innerHTML: options.playlist.displayName,\r\n className: 'title'\r\n })\r\n\r\n const playlistChannel = options.playlist.videoChannel\r\n const leftSubtitle = super.createEl('div', {\r\n innerHTML: playlistChannel\r\n ? this.player().localize('By {1}', [ playlistChannel.displayName ])\r\n : '',\r\n className: 'channel'\r\n })\r\n\r\n headerLeft.appendChild(leftTitle)\r\n headerLeft.appendChild(leftSubtitle)\r\n\r\n const tick = super.createEl('div', {\r\n className: 'cross'\r\n })\r\n tick.addEventListener('click', () => this.close())\r\n\r\n header.appendChild(headerLeft)\r\n header.appendChild(tick)\r\n\r\n const list = super.createEl('ol')\r\n\r\n for (const playlistElement of options.elements) {\r\n const item = new PlaylistMenuItem(this.player(), {\r\n element: playlistElement,\r\n onClicked: () => this.onItemClicked(playlistElement)\r\n })\r\n\r\n list.appendChild(item.el())\r\n\r\n this.menuItems.push(item)\r\n }\r\n\r\n menu.appendChild(header)\r\n menu.appendChild(list)\r\n\r\n return menu\r\n }\r\n\r\n update () {\r\n const options = this.getOptions()\r\n\r\n this.updateSelected(options.getCurrentPosition())\r\n }\r\n\r\n open () {\r\n this.player().addClass('playlist-menu-displayed')\r\n }\r\n\r\n close () {\r\n this.player().removeClass('playlist-menu-displayed')\r\n }\r\n\r\n updateSelected (newPosition: number) {\r\n for (const item of this.menuItems) {\r\n item.setSelected(item.getElement().position === newPosition)\r\n }\r\n }\r\n\r\n private getOptions () {\r\n return this.options_ as PlaylistPluginOptions\r\n }\r\n\r\n private onItemClicked (element: VideoPlaylistElement) {\r\n this.getOptions().onItemClicked(element)\r\n }\r\n}\r\n\r\nComponent.registerComponent('PlaylistMenu', PlaylistMenu)\r\n\r\nexport { PlaylistMenu }\r\n","import videojs from 'video.js'\r\nimport { PlaylistPluginOptions } from '../../types'\r\nimport { PlaylistButton } from './playlist-button'\r\nimport { PlaylistMenu } from './playlist-menu'\r\n\r\nconst Plugin = videojs.getPlugin('plugin')\r\n\r\nclass PlaylistPlugin extends Plugin {\r\n private playlistMenu: PlaylistMenu\r\n private playlistButton: PlaylistButton\r\n private options: PlaylistPluginOptions\r\n\r\n constructor (player: videojs.Player, options?: PlaylistPluginOptions) {\r\n super(player, options)\r\n\r\n this.options = options\r\n\r\n this.player.ready(() => {\r\n player.addClass('vjs-playlist')\r\n })\r\n\r\n this.playlistMenu = new PlaylistMenu(player, options)\r\n this.playlistButton = new PlaylistButton(player, { ...options, playlistMenu: this.playlistMenu })\r\n\r\n player.addChild(this.playlistMenu, options)\r\n player.addChild(this.playlistButton, options)\r\n }\r\n\r\n updateSelected () {\r\n this.playlistMenu.updateSelected(this.options.getCurrentPosition())\r\n }\r\n}\r\n\r\nvideojs.registerPlugin('playlist', PlaylistPlugin)\r\nexport { PlaylistPlugin }\r\n","import debug from 'debug'\r\nimport videojs from 'video.js'\r\nimport { logger } from '@root-helpers/logger'\r\nimport { PeerTubeMobileButtons } from './peertube-mobile-buttons'\r\n\r\nconst debugLogger = debug('peertube:player:mobile')\r\n\r\nconst Plugin = videojs.getPlugin('plugin')\r\n\r\nclass PeerTubeMobilePlugin extends Plugin {\r\n private static readonly DOUBLE_TAP_DELAY_MS = 250\r\n private static readonly SET_CURRENT_TIME_DELAY = 1000\r\n\r\n private peerTubeMobileButtons: PeerTubeMobileButtons\r\n\r\n private seekAmount = 0\r\n\r\n private lastTapEvent: TouchEvent\r\n private tapTimeout: ReturnType\r\n private newActiveState: boolean\r\n\r\n private setCurrentTimeTimeout: ReturnType\r\n\r\n constructor (player: videojs.Player, options: videojs.PlayerOptions) {\r\n super(player, options)\r\n\r\n this.peerTubeMobileButtons = player.addChild('PeerTubeMobileButtons', { reportTouchActivity: false }) as PeerTubeMobileButtons\r\n\r\n if (videojs.browser.IS_ANDROID && screen.orientation) {\r\n this.handleFullscreenRotation()\r\n }\r\n\r\n if (!this.player.options_.userActions) this.player.options_.userActions = {};\r\n\r\n // FIXME: typings\r\n (this.player.options_.userActions as any).click = false\r\n this.player.options_.userActions.doubleClick = false\r\n\r\n this.player.one('play', () => {\r\n this.initTouchStartEvents()\r\n })\r\n }\r\n\r\n private handleFullscreenRotation () {\r\n this.player.on('fullscreenchange', () => {\r\n if (!this.player.isFullscreen() || this.isPortraitVideo()) return\r\n\r\n screen.orientation.lock('landscape')\r\n .catch(err => logger.error('Cannot lock screen to landscape.', err))\r\n })\r\n }\r\n\r\n private isPortraitVideo () {\r\n return this.player.videoWidth() < this.player.videoHeight()\r\n }\r\n\r\n private initTouchStartEvents () {\r\n const handleTouchStart = (event: TouchEvent) => {\r\n if (this.tapTimeout) {\r\n clearTimeout(this.tapTimeout)\r\n this.tapTimeout = undefined\r\n }\r\n\r\n if (this.lastTapEvent && event.timeStamp - this.lastTapEvent.timeStamp < PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS) {\r\n debugLogger('Detected double tap')\r\n\r\n this.lastTapEvent = undefined\r\n this.onDoubleTap(event)\r\n return\r\n }\r\n\r\n this.newActiveState = !this.player.userActive()\r\n\r\n this.tapTimeout = setTimeout(() => {\r\n debugLogger('No double tap detected, set user active state to %s.', this.newActiveState)\r\n\r\n this.player.userActive(this.newActiveState)\r\n }, PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS)\r\n\r\n this.lastTapEvent = event\r\n }\r\n\r\n this.player.on('touchstart', (event: TouchEvent) => {\r\n // Only enable user active on player touch, we listen event on peertube mobile buttons to disable it\r\n if (this.player.userActive()) return\r\n\r\n handleTouchStart(event)\r\n })\r\n\r\n this.peerTubeMobileButtons.el().addEventListener('touchstart', (event: TouchEvent) => {\r\n // Prevent mousemove/click events firing on the player, that conflict with our user active logic\r\n event.preventDefault()\r\n\r\n handleTouchStart(event)\r\n }, { passive: false })\r\n }\r\n\r\n dispose () {\r\n this.player.off('touchstart')\r\n }\r\n\r\n private onDoubleTap (event: TouchEvent) {\r\n const playerWidth = this.player.currentWidth()\r\n\r\n const rect = this.findPlayerTarget((event.target as HTMLElement)).getBoundingClientRect()\r\n const offsetX = event.targetTouches[0].pageX - rect.left\r\n\r\n debugLogger('Calculating double tap zone (player width: %d, offset X: %d)', playerWidth, offsetX)\r\n\r\n if (offsetX > 0.66 * playerWidth) {\r\n if (this.seekAmount < 0) this.seekAmount = 0\r\n\r\n this.seekAmount += 10\r\n\r\n debugLogger('Will forward %d seconds', this.seekAmount)\r\n } else if (offsetX < 0.33 * playerWidth) {\r\n if (this.seekAmount > 0) this.seekAmount = 0\r\n\r\n this.seekAmount -= 10\r\n debugLogger('Will rewind %d seconds', this.seekAmount)\r\n }\r\n\r\n this.peerTubeMobileButtons.displayFastSeek(this.seekAmount)\r\n\r\n this.scheduleSetCurrentTime()\r\n }\r\n\r\n private findPlayerTarget (target: HTMLElement): HTMLElement {\r\n if (target.classList.contains('video-js')) return target\r\n\r\n return this.findPlayerTarget(target.parentElement)\r\n }\r\n\r\n private scheduleSetCurrentTime () {\r\n this.player.pause()\r\n this.player.addClass('vjs-fast-seeking')\r\n\r\n if (this.setCurrentTimeTimeout) clearTimeout(this.setCurrentTimeTimeout)\r\n\r\n this.setCurrentTimeTimeout = setTimeout(() => {\r\n let newTime = this.player.currentTime() + this.seekAmount\r\n this.seekAmount = 0\r\n\r\n newTime = Math.max(0, newTime)\r\n newTime = Math.min(this.player.duration(), newTime)\r\n\r\n this.player.currentTime(newTime)\r\n this.seekAmount = 0\r\n this.peerTubeMobileButtons.displayFastSeek(0)\r\n\r\n this.player.removeClass('vjs-fast-seeking')\r\n this.player.userActive(false)\r\n\r\n this.player.play()\r\n }, PeerTubeMobilePlugin.SET_CURRENT_TIME_DELAY)\r\n }\r\n}\r\n\r\nvideojs.registerPlugin('peertubeMobile', PeerTubeMobilePlugin)\r\nexport { PeerTubeMobilePlugin }\r\n","import videojs from 'video.js'\r\n\r\nconst Component = videojs.getComponent('Component')\r\nclass PeerTubeMobileButtons extends Component {\r\n\r\n private rewind: Element\r\n private forward: Element\r\n private rewindText: Element\r\n private forwardText: Element\r\n\r\n createEl () {\r\n const container = super.createEl('div', {\r\n className: 'vjs-mobile-buttons-overlay'\r\n }) as HTMLDivElement\r\n\r\n const mainButton = super.createEl('div', {\r\n className: 'main-button'\r\n }) as HTMLDivElement\r\n\r\n mainButton.addEventListener('touchstart', e => {\r\n e.stopPropagation()\r\n\r\n if (this.player_.paused() || this.player_.ended()) {\r\n this.player_.play()\r\n return\r\n }\r\n\r\n this.player_.pause()\r\n })\r\n\r\n this.rewind = super.createEl('div', { className: 'rewind-button vjs-hidden' })\r\n this.forward = super.createEl('div', { className: 'forward-button vjs-hidden' })\r\n\r\n for (let i = 0; i < 3; i++) {\r\n this.rewind.appendChild(super.createEl('span', { className: 'icon' }))\r\n this.forward.appendChild(super.createEl('span', { className: 'icon' }))\r\n }\r\n\r\n this.rewindText = this.rewind.appendChild(super.createEl('div', { className: 'text' }))\r\n this.forwardText = this.forward.appendChild(super.createEl('div', { className: 'text' }))\r\n\r\n container.appendChild(this.rewind)\r\n container.appendChild(mainButton)\r\n container.appendChild(this.forward)\r\n\r\n return container\r\n }\r\n\r\n displayFastSeek (amount: number) {\r\n if (amount === 0) {\r\n this.hideRewind()\r\n this.hideForward()\r\n return\r\n }\r\n\r\n if (amount > 0) {\r\n this.hideRewind()\r\n this.displayForward(amount)\r\n return\r\n }\r\n\r\n if (amount < 0) {\r\n this.hideForward()\r\n this.displayRewind(amount)\r\n return\r\n }\r\n }\r\n\r\n private hideRewind () {\r\n this.rewind.classList.add('vjs-hidden')\r\n this.rewindText.textContent = ''\r\n }\r\n\r\n private displayRewind (amount: number) {\r\n this.rewind.classList.remove('vjs-hidden')\r\n this.rewindText.textContent = this.player().localize('{1} seconds', [ amount + '' ])\r\n }\r\n\r\n private hideForward () {\r\n this.forward.classList.add('vjs-hidden')\r\n this.forwardText.textContent = ''\r\n }\r\n\r\n private displayForward (amount: number) {\r\n this.forward.classList.remove('vjs-hidden')\r\n this.forwardText.textContent = this.player().localize('{1} seconds', [ amount + '' ])\r\n }\r\n}\r\n\r\nvideojs.registerComponent('PeerTubeMobileButtons', PeerTubeMobileButtons)\r\n\r\nexport {\r\n PeerTubeMobileButtons\r\n}\r\n","import videojs from 'video.js'\r\n\r\ntype KeyHandler = { accept: (event: KeyboardEvent) => boolean, cb: (e: KeyboardEvent) => void }\r\n\r\nconst Plugin = videojs.getPlugin('plugin')\r\n\r\nclass PeerTubeHotkeysPlugin extends Plugin {\r\n private static readonly VOLUME_STEP = 0.1\r\n private static readonly SEEK_STEP = 5\r\n\r\n private readonly handleKeyFunction: (event: KeyboardEvent) => void\r\n\r\n private readonly handlers: KeyHandler[]\r\n\r\n constructor (player: videojs.Player, options: videojs.PlayerOptions) {\r\n super(player, options)\r\n\r\n this.handlers = this.buildHandlers()\r\n\r\n this.handleKeyFunction = (event: KeyboardEvent) => this.onKeyDown(event)\r\n document.addEventListener('keydown', this.handleKeyFunction)\r\n }\r\n\r\n dispose () {\r\n document.removeEventListener('keydown', this.handleKeyFunction)\r\n }\r\n\r\n private onKeyDown (event: KeyboardEvent) {\r\n if (!this.isValidKeyTarget(event.target as HTMLElement)) return\r\n\r\n for (const handler of this.handlers) {\r\n if (handler.accept(event)) {\r\n handler.cb(event)\r\n return\r\n }\r\n }\r\n }\r\n\r\n private buildHandlers () {\r\n const handlers: KeyHandler[] = [\r\n // Play\r\n {\r\n accept: e => (e.key === ' ' || e.key === 'MediaPlayPause'),\r\n cb: e => {\r\n e.preventDefault()\r\n e.stopPropagation()\r\n\r\n if (this.player.paused()) this.player.play()\r\n else this.player.pause()\r\n }\r\n },\r\n\r\n // Increase volume\r\n {\r\n accept: e => this.isNaked(e, 'ArrowUp'),\r\n cb: e => {\r\n e.preventDefault()\r\n this.player.volume(this.player.volume() + PeerTubeHotkeysPlugin.VOLUME_STEP)\r\n }\r\n },\r\n\r\n // Decrease volume\r\n {\r\n accept: e => this.isNaked(e, 'ArrowDown'),\r\n cb: e => {\r\n e.preventDefault()\r\n this.player.volume(this.player.volume() - PeerTubeHotkeysPlugin.VOLUME_STEP)\r\n }\r\n },\r\n\r\n // Rewind\r\n {\r\n accept: e => this.isNaked(e, 'ArrowLeft') || this.isNaked(e, 'MediaRewind'),\r\n cb: e => {\r\n e.preventDefault()\r\n\r\n const target = Math.max(0, this.player.currentTime() - PeerTubeHotkeysPlugin.SEEK_STEP)\r\n this.player.currentTime(target)\r\n }\r\n },\r\n\r\n // Forward\r\n {\r\n accept: e => this.isNaked(e, 'ArrowRight') || this.isNaked(e, 'MediaForward'),\r\n cb: e => {\r\n e.preventDefault()\r\n\r\n const target = Math.min(this.player.duration(), this.player.currentTime() + PeerTubeHotkeysPlugin.SEEK_STEP)\r\n this.player.currentTime(target)\r\n }\r\n },\r\n\r\n // Fullscreen\r\n {\r\n // f key or Ctrl + Enter\r\n accept: e => this.isNaked(e, 'f') || (!e.altKey && e.ctrlKey && e.key === 'Enter'),\r\n cb: e => {\r\n e.preventDefault()\r\n\r\n if (this.player.isFullscreen()) this.player.exitFullscreen()\r\n else this.player.requestFullscreen()\r\n }\r\n },\r\n\r\n // Mute\r\n {\r\n accept: e => this.isNaked(e, 'm'),\r\n cb: e => {\r\n e.preventDefault()\r\n\r\n this.player.muted(!this.player.muted())\r\n }\r\n },\r\n\r\n // Increase playback rate\r\n {\r\n accept: e => e.key === '>',\r\n cb: () => {\r\n const target = Math.min(this.player.playbackRate() + 0.1, 5)\r\n\r\n this.player.playbackRate(parseFloat(target.toFixed(2)))\r\n }\r\n },\r\n\r\n // Decrease playback rate\r\n {\r\n accept: e => e.key === '<',\r\n cb: () => {\r\n const target = Math.max(this.player.playbackRate() - 0.1, 0.10)\r\n\r\n this.player.playbackRate(parseFloat(target.toFixed(2)))\r\n }\r\n },\r\n\r\n // Previous frame\r\n {\r\n accept: e => e.key === ',',\r\n cb: () => {\r\n this.player.pause()\r\n\r\n // Calculate movement distance (assuming 30 fps)\r\n const dist = 1 / 30\r\n this.player.currentTime(this.player.currentTime() - dist)\r\n }\r\n },\r\n\r\n // Next frame\r\n {\r\n accept: e => e.key === '.',\r\n cb: () => {\r\n this.player.pause()\r\n\r\n // Calculate movement distance (assuming 30 fps)\r\n const dist = 1 / 30\r\n this.player.currentTime(this.player.currentTime() + dist)\r\n }\r\n }\r\n ]\r\n\r\n // 0-9 key handlers\r\n for (let i = 0; i < 10; i++) {\r\n handlers.push({\r\n accept: e => e.key === i + '' && !e.ctrlKey, // If using ctrl key, it's a web browser hotkey\r\n cb: e => {\r\n e.preventDefault()\r\n\r\n this.player.currentTime(this.player.duration() * i * 0.1)\r\n }\r\n })\r\n }\r\n\r\n return handlers\r\n }\r\n\r\n private isValidKeyTarget (eventEl: HTMLElement) {\r\n const playerEl = this.player.el()\r\n const activeEl = document.activeElement\r\n const currentElTagName = eventEl.tagName.toLowerCase()\r\n\r\n return (\r\n activeEl === playerEl ||\r\n activeEl === playerEl.querySelector('.vjs-tech') ||\r\n activeEl === playerEl.querySelector('.vjs-control-bar') ||\r\n eventEl.id === 'content' ||\r\n currentElTagName === 'body' ||\r\n currentElTagName === 'video'\r\n )\r\n }\r\n\r\n private isNaked (event: KeyboardEvent, key: string) {\r\n return (!event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey && event.key === key)\r\n }\r\n}\r\n\r\nvideojs.registerPlugin('peerTubeHotkeysPlugin', PeerTubeHotkeysPlugin)\r\nexport { PeerTubeHotkeysPlugin }\r\n","import {\r\n CommonOptions,\r\n NextPreviousVideoButtonOptions,\r\n PeerTubeLinkButtonOptions,\r\n PeertubePlayerManagerOptions,\r\n PlayerMode\r\n} from '../../types'\r\n\r\nexport class ControlBarOptionsBuilder {\r\n private options: CommonOptions\r\n\r\n constructor (\r\n globalOptions: PeertubePlayerManagerOptions,\r\n private mode: PlayerMode\r\n ) {\r\n this.options = globalOptions.common\r\n }\r\n\r\n getChildrenOptions () {\r\n const children = {}\r\n\r\n if (this.options.previousVideo) {\r\n Object.assign(children, this.getPreviousVideo())\r\n }\r\n\r\n Object.assign(children, { playToggle: {} })\r\n\r\n if (this.options.nextVideo) {\r\n Object.assign(children, this.getNextVideo())\r\n }\r\n\r\n Object.assign(children, {\r\n currentTimeDisplay: {},\r\n timeDivider: {},\r\n durationDisplay: {},\r\n liveDisplay: {},\r\n\r\n flexibleWidthSpacer: {},\r\n\r\n ...this.getProgressControl(),\r\n\r\n p2PInfoButton: {\r\n p2pEnabled: this.options.p2pEnabled\r\n },\r\n\r\n muteToggle: {},\r\n volumeControl: {},\r\n\r\n ...this.getSettingsButton()\r\n })\r\n\r\n /*if (this.options.peertubeLink === true) {\r\n Object.assign(children, {\r\n peerTubeLinkButton: {\r\n shortUUID: this.options.videoShortUUID,\r\n //instanceName: this.options.instanceName\r\n } as PeerTubeLinkButtonOptions\r\n })\r\n }*/\r\n\r\n Object.assign(children, {\r\n PictureInPictureBastyon: {}\r\n })\r\n\r\n if (this.options.theaterButton === true) {\r\n Object.assign(children, {\r\n theaterButton: {}\r\n })\r\n }\r\n\r\n Object.assign(children, {\r\n fullscreenToggle: {}\r\n })\r\n\r\n return children\r\n }\r\n\r\n private getSettingsButton () {\r\n const settingEntries: string[] = []\r\n\r\n settingEntries.push('playbackRateMenuButton')\r\n\r\n //if (this.options.captions === true) settingEntries.push('captionsButton')\r\n\r\n settingEntries.push('resolutionMenuButton')\r\n\r\n return {\r\n settingsButton: {\r\n setup: {\r\n maxHeightOffset: 40\r\n },\r\n entries: settingEntries\r\n }\r\n }\r\n }\r\n\r\n private getProgressControl () {\r\n const loadProgressBar = 'loadProgressBar'\r\n\r\n return {\r\n progressControl: {\r\n children: {\r\n seekBar: {\r\n children: {\r\n [loadProgressBar]: {},\r\n mouseTimeDisplay: {},\r\n playProgressBar: {}\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n private getPreviousVideo () {\r\n const buttonOptions: NextPreviousVideoButtonOptions = {\r\n type: 'previous',\r\n handler: this.options.previousVideo,\r\n isDisabled: () => {\r\n if (!this.options.hasPreviousVideo) return false\r\n\r\n return !this.options.hasPreviousVideo()\r\n }\r\n }\r\n\r\n return { previousVideoButton: buttonOptions }\r\n }\r\n\r\n private getNextVideo () {\r\n const buttonOptions: NextPreviousVideoButtonOptions = {\r\n type: 'next',\r\n handler: this.options.nextVideo,\r\n isDisabled: () => {\r\n if (!this.options.hasNextVideo) return false\r\n\r\n return !this.options.hasNextVideo()\r\n }\r\n }\r\n\r\n return { nextVideoButton: buttonOptions }\r\n }\r\n}\r\n","import { basename, dirname } from 'path'\r\nimport { logger } from '@root-helpers/logger'\r\n\r\nclass RedundancyUrlManager {\r\n\r\n constructor (private baseUrls: string[] = []) {\r\n // empty\r\n }\r\n\r\n removeBySegmentUrl (segmentUrl: string) {\r\n logger.info(`Removing redundancy of segment URL ${segmentUrl}.`)\r\n\r\n const baseUrl = dirname(segmentUrl)\r\n\r\n this.baseUrls = this.baseUrls.filter(u => u !== baseUrl && u !== baseUrl + '/')\r\n }\r\n\r\n buildUrl (url: string) {\r\n const max = this.baseUrls.length + 1\r\n const i = this.getRandomInt(max)\r\n\r\n if (i === max - 1) return url\r\n\r\n const newBaseUrl = this.baseUrls[i]\r\n const slashPart = newBaseUrl.endsWith('/') ? '' : '/'\r\n\r\n return newBaseUrl + slashPart + basename(url)\r\n }\r\n\r\n countBaseUrls () {\r\n return this.baseUrls.length\r\n }\r\n\r\n private getRandomInt (max: number) {\r\n return Math.floor(Math.random() * Math.floor(max))\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n\r\nexport {\r\n RedundancyUrlManager\r\n}\r\n","import { Segment } from 'p2p-media-loader-core-basyton'\r\nimport { RedundancyUrlManager } from './redundancy-url-manager'\r\n\r\nfunction segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager) {\r\n return function segmentBuilder (segment: Segment) {\r\n return redundancyUrlManager.buildUrl(segment.url)\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n\r\nexport {\r\n segmentUrlBuilderFactory\r\n}\r\n","function copyToClipboard (text: string) {\r\n const el = document.createElement('textarea')\r\n el.value = text\r\n el.setAttribute('readonly', '')\r\n el.style.position = 'absolute'\r\n el.style.left = '-9999px'\r\n document.body.appendChild(el)\r\n el.select()\r\n document.execCommand('copy')\r\n document.body.removeChild(el)\r\n}\r\n\r\nfunction wait (ms: number) {\r\n return new Promise(res => {\r\n setTimeout(() => res(), ms)\r\n })\r\n}\r\n\r\nexport {\r\n copyToClipboard,\r\n wait\r\n}\r\n","import { basename } from 'path'\r\nimport { Segment } from 'p2p-media-loader-core-basyton'\r\nimport { logger } from '@root-helpers/logger'\r\nimport { wait } from '@root-helpers/utils'\r\n\r\ntype SegmentsJSON = { [filename: string]: string | { [byterange: string]: string } }\r\n\r\nconst maxRetries = 3\r\n\r\nfunction findbyqualityname(segments : any, name : string){\r\n\r\n var result = undefined\r\n\r\n name = name.substring(36)\r\n\r\n\r\n\r\n for (var key in segments) {\r\n if (segments.hasOwnProperty(key) && key.indexOf(name) > -1) {\r\n result = segments[key]\r\n }\r\n }\r\n\r\n\r\n return result\r\n}\r\n\r\nfunction segmentValidatorFactory (segmentsSha256Url: string, isLive: boolean) {\r\n let segmentsJSON = fetchSha256Segments(segmentsSha256Url)\r\n const regex = /bytes=(\\d+)-(\\d+)/\r\n\r\n return async function segmentValidator (segment: Segment, _method: string, _peerId: string, retry = 1) {\r\n // Wait for hash generation from the server\r\n if (isLive) await wait(1000)\r\n\r\n const filename = basename(segment.url)\r\n\r\n const segments = (await segmentsJSON)\r\n\r\n const segmentValue = segments[filename] || (!isLive ? findbyqualityname(segments, filename) : null)\r\n\r\n if (!segmentValue && retry > maxRetries) {\r\n throw new Error(`Unknown segment name ${filename} in segment validator`)\r\n }\r\n\r\n if (!segmentValue) {\r\n logger.info(`Refetching sha segments for ${filename}`)\r\n\r\n await wait(1000)\r\n\r\n segmentsJSON = fetchSha256Segments(segmentsSha256Url)\r\n await segmentValidator(segment, _method, _peerId, retry + 1)\r\n\r\n return\r\n }\r\n\r\n let hashShouldBe: string\r\n let range = ''\r\n\r\n if (typeof segmentValue === 'string') {\r\n hashShouldBe = segmentValue\r\n } else {\r\n const captured = regex.exec(segment.range)\r\n range = captured[1] + '-' + captured[2]\r\n\r\n hashShouldBe = segmentValue[range]\r\n }\r\n\r\n if (hashShouldBe === undefined) {\r\n throw new Error(`Unknown segment name ${filename}/${range} in segment validator`)\r\n }\r\n\r\n\r\n console.log('segment.data', segment.url, range, segment.data)\r\n\r\n const calculatedSha = await sha256Hex(segment.data)\r\n if (calculatedSha !== hashShouldBe) {\r\n\r\n \r\n\r\n throw new Error(\r\n `Hashes does not correspond for segment ${filename}/${range}` +\r\n `(expected: ${hashShouldBe} instead of ${calculatedSha})`\r\n )\r\n }\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n\r\nexport {\r\n segmentValidatorFactory\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction fetchSha256Segments (url: string) {\r\n return fetch(url)\r\n .then(res => res.json() as Promise)\r\n .catch(err => {\r\n logger.error('Cannot get sha256 segments', err)\r\n return {}\r\n })\r\n}\r\n\r\nasync function sha256Hex (data?: ArrayBuffer) {\r\n if (!data) return undefined\r\n\r\n if (window.crypto.subtle) {\r\n return window.crypto.subtle.digest('SHA-256', data)\r\n .then(data => bufferToHex(data))\r\n }\r\n\r\n // Fallback for non HTTPS context\r\n const shaModule = (await import('sha.js') as any).default\r\n // eslint-disable-next-line new-cap\r\n return new shaModule.sha256().update(data).digest('hex')\r\n}\r\n\r\n// Thanks: https://stackoverflow.com/a/53307879\r\nfunction bufferToHex (buffer?: ArrayBuffer) {\r\n if (!buffer) return ''\r\n\r\n let s = ''\r\n const h = '0123456789abcdef'\r\n const o = new Uint8Array(buffer)\r\n\r\n o.forEach((v: any) => {\r\n s += h[v >> 4] + h[v & 15]\r\n })\r\n\r\n return s\r\n}\r\n","import { HybridLoaderSettings } from 'p2p-media-loader-core-basyton'\r\nimport { HlsJsEngineSettings } from 'p2p-media-loader-hlsjs-basyton'\r\nimport { logger } from '@root-helpers/logger'\r\nimport { LiveVideoLatencyMode } from '@shared/models'\r\nimport { getAverageBandwidthInStore } from '../../peertube-player-local-storage'\r\nimport { P2PMediaLoader, P2PMediaLoaderPluginOptions } from '../../types'\r\nimport { PeertubePlayerManagerOptions } from '../../types/manager-options'\r\nimport { getRtcConfig } from '../common'\r\nimport { RedundancyUrlManager } from '../p2p-media-loader/redundancy-url-manager'\r\nimport { segmentUrlBuilderFactory } from '../p2p-media-loader/segment-url-builder'\r\nimport { segmentValidatorFactory } from '../p2p-media-loader/segment-validator'\r\n//import CapLevelController from './peertube-cap-level-controller'\r\n\r\nexport class HLSOptionsBuilder {\r\n\r\n constructor (\r\n private options: PeertubePlayerManagerOptions,\r\n private p2pMediaLoaderModule?: any\r\n ) {\r\n\r\n }\r\n\r\n getPluginOptions () {\r\n const commonOptions = this.options.common\r\n\r\n const redundancyUrlManager = new RedundancyUrlManager(this.options.p2pMediaLoader.redundancyBaseUrls)\r\n\r\n const p2pMediaLoaderConfig = this.getP2PMediaLoaderOptions(redundancyUrlManager)\r\n const loader = new this.p2pMediaLoaderModule.Engine(p2pMediaLoaderConfig).createLoaderClass() as P2PMediaLoader\r\n\r\n const p2pMediaLoader: P2PMediaLoaderPluginOptions = {\r\n redundancyUrlManager,\r\n type: 'application/x-mpegURL',\r\n startTime: commonOptions.startTime,\r\n src: this.options.p2pMediaLoader.playlistUrl,\r\n loader\r\n }\r\n\r\n const hlsjs = {\r\n levelLabelHandler: (level: { height: number, width: number }) => {\r\n const resolution = Math.min(level.height || 0, level.width || 0)\r\n\r\n const file = this.options.p2pMediaLoader.videoFiles.find(f => f.resolution.id === resolution)\r\n // We don't have files for live videos\r\n if (!file) return level.height\r\n\r\n let label = file.resolution.label\r\n if (file.fps >= 50) label += file.fps\r\n\r\n return label\r\n }\r\n }\r\n\r\n const html5 = {\r\n hlsjsConfig: this.getHLSJSOptions(loader)\r\n }\r\n\r\n return { p2pMediaLoader, hlsjs, html5 }\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n\r\n private getP2PMediaLoaderOptions (redundancyUrlManager: RedundancyUrlManager): HlsJsEngineSettings {\r\n let consumeOnly = false\r\n if ((navigator as any)?.connection?.type === 'cellular' /*|| (window as any).cordova*/) {\r\n logger.info('We are on a cellular connection: disabling seeding.')\r\n consumeOnly = true\r\n }\r\n\r\n const trackerAnnounce = this.options.p2pMediaLoader.trackerAnnounce\r\n .filter(t => t.startsWith('ws'))\r\n\r\n const specificLiveOrVODOptions = this.options.common.isLive\r\n ? this.getP2PMediaLoaderLiveOptions()\r\n : this.getP2PMediaLoaderVODOptions()\r\n\r\n return {\r\n loader: {\r\n trackerAnnounce,\r\n rtcConfig: getRtcConfig(),\r\n\r\n simultaneousHttpDownloads: 1,\r\n httpFailedSegmentTimeout: 1000,\r\n\r\n segmentValidator: !this.options.common.localTransport ? segmentValidatorFactory(this.options.p2pMediaLoader.segmentsSha256Url, this.options.common.isLive) : undefined,\r\n segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager),\r\n\r\n useP2P: this.options.common.p2pEnabled,\r\n consumeOnly,\r\n segmentsStorage : this.options.common.isLive ? undefined : this.options.segmentsStorage,\r\n\r\n localTransport : this.options.common.localTransport,\r\n\r\n ...specificLiveOrVODOptions\r\n },\r\n segments: {\r\n assetsStorage : this.options.common.isLive ? undefined : this.options.assetsStorage,\r\n swarmId: this.options.p2pMediaLoader.playlistUrl,\r\n forwardSegmentCount: specificLiveOrVODOptions.p2pDownloadMaxPriority ?? 20\r\n }\r\n }\r\n }\r\n\r\n private getP2PMediaLoaderLiveOptions (): Partial {\r\n const base = {\r\n requiredSegmentsPriority: 1\r\n }\r\n\r\n const latencyMode = this.options.common.liveOptions.latencyMode\r\n\r\n switch (latencyMode) {\r\n case LiveVideoLatencyMode.SMALL_LATENCY:\r\n return {\r\n ...base,\r\n\r\n useP2P: false,\r\n httpDownloadProbability: 1\r\n }\r\n\r\n case LiveVideoLatencyMode.HIGH_LATENCY:\r\n return base\r\n\r\n default:\r\n return base\r\n }\r\n }\r\n\r\n private getP2PMediaLoaderVODOptions (): Partial {\r\n return {\r\n requiredSegmentsPriority: 3,\r\n skipSegmentBuilderPriority: 1,\r\n\r\n cachedSegmentExpiration: 10 * 60 * 1000,\r\n cachedSegmentsCount: 30,\r\n\r\n httpDownloadMaxPriority: 9,\r\n httpDownloadProbability: 0.06,\r\n httpDownloadProbabilitySkipIfNoPeers: true,\r\n\r\n p2pDownloadMaxPriority: 50\r\n }\r\n }\r\n\r\n // ---------------------------------------------------------------------------\r\n\r\n private getHLSJSOptions (loader: P2PMediaLoader) {\r\n const specificLiveOrVODOptions = this.options.common.isLive\r\n ? this.getHLSLiveOptions()\r\n : this.getHLSVODOptions()\r\n\r\n\r\n console.log('specificLiveOrVODOptions', specificLiveOrVODOptions)\r\n\r\n //autoLevelEnabled\r\n\r\n const base = {\r\n capLevelToPlayerSize: true,\r\n autoStartLoad: false,\r\n\r\n loader,\r\n\r\n ...specificLiveOrVODOptions\r\n }\r\n\r\n\r\n const averageBandwidth = getAverageBandwidthInStore()\r\n if (!averageBandwidth) return base\r\n\r\n return {\r\n ...base,\r\n\r\n abrEwmaDefaultEstimate: averageBandwidth * 8, // We want bit/s\r\n backBufferLength: 90,\r\n startLevel: -1,\r\n testBandwidth: false,\r\n debug: false,\r\n\r\n //autoLevelEnabled : !(this.options.common.videoDuration > 0 && this.options.common.videoDuration < 60000)\r\n\r\n // capLevelController : CapLevelController\r\n }\r\n }\r\n\r\n private getHLSLiveOptions () {\r\n const latencyMode = this.options.common.liveOptions.latencyMode\r\n\r\n switch (latencyMode) {\r\n case LiveVideoLatencyMode.SMALL_LATENCY:\r\n return {\r\n liveSyncDurationCount: 2\r\n }\r\n\r\n case LiveVideoLatencyMode.HIGH_LATENCY:\r\n return {\r\n liveSyncDurationCount: 10\r\n }\r\n\r\n default:\r\n return {\r\n liveSyncDurationCount: 5\r\n }\r\n }\r\n }\r\n\r\n private getHLSVODOptions () {\r\n return {\r\n liveSyncDurationCount: 5\r\n }\r\n }\r\n}\r\n","import { PeertubePlayerManagerOptions } from '../../types'\r\n\r\nexport class WebTorrentOptionsBuilder {\r\n\r\n constructor (\r\n private options: PeertubePlayerManagerOptions,\r\n private autoPlayValue: any\r\n ) {\r\n\r\n }\r\n\r\n getPluginOptions () {\r\n const commonOptions = this.options.common\r\n const webtorrentOptions = this.options.webtorrent\r\n const p2pMediaLoaderOptions = this.options.p2pMediaLoader\r\n\r\n const autoplay = this.autoPlayValue === 'play'\r\n\r\n const webtorrent = {\r\n autoplay,\r\n\r\n playerRefusedP2P: commonOptions.p2pEnabled === false,\r\n videoDuration: commonOptions.videoDuration,\r\n playerElement: commonOptions.playerElement,\r\n\r\n videoFiles: webtorrentOptions.videoFiles.length !== 0\r\n ? webtorrentOptions.videoFiles\r\n // The WebTorrent plugin won't be able to play these files, but it will fallback to HTTP mode\r\n : p2pMediaLoaderOptions?.videoFiles || [],\r\n\r\n startTime: commonOptions.startTime\r\n }\r\n\r\n return { webtorrent }\r\n }\r\n}\r\n","import videojs from 'video.js'\r\nimport { copyToClipboard } from '@root-helpers/utils'\r\nimport { isIOS, isSafari } from '@root-helpers/web-browser'\r\nimport { buildVideoLink, decorateVideoLink, pick } from '@shared/core-utils'\r\nimport { isDefaultLocale } from '@shared/core-utils/i18n'\r\nimport { VideoJSPluginOptions } from '../../types'\r\nimport { CommonOptions, PeertubePlayerManagerOptions, PlayerMode } from '../../types/manager-options'\r\nimport { ControlBarOptionsBuilder } from './control-bar-options-builder'\r\nimport { HLSOptionsBuilder } from './hls-options-builder'\r\nimport { WebTorrentOptionsBuilder } from './webtorrent-options-builder'\r\n\r\nexport class ManagerOptionsBuilder {\r\n\r\n constructor (\r\n private mode: PlayerMode,\r\n private options: PeertubePlayerManagerOptions,\r\n private p2pMediaLoaderModule?: any\r\n ) {\r\n\r\n }\r\n\r\n getVideojsOptions (alreadyPlayed: boolean): videojs.PlayerOptions {\r\n const commonOptions = this.options.common\r\n\r\n let autoplay = this.getAutoPlayValue(commonOptions.autoplay, alreadyPlayed)\r\n const html5 = {\r\n preloadTextTracks: false\r\n }\r\n\r\n const plugins: VideoJSPluginOptions = {\r\n peertube: {\r\n mode: this.mode,\r\n autoplay, // Use peertube plugin autoplay because we could get the file by webtorrent\r\n\r\n ...pick(commonOptions, [\r\n 'videoViewUrl',\r\n 'authorizationHeader',\r\n 'startTime',\r\n 'videoDuration',\r\n 'subtitle',\r\n // 'videoCaptions',\r\n 'stopTime',\r\n 'isLive',\r\n 'videoUUID',\r\n ])\r\n }\r\n }\r\n\r\n /*if (commonOptions.playlist) {\r\n plugins.playlist = commonOptions.playlist\r\n }*/\r\n\r\n\r\n\r\n if (this.mode === 'p2p-media-loader') {\r\n const hlsOptionsBuilder = new HLSOptionsBuilder(this.options, this.p2pMediaLoaderModule)\r\n const options = hlsOptionsBuilder.getPluginOptions()\r\n\r\n Object.assign(plugins, pick(options, [ 'hlsjs', 'p2pMediaLoader' ]))\r\n Object.assign(html5, options.html5)\r\n } else if (this.mode === 'webtorrent') {\r\n const webtorrentOptionsBuilder = new WebTorrentOptionsBuilder(this.options, this.getAutoPlayValue(autoplay, alreadyPlayed))\r\n\r\n Object.assign(plugins, webtorrentOptionsBuilder.getPluginOptions())\r\n\r\n // WebTorrent plugin handles autoplay, because we do some hackish stuff in there\r\n autoplay = false\r\n }\r\n\r\n Object.assign(plugins, {\r\n hotkeys : {}\r\n })\r\n\r\n const controlBarOptionsBuilder = new ControlBarOptionsBuilder(this.options, this.mode)\r\n\r\n const videojsOptions = {\r\n html5,\r\n\r\n // We don't use text track settings for now\r\n textTrackSettings: false as any, // FIXME: typings\r\n controls: commonOptions.controls !== undefined ? commonOptions.controls : true,\r\n loop: commonOptions.loop !== undefined ? commonOptions.loop : false,\r\n\r\n muted: commonOptions.muted !== undefined\r\n ? commonOptions.muted\r\n : undefined, // Undefined so the player knows it has to check the local storage\r\n\r\n autoplay: this.getAutoPlayValue(autoplay, alreadyPlayed),\r\n\r\n poster: commonOptions.poster,\r\n inactivityTimeout: commonOptions.inactivityTimeout,\r\n playbackRates: [ 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2 ],\r\n\r\n plugins,\r\n\r\n sources : commonOptions.sources,\r\n\r\n controlBar: {\r\n children: controlBarOptionsBuilder.getChildrenOptions() as any // FIXME: typings\r\n },\r\n\r\n\r\n }\r\n\r\n if (commonOptions.language && !isDefaultLocale(commonOptions.language)) {\r\n Object.assign(videojsOptions, { language: commonOptions.language })\r\n }\r\n\r\n return videojsOptions\r\n }\r\n\r\n private getAutoPlayValue (autoplay: any, alreadyPlayed: boolean) {\r\n if (autoplay !== true) return autoplay\r\n\r\n // On first play, disable autoplay to avoid issues\r\n // But if the player already played videos, we can safely autoplay next ones\r\n if (isIOS() || isSafari()) {\r\n return alreadyPlayed ? 'play' : false\r\n }\r\n\r\n return 'play'\r\n }\r\n\r\n getContextMenuOptions (player: videojs.Player, commonOptions: CommonOptions) {\r\n const videoUUID = commonOptions.videoUUID\r\n const serverUrl = commonOptions.serverUrl\r\n\r\n const content = () => {\r\n const isLoopEnabled = player.options_['loop']\r\n\r\n const items = [\r\n {\r\n icon: 'repeat',\r\n label: player.localize('Play in loop') + (isLoopEnabled ? '' : ''),\r\n listener: function () {\r\n player.options_['loop'] = !isLoopEnabled\r\n }\r\n },\r\n /*{\r\n // icon: 'repeat',\r\n label: 'Send video playback information to devs',\r\n listener: function (this: videojs.Player) {\r\n (this as any).tech_.hlsProvider.sendLogsCache(videoUUID, serverUrl);\r\n }\r\n },*/\r\n // {\r\n // label: player.localize('Copy the video URL'),\r\n // listener: function () {\r\n // copyToClipboard(buildVideoLink({ shortUUID: commonOptions.videoShortUUID }))\r\n // }\r\n // },\r\n // {\r\n // label: player.localize('Copy the video URL at the current time'),\r\n // listener: function (this: videojs.Player) {\r\n // const url = buildVideoLink({ shortUUID: commonOptions.videoShortUUID })\r\n\r\n // copyToClipboard(decorateVideoLink({ url, startTime: this.currentTime() }))\r\n // }\r\n // },\r\n /*{\r\n icon: 'code',\r\n label: player.localize('Copy embed code'),\r\n listener: () => {\r\n copyToClipboard(buildVideoOrPlaylistEmbed(commonOptions.embedUrl, commonOptions.embedTitle))\r\n }\r\n }*/\r\n ]\r\n\r\n /*if (this.mode === 'webtorrent') {\r\n items.push({\r\n label: player.localize('Copy magnet URI'),\r\n listener: function (this: videojs.Player) {\r\n copyToClipboard(this.webtorrent().getCurrentVideoFile().magnetUri)\r\n }\r\n })\r\n }*/\r\n\r\n items.push({\r\n icon: 'info',\r\n label: player.localize('Stats for nerds'),\r\n listener: () => {\r\n player.stats().show()\r\n }\r\n })\r\n\r\n return items.map(i => ({\r\n ...i,\r\n label: `` + i.label\r\n }))\r\n }\r\n\r\n return { content }\r\n }\r\n}\r\n","//@ts-nocheck\r\n\r\nimport { Events } from 'hls.js/src/events';\r\n\r\nimport type {\r\n BufferCodecsData,\r\n MediaAttachingData,\r\n FPSDropLevelCappingData,\r\n} from 'hls.js/src/types/events';\r\nimport type { ComponentAPI } from 'hls.js/src/types/component-api';\r\nimport type Hls from \"hls.js\";\r\n\r\n\r\nclass CapLevelController implements ComponentAPI {\r\n public autoLevelCapping: number;\r\n public firstLevel: number;\r\n public media: HTMLVideoElement | null;\r\n public restrictedLevels: Array;\r\n public timer: number | undefined;\r\n public paused: Boolean\r\n\r\n private hls: Hls;\r\n\r\n private streamController?: any;\r\n public clientRect: { width: number; height: number } | null;\r\n public clientRectLast: { width: number; height: number } | null;\r\n\r\n constructor(hls: Hls) {\r\n this.hls = hls;\r\n this.autoLevelCapping = Number.POSITIVE_INFINITY;\r\n this.firstLevel = -1;\r\n this.media = null;\r\n this.restrictedLevels = [];\r\n this.timer = undefined;\r\n this.clientRect = null;\r\n this.paused = true\r\n\r\n /*this.hls.pauseCapping = () => {\r\n this.paused = true\r\n }\r\n\r\n this.hls.resumeCapping = () => {\r\n this.paused = false\r\n }*/\r\n\r\n this.registerListeners();\r\n }\r\n\r\n public setStreamController(streamController: StreamController) {\r\n this.streamController = streamController;\r\n }\r\n\r\n public destroy() {\r\n this.unregisterListener();\r\n if (this.hls.config.capLevelToPlayerSize) {\r\n this.stopCapping();\r\n }\r\n this.media = null;\r\n this.clientRect = null;\r\n // @ts-ignore\r\n this.hls = this.streamController = null;\r\n }\r\n\r\n protected registerListeners() {\r\n const { hls } = this;\r\n hls.on(Events.FPS_DROP_LEVEL_CAPPING, this.onFpsDropLevelCapping, this);\r\n hls.on(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);\r\n hls.on(Events.MANIFEST_PARSED, this.onManifestParsed, this);\r\n hls.on(Events.BUFFER_CODECS, this.onBufferCodecs, this);\r\n hls.on(Events.MEDIA_DETACHING, this.onMediaDetaching, this);\r\n }\r\n\r\n protected unregisterListener() {\r\n const { hls } = this;\r\n hls.off(Events.FPS_DROP_LEVEL_CAPPING, this.onFpsDropLevelCapping, this);\r\n hls.off(Events.MEDIA_ATTACHING, this.onMediaAttaching, this);\r\n hls.off(Events.MANIFEST_PARSED, this.onManifestParsed, this);\r\n hls.off(Events.BUFFER_CODECS, this.onBufferCodecs, this);\r\n hls.off(Events.MEDIA_DETACHING, this.onMediaDetaching, this);\r\n }\r\n\r\n protected onFpsDropLevelCapping(\r\n event: Events.FPS_DROP_LEVEL_CAPPING,\r\n data: FPSDropLevelCappingData\r\n ) {\r\n // Don't add a restricted level more than once\r\n if (\r\n CapLevelController.isLevelAllowed(\r\n data.droppedLevel,\r\n this.restrictedLevels\r\n )\r\n ) {\r\n this.restrictedLevels.push(data.droppedLevel);\r\n }\r\n }\r\n\r\n protected onMediaAttaching(\r\n event: Events.MEDIA_ATTACHING,\r\n data: MediaAttachingData\r\n ) {\r\n this.media = data.media instanceof HTMLVideoElement ? data.media : null;\r\n }\r\n\r\n protected onManifestParsed(\r\n event: any,\r\n data: any\r\n ) {\r\n const hls = this.hls;\r\n this.restrictedLevels = [];\r\n this.firstLevel = data.firstLevel;\r\n if (hls.config.capLevelToPlayerSize && data.video) {\r\n // Start capping immediately if the manifest has signaled video codecs\r\n this.startCapping();\r\n }\r\n }\r\n\r\n // Only activate capping when playing a video stream; otherwise, multi-bitrate audio-only streams will be restricted\r\n // to the first level\r\n protected onBufferCodecs(\r\n event: Events.BUFFER_CODECS,\r\n data: BufferCodecsData\r\n ) {\r\n const hls = this.hls;\r\n if (hls.config.capLevelToPlayerSize && data.video) {\r\n // If the manifest did not signal a video codec capping has been deferred until we're certain video is present\r\n this.startCapping();\r\n }\r\n }\r\n\r\n protected onMediaDetaching() {\r\n this.stopCapping();\r\n }\r\n\r\n detectPlayerSize() {\r\n if (this.media && this.mediaHeight > 0 && this.mediaWidth > 0) {\r\n const levels = this.hls.levels;\r\n \r\n if (levels.length) {\r\n const hls = this.hls;\r\n hls.autoLevelCapping = this.getMaxLevel(levels.length - 1);\r\n\r\n if (\r\n hls.autoLevelCapping > this.autoLevelCapping &&\r\n this.streamController\r\n ) {\r\n\r\n // if auto level capping has a higher value for the previous one, flush the buffer using nextLevelSwitch\r\n // usually happen when the user go to the fullscreen mode.\r\n this.streamController.nextLevelSwitch();\r\n }\r\n this.autoLevelCapping = hls.autoLevelCapping;\r\n }\r\n }\r\n }\r\n\r\n /*\r\n * returns level should be the one with the dimensions equal or greater than the media (player) dimensions (so the video will be downscaled)\r\n */\r\n getMaxLevel(capLevelIndex: number): number {\r\n const levels = this.hls.levels;\r\n if (!levels.length) {\r\n return -1;\r\n }\r\n\r\n const validLevels = levels.filter(\r\n (level, index) =>\r\n CapLevelController.isLevelAllowed(index, this.restrictedLevels) &&\r\n index <= capLevelIndex\r\n );\r\n\r\n\r\n\r\n this.clientRect = null;\r\n return CapLevelController.getMaxLevelByMediaSize(\r\n validLevels,\r\n this.mediaWidth,\r\n this.mediaHeight\r\n );\r\n }\r\n\r\n capp(){\r\n this.autoLevelCapping = Number.POSITIVE_INFINITY;\r\n this.hls.firstLevel = this.getMaxLevel(this.firstLevel);\r\n \r\n this.detectPlayerSize();\r\n }\r\n\r\n startCapping() {\r\n if (this.timer) {\r\n // Don't reset capping if started twice; this can happen if the manifest signals a video codec\r\n return;\r\n }\r\n this.autoLevelCapping = Number.POSITIVE_INFINITY;\r\n this.hls.firstLevel = this.getMaxLevel(this.firstLevel);\r\n self.clearInterval(this.timer);\r\n this.timer = self.setInterval(this.detectPlayerSize.bind(this), 10000);\r\n this.detectPlayerSize();\r\n }\r\n\r\n stopCapping() {\r\n this.restrictedLevels = [];\r\n this.firstLevel = -1;\r\n //this.autoLevelCapping = Number.POSITIVE_INFINITY;\r\n \r\n if (this.timer) {\r\n self.clearInterval(this.timer);\r\n this.timer = undefined;\r\n }\r\n }\r\n\r\n\r\n getDimensions(): { width: number; height: number } {\r\n\r\n if (this.paused && this.clientRectLast){\r\n return this.clientRectLast\r\n }\r\n\r\n if (this.clientRect) {\r\n return this.clientRect;\r\n }\r\n const media = this.media;\r\n const boundsRect = {\r\n width: 0,\r\n height: 0,\r\n };\r\n\r\n if (media) {\r\n const clientRect = media.getBoundingClientRect();\r\n boundsRect.width = clientRect.width;\r\n boundsRect.height = clientRect.height;\r\n if (!boundsRect.width && !boundsRect.height) {\r\n // When the media element has no width or height (equivalent to not being in the DOM),\r\n // then use its width and height attributes (media.width, media.height)\r\n boundsRect.width =\r\n clientRect.right - clientRect.left || media.width || 0;\r\n boundsRect.height =\r\n clientRect.bottom - clientRect.top || media.height || 0;\r\n }\r\n }\r\n\r\n this.clientRectLast = this.clientRect = boundsRect;\r\n \r\n return boundsRect;\r\n }\r\n\r\n get mediaWidth(): number {\r\n return this.getDimensions().width * this.contentScaleFactor;\r\n }\r\n\r\n get mediaHeight(): number {\r\n return this.getDimensions().height * this.contentScaleFactor;\r\n }\r\n\r\n get contentScaleFactor(): number {\r\n let pixelRatio = 1;\r\n try {\r\n pixelRatio = self.devicePixelRatio;\r\n } catch (e) {\r\n /* no-op */\r\n }\r\n\r\n if (pixelRatio > 1.5) pixelRatio = 1.5\r\n\r\n return pixelRatio;\r\n }\r\n\r\n static isLevelAllowed(\r\n level: number,\r\n restrictedLevels: Array = []\r\n ): boolean {\r\n return restrictedLevels.indexOf(level) === -1;\r\n }\r\n\r\n static getMaxLevelByMediaSize(\r\n levels: Array,\r\n width: number,\r\n height: number\r\n ): number {\r\n if (!levels || !levels.length) {\r\n return -1;\r\n }\r\n\r\n // Levels can have the same dimensions but differing bandwidths - since levels are ordered, we can look to the next\r\n // to determine whether we've chosen the greatest bandwidth for the media's dimensions\r\n const atGreatestBandiwdth = (curLevel : any, nextLevel : any) => {\r\n if (!nextLevel) {\r\n return true;\r\n }\r\n\r\n return (\r\n curLevel.width !== nextLevel.width ||\r\n curLevel.height !== nextLevel.height\r\n );\r\n };\r\n\r\n\r\n // If we run through the loop without breaking, the media's dimensions are greater than every level, so default to\r\n // the max level\r\n let maxLevelIndex = levels.length - 1;\r\n\r\n for (let i = 0; i < levels.length; i += 1) {\r\n const level = levels[i];\r\n if (\r\n (level.width >= width || level.height >= height) &&\r\n atGreatestBandiwdth(level, levels[i + 1])\r\n ) {\r\n maxLevelIndex = i;\r\n break;\r\n }\r\n }\r\n\r\n return maxLevelIndex;\r\n }\r\n}\r\n\r\nexport default CapLevelController;\r\n","import EwmaBandWidthEstimator from 'hls.js/src/utils/ewma-bandwidth-estimator';\r\nimport { Events } from 'hls.js/src/events';\r\nimport { BufferHelper } from 'hls.js/src/utils/buffer-helper';\r\nimport { ErrorDetails } from 'hls.js/src/errors';\r\nimport { PlaylistLevelType } from 'hls.js/src/types/loader';\r\nimport { logger } from 'hls.js/src/utils/logger';\r\n\r\n\r\nimport type { Bufferable } from 'hls.js/src/utils/buffer-helper';\r\n//import type { LoaderStats } from 'hls.js/src/types/loader';\r\nimport type Hls from \"hls.js\";\r\nimport type {\r\n FragLoadingData,\r\n FragLoadedData,\r\n FragBufferedData,\r\n ErrorData,\r\n LevelLoadedData,\r\n} from 'hls.js/src/types/events';\r\nimport type { ComponentAPI } from 'hls.js/src/types/component-api';\r\n\r\nclass AbrController implements ComponentAPI {\r\n protected hls: Hls;\r\n private lastLoadedFragLevel: number = 0;\r\n private _nextAutoLevel: number = -1;\r\n private timer?: number;\r\n private onCheck: Function = this._abandonRulesCheck.bind(this);\r\n private fragCurrent: any | null = null;\r\n private partCurrent: any | null = null;\r\n private bitrateTestDelay: number = 0;\r\n\r\n public readonly bwEstimator: EwmaBandWidthEstimator;\r\n\r\n constructor(hls: Hls) {\r\n this.hls = hls;\r\n\r\n const config = hls.config;\r\n this.bwEstimator = new EwmaBandWidthEstimator(\r\n config.abrEwmaSlowVoD,\r\n config.abrEwmaFastVoD,\r\n config.abrEwmaDefaultEstimate\r\n );\r\n\r\n this.registerListeners();\r\n }\r\n\r\n protected registerListeners() {\r\n const { hls } = this;\r\n hls.on(Events.FRAG_LOADING, this.onFragLoading as any, this);\r\n hls.on(Events.FRAG_LOADED, this.onFragLoaded as any, this);\r\n hls.on(Events.FRAG_BUFFERED, this.onFragBuffered as any, this);\r\n hls.on(Events.LEVEL_LOADED, this.onLevelLoaded as any, this);\r\n hls.on(Events.ERROR, this.onError as any, this);\r\n }\r\n\r\n protected unregisterListeners() {\r\n const { hls } = this;\r\n hls.off(Events.FRAG_LOADING, this.onFragLoading as any, this);\r\n hls.off(Events.FRAG_LOADED, this.onFragLoaded as any, this);\r\n hls.off(Events.FRAG_BUFFERED, this.onFragBuffered as any, this);\r\n hls.off(Events.LEVEL_LOADED, this.onLevelLoaded as any, this);\r\n hls.off(Events.ERROR, this.onError as any, this);\r\n }\r\n\r\n public destroy() {\r\n this.unregisterListeners();\r\n this.clearTimer();\r\n // @ts-ignore\r\n this.hls = this.onCheck = null;\r\n this.fragCurrent = this.partCurrent = null;\r\n }\r\n\r\n protected onFragLoading(event: Events.FRAG_LOADING, data: FragLoadingData) {\r\n const frag = data.frag;\r\n if (frag.type === PlaylistLevelType.MAIN) {\r\n if (!this.timer) {\r\n this.fragCurrent = frag;\r\n this.partCurrent = data.part ?? null;\r\n this.timer = self.setInterval(this.onCheck, 100);\r\n }\r\n }\r\n }\r\n\r\n protected onLevelLoaded(event: Events.LEVEL_LOADED, data: LevelLoadedData) {\r\n const config = this.hls.config;\r\n if (data.details.live) {\r\n this.bwEstimator.update(config.abrEwmaSlowLive, config.abrEwmaFastLive);\r\n } else {\r\n this.bwEstimator.update(config.abrEwmaSlowVoD, config.abrEwmaFastVoD);\r\n }\r\n }\r\n\r\n /*\r\n This method monitors the download rate of the current fragment, and will downswitch if that fragment will not load\r\n quickly enough to prevent underbuffering\r\n */\r\n private _abandonRulesCheck() {\r\n const { fragCurrent: frag, partCurrent: part, hls } = this;\r\n const { autoLevelEnabled, config, media } = hls;\r\n if (!frag || !media) {\r\n return;\r\n }\r\n\r\n const stats: any = part ? part.stats : frag.stats;\r\n const duration = part ? part.duration : frag.duration;\r\n // If frag loading is aborted, complete, or from lowest level, stop timer and return\r\n if (\r\n stats.aborted ||\r\n (stats.loaded && stats.loaded === stats.total) ||\r\n frag.level === 0\r\n ) {\r\n this.clearTimer();\r\n // reset forced auto level value so that next level will be selected\r\n this._nextAutoLevel = -1;\r\n return;\r\n }\r\n\r\n // This check only runs if we're in ABR mode and actually playing\r\n if (\r\n !autoLevelEnabled ||\r\n media.paused ||\r\n !media.playbackRate ||\r\n !media.readyState\r\n ) {\r\n return;\r\n }\r\n\r\n const bufferInfo = hls.mainForwardBufferInfo;\r\n if (bufferInfo === null) {\r\n return;\r\n }\r\n\r\n const requestDelay = performance.now() - stats.loading.start;\r\n const playbackRate = Math.abs(media.playbackRate);\r\n // In order to work with a stable bandwidth, only begin monitoring bandwidth after half of the fragment has been loaded\r\n if (requestDelay <= (500 * duration) / playbackRate) {\r\n return;\r\n }\r\n\r\n const loadedFirstByte = stats.loaded && stats.loading.first;\r\n const bwEstimate: number = this.bwEstimator.getEstimate();\r\n const { levels, minAutoLevel } = hls;\r\n const level = levels[frag.level];\r\n const expectedLen =\r\n stats.total ||\r\n Math.max(stats.loaded, Math.round((duration * level.maxBitrate) / 8));\r\n const loadRate = loadedFirstByte ? (stats.loaded * 1000) / requestDelay : 0;\r\n\r\n // fragLoadDelay is an estimate of the time (in seconds) it will take to buffer the remainder of the fragment\r\n const fragLoadedDelay = loadRate\r\n ? (expectedLen - stats.loaded) / loadRate\r\n : (expectedLen * 8) / bwEstimate;\r\n\r\n // bufferStarvationDelay is an estimate of the amount time (in seconds) it will take to exhaust the buffer\r\n const bufferStarvationDelay = bufferInfo.len / playbackRate;\r\n\r\n // Only downswitch if the time to finish loading the current fragment is greater than the amount of buffer left\r\n if (fragLoadedDelay <= bufferStarvationDelay) {\r\n return;\r\n }\r\n\r\n let fragLevelNextLoadedDelay: number = Number.POSITIVE_INFINITY;\r\n let nextLoadLevel: number;\r\n // Iterate through lower level and try to find the largest one that avoids rebuffering\r\n for (\r\n nextLoadLevel = frag.level - 1;\r\n nextLoadLevel > minAutoLevel;\r\n nextLoadLevel--\r\n ) {\r\n // compute time to load next fragment at lower level\r\n // 0.8 : consider only 80% of current bw to be conservative\r\n // 8 = bits per byte (bps/Bps)\r\n const levelNextBitrate = levels[nextLoadLevel].maxBitrate;\r\n fragLevelNextLoadedDelay = loadRate\r\n ? (duration * levelNextBitrate) / (8 * 0.8 * loadRate)\r\n : (duration * levelNextBitrate) / bwEstimate;\r\n\r\n if (fragLevelNextLoadedDelay < bufferStarvationDelay) {\r\n break;\r\n }\r\n }\r\n // Only emergency switch down if it takes less time to load a new fragment at lowest level instead of continuing\r\n // to load the current one\r\n if (fragLevelNextLoadedDelay >= fragLoadedDelay) {\r\n return;\r\n }\r\n logger.warn(`Fragment ${frag.sn}${\r\n part ? ' part ' + part.index : ''\r\n } of level ${\r\n frag.level\r\n } is loading too slowly and will cause an underbuffer; aborting and switching to level ${nextLoadLevel}\r\n Current BW estimate: ${\r\n Number.isFinite(bwEstimate) ? (bwEstimate / 1024).toFixed(3) : 'Unknown'\r\n } Kb/s\r\n Estimated load time for current fragment: ${fragLoadedDelay.toFixed(3)} s\r\n Estimated load time for the next fragment: ${fragLevelNextLoadedDelay.toFixed(\r\n 3\r\n )} s\r\n Time to underbuffer: ${bufferStarvationDelay.toFixed(3)} s`);\r\n hls.nextLoadLevel = nextLoadLevel;\r\n if (loadedFirstByte) {\r\n // If there has been loading progress, sample bandwidth\r\n this.bwEstimator.sample(requestDelay, stats.loaded);\r\n }\r\n this.clearTimer();\r\n if (frag.loader) {\r\n this.fragCurrent = this.partCurrent = null;\r\n frag.loader.abort();\r\n }\r\n hls.trigger(Events.FRAG_LOAD_EMERGENCY_ABORTED, { frag, part, stats });\r\n }\r\n\r\n protected onFragLoaded(\r\n event: Events.FRAG_LOADED,\r\n { frag, part }: FragLoadedData\r\n ) {\r\n if (\r\n frag.type === PlaylistLevelType.MAIN &&\r\n Number.isFinite(frag.sn as number)\r\n ) {\r\n const stats = part ? part.stats : frag.stats;\r\n const duration = part ? part.duration : frag.duration;\r\n // stop monitoring bw once frag loaded\r\n this.clearTimer();\r\n // store level id after successful fragment load\r\n this.lastLoadedFragLevel = frag.level;\r\n // reset forced auto level value so that next level will be selected\r\n this._nextAutoLevel = -1;\r\n\r\n // compute level average bitrate\r\n if (this.hls.config.abrMaxWithRealBitrate) {\r\n const level = this.hls.levels[frag.level];\r\n const loadedBytes =\r\n (level.loaded ? level.loaded.bytes : 0) + stats.loaded;\r\n const loadedDuration =\r\n (level.loaded ? level.loaded.duration : 0) + duration;\r\n level.loaded = { bytes: loadedBytes, duration: loadedDuration };\r\n level.realBitrate = Math.round((8 * loadedBytes) / loadedDuration);\r\n }\r\n if (frag.bitrateTest) {\r\n const fragBufferedData: FragBufferedData = {\r\n stats,\r\n frag,\r\n part,\r\n id: frag.type,\r\n };\r\n this.onFragBuffered(Events.FRAG_BUFFERED, fragBufferedData);\r\n }\r\n }\r\n }\r\n\r\n protected onFragBuffered(\r\n event: Events.FRAG_BUFFERED,\r\n data: any //FragBufferedData\r\n ) {\r\n const { frag, part } = data;\r\n const stats = part ? part.stats : frag.stats;\r\n\r\n if (stats.aborted) {\r\n return;\r\n }\r\n // Only count non-alt-audio frags which were actually buffered in our BW calculations\r\n if (frag.type !== PlaylistLevelType.MAIN || frag.sn === 'initSegment') {\r\n return;\r\n }\r\n // Use the difference between parsing and request instead of buffering and request to compute fragLoadingProcessing;\r\n // rationale is that buffer appending only happens once media is attached. This can happen when config.startFragPrefetch\r\n // is used. If we used buffering in that case, our BW estimate sample will be very large.\r\n const processingMs = stats.parsing.end - stats.loading.start;\r\n\r\n if(stats.bwEstimateSample)\r\n this.bwEstimator.sample(processingMs, stats.loaded);\r\n\r\n stats.bwEstimate = this.bwEstimator.getEstimate();\r\n\r\n console.log('stats.bwEstimate', stats.bwEstimate)\r\n \r\n if (frag.bitrateTest) {\r\n this.bitrateTestDelay = processingMs / 1000;\r\n } else {\r\n this.bitrateTestDelay = 0;\r\n }\r\n }\r\n\r\n protected onError(event: Events.ERROR, data: ErrorData) {\r\n // stop timer in case of frag loading error\r\n switch (data.details) {\r\n case ErrorDetails.FRAG_LOAD_ERROR:\r\n case ErrorDetails.FRAG_LOAD_TIMEOUT:\r\n this.clearTimer();\r\n break;\r\n default:\r\n break;\r\n }\r\n }\r\n\r\n clearTimer() {\r\n self.clearInterval(this.timer);\r\n this.timer = undefined;\r\n }\r\n\r\n // return next auto level\r\n get nextAutoLevel() {\r\n\r\n const forcedAutoLevel = this._nextAutoLevel;\r\n const bwEstimator = this.bwEstimator;\r\n // in case next auto level has been forced, and bw not available or not reliable, return forced value\r\n if (forcedAutoLevel !== -1 && !bwEstimator.canEstimate()) {\r\n return forcedAutoLevel;\r\n }\r\n\r\n // compute next level using ABR logic\r\n let nextABRAutoLevel = this.getNextABRAutoLevel();\r\n\r\n\r\n // use forced auto level when ABR selected level has errored\r\n if (forcedAutoLevel !== -1 && this.hls.levels[nextABRAutoLevel].loadError) {\r\n return forcedAutoLevel;\r\n }\r\n // if forced auto level has been defined, use it to cap ABR computed quality level\r\n if (forcedAutoLevel !== -1) {\r\n nextABRAutoLevel = Math.min(forcedAutoLevel, nextABRAutoLevel);\r\n }\r\n\r\n return nextABRAutoLevel;\r\n }\r\n\r\n private getNextABRAutoLevel() {\r\n const { fragCurrent, partCurrent, hls } = this;\r\n const { maxAutoLevel, config, minAutoLevel, media } = hls;\r\n const currentFragDuration = partCurrent\r\n ? partCurrent.duration\r\n : fragCurrent\r\n ? fragCurrent.duration\r\n : 0;\r\n const pos = media ? media.currentTime : 0;\r\n\r\n // playbackRate is the absolute value of the playback rate; if media.playbackRate is 0, we use 1 to load as\r\n // if we're playing back at the normal rate.\r\n const playbackRate =\r\n media && media.playbackRate !== 0 ? Math.abs(media.playbackRate) : 1.0;\r\n const avgbw = this.bwEstimator\r\n ? this.bwEstimator.getEstimate()\r\n : config.abrEwmaDefaultEstimate;\r\n // bufferStarvationDelay is the wall-clock time left until the playback buffer is exhausted.\r\n const bufferInfo = hls.mainForwardBufferInfo;\r\n const bufferStarvationDelay =\r\n (bufferInfo ? bufferInfo.len : 0) / playbackRate;\r\n\r\n // First, look to see if we can find a level matching with our avg bandwidth AND that could also guarantee no rebuffering at all\r\n let bestLevel = this.findBestLevel(\r\n avgbw,\r\n minAutoLevel,\r\n maxAutoLevel,\r\n bufferStarvationDelay,\r\n config.abrBandWidthFactor,\r\n config.abrBandWidthUpFactor\r\n );\r\n if (bestLevel >= 0) {\r\n return bestLevel;\r\n }\r\n logger.trace(\r\n `${\r\n bufferStarvationDelay ? 'rebuffering expected' : 'buffer is empty'\r\n }, finding optimal quality level`\r\n );\r\n // not possible to get rid of rebuffering ... let's try to find level that will guarantee less than maxStarvationDelay of rebuffering\r\n // if no matching level found, logic will return 0\r\n let maxStarvationDelay = currentFragDuration\r\n ? Math.min(currentFragDuration, config.maxStarvationDelay)\r\n : config.maxStarvationDelay;\r\n let bwFactor = config.abrBandWidthFactor;\r\n let bwUpFactor = config.abrBandWidthUpFactor;\r\n\r\n if (!bufferStarvationDelay) {\r\n // in case buffer is empty, let's check if previous fragment was loaded to perform a bitrate test\r\n const bitrateTestDelay = this.bitrateTestDelay;\r\n if (bitrateTestDelay) {\r\n // if it is the case, then we need to adjust our max starvation delay using maxLoadingDelay config value\r\n // max video loading delay used in automatic start level selection :\r\n // in that mode ABR controller will ensure that video loading time (ie the time to fetch the first fragment at lowest quality level +\r\n // the time to fetch the fragment at the appropriate quality level is less than ```maxLoadingDelay``` )\r\n // cap maxLoadingDelay and ensure it is not bigger 'than bitrate test' frag duration\r\n const maxLoadingDelay = currentFragDuration\r\n ? Math.min(currentFragDuration, config.maxLoadingDelay)\r\n : config.maxLoadingDelay;\r\n maxStarvationDelay = maxLoadingDelay - bitrateTestDelay;\r\n logger.trace(\r\n `bitrate test took ${Math.round(\r\n 1000 * bitrateTestDelay\r\n )}ms, set first fragment max fetchDuration to ${Math.round(\r\n 1000 * maxStarvationDelay\r\n )} ms`\r\n );\r\n // don't use conservative factor on bitrate test\r\n bwFactor = bwUpFactor = 1;\r\n }\r\n }\r\n bestLevel = this.findBestLevel(\r\n avgbw,\r\n minAutoLevel,\r\n maxAutoLevel,\r\n bufferStarvationDelay + maxStarvationDelay,\r\n bwFactor,\r\n bwUpFactor\r\n );\r\n return Math.max(bestLevel, 0);\r\n }\r\n\r\n private findBestLevel(\r\n currentBw: number,\r\n minAutoLevel: number,\r\n maxAutoLevel: number,\r\n maxFetchDuration: number,\r\n bwFactor: number,\r\n bwUpFactor: number\r\n ): number {\r\n const {\r\n fragCurrent,\r\n partCurrent,\r\n lastLoadedFragLevel: currentLevel,\r\n } = this;\r\n const { levels } = this.hls;\r\n const level = levels[currentLevel];\r\n const live = !!level?.details?.live;\r\n const currentCodecSet = level?.codecSet;\r\n\r\n const currentFragDuration = partCurrent\r\n ? partCurrent.duration\r\n : fragCurrent\r\n ? fragCurrent.duration\r\n : 0;\r\n for (let i = maxAutoLevel; i >= minAutoLevel; i--) {\r\n const levelInfo = levels[i];\r\n\r\n if (\r\n !levelInfo ||\r\n (currentCodecSet && levelInfo.codecSet !== currentCodecSet)\r\n ) {\r\n continue;\r\n }\r\n\r\n const levelDetails = levelInfo.details;\r\n const avgDuration =\r\n (partCurrent\r\n ? levelDetails?.partTarget\r\n : levelDetails?.averagetargetduration) || currentFragDuration;\r\n\r\n let adjustedbw: number;\r\n // follow algorithm captured from stagefright :\r\n // https://android.googlesource.com/platform/frameworks/av/+/master/media/libstagefright/httplive/LiveSession.cpp\r\n // Pick the highest bandwidth stream below or equal to estimated bandwidth.\r\n // consider only 80% of the available bandwidth, but if we are switching up,\r\n // be even more conservative (70%) to avoid overestimating and immediately\r\n // switching back.\r\n if (i <= currentLevel) {\r\n adjustedbw = bwFactor * currentBw;\r\n } else {\r\n adjustedbw = bwUpFactor * currentBw;\r\n }\r\n\r\n const bitrate: number = levels[i].maxBitrate;\r\n const fetchDuration: number = (bitrate * avgDuration) / adjustedbw;\r\n\r\n logger.trace(\r\n `level/adjustedbw/bitrate/avgDuration/maxFetchDuration/fetchDuration: ${i}/${Math.round(\r\n adjustedbw\r\n )}/${bitrate}/${avgDuration}/${maxFetchDuration}/${fetchDuration}`\r\n );\r\n\r\n\r\n\r\n // if adjusted bw is greater than level bitrate AND\r\n if (\r\n adjustedbw > bitrate &&\r\n // fragment fetchDuration unknown OR live stream OR fragment fetchDuration less than max allowed fetch duration, then this level matches\r\n // we don't account for max Fetch Duration for live streams, this is to avoid switching down when near the edge of live sliding window ...\r\n // special case to support startLevel = -1 (bitrateTest) on live streams : in that case we should not exit loop so that findBestLevel will return -1\r\n (fetchDuration === 0 ||\r\n !Number.isFinite(fetchDuration) ||\r\n (live && !this.bitrateTestDelay) ||\r\n fetchDuration < maxFetchDuration)\r\n ) {\r\n\r\n // as we are looping from highest to lowest, this will return the best achievable quality level\r\n return i;\r\n }\r\n }\r\n // not enough time budget even with quality level 0 ... rebuffering might happen\r\n return -1;\r\n }\r\n\r\n set nextAutoLevel(nextLevel) {\r\n this._nextAutoLevel = nextLevel;\r\n }\r\n}\r\n\r\nexport default AbrController;\r\n","// Thanks https://github.com/streamroot/videojs-hlsjs-plugin\r\n// We duplicated this plugin to choose the hls.js version we want, because streamroot only provide a bundled file\r\n\r\nimport Hlsjs, { ErrorData, HlsConfig, Level, LevelSwitchingData, ManifestParsedData } from 'hls.js'\r\nimport videojs from 'video.js'\r\nimport { logger, Logger } from '@root-helpers/logger'\r\nimport { HlsjsConfigHandlerOptions, PeerTubeResolution, VideoJSTechHLS } from '../../types'\r\nimport CapLevelController from './cap-level-controller'\r\nimport AbrController from './abr-controler'\r\n\r\ntype ErrorCounts = {\r\n [ type: string ]: number\r\n}\r\n\r\ntype Metadata = {\r\n levels: Level[]\r\n}\r\n\r\ntype HookFn = (player: videojs.Player, hljs: Hlsjs) => void\r\n\r\nconst VIDEO_HLS_ERROR = 'HLS Error'\r\n\r\nconst registerSourceHandler = function (vjs: typeof videojs) {\r\n if (!Hlsjs.isSupported()) {\r\n logger.warn('Hls.js is not supported in this browser!')\r\n return\r\n }\r\n\r\n const html5 = vjs.getTech('Html5')\r\n\r\n if (!html5) {\r\n logger.error('No Hml5 tech found in videojs')\r\n return\r\n }\r\n\r\n // FIXME: typings\r\n (html5 as any).registerSourceHandler({\r\n canHandleSource: function (source: videojs.Tech.SourceObject) {\r\n const hlsTypeRE = /^application\\/x-mpegURL|application\\/vnd\\.apple\\.mpegurl$/i\r\n const hlsExtRE = /\\.m3u8/i\r\n\r\n if (hlsTypeRE.test(source.type)) return 'probably'\r\n if (hlsExtRE.test(source.src)) return 'maybe'\r\n\r\n return ''\r\n },\r\n\r\n handleSource: function (source: videojs.Tech.SourceObject, tech: VideoJSTechHLS) {\r\n if (tech.hlsProvider) {\r\n tech.hlsProvider.dispose()\r\n }\r\n\r\n tech.hlsProvider = new Html5Hlsjs(vjs, source, tech)\r\n\r\n return tech.hlsProvider\r\n }\r\n }, 0);\r\n\r\n // FIXME: typings\r\n (vjs as any).Html5Hlsjs = Html5Hlsjs\r\n}\r\n\r\nfunction hlsjsConfigHandler (this: videojs.Player, options: HlsjsConfigHandlerOptions) {\r\n const player = this\r\n\r\n if (!options) return\r\n\r\n if (!player.srOptions_) {\r\n player.srOptions_ = {}\r\n }\r\n\r\n if (!player.srOptions_.hlsjsConfig) {\r\n player.srOptions_.hlsjsConfig = options.hlsjsConfig\r\n }\r\n\r\n\r\n\r\n if (options.levelLabelHandler && !player.srOptions_.levelLabelHandler) {\r\n player.srOptions_.levelLabelHandler = options.levelLabelHandler\r\n }\r\n}\r\n\r\nconst registerConfigPlugin = function (vjs: typeof videojs) {\r\n // Used in Brightcove since we don't pass options directly there\r\n const registerVjsPlugin = vjs.registerPlugin || vjs.plugin\r\n registerVjsPlugin('hlsjs', hlsjsConfigHandler)\r\n}\r\n\r\nclass Html5Hlsjs {\r\n private static readonly hooks: { [id: string]: HookFn[] } = {}\r\n\r\n private readonly videoElement: HTMLVideoElement\r\n private readonly errorCounts: ErrorCounts = {}\r\n private readonly player: videojs.Player\r\n private readonly tech: videojs.Tech\r\n private readonly source: videojs.Tech.SourceObject\r\n private readonly vjs: typeof videojs\r\n\r\n private maxNetworkErrorRecovery = 10\r\n\r\n private hls: Hlsjs\r\n private hlsjsConfig: Partial = null\r\n\r\n private videoLogger: Logger\r\n\r\n private _duration: number = null\r\n private metadata: Metadata = null\r\n private isLive: boolean = null\r\n private dvrDuration: number = null\r\n private edgeMargin: number = null\r\n\r\n private handlers: { [ id in 'play' ]: EventListener } = {\r\n play: null\r\n }\r\n\r\n constructor (vjs: typeof videojs, source: videojs.Tech.SourceObject, tech: videojs.Tech) {\r\n this.vjs = vjs\r\n this.source = source\r\n\r\n this.tech = tech;\r\n (this.tech as any).name_ = 'Hlsjs'\r\n\r\n this.videoElement = tech.el() as HTMLVideoElement\r\n this.player = vjs((tech.options_ as any).playerId)\r\n\r\n this.videoLogger = new Logger(true)\r\n\r\n this.videoElement.addEventListener('error', event => {\r\n let errorTxt: string\r\n const mediaError = ((event.currentTarget || event.target) as HTMLVideoElement).error\r\n\r\n if (!mediaError) return\r\n\r\n logger.info(mediaError)\r\n switch (mediaError.code) {\r\n case mediaError.MEDIA_ERR_ABORTED:\r\n errorTxt = 'You aborted the video playback'\r\n break\r\n case mediaError.MEDIA_ERR_DECODE:\r\n errorTxt = 'The video playback was aborted due to a corruption problem or because the video used features ' +\r\n 'your browser did not support'\r\n this._handleMediaError(mediaError)\r\n break\r\n case mediaError.MEDIA_ERR_NETWORK:\r\n errorTxt = 'A network error caused the video download to fail part-way'\r\n break\r\n case mediaError.MEDIA_ERR_SRC_NOT_SUPPORTED:\r\n errorTxt = 'The video could not be loaded, either because the server or network failed or because the format is not supported'\r\n break\r\n\r\n default:\r\n errorTxt = mediaError.message\r\n }\r\n\r\n logger.error(`MEDIA_ERROR: ${errorTxt}`)\r\n })\r\n\r\n this.initialize()\r\n }\r\n\r\n duration () {\r\n if (this._duration === Infinity) return Infinity\r\n if (!isNaN(this.videoElement.duration)) return this.videoElement.duration\r\n\r\n return this._duration || 0\r\n }\r\n\r\n seekable () {\r\n if (this.hls.media) {\r\n if (!this.isLive) {\r\n return this.vjs.createTimeRanges(0, this.hls.media.duration)\r\n }\r\n\r\n // Video.js doesn't seem to like floating point timeranges\r\n const startTime = Math.round(this.hls.media.duration - this.dvrDuration)\r\n const endTime = Math.round(this.hls.media.duration - this.edgeMargin)\r\n\r\n return this.vjs.createTimeRanges(startTime, endTime)\r\n }\r\n\r\n return this.vjs.createTimeRanges()\r\n }\r\n\r\n // See comment for `initialize` method.\r\n dispose () {\r\n this.videoElement.removeEventListener('play', this.handlers.play)\r\n\r\n // FIXME: https://github.com/video-dev/hls.js/issues/4092\r\n const untypedHLS = this.hls as any\r\n\r\n untypedHLS.log = untypedHLS.warn = () => {\r\n // empty\r\n }\r\n\r\n\r\n this.videoLogger.destroyLogs()\r\n\r\n this.hls.destroy()\r\n }\r\n\r\n static addHook (type: string, callback: HookFn) {\r\n Html5Hlsjs.hooks[type] = this.hooks[type] || []\r\n Html5Hlsjs.hooks[type].push(callback)\r\n }\r\n\r\n static removeHook (type: string, callback: HookFn) {\r\n if (Html5Hlsjs.hooks[type] === undefined) return false\r\n\r\n const index = Html5Hlsjs.hooks[type].indexOf(callback)\r\n if (index === -1) return false\r\n\r\n Html5Hlsjs.hooks[type].splice(index, 1)\r\n\r\n return true\r\n }\r\n\r\n private _executeHooksFor (type: string) {\r\n if (Html5Hlsjs.hooks[type] === undefined) {\r\n return\r\n }\r\n\r\n // ES3 and IE < 9\r\n for (let i = 0; i < Html5Hlsjs.hooks[type].length; i++) {\r\n Html5Hlsjs.hooks[type][i](this.player, this.hls)\r\n }\r\n }\r\n\r\n private _handleMediaError (error: any) {\r\n\r\n if(error.code == 3){\r\n\r\n var time = this.player.currentTime() + 2\r\n\r\n this.dispose()\r\n this._initHlsjs()\r\n\r\n this.player.currentTime(time)\r\n this.player.play()\r\n this.hls.once(Hlsjs.Events.FRAG_LOADED, () => {\r\n this.player.play()\r\n })\r\n\r\n\r\n return\r\n }\r\n\r\n if (this.errorCounts[Hlsjs.ErrorTypes.MEDIA_ERROR] === 1) {\r\n logger.info('trying to recover media error')\r\n this.hls.recoverMediaError()\r\n return\r\n }\r\n\r\n if (this.errorCounts[Hlsjs.ErrorTypes.MEDIA_ERROR] === 2) {\r\n logger.info('2nd try to recover media error (by swapping audio codec')\r\n this.hls.swapAudioCodec()\r\n this.hls.recoverMediaError()\r\n return\r\n }\r\n\r\n if (this.errorCounts[Hlsjs.ErrorTypes.MEDIA_ERROR] > 2) {\r\n logger.info('bubbling media error up to VIDEOJS')\r\n this.hls.destroy()\r\n this.tech.error = () => error\r\n this.tech.trigger('error')\r\n }\r\n }\r\n\r\n private _handleNetworkError (error: any) {\r\n\r\n if (navigator.onLine === false) return\r\n\r\n if (this.errorCounts[Hlsjs.ErrorTypes.NETWORK_ERROR] <= this.maxNetworkErrorRecovery) {\r\n logger.info('trying to recover network error')\r\n\r\n // Wait 1 second and retry\r\n setTimeout(() => this.hls.startLoad(), 1000)\r\n\r\n // Reset error count on success\r\n this.hls.once(Hlsjs.Events.FRAG_LOADED, () => {\r\n this.errorCounts[Hlsjs.ErrorTypes.NETWORK_ERROR] = 0\r\n })\r\n\r\n return\r\n }\r\n\r\n logger.info('bubbling network error up to VIDEOJS')\r\n this.hls.destroy()\r\n this.tech.error = () => error\r\n this.tech.trigger('error')\r\n }\r\n\r\n private _onError (_event: any, data: ErrorData) {\r\n const error: { message: string, code?: number } = {\r\n message: `HLS.js error: ${data.type} - fatal: ${data.fatal} - ${data.details}`\r\n }\r\n\r\n this.videoLogger.log(error.message, {\r\n id: VIDEO_HLS_ERROR\r\n })\r\n\r\n // increment/set error count\r\n if (this.errorCounts[data.type]) this.errorCounts[data.type] += 1\r\n else this.errorCounts[data.type] = 1\r\n\r\n if(!data.fatal) logger.warn(error.message)\r\n else logger.error(error.message, { data })\r\n\r\n if (data.type === Hlsjs.ErrorTypes.NETWORK_ERROR) {\r\n error.code = 2\r\n this._handleNetworkError(error)\r\n } else if (data.fatal && data.type === Hlsjs.ErrorTypes.MEDIA_ERROR && data.details !== 'manifestIncompatibleCodecsError') {\r\n error.code = 3\r\n this._handleMediaError(error)\r\n } else if (data.fatal) {\r\n this.hls.destroy()\r\n logger.info('bubbling error up to VIDEOJS')\r\n this.tech.error = () => error as any\r\n this.tech.trigger('error')\r\n }\r\n }\r\n\r\n private buildLevelLabel (level: Level) {\r\n if (this.player.srOptions_.levelLabelHandler) {\r\n return this.player.srOptions_.levelLabelHandler(level as any)\r\n }\r\n\r\n if (level.height) return level.height + 'p'\r\n if (level.width) return Math.round(level.width * 9 / 16) + 'p'\r\n if (level.bitrate) return (level.bitrate / 1000) + 'kbps'\r\n\r\n return '0'\r\n }\r\n\r\n private _notifyVideoQualities () {\r\n if (!this.metadata) return\r\n\r\n const resolutions: PeerTubeResolution[] = []\r\n\r\n this.metadata.levels.forEach((level, index) => {\r\n resolutions.push({\r\n id: index,\r\n height: level.height,\r\n width: level.width,\r\n bitrate: level.bitrate,\r\n label: this.buildLevelLabel(level),\r\n selected: level.id === this.hls.manualLevel,\r\n\r\n selectCallback: () => {\r\n this.hls.currentLevel = index\r\n }\r\n })\r\n })\r\n\r\n resolutions.push({\r\n id: -1,\r\n label: this.player.localize('Auto'),\r\n selected: true,\r\n selectCallback: () => this.hls.currentLevel = -1\r\n })\r\n\r\n this.player.peertubeResolutions().add(resolutions)\r\n }\r\n\r\n private _startLoad () {\r\n this.hls.startLoad(-1)\r\n this.videoElement.removeEventListener('play', this.handlers.play)\r\n }\r\n\r\n private _oneLevelObjClone (obj: { [ id: string ]: any }) {\r\n const result = {}\r\n const objKeys = Object.keys(obj)\r\n for (let i = 0; i < objKeys.length; i++) {\r\n result[objKeys[i]] = obj[objKeys[i]]\r\n }\r\n\r\n return result\r\n }\r\n\r\n public sendLogsCache (videoId: String, serverUrl: String) {\r\n this.videoLogger.returnLog(videoId, serverUrl)\r\n }\r\n\r\n private _onMetaData (_event: any, data: ManifestParsedData) {\r\n // This could arrive before 'loadedqualitydata' handlers is registered, remember it so we can raise it later\r\n this.metadata = data\r\n this._notifyVideoQualities()\r\n }\r\n\r\n private _initHlsjs () {\r\n const techOptions = this.tech.options_ as HlsjsConfigHandlerOptions\r\n const srOptions_ = this.player.srOptions_\r\n\r\n const hlsjsConfigRef = srOptions_?.hlsjsConfig || techOptions.hlsjsConfig\r\n // Hls.js will write to the reference thus change the object for later streams\r\n this.hlsjsConfig = hlsjsConfigRef ? this._oneLevelObjClone(hlsjsConfigRef) : {}\r\n\r\n if ([ '', 'auto' ].includes(this.videoElement.preload) && !this.videoElement.autoplay && this.hlsjsConfig.autoStartLoad === undefined) {\r\n this.hlsjsConfig.autoStartLoad = false\r\n }\r\n\r\n // If the user explicitly sets autoStartLoad to false, we're not going to enter the if block above\r\n // That's why we have a separate if block here to set the 'play' listener\r\n if (this.hlsjsConfig.autoStartLoad === false) {\r\n this.handlers.play = this._startLoad.bind(this)\r\n this.videoElement.addEventListener('play', this.handlers.play)\r\n }\r\n\r\n\r\n //@ts-ignore\r\n this.hlsjsConfig.capLevelController = CapLevelController\r\n this.hlsjsConfig.abrController = AbrController as any\r\n this.hlsjsConfig.abrBandWidthUpFactor = 0.3\r\n\r\n //if(!data.details.live && data.details.totalduration )\r\n\r\n //this.hlsjsConfig.debug = this.videoLogger\r\n\r\n this.hls = new Hlsjs(this.hlsjsConfig)\r\n\r\n\r\n\r\n //@ts-ignore\r\n this.player.hls = this.hls;\r\n //(this.player as any).hls = this.hls;\r\n\r\n //this._executeHooksFor('beforeinitialize')\r\n\r\n this.hls.on(Hlsjs.Events.ERROR, (event, data) => this._onError(event, data))\r\n this.hls.on(Hlsjs.Events.MANIFEST_PARSED, (event, data) => this._onMetaData(event, data))\r\n this.hls.on(Hlsjs.Events.LEVEL_LOADED, (event, data) => {\r\n // The DVR plugin will auto seek to \"live edge\" on start up\r\n if (this.hlsjsConfig.liveSyncDuration) {\r\n this.edgeMargin = this.hlsjsConfig.liveSyncDuration\r\n } else if (this.hlsjsConfig.liveSyncDurationCount) {\r\n this.edgeMargin = this.hlsjsConfig.liveSyncDurationCount * data.details.targetduration\r\n }\r\n\r\n this.isLive = data.details.live\r\n this.dvrDuration = data.details.totalduration\r\n\r\n this._duration = this.isLive ? Infinity : data.details.totalduration\r\n\r\n this.player.duration(Math.round(this._duration))\r\n\r\n //if(this._duration < 60){\r\n //this.player.peertubeResolutions().disableAutoResolution()\r\n //}\r\n\r\n // Increase network error recovery for lives since they can be broken (server restart, stream interruption etc)\r\n if (this.isLive) this.maxNetworkErrorRecovery = 300\r\n })\r\n\r\n this.hls.once(Hlsjs.Events.FRAG_LOADED, () => {\r\n // Emit custom 'loadedmetadata' event for parity with `videojs-contrib-hls`\r\n // Ref: https://github.com/videojs/videojs-contrib-hls#loadedmetadata\r\n this.tech.trigger('loadedmetadata')\r\n })\r\n\r\n this.hls.on(Hlsjs.Events.FRAG_LOADED, (e: any, frag : any) => {\r\n console.log('frag', frag)\r\n })\r\n\r\n this.hls.on(Hlsjs.Events.LEVEL_SWITCHING, (_e, data: LevelSwitchingData) => {\r\n\r\n const resolutionId = this.hls.autoLevelEnabled\r\n ? -1\r\n : data.level\r\n\r\n const autoResolutionChosenId = this.hls.autoLevelEnabled\r\n ? data.level\r\n : -1\r\n\r\n this.player.peertubeResolutions().select({ id: resolutionId, autoResolutionChosenId, byEngine: true })\r\n })\r\n\r\n this.hls.attachMedia(this.videoElement)\r\n\r\n this.hls.loadSource(this.source.src)\r\n }\r\n\r\n private initialize () {\r\n this._initHlsjs()\r\n }\r\n}\r\n\r\nexport {\r\n Html5Hlsjs,\r\n registerSourceHandler,\r\n registerConfigPlugin\r\n}\r\n","import Hlsjs from 'hls.js'\r\nimport videojs from 'video.js'\r\nimport { Events, Segment } from 'p2p-media-loader-core-basyton'\r\nimport { Engine, initHlsJsPlayer, initVideoJsContribHlsJsPlayer } from 'p2p-media-loader-hlsjs-basyton'\r\nimport { timeToInt } from '@shared/core-utils'\r\nimport { P2PMediaLoaderPluginOptions, PlayerNetworkInfo } from '../../types'\r\nimport { registerConfigPlugin, registerSourceHandler } from './hls-plugin'\r\nimport { logger } from '@root-helpers/logger'\r\n\r\nregisterConfigPlugin(videojs)\r\nregisterSourceHandler(videojs)\r\n\r\nconst Plugin = videojs.getPlugin('plugin')\r\nclass P2pMediaLoaderPlugin extends Plugin {\r\n\r\n private readonly CONSTANTS = {\r\n INFO_SCHEDULER: 1000 // Don't change this\r\n }\r\n private readonly options: P2PMediaLoaderPluginOptions\r\n\r\n private hlsjs: Hlsjs\r\n private p2pEngine: Engine\r\n private statsP2PBytes = {\r\n pendingDownload: [] as number[],\r\n pendingUpload: [] as number[],\r\n numPeers: 0,\r\n totalDownload: 0,\r\n totalUpload: 0\r\n }\r\n private statsHTTPBytes = {\r\n pendingDownload: [] as number[],\r\n pendingUpload: [] as number[],\r\n totalDownload: 0,\r\n totalUpload: 0\r\n }\r\n private startTime: number\r\n\r\n private networkInfoInterval: any\r\n\r\n constructor (player: videojs.Player, options?: P2PMediaLoaderPluginOptions | any) {\r\n super(player)\r\n\r\n this.options = options\r\n\r\n if(!this.options) return\r\n\r\n\r\n // FIXME: typings https://github.com/Microsoft/TypeScript/issues/14080\r\n if (!(videojs as any).Html5Hlsjs) {\r\n logger.warn('HLS.js does not seem to be supported. Try to fallback to built in HLS.')\r\n\r\n if (!player.canPlayType('application/vnd.apple.mpegurl')) {\r\n const message = 'Cannot fallback to built-in HLS'\r\n logger.warn(message)\r\n\r\n player.ready(() => player.trigger('error', new Error(message)))\r\n return\r\n }\r\n } else {\r\n \r\n\r\n initVideoJsContribHlsJsPlayer(player)\r\n }\r\n\r\n this.startTime = timeToInt(this.options.startTime)\r\n\r\n player.src({\r\n type: this.options.type,\r\n src: this.options.src\r\n })\r\n\r\n player.ready(() => {\r\n this.initializeCore()\r\n\r\n\r\n this.hlsjs = (player as any).hls\r\n\r\n if ((videojs as any).Html5Hlsjs) {\r\n this.initializePlugin()\r\n }\r\n })\r\n }\r\n\r\n dispose () {\r\n\r\n if (this.hlsjs) this.hlsjs.destroy()\r\n if (this.p2pEngine) this.p2pEngine.destroy()\r\n\r\n clearInterval(this.networkInfoInterval)\r\n }\r\n\r\n getCurrentLevel () {\r\n return this.hlsjs.levels[this.hlsjs.currentLevel]\r\n }\r\n\r\n getLiveLatency () {\r\n return Math.round(this.hlsjs.latency)\r\n }\r\n\r\n getHLSJS () {\r\n return this.hlsjs\r\n }\r\n\r\n private initializeCore () {\r\n this.player.one('play', () => {\r\n this.player.addClass('vjs-has-big-play-button-clicked')\r\n })\r\n\r\n this.player.one('canplay', () => {\r\n if (this.startTime) {\r\n this.player.currentTime(this.startTime)\r\n }\r\n })\r\n }\r\n\r\n private initializePlugin () {\r\n initHlsJsPlayer(this.hlsjs)\r\n\r\n this.p2pEngine = this.options.loader.getEngine()\r\n\r\n this.p2pEngine.on(Events.SegmentError, (segment: Segment, err) => {\r\n logger.error(`Segment ${segment.id} error.`, err)\r\n\r\n if(segment.requestUrl)\r\n this.options.redundancyUrlManager.removeBySegmentUrl(segment.requestUrl)\r\n })\r\n\r\n this.statsP2PBytes.numPeers = 1 + this.options.redundancyUrlManager.countBaseUrls()\r\n\r\n this.runStats()\r\n }\r\n\r\n private runStats () {\r\n this.p2pEngine.on(Events.PieceBytesDownloaded, (method: string, _segment, bytes: number) => {\r\n const elem = method === 'p2p' ? this.statsP2PBytes : this.statsHTTPBytes\r\n\r\n elem.pendingDownload.push(bytes)\r\n elem.totalDownload += bytes\r\n })\r\n\r\n this.p2pEngine.on(Events.PieceBytesUploaded, (method: string, _segment, bytes: number) => {\r\n const elem = method === 'p2p' ? this.statsP2PBytes : this.statsHTTPBytes\r\n\r\n elem.pendingUpload.push(bytes)\r\n elem.totalUpload += bytes\r\n })\r\n\r\n this.p2pEngine.on(Events.PeerConnect, () => this.statsP2PBytes.numPeers++)\r\n this.p2pEngine.on(Events.PeerClose, () => this.statsP2PBytes.numPeers--)\r\n\r\n this.networkInfoInterval = setInterval(() => {\r\n const p2pDownloadSpeed = this.arraySum(this.statsP2PBytes.pendingDownload)\r\n const p2pUploadSpeed = this.arraySum(this.statsP2PBytes.pendingUpload)\r\n\r\n const httpDownloadSpeed = this.arraySum(this.statsHTTPBytes.pendingDownload)\r\n const httpUploadSpeed = this.arraySum(this.statsHTTPBytes.pendingUpload)\r\n\r\n this.statsP2PBytes.pendingDownload = []\r\n this.statsP2PBytes.pendingUpload = []\r\n this.statsHTTPBytes.pendingDownload = []\r\n this.statsHTTPBytes.pendingUpload = []\r\n\r\n return this.player.trigger('p2pInfo', {\r\n source: 'p2p-media-loader',\r\n http: {\r\n downloadSpeed: httpDownloadSpeed,\r\n uploadSpeed: httpUploadSpeed,\r\n downloaded: this.statsHTTPBytes.totalDownload,\r\n uploaded: this.statsHTTPBytes.totalUpload\r\n },\r\n p2p: {\r\n downloadSpeed: p2pDownloadSpeed,\r\n uploadSpeed: p2pUploadSpeed,\r\n numPeers: this.statsP2PBytes.numPeers,\r\n downloaded: this.statsP2PBytes.totalDownload,\r\n uploaded: this.statsP2PBytes.totalUpload\r\n },\r\n bandwidthEstimate: (this.hlsjs as any).bandwidthEstimate / 8\r\n } as PlayerNetworkInfo)\r\n }, this.CONSTANTS.INFO_SCHEDULER)\r\n }\r\n\r\n private arraySum (data: number[]) {\r\n return data.reduce((a: number, b: number) => a + b, 0)\r\n }\r\n}\r\n\r\nvideojs.registerPlugin('p2pMediaLoader', P2pMediaLoaderPlugin)\r\nexport { P2pMediaLoaderPlugin }\r\n","import '@peertube/videojs-contextmenu'\r\nimport './shared/upnext/end-card'\r\nimport './shared/upnext/upnext-plugin'\r\nimport './shared/stats/stats-card'\r\nimport './shared/stats/stats-plugin'\r\nimport './shared/bezels/bezels-plugin'\r\nimport './shared/peertube/peertube-plugin'\r\nimport './shared/resolutions/peertube-resolutions-plugin'\r\nimport './shared/control-bar/next-previous-video-button'\r\nimport './shared/control-bar/p2p-info-button'\r\n//import './shared/control-bar/peertube-link-button'\r\nimport './shared/control-bar/picture-in-picture-bastyon'\r\nimport './shared/control-bar/peertube-load-progress-bar'\r\nimport './shared/control-bar/theater-button'\r\nimport './shared/settings/resolution-menu-button'\r\nimport './shared/settings/resolution-menu-item'\r\nimport './shared/settings/settings-dialog'\r\nimport './shared/settings/settings-menu-button'\r\nimport './shared/settings/settings-menu-item'\r\nimport './shared/settings/settings-panel'\r\nimport './shared/settings/settings-panel-child'\r\nimport './shared/playlist/playlist-plugin'\r\nimport './shared/mobile/peertube-mobile-plugin'\r\nimport './shared/mobile/peertube-mobile-buttons'\r\nimport './shared/hotkeys/peertube-hotkeys-plugin'\r\nimport \"./shared/videojs-helpers/hotkeys.js\";\r\n\r\nimport videojs from 'video.js'\r\nimport { logger } from '@root-helpers/logger'\r\nimport { isMobile } from '@root-helpers/web-browser'\r\nimport { saveAverageBandwidth } from './peertube-player-local-storage'\r\nimport { ManagerOptionsBuilder } from './shared/manager-options'\r\nimport { TranslationsManager } from './translations-manager'\r\nimport { CommonOptions, PeertubePlayerManagerOptions, PlayerMode, PlayerNetworkInfo } from './types'\r\nimport './shared/p2p-media-loader/p2p-media-loader-plugin'\r\nimport * as p2pMediaLoaderModule from 'p2p-media-loader-hlsjs-basyton'\r\n\r\n\r\n\r\nconst Fn: any = require('./shared/videojs-helpers/fn.js');\r\n\r\n\r\nconst Slider = videojs.getComponent('Slider') as any\r\nconst SeekBar = videojs.getComponent('SeekBar') as any\r\n\r\nSlider.prototype.update = function(){\r\n\r\n // In VolumeBar init we have a setTimeout for update that pops and update\r\n // to the end of the execution stack. The player is destroyed before then\r\n // update will cause an error\r\n // If there's no bar...\r\n if (!this.el_ || !this.bar) {\r\n return;\r\n }\r\n\r\n // clamp progress between 0 and 1\r\n // and only round to four decimal places, as we round to two below\r\n const progress = this.getProgress();\r\n\r\n if (progress === this.progress_) {\r\n return progress;\r\n }\r\n\r\n this.progress_ = progress;\r\n\r\n // Set the new bar width or height\r\n var el = this.bar.el()\r\n\r\n if(!this.vertical()){\r\n //el.style['transform-origin'] = 'left'\r\n el.style['transform'] = 'scaleX('+(progress).toFixed(2)+')'\r\n }\r\n else{\r\n el.style['transform-origin'] = 'bottom'\r\n el.style['transform'] = 'scaleY('+(progress).toFixed(2)+')'\r\n }\r\n\r\n return progress;\r\n}\r\n\r\nSeekBar.prototype.getPercent = function getPercent () {\r\n const time = this.player_.currentTime()\r\n const percent = time / this.player_.duration()\r\n return percent >= 1 ? 1 : percent\r\n}\r\n\r\nSeekBar.prototype.setEventHandlers_ = function () {\r\n\r\n this.update_ = Fn.bind(this, this.update);\r\n this.update = Fn.throttle(this.update_, Fn.UPDATE_REFRESH_INTERVAL);\r\n\r\n this.on(this.player_, ['ended', 'durationchange', 'timeupdate'], this.update);\r\n if (this.player_.liveTracker) {\r\n this.on(this.player_.liveTracker, 'liveedgechange', this.update);\r\n }\r\n\r\n // when playing, let's ensure we smoothly update the play progress bar\r\n // via an interval\r\n this.updateInterval = null;\r\n\r\n this.enableIntervalHandler_ = (e :any) => this.enableInterval_(e);\r\n this.disableIntervalHandler_ = (e :any) => this.disableInterval_(e);\r\n\r\n this.on(this.player_, ['playing'], this.enableIntervalHandler_);\r\n\r\n this.on(this.player_, ['ended', 'pause', 'waiting'], this.disableIntervalHandler_);\r\n\r\n // we don't need to update the play progress if the document is hidden,\r\n // also, this causes the CPU to spike and eventually crash the page on IE11.\r\n if ('hidden' in document && 'visibilityState' in document) {\r\n this.on(document, 'visibilitychange', this.toggleVisibility_);\r\n }\r\n}\r\n\r\nSeekBar.prototype.enableInterval_ = function() {\r\n if (this.updateInterval) {\r\n return;\r\n\r\n }\r\n this.updateInterval = this.setInterval(this.update, Fn.UPDATE_REFRESH_INTERVAL);\r\n}\r\n\r\nSeekBar.prototype.update = function (event : any) {\r\n if (document.visibilityState === 'hidden') {\r\n return;\r\n }\r\n\r\n const percent = this.getPercent();\r\n\r\n var el = this.bar.el()\r\n\r\n el.style['transform-origin'] = 'left'\r\n el.style['transform'] = 'scaleX('+(percent).toFixed(2)+')'\r\n\r\n return percent;\r\n \r\n}\r\n\r\nconst CaptionsButton = videojs.getComponent('CaptionsButton') as any\r\n// Change Captions to Subtitles/CC\r\nCaptionsButton.prototype.controlText_ = 'Subtitles/CC'\r\n// We just want to display 'Off' instead of 'captions off', keep a space so the variable == true (hacky I know)\r\nCaptionsButton.prototype.label_ = ' '\r\n\r\nexport class PeertubePlayerManager {\r\n private static playerElementClassName: string\r\n private static onPlayerChange: (player: videojs.Player) => void\r\n private static alreadyPlayed = false\r\n //private static pluginsManager: PluginsManager\r\n\r\n private static videojsDecodeErrors = 0\r\n\r\n\r\n private static p2pMediaLoaderModule: any\r\n\r\n static initState () {\r\n this.alreadyPlayed = false\r\n }\r\n\r\n static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions, onPlayerChange: (player: videojs.Player) => void) {\r\n //this.pluginsManager = options.pluginsManager\r\n\r\n this.onPlayerChange = onPlayerChange\r\n this.playerElementClassName = options.common.playerElement.className\r\n\r\n //if (mode === 'webtorrent') await import('./shared/webtorrent/webtorrent-plugin')\r\n\r\n\r\n if (mode === 'p2p-media-loader') {\r\n this.p2pMediaLoaderModule = p2pMediaLoaderModule\r\n }\r\n\r\n\r\n return this.buildPlayer(mode, options)\r\n }\r\n\r\n private static async buildPlayer (mode: PlayerMode, options: PeertubePlayerManagerOptions): Promise {\r\n const videojsOptionsBuilder = new ManagerOptionsBuilder(mode, options, this.p2pMediaLoaderModule)\r\n const videojsOptions = videojsOptionsBuilder.getVideojsOptions(this.alreadyPlayed)\r\n\r\n /*const videojsOptions = await this.pluginsManager.runHook(\r\n 'filter:internal.player.videojs.options.result',\r\n videojsOptionsBuilder.getVideojsOptions(this.alreadyPlayed)\r\n )*/\r\n\r\n console.log('buildPlayer')\r\n\r\n // If video is audio\r\n if (options && options.isAudio && videojsOptions && videojsOptions.controlBar && videojsOptions.controlBar.children) {\r\n videojsOptions.controlBar.children['settingsButton'].entries = ['playbackRateMenuButton'];\r\n videojsOptions.controlBar.fullscreenToggle = false;\r\n //videojsOptions.bigPlayButton = false;\r\n videojsOptions.inactivityTimeout = 0;\r\n // Mouse events\r\n videojsOptions.userActions = videojsOptions.userActions || {}\r\n videojsOptions.userActions.doubleClick = false;\r\n }\r\n\r\n const self = this\r\n return new Promise(res => {\r\n videojs(options.common.playerElement, videojsOptions, function (this: videojs.Player) {\r\n const player = this\r\n\r\n //let alreadyFallback = false\r\n\r\n const handleError = () => {\r\n //if (alreadyFallback) return\r\n //alreadyFallback = true\r\n\r\n if (mode === 'p2p-media-loader') {\r\n //self.tryToRecoverHLSError(player.error(), player, options)\r\n } else {\r\n /// remove torrent /// self.maybeFallbackToWebTorrent(mode, player, options)\r\n }\r\n }\r\n\r\n if (options && options.isAudio)\r\n player.addClass('vjs-is-audio')\r\n\r\n player.one('error', () => handleError())\r\n\r\n player.one('play', () => {\r\n self.alreadyPlayed = true\r\n })\r\n\r\n self.addContextMenu(videojsOptionsBuilder, player, options.common)\r\n\r\n if (isMobile() || options.mobile) player.peertubeMobile()\r\n //if (options.common.enableHotkeys === true) player.peerTubeHotkeysPlugin()\r\n if (options.common.controlBar === false) player.controlBar.addClass('control-bar-hidden')\r\n\r\n player.bezels()\r\n\r\n if(mode != 'localvideo'){\r\n \r\n player.stats({\r\n videoUUID: options.common.videoUUID,\r\n videoIsLive: options.common.isLive,\r\n mode,\r\n p2pEnabled: options.common.p2pEnabled\r\n })\r\n\r\n player.on('p2pInfo', (_, data: PlayerNetworkInfo) => {\r\n if (data.source !== 'p2p-media-loader' || isNaN(data.bandwidthEstimate)) return\r\n\r\n saveAverageBandwidth(data.bandwidthEstimate)\r\n })\r\n\r\n }\r\n else{\r\n player.on('durationchange', () => {\r\n if(player.duration() != options.common.videoDuration)\r\n player.duration(options.common.videoDuration)\r\n })\r\n\r\n }\r\n\r\n return res(player)\r\n })\r\n })\r\n }\r\n\r\n private static async tryToRecoverHLSError (err: any, currentPlayer: videojs.Player, options: PeertubePlayerManagerOptions) {\r\n if (err.code === 3) { // Decode error\r\n\r\n // Display a notification to user\r\n if (this.videojsDecodeErrors === 0) {\r\n options.common.errorNotifier(currentPlayer.localize('The video failed to play, will try to fast forward.'))\r\n }\r\n\r\n if (this.videojsDecodeErrors === 20) {\r\n this.maybeFallbackToWebTorrent('p2p-media-loader', currentPlayer, options)\r\n return\r\n }\r\n\r\n logger.info('Fast forwarding HLS to recover from an error.')\r\n\r\n this.videojsDecodeErrors++\r\n\r\n options.common.startTime = currentPlayer.currentTime() + 2\r\n options.common.autoplay = true\r\n this.rebuildAndUpdateVideoElement(currentPlayer, options.common)\r\n\r\n const newPlayer = await this.buildPlayer('p2p-media-loader', options)\r\n this.onPlayerChange(newPlayer)\r\n } else {\r\n this.maybeFallbackToWebTorrent('p2p-media-loader', currentPlayer, options)\r\n }\r\n }\r\n\r\n private static async maybeFallbackToWebTorrent (\r\n currentMode: PlayerMode,\r\n currentPlayer: videojs.Player,\r\n options: PeertubePlayerManagerOptions\r\n ) {\r\n\r\n if (options.webtorrent.videoFiles.length === 0 || currentMode === 'webtorrent') {\r\n currentPlayer.peertube().displayFatalError()\r\n return\r\n }\r\n\r\n logger.info('Fallback to webtorrent.')\r\n\r\n this.rebuildAndUpdateVideoElement(currentPlayer, options.common)\r\n\r\n //await import('./shared/webtorrent/webtorrent-plugin')\r\n\r\n const newPlayer = await this.buildPlayer('webtorrent', options)\r\n this.onPlayerChange(newPlayer)\r\n }\r\n\r\n private static rebuildAndUpdateVideoElement (player: videojs.Player, commonOptions: CommonOptions) {\r\n const newVideoElement = document.createElement('video')\r\n newVideoElement.className = this.playerElementClassName\r\n\r\n // VideoJS wraps our video element inside a div\r\n let currentParentPlayerElement = commonOptions.playerElement.parentNode\r\n // Fix on IOS, don't ask me why\r\n if (!currentParentPlayerElement) currentParentPlayerElement = document.getElementById(commonOptions.playerElement.id).parentNode\r\n\r\n currentParentPlayerElement.parentNode.insertBefore(newVideoElement, currentParentPlayerElement)\r\n\r\n commonOptions.playerElement = newVideoElement\r\n commonOptions.onPlayerElementChange(newVideoElement)\r\n\r\n player.dispose()\r\n\r\n return newVideoElement\r\n }\r\n\r\n private static addContextMenu (optionsBuilder: ManagerOptionsBuilder, player: videojs.Player, commonOptions: CommonOptions) {\r\n const options = optionsBuilder.getContextMenuOptions(player, commonOptions)\r\n\r\n player.contextmenuUI(options)\r\n }\r\n}\r\n\r\n// ############################################################################\r\n\r\nexport {\r\n videojs\r\n}\r\n","module.exports = require('path-browserify')\r\n","/**\r\n * @file guid.js\r\n * @module guid\r\n */\r\n\r\n// Default value for GUIDs. This allows us to reset the GUID counter in tests.\r\n//\r\n// The initial GUID is 3 because some users have come to rely on the first\r\n// default player ID ending up as `vjs_video_3`.\r\n//\r\n// See: https://github.com/videojs/video.js/pull/6216\r\nconst _initialGuid = 3;\r\n\r\n/**\r\n * Unique ID for an element or function\r\n *\r\n * @type {Number}\r\n */\r\nlet _guid = _initialGuid;\r\n\r\n/**\r\n * Get a unique auto-incrementing ID by number that has not been returned before.\r\n *\r\n * @return {number}\r\n * A new unique ID.\r\n */\r\nexport function newGUID() {\r\n return _guid++;\r\n}\r\n\r\n/**\r\n * Reset the unique auto-incrementing ID for testing only.\r\n */\r\nexport function resetGuidInTestsOnly() {\r\n _guid = _initialGuid;\r\n}","\r\n/**\r\n * @file fn.js\r\n * @module fn\r\n */\r\n import { newGUID } from './guid.js';\r\n import window from 'global/window';\r\n \r\n export const UPDATE_REFRESH_INTERVAL = 30;\r\n \r\n /**\r\n * Bind (a.k.a proxy or context). A simple method for changing the context of\r\n * a function.\r\n *\r\n * It also stores a unique id on the function so it can be easily removed from\r\n * events.\r\n *\r\n * @function\r\n * @param {Mixed} context\r\n * The object to bind as scope.\r\n *\r\n * @param {Function} fn\r\n * The function to be bound to a scope.\r\n *\r\n * @param {number} [uid]\r\n * An optional unique ID for the function to be set\r\n *\r\n * @return {Function}\r\n * The new function that will be bound into the context given\r\n */\r\n export const bind = function(context, fn, uid) {\r\n // Make sure the function has a unique ID\r\n if (!fn.guid) {\r\n fn.guid = newGUID();\r\n }\r\n \r\n // Create the new function that changes the context\r\n const bound = fn.bind(context);\r\n \r\n // Allow for the ability to individualize this function\r\n // Needed in the case where multiple objects might share the same prototype\r\n // IF both items add an event listener with the same function, then you try to remove just one\r\n // it will remove both because they both have the same guid.\r\n // when using this, you need to use the bind method when you remove the listener as well.\r\n // currently used in text tracks\r\n bound.guid = (uid) ? uid + '_' + fn.guid : fn.guid;\r\n \r\n return bound;\r\n };\r\n \r\n /**\r\n * Wraps the given function, `fn`, with a new function that only invokes `fn`\r\n * at most once per every `wait` milliseconds.\r\n *\r\n * @function\r\n * @param {Function} fn\r\n * The function to be throttled.\r\n *\r\n * @param {number} wait\r\n * The number of milliseconds by which to throttle.\r\n *\r\n * @return {Function}\r\n */\r\n export const throttle = function(fn, wait) {\r\n let last = window.performance.now();\r\n \r\n const throttled = function(...args) {\r\n const now = window.performance.now();\r\n \r\n if (now - last >= wait) {\r\n fn(...args);\r\n last = now;\r\n }\r\n };\r\n \r\n return throttled;\r\n };\r\n \r\n /**\r\n * Creates a debounced function that delays invoking `func` until after `wait`\r\n * milliseconds have elapsed since the last time the debounced function was\r\n * invoked.\r\n *\r\n * Inspired by lodash and underscore implementations.\r\n *\r\n * @function\r\n * @param {Function} func\r\n * The function to wrap with debounce behavior.\r\n *\r\n * @param {number} wait\r\n * The number of milliseconds to wait after the last invocation.\r\n *\r\n * @param {boolean} [immediate]\r\n * Whether or not to invoke the function immediately upon creation.\r\n *\r\n * @param {Object} [context=window]\r\n * The \"context\" in which the debounced function should debounce. For\r\n * example, if this function should be tied to a Video.js player,\r\n * the player can be passed here. Alternatively, defaults to the\r\n * global `window` object.\r\n *\r\n * @return {Function}\r\n * A debounced function.\r\n */\r\n export const debounce = function(func, wait, immediate, context = window) {\r\n let timeout;\r\n \r\n const cancel = () => {\r\n context.clearTimeout(timeout);\r\n timeout = null;\r\n };\r\n \r\n /* eslint-disable consistent-this */\r\n const debounced = function() {\r\n const self = this;\r\n const args = arguments;\r\n \r\n let later = function() {\r\n timeout = null;\r\n later = null;\r\n if (!immediate) {\r\n func.apply(self, args);\r\n }\r\n };\r\n \r\n if (!timeout && immediate) {\r\n func.apply(self, args);\r\n }\r\n \r\n context.clearTimeout(timeout);\r\n timeout = context.setTimeout(later, wait);\r\n };\r\n /* eslint-enable consistent-this */\r\n \r\n debounced.cancel = cancel;\r\n \r\n return debounced;\r\n };","/*\r\n * Video.js Hotkeys\r\n * https://github.com/ctd1500/videojs-hotkeys\r\n *\r\n * Copyright (c) 2015 Chris Dougherty\r\n * Licensed under the Apache-2.0 license.\r\n */\r\n\r\n;(function(root, factory) {\r\n if (typeof window !== 'undefined' && window.videojs) {\r\n factory(window.videojs);\r\n } else if (typeof define === 'function' && define.amd) {\r\n define('videojs-hotkeys', ['video.js'], function (module) {\r\n return factory(module.default || module);\r\n });\r\n } else if (typeof module !== 'undefined' && module.exports) {\r\n module.exports = factory(require('video.js'));\r\n }\r\n }(this, function (videojs) {\r\n \"use strict\";\r\n if (typeof window !== 'undefined') {\r\n window['videojs_hotkeys'] = { version: \"0.2.27\" };\r\n }\r\n\r\n \r\n var hotkeys = function(options) {\r\n var player = this;\r\n var pEl = player.el();\r\n var doc = document;\r\n var def_options = {\r\n volumeStep: 0.1,\r\n seekStep: 5,\r\n enableMute: true,\r\n enableVolumeScroll: true,\r\n enableHoverScroll: false,\r\n enableFullscreen: true,\r\n enableNumbers: true,\r\n enableJogStyle: false,\r\n alwaysCaptureHotkeys: false,\r\n captureDocumentHotkeys: false,\r\n documentHotkeysFocusElementFilter: function () { return false },\r\n enableModifiersForNumbers: true,\r\n enableInactiveFocus: true,\r\n skipInitialFocus: false,\r\n playPauseKey: playPauseKey,\r\n rewindKey: rewindKey,\r\n forwardKey: forwardKey,\r\n volumeUpKey: volumeUpKey,\r\n volumeDownKey: volumeDownKey,\r\n muteKey: muteKey,\r\n fullscreenKey: fullscreenKey,\r\n customKeys: {}\r\n };\r\n \r\n var cPlay = 1,\r\n cRewind = 2,\r\n cForward = 3,\r\n cVolumeUp = 4,\r\n cVolumeDown = 5,\r\n cMute = 6,\r\n cFullscreen = 7;\r\n \r\n // Use built-in merge function from Video.js v5.0+ or v4.4.0+\r\n var mergeOptions = videojs.mergeOptions || videojs.util.mergeOptions;\r\n options = mergeOptions(def_options, options || {});\r\n \r\n var volumeStep = options.volumeStep,\r\n seekStep = options.seekStep,\r\n enableMute = options.enableMute,\r\n enableVolumeScroll = options.enableVolumeScroll,\r\n enableHoverScroll = options.enableHoverScroll,\r\n enableFull = options.enableFullscreen,\r\n enableNumbers = options.enableNumbers,\r\n enableJogStyle = options.enableJogStyle,\r\n alwaysCaptureHotkeys = options.alwaysCaptureHotkeys,\r\n captureDocumentHotkeys = options.captureDocumentHotkeys,\r\n documentHotkeysFocusElementFilter = options.documentHotkeysFocusElementFilter,\r\n enableModifiersForNumbers = options.enableModifiersForNumbers,\r\n enableInactiveFocus = options.enableInactiveFocus,\r\n skipInitialFocus = options.skipInitialFocus;\r\n \r\n var videojsVer = videojs.VERSION;\r\n \r\n // Set default player tabindex to handle keydown and doubleclick events\r\n if (!pEl.hasAttribute('tabIndex')) {\r\n pEl.setAttribute('tabIndex', '-1');\r\n }\r\n \r\n // Remove player outline to fix video performance issue\r\n pEl.style.outline = \"none\";\r\n \r\n if (alwaysCaptureHotkeys || !player.autoplay()) {\r\n if (!skipInitialFocus) {\r\n player.one('play', function() {\r\n pEl.focus(); // Fixes the .vjs-big-play-button handing focus back to body instead of the player\r\n });\r\n }\r\n }\r\n \r\n if (enableInactiveFocus) {\r\n player.on('userinactive', function() {\r\n // When the control bar fades, re-apply focus to the player if last focus was a control button\r\n var cancelFocusingPlayer = function() {\r\n clearTimeout(focusingPlayerTimeout);\r\n };\r\n var focusingPlayerTimeout = setTimeout(function() {\r\n player.off('useractive', cancelFocusingPlayer);\r\n var activeElement = doc.activeElement;\r\n var controlBar = pEl.querySelector('.vjs-control-bar');\r\n if (activeElement && activeElement.parentElement == controlBar) {\r\n pEl.focus();\r\n }\r\n }, 10);\r\n \r\n player.one('useractive', cancelFocusingPlayer);\r\n });\r\n }\r\n \r\n player.on('play', function() {\r\n // Fix allowing the YouTube plugin to have hotkey support.\r\n var ifblocker = pEl.querySelector('.iframeblocker');\r\n if (ifblocker && ifblocker.style.display === '') {\r\n ifblocker.style.display = \"block\";\r\n ifblocker.style.bottom = \"39px\";\r\n }\r\n });\r\n \r\n var keyDown = function keyDown(event) {\r\n var ewhich = event.which, wasPlaying, seekTime;\r\n var ePreventDefault = event.preventDefault.bind(event);\r\n var duration = player.duration();\r\n // When controls are disabled, hotkeys will be disabled as well\r\n if (player.controls()) {\r\n \r\n // Don't catch keys if any control buttons are focused, unless alwaysCaptureHotkeys is true\r\n var activeEl = doc.activeElement;\r\n if (\r\n alwaysCaptureHotkeys ||\r\n (captureDocumentHotkeys && documentHotkeysFocusElementFilter(activeEl)) ||\r\n \r\n activeEl == pEl ||\r\n activeEl == pEl.querySelector('.vjs-tech') ||\r\n activeEl == pEl.querySelector('.vjs-control-bar') ||\r\n activeEl == pEl.querySelector('.iframeblocker')\r\n ) {\r\n \r\n switch (checkKeys(event, player)) {\r\n // Spacebar toggles play/pause\r\n case cPlay:\r\n ePreventDefault();\r\n if (alwaysCaptureHotkeys || captureDocumentHotkeys) {\r\n // Prevent control activation with space\r\n event.stopPropagation();\r\n }\r\n \r\n if (player.paused()) {\r\n silencePromise(player.play());\r\n } else {\r\n player.pause();\r\n }\r\n break;\r\n \r\n // Seeking with the left/right arrow keys\r\n case cRewind: // Seek Backward\r\n wasPlaying = !player.paused();\r\n ePreventDefault();\r\n /*if (wasPlaying) {\r\n player.pause();\r\n }*/\r\n seekTime = player.currentTime() - seekStepD(event);\r\n // The flash player tech will allow you to seek into negative\r\n // numbers and break the seekbar, so try to prevent that.\r\n if (seekTime <= 0) {\r\n seekTime = 0;\r\n }\r\n\r\n player.currentTime(seekTime);\r\n /* if (wasPlaying) {\r\n silencePromise(player.play());\r\n }*/\r\n break;\r\n case cForward: // Seek Forward\r\n wasPlaying = !player.paused();\r\n ePreventDefault();\r\n /*if (wasPlaying) {\r\n player.pause();\r\n }*/\r\n seekTime = player.currentTime() + seekStepD(event);\r\n // Fixes the player not sending the end event if you\r\n // try to seek past the duration on the seekbar.\r\n if (seekTime >= duration) {\r\n seekTime = wasPlaying ? duration - .001 : duration;\r\n }\r\n player.currentTime(seekTime);\r\n /*if (wasPlaying) {\r\n silencePromise(player.play());\r\n }*/\r\n break;\r\n \r\n // Volume control with the up/down arrow keys\r\n case cVolumeDown:\r\n ePreventDefault();\r\n if (!enableJogStyle) {\r\n player.volume(player.volume() - volumeStep);\r\n } else {\r\n seekTime = player.currentTime() - 1;\r\n if (player.currentTime() <= 1) {\r\n seekTime = 0;\r\n }\r\n player.currentTime(seekTime);\r\n }\r\n break;\r\n case cVolumeUp:\r\n ePreventDefault();\r\n if (!enableJogStyle) {\r\n player.volume(player.volume() + volumeStep);\r\n } else {\r\n seekTime = player.currentTime() + 1;\r\n if (seekTime >= duration) {\r\n seekTime = duration;\r\n }\r\n player.currentTime(seekTime);\r\n }\r\n break;\r\n \r\n // Toggle Mute with the M key\r\n case cMute:\r\n if (enableMute) {\r\n player.muted(!player.muted());\r\n }\r\n break;\r\n \r\n // Toggle Fullscreen with the F key\r\n case cFullscreen:\r\n if (enableFull) {\r\n if (player.isFullscreen()) {\r\n player.exitFullscreen();\r\n } else {\r\n player.requestFullscreen();\r\n }\r\n }\r\n break;\r\n \r\n default:\r\n // Number keys from 0-9 skip to a percentage of the video. 0 is 0% and 9 is 90%\r\n if ((ewhich > 47 && ewhich < 59) || (ewhich > 95 && ewhich < 106)) {\r\n // Do not handle if enableModifiersForNumbers set to false and keys are Ctrl, Cmd or Alt\r\n if (enableModifiersForNumbers || !(event.metaKey || event.ctrlKey || event.altKey)) {\r\n if (enableNumbers) {\r\n var sub = 48;\r\n if (ewhich > 95) {\r\n sub = 96;\r\n }\r\n var number = ewhich - sub;\r\n ePreventDefault();\r\n player.currentTime(player.duration() * number * 0.1);\r\n }\r\n }\r\n }\r\n \r\n // Handle any custom hotkeys\r\n for (var customKey in options.customKeys) {\r\n var customHotkey = options.customKeys[customKey];\r\n // Check for well formed custom keys\r\n if (customHotkey && customHotkey.key && customHotkey.handler) {\r\n // Check if the custom key's condition matches\r\n if (customHotkey.key(event)) {\r\n ePreventDefault();\r\n customHotkey.handler(player, options, event);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n };\r\n \r\n var doubleClick = function doubleClick(event) {\r\n // Video.js added double-click fullscreen in 7.1.0\r\n if (videojsVer != null && videojsVer <= \"7.1.0\") {\r\n // When controls are disabled, hotkeys will be disabled as well\r\n if (player.controls()) {\r\n \r\n // Don't catch clicks if any control buttons are focused\r\n var activeEl = event.relatedTarget || event.toElement || doc.activeElement;\r\n if (activeEl == pEl ||\r\n activeEl == pEl.querySelector('.vjs-tech') ||\r\n activeEl == pEl.querySelector('.iframeblocker')) {\r\n \r\n if (enableFull) {\r\n if (player.isFullscreen()) {\r\n player.exitFullscreen();\r\n } else {\r\n player.requestFullscreen();\r\n }\r\n }\r\n }\r\n }\r\n }\r\n };\r\n \r\n var volumeHover = false;\r\n var volumeSelector = pEl.querySelector('.vjs-volume-menu-button') || pEl.querySelector('.vjs-volume-panel');\r\n if (volumeSelector != null) {\r\n volumeSelector.onmouseover = function() { volumeHover = true; };\r\n volumeSelector.onmouseout = function() { volumeHover = false; };\r\n }\r\n \r\n var mouseScroll = function mouseScroll(event) {\r\n if (enableHoverScroll) {\r\n // If we leave this undefined then it can match non-existent elements below\r\n var activeEl = 0;\r\n } else {\r\n var activeEl = doc.activeElement;\r\n }\r\n \r\n // When controls are disabled, hotkeys will be disabled as well\r\n if (player.controls()) {\r\n if (alwaysCaptureHotkeys ||\r\n activeEl == pEl ||\r\n activeEl == pEl.querySelector('.vjs-tech') ||\r\n activeEl == pEl.querySelector('.iframeblocker') ||\r\n activeEl == pEl.querySelector('.vjs-control-bar') ||\r\n volumeHover) {\r\n \r\n if (enableVolumeScroll) {\r\n event = window.event || event;\r\n var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));\r\n event.preventDefault();\r\n \r\n if (delta == 1) {\r\n player.volume(player.volume() + volumeStep);\r\n } else if (delta == -1) {\r\n player.volume(player.volume() - volumeStep);\r\n }\r\n }\r\n }\r\n }\r\n };\r\n \r\n var checkKeys = function checkKeys(e, player) {\r\n // Allow some modularity in defining custom hotkeys\r\n \r\n // Play/Pause check\r\n if (options.playPauseKey(e, player)) {\r\n return cPlay;\r\n }\r\n \r\n // Seek Backward check\r\n if (options.rewindKey(e, player)) {\r\n return cRewind;\r\n }\r\n \r\n // Seek Forward check\r\n if (options.forwardKey(e, player)) {\r\n return cForward;\r\n }\r\n \r\n // Volume Up check\r\n if (options.volumeUpKey(e, player)) {\r\n return cVolumeUp;\r\n }\r\n \r\n // Volume Down check\r\n if (options.volumeDownKey(e, player)) {\r\n return cVolumeDown;\r\n }\r\n \r\n // Mute check\r\n if (options.muteKey(e, player)) {\r\n return cMute;\r\n }\r\n \r\n // Fullscreen check\r\n if (options.fullscreenKey(e, player)) {\r\n return cFullscreen;\r\n }\r\n };\r\n \r\n function playPauseKey(e) {\r\n // Space bar or MediaPlayPause\r\n return (e.which === 32 || e.which === 179);\r\n }\r\n \r\n function rewindKey(e) {\r\n // Left Arrow or MediaRewind\r\n return (e.which === 37 || e.which === 177);\r\n }\r\n \r\n function forwardKey(e) {\r\n // Right Arrow or MediaForward\r\n return (e.which === 39 || e.which === 176);\r\n }\r\n \r\n function volumeUpKey(e) {\r\n // Up Arrow\r\n return (e.which === 38);\r\n }\r\n \r\n function volumeDownKey(e) {\r\n // Down Arrow\r\n return (e.which === 40);\r\n }\r\n \r\n function muteKey(e) {\r\n // M key\r\n return (e.which === 77);\r\n }\r\n \r\n function fullscreenKey(e) {\r\n // F key\r\n return (e.which === 70);\r\n }\r\n \r\n function seekStepD(e) {\r\n // SeekStep caller, returns an int, or a function returning an int\r\n return (typeof seekStep === \"function\" ? seekStep(e) : seekStep);\r\n }\r\n \r\n function silencePromise(value) {\r\n if (value != null && typeof value.then === 'function') {\r\n value.then(null, function(e) {});\r\n }\r\n }\r\n\r\n\r\n var active = false\r\n\r\n\r\n player.on('enablehotkeys', function(){\r\n\r\n\r\n player.on('keydown', keyDown);\r\n player.on('dblclick', doubleClick);\r\n player.on('mousewheel', mouseScroll);\r\n player.on(\"DOMMouseScroll\", mouseScroll);\r\n \r\n if (captureDocumentHotkeys) {\r\n document.addEventListener('keydown', keyDown);\r\n }\r\n\r\n active = true\r\n })\r\n\r\n var off = function(){\r\n\r\n if(active){\r\n player.off('keydown', keyDown);\r\n player.off('dblclick', doubleClick);\r\n player.off('mousewheel', mouseScroll);\r\n player.off(\"DOMMouseScroll\", mouseScroll);\r\n \r\n if (captureDocumentHotkeys) {\r\n document.removeEventListener('keydown', keyDown);\r\n }\r\n }\r\n\r\n active = false\r\n \r\n }\r\n \r\n player.on('disablehotkeys', off)\r\n player.on('dispose', function(){\r\n\r\n off()\r\n\r\n player = null\r\n pEl = null\r\n })\r\n \r\n return this;\r\n };\r\n \r\n var registerPlugin = videojs.registerPlugin || videojs.plugin;\r\n registerPlugin('hotkeys', hotkeys);\r\n }));"],"names":["EndCard","player","options","dashOffsetTotal","dashOffsetStart","interval","upNextEvents","videojs","ticks","totalTicks","options_","timeout","on","_","condition","addClass","showCard","canceled","removeClass","container","style","display","next","trigger","className","innerHTML","this","headText","cancelText","suspendedText","autoplayRing","getElementsByClassName","title","cancelButton","suspendedMessage","nextButton","onclick","cb","setAttribute","getTitle","one","clearTimeout","goToPercent","percent","newOffset","Math","max","tick","update","suspended","innerText","setTimeout","bind","UpNextPlugin","settings","ready","addChild","timeToInt","time","matches","match","parseInt","secondsToTime","seconds","full","symbol","hourSymbol","minuteSymbol","secondsSymbol","hours","floor","minutes","pick","object","keys","result","key","Object","prototype","hasOwnProperty","call","I18N_LOCALE_ALIAS","getCompleteLocale","locale","concat","map","l","TEXT_RULES","TEXT_WITH_HTML_RULES","toTitleCase","str","charAt","toUpperCase","slice","dictionaryBytes","type","decimals","bytes","value","format","find","d","length","toFixed","StatsCard","metadataStore","intervalMs","playerNetworkInfo","containerEl","infoListEl","closeButton","tabindex","hide","appendChild","populateInfoBlocks","player_","event","data","mode","source","p2pStats","p2p","httpStats","http","downloadSpeed","join","uploadSpeed","totalDownloaded","downloaded","totalUploaded","uploaded","numPeers","averageBandwidth","bandwidthEstimate","downloadedFromServer","downloadedFromPeers","updateInterval","show","setInterval","buildHLSOptions","populateInfoValues","err","logger","clearInterval","progress","latency","p2pMediaLoader","level","getCurrentLevel","codecs","videoCodec","audioCodec","undefined","resolution","height","attrs","buffer","timeRangesToString","buffered","videoIsLive","getLiveLatency","bufferedPercent","playerMode","buildInfoRow","localize","uuid","viewport","volume","color","connection","network","transferred","download","bufferProgress","bufferState","liveLatency","root","colorSpace","videoQuality","getVideoPlaybackQuality","frames","document","documentElement","clientWidth","window","innerWidth","clientHeight","innerHeight","devicePixelRatio","droppedVideoFrames","totalVideoFrames","duration","round","muted","networkActivity","totalTransferred","downloadBreakdown","setInfoValue","p2pEnabled","videoUUID","el","labelText","valueHTML","label","r","i","start","end","StatsForNerdsPlugin","statsCard","isMobile","test","navigator","userAgent","PauseBezel","seeking","ended","showBezel","BezelsPlugin","KEY_PREFIX","getLocalStorage","localStorage","getItem","setLocalStorage","setItem","_a","debugLogger","debug","PeerTubePlugin","CONSTANTS","USER_VIEW_VIDEO_INTERVAL","menuOpened","mouseInControlBar","mouseInSettings","videoViewUrl","authorizationHeader","startTime","initialInactivityTimeout","inactivityTimeout","autoplay","playerOptions","valueNumber","parseFloat","isNaN","getStoredVolume","getStoredMute","defaultSubtitle","subtitle","toString","stopTime","self","onTimeUpdate","currentTime","pause","off","textTracks","addEventListener","showing","tracks_","t","kind","language","videoDuration","initializePlayer","runUserViewing","stopListen","videoViewInterval","alterInactivity","listenControlBarMouse","listenFullScreenChange","lastViewEvent","lastCurrentTime","notifyUserIsWatching","abs","catch","JSON","stringify","parse","error","getStoredVideoWatchHistory","date","Date","toISOString","viewEvent","Promise","resolve","body","headers","Headers","set","fetch","method","e","isFullscreen","focus","controlBar","settingsButton","dialog","setInactivityTimeout","reportUserActivity","cache_","PeerTubeResolutionsPlugin","resolutions","autoResolutionEnabled","push","currentSelection","getSelected","sort","selected","id","autoResolutionChosenId","byEngine","selectCallback","a","b","NextPreviousVideoButton","nextPreviousVideoButtonOptions","button","nextIcon","handler","isDisabled","P2pInfoButton","div","subDivWebtorrent","downloadIcon","downloadSpeedText","downloadSpeedNumber","downloadSpeedUnit","uploadIcon","uploadSpeedText","uploadSpeedNumber","uploadSpeedUnit","peersText","peersNumber","subDivHttp","subDivHttpText","textContent","PictureInPictureBastyon","controlText","buildElement","classList","add","Component","registerComponent","PeerTubeLoadProgressBar","TheaterButton","enabled","getStoredTheater","THEATER_MODE_CLASS","handleTheaterChange","theaterEnabled","isTheaterEnabled","toggleClass","hasClass","ResolutionMenuItem","selectable","autoResolutionChosen","resolutionId","peertubeResolutions","updateSelection","updateAutoResolution","select","selectedResolution","getAutoResolutionChosen","isAutoResolutionEnabeld","Menu","ResolutionMenuButton","buildQualities","labelEl_","component","children","menu","child","getResolutions","m","addClickListener","SettingsDialog","uniqueId","dialogLabelId","dialogDescriptionId","tabIndex","role","MenuItem","SettingsMenuItem","menuButton","mainMenu","panel","getChild","panelChild","panelChildEl","size","menuToLoad","subMenuName","entry","SubMenuComponent","Error","newOptions","assign","subMenu","subMenuClass","buildCSSClass","split","settingsSubMenuEl_","eventHandlers","build","submenuClickHandler","bindClickEvents","reset","onSubmenuClick","transitionEndHandler","onTransitionEnd","target","currentTarget","contains","loadMainMenu","settingsSubMenuTitleEl_","settingsSubMenuValueEl_","opacity","marginRight","setDialogSize","firstChild","element","callback","action","prefix","p","toLowerCase","removeEventListener","propertyName","setMargin","mainMenuEl","mainMenuAny","width","setSize","createBackButton","PrefixedEvent","name","html","subMenuItem","children_","subMenuItemUntyped","getLabel","hideDialog","item","getComponentSize","contentElType","Button","SettingsButton","settingsButtonOptions","dialogEl","addSettingsItemHandler","onAddSettingsItem","disposeSettingsItemHandler","onDisposeSettingsItem","documentClickHandler","onDocumentClick","userInactiveHandler","onUserInactive","buildMenu","bindEvents","parentElement","_b","_c","dispose","removeChild","entries","isInIframe","addMenuItem","showDialog","peertube","onMenuOpened","onMenuClosed","resetChildren","offsetWidth","offsetHeight","offset","setup","maxHeightOffset","maxHeight","panelEl","settingsMenuItem","hideChildren","el_","menuChild","hideSubMenu","top","SettingsPanel","SettingsPanelChild","PlaylistButton","wrapper","icon","playlistInfoElement","getCurrentPosition","playlist","videosLength","displayName","getPlaylistMenu","open","playlistMenu","PlaylistMenuItem","emitTapEvents","switchPlaylistItem","handleKeyDown","li","video","positionBlock","position","buildAvailableVideo","buildUnavailableVideo","videoElement","thumbnail","src","location","origin","thumbnailPath","infoBlock","channel","startTimestamp","stopTimestamp","timestamps","append","block","code","onClicked","PlaylistMenu","mouseenter","mouseleave","current","close","menuItems","getOptions","header","headerLeft","leftTitle","playlistChannel","videoChannel","leftSubtitle","list","playlistElement","elements","onItemClicked","updateSelected","newPosition","setSelected","getElement","PlaylistPlugin","playlistButton","PeerTubeMobilePlugin","seekAmount","peerTubeMobileButtons","reportTouchActivity","screen","orientation","handleFullscreenRotation","userActions","click","doubleClick","initTouchStartEvents","isPortraitVideo","lock","videoWidth","videoHeight","handleTouchStart","tapTimeout","lastTapEvent","timeStamp","DOUBLE_TAP_DELAY_MS","onDoubleTap","newActiveState","userActive","preventDefault","passive","playerWidth","currentWidth","rect","findPlayerTarget","getBoundingClientRect","offsetX","targetTouches","pageX","left","displayFastSeek","scheduleSetCurrentTime","setCurrentTimeTimeout","newTime","min","play","SET_CURRENT_TIME_DELAY","PeerTubeMobileButtons","mainButton","stopPropagation","paused","rewind","forward","rewindText","forwardText","amount","hideRewind","hideForward","displayForward","displayRewind","remove","PeerTubeHotkeysPlugin","handlers","buildHandlers","handleKeyFunction","onKeyDown","isValidKeyTarget","accept","isNaked","VOLUME_STEP","SEEK_STEP","altKey","ctrlKey","exitFullscreen","requestFullscreen","playbackRate","eventEl","playerEl","activeEl","activeElement","currentElTagName","tagName","querySelector","metaKey","shiftKey","ControlBarOptionsBuilder","globalOptions","common","previousVideo","getPreviousVideo","playToggle","nextVideo","getNextVideo","currentTimeDisplay","timeDivider","durationDisplay","liveDisplay","flexibleWidthSpacer","getProgressControl","p2PInfoButton","muteToggle","volumeControl","getSettingsButton","theaterButton","fullscreenToggle","settingEntries","progressControl","seekBar","mouseTimeDisplay","playProgressBar","previousVideoButton","hasPreviousVideo","nextVideoButton","hasNextVideo","RedundancyUrlManager","baseUrls","segmentUrl","baseUrl","dirname","filter","u","url","getRandomInt","newBaseUrl","slashPart","endsWith","basename","random","segmentUrlBuilderFactory","redundancyUrlManager","segment","buildUrl","wait","ms","res","findbyqualityname","segments","substring","indexOf","segmentValidatorFactory","segmentsSha256Url","isLive","segmentsJSON","fetchSha256Segments","regex","_method","_peerId","retry","hashShouldBe","filename","segmentValue","segmentValidator","range","captured","exec","console","log","calculatedSha","sha256Hex","then","json","crypto","subtle","digest","bufferToHex","default","sha256","s","h","Uint8Array","forEach","v","HLSOptionsBuilder","p2pMediaLoaderModule","commonOptions","redundancyBaseUrls","p2pMediaLoaderConfig","getP2PMediaLoaderOptions","loader","Engine","createLoaderClass","playlistUrl","hlsjs","levelLabelHandler","file","videoFiles","f","fps","html5","hlsjsConfig","getHLSJSOptions","consumeOnly","trackerAnnounce","startsWith","specificLiveOrVODOptions","getP2PMediaLoaderLiveOptions","getP2PMediaLoaderVODOptions","rtcConfig","iceServers","urls","username","credential","simultaneousHttpDownloads","httpFailedSegmentTimeout","localTransport","segmentUrlBuilder","useP2P","segmentsStorage","assetsStorage","swarmId","forwardSegmentCount","p2pDownloadMaxPriority","base","requiredSegmentsPriority","liveOptions","latencyMode","httpDownloadProbability","skipSegmentBuilderPriority","cachedSegmentExpiration","cachedSegmentsCount","httpDownloadMaxPriority","httpDownloadProbabilitySkipIfNoPeers","getHLSLiveOptions","getHLSVODOptions","capLevelToPlayerSize","autoStartLoad","getAverageBandwidthInStore","abrEwmaDefaultEstimate","backBufferLength","startLevel","testBandwidth","liveSyncDurationCount","WebTorrentOptionsBuilder","autoPlayValue","webtorrentOptions","webtorrent","p2pMediaLoaderOptions","playerRefusedP2P","playerElement","ManagerOptionsBuilder","alreadyPlayed","getAutoPlayValue","preloadTextTracks","plugins","getPluginOptions","webtorrentOptionsBuilder","hotkeys","controlBarOptionsBuilder","videojsOptions","textTrackSettings","controls","loop","poster","playbackRates","sources","getChildrenOptions","platform","maxTouchPoints","includes","content","isLoopEnabled","items","listener","stats","CapLevelController","hls","autoLevelCapping","Number","POSITIVE_INFINITY","firstLevel","media","restrictedLevels","timer","clientRect","registerListeners","levels","maxLevelIndex","curLevel","nextLevel","streamController","unregisterListener","config","stopCapping","Events","onFpsDropLevelCapping","onMediaAttaching","onManifestParsed","onBufferCodecs","onMediaDetaching","isLevelAllowed","droppedLevel","HTMLVideoElement","startCapping","mediaHeight","mediaWidth","getMaxLevel","nextLevelSwitch","capLevelIndex","validLevels","index","getMaxLevelByMediaSize","detectPlayerSize","clientRectLast","boundsRect","right","bottom","getDimensions","contentScaleFactor","pixelRatio","AbrController","lastLoadedFragLevel","_nextAutoLevel","onCheck","_abandonRulesCheck","fragCurrent","partCurrent","bitrateTestDelay","bwEstimator","EwmaBandWidthEstimator","abrEwmaSlowVoD","abrEwmaFastVoD","onFragLoading","onFragLoaded","onFragBuffered","onLevelLoaded","onError","unregisterListeners","clearTimer","frag","PlaylistLevelType","part","details","live","abrEwmaSlowLive","abrEwmaFastLive","autoLevelEnabled","aborted","loaded","total","readyState","bufferInfo","mainForwardBufferInfo","requestDelay","performance","now","loading","loadedFirstByte","first","bwEstimate","getEstimate","minAutoLevel","expectedLen","maxBitrate","loadRate","fragLoadedDelay","bufferStarvationDelay","len","nextLoadLevel","fragLevelNextLoadedDelay","levelNextBitrate","sn","isFinite","sample","abort","abrMaxWithRealBitrate","loadedBytes","loadedDuration","realBitrate","bitrateTest","processingMs","parsing","bwEstimateSample","ErrorDetails","forcedAutoLevel","canEstimate","nextABRAutoLevel","getNextABRAutoLevel","loadError","maxAutoLevel","currentFragDuration","avgbw","bestLevel","findBestLevel","abrBandWidthFactor","abrBandWidthUpFactor","maxStarvationDelay","bwFactor","bwUpFactor","maxLoadingDelay","currentBw","maxFetchDuration","currentLevel","currentCodecSet","codecSet","levelInfo","adjustedbw","levelDetails","avgDuration","partTarget","averagetargetduration","bitrate","fetchDuration","Html5Hlsjs","vjs","tech","errorCounts","maxNetworkErrorRecovery","_duration","metadata","dvrDuration","edgeMargin","name_","playerId","videoLogger","Logger","errorTxt","mediaError","MEDIA_ERR_ABORTED","MEDIA_ERR_DECODE","_handleMediaError","MEDIA_ERR_NETWORK","MEDIA_ERR_SRC_NOT_SUPPORTED","message","initialize","hooks","splice","Infinity","createTimeRanges","endTime","untypedHLS","warn","destroyLogs","destroy","_initHlsjs","once","Hlsjs","recoverMediaError","swapAudioCodec","onLine","startLoad","_event","fatal","_handleNetworkError","srOptions_","buildLevelLabel","manualLevel","obj","objKeys","videoId","serverUrl","returnLog","_notifyVideoQualities","hlsjsConfigRef","_oneLevelObjClone","preload","_startLoad","capLevelController","abrController","_onError","_onMetaData","liveSyncDuration","targetduration","totalduration","_e","attachMedia","loadSource","registerPlugin","plugin","getTech","registerSourceHandler","canHandleSource","handleSource","hlsProvider","P2pMediaLoaderPlugin","INFO_SCHEDULER","statsP2PBytes","pendingDownload","pendingUpload","totalDownload","totalUpload","statsHTTPBytes","initVideoJsContribHlsJsPlayer","canPlayType","initializeCore","initializePlugin","p2pEngine","networkInfoInterval","initHlsJsPlayer","getEngine","requestUrl","removeBySegmentUrl","countBaseUrls","runStats","_segment","elem","p2pDownloadSpeed","arraySum","p2pUploadSpeed","httpDownloadSpeed","httpUploadSpeed","reduce","Fn","require","Slider","SeekBar","bar","getProgress","progress_","vertical","getPercent","setEventHandlers_","update_","throttle","UPDATE_REFRESH_INTERVAL","liveTracker","enableIntervalHandler_","enableInterval_","disableIntervalHandler_","disableInterval_","toggleVisibility_","visibilityState","CaptionsButton","controlText_","label_","PeertubePlayerManager","onPlayerChange","playerElementClassName","buildPlayer","videojsOptionsBuilder","getVideojsOptions","isAudio","addContextMenu","mobile","peertubeMobile","bezels","currentPlayer","videojsDecodeErrors","errorNotifier","maybeFallbackToWebTorrent","rebuildAndUpdateVideoElement","newPlayer","currentMode","displayFatalError","newVideoElement","createElement","currentParentPlayerElement","parentNode","getElementById","insertBefore","onPlayerElementChange","optionsBuilder","getContextMenuOptions","contextmenuUI","module","exports","_guid","context","fn","uid","guid","bound","last","debounce","func","immediate","cancel","debounced","args","arguments","later","apply","factory","version","pEl","doc","volumeStep","mergeOptions","util","seekStep","enableMute","enableVolumeScroll","enableHoverScroll","enableFullscreen","enableNumbers","enableJogStyle","alwaysCaptureHotkeys","captureDocumentHotkeys","documentHotkeysFocusElementFilter","enableModifiersForNumbers","enableInactiveFocus","skipInitialFocus","playPauseKey","which","rewindKey","forwardKey","volumeUpKey","volumeDownKey","muteKey","fullscreenKey","customKeys","enableFull","videojsVer","VERSION","hasAttribute","outline","cancelFocusingPlayer","focusingPlayerTimeout","ifblocker","keyDown","wasPlaying","seekTime","ewhich","ePreventDefault","checkKeys","seekStepD","sub","number","customKey","customHotkey","relatedTarget","toElement","volumeHover","volumeSelector","onmouseover","onmouseout","mouseScroll","delta","wheelDelta","detail","active","define"],"sourceRoot":""}