diff --git a/CHANGELOG.md b/CHANGELOG.md index f577955d2f..5d7e37f32f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Versioning](https://semver.org/spec/v2.0.0.html). ### Changed +- Upgrade video.js to version 8 (#25350) - Replace CRA by Vite (#2530) - Replace grommet Image and Grid component (#2518) - Optimized apps bundle (#2528) diff --git a/renovate.json b/renovate.json index 0c10ccbc3e..06f22894c3 100644 --- a/renovate.json +++ b/renovate.json @@ -24,9 +24,7 @@ "rehype-highlight", "rehype-raw", "remark-math", - "styled-components", - "video.js", - "videojs-contrib-quality-levels" + "styled-components" ] }, { diff --git a/src/frontend/apps/lti_site/babel.config.js b/src/frontend/apps/lti_site/babel.config.js index f2000080a6..f04423b09b 100644 --- a/src/frontend/apps/lti_site/babel.config.js +++ b/src/frontend/apps/lti_site/babel.config.js @@ -1,5 +1,11 @@ module.exports = { plugins: [ + [ + '@babel/plugin-transform-typescript', + { + allowDeclareFields: true, + }, + ], [ 'react-intl', { diff --git a/src/frontend/apps/lti_site/package.json b/src/frontend/apps/lti_site/package.json index 2ffb14e735..9c983eb1c8 100644 --- a/src/frontend/apps/lti_site/package.json +++ b/src/frontend/apps/lti_site/package.json @@ -25,6 +25,7 @@ "@babel/core": "7.23.9", "@babel/plugin-proposal-class-properties": "7.18.6", "@babel/plugin-syntax-dynamic-import": "7.8.3", + "@babel/plugin-transform-typescript": "*", "@babel/polyfill": "7.12.1", "@babel/preset-env": "7.23.9", "@babel/preset-react": "7.23.3", diff --git a/src/frontend/apps/standalone_site/babel.config.js b/src/frontend/apps/standalone_site/babel.config.js index 7d64c7ff5f..340c2acdd4 100644 --- a/src/frontend/apps/standalone_site/babel.config.js +++ b/src/frontend/apps/standalone_site/babel.config.js @@ -12,6 +12,12 @@ module.exports = babelJest.createTransformer({ ast: true, }, ], + [ + '@babel/plugin-transform-typescript', + { + allowDeclareFields: true, + }, + ], 'babel-plugin-import-remove-resource-query', '@babel/plugin-syntax-dynamic-import', 'babel-plugin-transform-vite-meta-env', diff --git a/src/frontend/apps/standalone_site/package.json b/src/frontend/apps/standalone_site/package.json index ccf5d5689f..b6e9577798 100644 --- a/src/frontend/apps/standalone_site/package.json +++ b/src/frontend/apps/standalone_site/package.json @@ -39,6 +39,7 @@ "devDependencies": { "@babel/core": "7.23.9", "@babel/plugin-syntax-dynamic-import": "7.8.3", + "@babel/plugin-transform-typescript": "*", "@babel/preset-env": "7.23.9", "@babel/preset-typescript": "7.23.3", "@testing-library/jest-dom": "*", diff --git a/src/frontend/package.json b/src/frontend/package.json index fc7eeba0fb..822793b93d 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -40,6 +40,7 @@ }, "resolutions": { "@babel/plugin-proposal-private-property-in-object": "7.21.11", + "@babel/plugin-transform-typescript": "7.23.6", "@codemirror/lang-markdown": "6.2.4", "@codemirror/language": "6.10.1", "@codemirror/language-data": "6.4.1", diff --git a/src/frontend/packages/lib_video/babel.config.js b/src/frontend/packages/lib_video/babel.config.js index 4bfd2bff38..6419139179 100644 --- a/src/frontend/packages/lib_video/babel.config.js +++ b/src/frontend/packages/lib_video/babel.config.js @@ -8,6 +8,12 @@ module.exports = { ast: true, }, ], + [ + '@babel/plugin-transform-typescript', + { + allowDeclareFields: true, + }, + ], '@babel/proposal-class-properties', '@babel/plugin-syntax-dynamic-import', '@babel/plugin-transform-runtime', diff --git a/src/frontend/packages/lib_video/package.json b/src/frontend/packages/lib_video/package.json index eeb0a8ae0d..fdb283aea8 100644 --- a/src/frontend/packages/lib_video/package.json +++ b/src/frontend/packages/lib_video/package.json @@ -33,9 +33,11 @@ "@babel/plugin-proposal-class-properties": "7.18.6", "@babel/plugin-syntax-dynamic-import": "7.8.3", "@babel/plugin-transform-runtime": "7.23.9", + "@babel/plugin-transform-typescript": "*", "@babel/polyfill": "7.12.1", "@babel/preset-env": "7.23.9", "@babel/preset-typescript": "7.23.3", + "@faker-js/faker": "*", "@formatjs/cli": "6.2.7", "@formatjs/intl": "2.10.0", "@openfun/cunningham-react": "*", @@ -59,7 +61,6 @@ "cross-env": "7.0.3", "eslint": "*", "eslint-config-marsha": "*", - "@faker-js/faker": "*", "grommet": "*", "grommet-icons": "4.12.0", "jest": "29.7.0", @@ -84,16 +85,16 @@ "dependencies": { "@streamroot/videojs-hlsjs-plugin": "1.0.16", "altamoon-robust-websocket": "1.0.3", - "m3u8-parser": "7.1.0", "lib-common": "*", "lib-components": "*", "linkifyjs": "4.1.3", + "m3u8-parser": "7.1.0", "p2p-media-loader-hlsjs": "0.6.2", "process": "0.11.10", "react-icalendar-link": "3.0.2", - "video.js": "7.21.1", - "videojs-contrib-quality-levels": "2.2.1", - "videojs-http-source-selector": "1.1.6", + "video.js": "8.7.0", + "videojs-contrib-quality-levels": "4.0.0", + "videojs-http-source-selector": "https://github.com/FreeTubeApp/videojs-http-source-selector.git", "vtt.js": "0.13.0" }, "volta": { diff --git a/src/frontend/packages/lib_video/src/components/common/Player/createPlayer.ts b/src/frontend/packages/lib_video/src/components/common/Player/createPlayer.ts index 5658a2e44c..bd5a8f298f 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/createPlayer.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/createPlayer.ts @@ -23,7 +23,7 @@ export const createPlayer: VideoPlayerCreator = ( ); const trackTextKind: { - [key in timedTextMode]?: videojs.default.TextTrack.Kind; + [key in timedTextMode]?: string; } = { [timedTextMode.CLOSED_CAPTIONING]: 'captions', [timedTextMode.SUBTITLE]: 'subtitles', diff --git a/src/frontend/packages/lib_video/src/components/common/Player/createVideojsPlayer.ts b/src/frontend/packages/lib_video/src/components/common/Player/createVideojsPlayer.ts index c0a5d7c09c..af96d14aae 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/createVideojsPlayer.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/createVideojsPlayer.ts @@ -1,6 +1,5 @@ import 'video.js/dist/video-js.css'; -import 'videojs-contrib-quality-levels'; import 'videojs-http-source-selector'; import './videojs/qualitySelectorPlugin'; import './videojs/p2pHlsPlugin'; @@ -12,13 +11,8 @@ import './videojs/transcriptPlugin'; import { Maybe } from 'lib-common'; import { Video, useP2PConfig, videoSize } from 'lib-components'; -import videojs, { - VideoJsPlayer, - VideoJsPlayerOptions, - VideoJsPlayerPluginOptions, -} from 'video.js'; +import videojs, { Player, Plugins, Source } from 'video.js'; -import { VideoJsExtendedSourceObject } from '@lib-video/types/libs/video.js/extend'; import { isMSESupported } from '@lib-video/utils/isMSESupported'; export const createVideojsPlayer = ( @@ -26,8 +20,8 @@ export const createVideojsPlayer = ( dispatchPlayerTimeUpdate: (time: number) => void, video: Video, locale: Maybe, - onReady: Maybe<(player: VideoJsPlayer) => void> = undefined, -): VideoJsPlayer => { + onReady: Maybe<(player: Player) => void> = undefined, +): Player => { const { isP2PEnabled } = useP2PConfig.getState(); // This property should be deleted once the feature has been // deployed, tested and approved in a production environment @@ -43,8 +37,8 @@ export const createVideojsPlayer = ( // add the video-js class name to the video attribute. videoNode.classList.add('video-js', 'vjs-big-play-centered'); - const sources: VideoJsExtendedSourceObject[] = []; - const plugins: VideoJsPlayerPluginOptions = {}; + const sources: Source[] = []; + const plugins: Partial = {}; if (!isMSESupported()) { plugins.qualitySelector = { @@ -67,7 +61,7 @@ export const createVideojsPlayer = ( }); } - const options: VideoJsPlayerOptions = { + const options = { autoplay: video.is_live, controls: true, controlBar: { @@ -98,12 +92,13 @@ export const createVideojsPlayer = ( sources, }; - const player = videojs(videoNode, options, function () { - if (video.is_live) { - this.play(); - } - onReady?.(this); - }); + const player = videojs(videoNode, options) as Player; + + if (video.is_live) { + player.play(); + } + + onReady?.(player); // plugins initialization if (isMSESupported()) { @@ -120,6 +115,17 @@ export const createVideojsPlayer = ( } player.transcriptPlugin({ video }); player.httpSourceSelector(); + + // The icon of the quality selector is not displayed with the plugin httpSourceSelector, + // so we add the class vjs-icon-cog to the element to display the icon. + player.on('loadeddata', () => { + player + .getChild('controlBar') + ?.el() + ?.getElementsByClassName('vjs-http-source-selector')[0] + ?.getElementsByClassName('vjs-menu-button')[0] + ?.classList.add('vjs-icon-cog'); + }); } player.id3Plugin(); player.xapiPlugin({ video, locale, dispatchPlayerTimeUpdate }); diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/components/DownloadVideoButton.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/components/DownloadVideoButton.ts index 5b1779df9e..e2c3373e95 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/components/DownloadVideoButton.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/components/DownloadVideoButton.ts @@ -1,13 +1,18 @@ import { videoSize } from '@lib-components/types'; import { getIntl } from 'lib-common'; import { defineMessages } from 'react-intl'; -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import Component from 'video.js/dist/types/component'; +import MenuButton from 'video.js/dist/types/menu/menu-button'; +import MenuItemOptions from 'video.js/dist/types/menu/menu-item'; import { DownloadVideoPluginOptions } from '../types'; import { DownloadVideoQualityItem } from './DownloadVideoQualityItem'; -const MenuButton = videojs.getComponent('MenuButton'); +const MenuButtonClass = videojs.getComponent( + 'MenuButton', +) as unknown as typeof MenuButton; const messages = defineMessages({ downloadVideoButton: { defaultMessage: 'Download Video', @@ -15,8 +20,10 @@ const messages = defineMessages({ id: 'videojs.menu.downloadVideoButton', }, }); -export class DownloadVideoButton extends MenuButton { - constructor(player: videojs.Player, options?: videojs.MenuItemOptions) { +export class DownloadVideoButton extends MenuButtonClass { + declare player: () => Player; + + constructor(player: Player, options?: MenuItemOptions) { super(player, options); this.menuButton_.setAttribute( 'title', @@ -42,7 +49,7 @@ export class DownloadVideoButton extends MenuButton { .sort((a, b) => b - a) .map( (size) => - new DownloadVideoQualityItem(this.player_, { + new DownloadVideoQualityItem(this.player(), { label: `${size}p`, src: urls[size], }), @@ -50,4 +57,7 @@ export class DownloadVideoButton extends MenuButton { } } -videojs.registerComponent('DownloadVideoButton', DownloadVideoButton); +videojs.registerComponent( + 'DownloadVideoButton', + DownloadVideoButton as unknown as typeof Component, +); diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/components/DownloadVideoQualityItem.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/components/DownloadVideoQualityItem.ts index 90b6e4b0e7..3eeb6a6704 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/components/DownloadVideoQualityItem.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/components/DownloadVideoQualityItem.ts @@ -1,22 +1,25 @@ -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import Component from 'video.js/dist/types/component'; +import MenuItem from 'video.js/dist/types/menu/menu-item'; import { DownloadVideoQualityItemOptions } from '../types'; -const Component = videojs.getComponent('Component'); -const MenuItem = videojs.getComponent('MenuItem'); +const MenuItemClass = videojs.getComponent( + 'MenuItem', +) as unknown as typeof MenuItem; -export class DownloadVideoQualityItem extends MenuItem { +export class DownloadVideoQualityItem extends MenuItemClass { source: string | undefined; constructor( - player: videojs.Player, - options: DownloadVideoQualityItemOptions, + player: Player, + options: Partial, ) { options.selectable = false; options.multiSelectable = false; super(player, options); - this.setAttribute('title', options.label); + this.setAttribute('title', options.label || ''); this.source = options.src; } @@ -34,4 +37,7 @@ export class DownloadVideoQualityItem extends MenuItem { } } -Component.registerComponent('DownloadVideoMenuItem', DownloadVideoQualityItem); +videojs.registerComponent( + 'DownloadVideoMenuItem', + DownloadVideoQualityItem as unknown as typeof Component, +); diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/index.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/index.ts index 7eeec34ee5..4bcc2ba553 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/index.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/index.ts @@ -1,13 +1,15 @@ -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; import './components/DownloadVideoButton'; import './components/DownloadVideoQualityItem'; -import { DownloadVideoPluginOptions } from './types'; +import { DownloadVideoPluginOptions, DownloadVideoPluginType } from './types'; -const Plugin = videojs.getPlugin('plugin'); +const Plugin = videojs.getPlugin('plugin') as DownloadVideoPluginType; export class DownloadVideoPlugin extends Plugin { - constructor(player: videojs.Player, options: DownloadVideoPluginOptions) { + declare player: Player; + + constructor(player: Player, options: DownloadVideoPluginOptions) { super(player, options); const controlBar = this.player.controlBar; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/types.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/types.ts index 43e3013178..02a720d5cc 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/types.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/downloadVideoPlugin/types.ts @@ -1,8 +1,11 @@ import { urls } from 'lib-components'; -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import MenuItemOptions from 'video.js/dist/types/menu/menu-item'; +import PluginType from 'video.js/dist/types/plugin'; -export interface DownloadVideoQualityItemOptions - extends videojs.MenuItemOptions { +const Plugin = videojs.getPlugin('plugin') as typeof PluginType; + +export interface DownloadVideoQualityItemOptions extends MenuItemOptions { label: string; src: string | undefined; } @@ -10,3 +13,13 @@ export interface DownloadVideoQualityItemOptions export interface DownloadVideoPluginOptions { urls: Partial; } + +export class DownloadVideoPlugin extends Plugin { + declare player: Player; + + constructor(player: Player, _options?: DownloadVideoPluginOptions) { + super(player); + } +} + +export type DownloadVideoPluginType = typeof DownloadVideoPlugin; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/id3Plugin/index.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/id3Plugin/index.ts index 35639c2eee..22c36be287 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/id3Plugin/index.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/id3Plugin/index.ts @@ -1,28 +1,32 @@ import { Id3VideoType, useVideo } from 'lib-components'; -import videojs from 'video.js'; -const Plugin = videojs.getPlugin('plugin'); +import videojs, { Player } from 'video.js'; + +import { id3PluginType } from './type'; type Id3MessageType = { video: Id3VideoType; }; -export class id3Plugin extends Plugin { +const PluginClass = videojs.getPlugin('plugin') as id3PluginType; + +export class id3Plugin extends PluginClass { lastReceivedVideo: Id3VideoType | undefined; videoState; + declare player: Player; - constructor(player: videojs.Player, options: unknown) { + constructor(player: Player, options: unknown) { super(player, options); this.videoState = useVideo.getState(); this.videoState.setIsWatchingVideo(true); - player.on('loadedmetadata', this.handleLoadedMetadata.bind(this)); + this.player.on('loadedmetadata', this.handleLoadedMetadata.bind(this)); - player.on('play', this.handleStart.bind(this)); + this.player.on('play', this.handleStart.bind(this)); - player.on('ended', this.handleEnded.bind(this)); + this.player.on('ended', this.handleEnded.bind(this)); - player.on('dispose', this.handleDispose.bind(this)); + this.player.on('dispose', this.handleDispose.bind(this)); } handleLoadedMetadata() { diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/id3Plugin/type.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/id3Plugin/type.ts new file mode 100644 index 0000000000..0b4e35af80 --- /dev/null +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/id3Plugin/type.ts @@ -0,0 +1,13 @@ +import videojs, { Player } from 'video.js'; +import PluginType from 'video.js/dist/types/plugin'; + +const Plugin = videojs.getPlugin('plugin') as typeof PluginType; +export class id3PluginClass extends Plugin { + declare player: Player; + + constructor(player: Player, _options?: unknown) { + super(player); + } +} + +export type id3PluginType = typeof id3PluginClass; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/index.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/index.ts new file mode 100644 index 0000000000..8c8fd00c6d --- /dev/null +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/index.ts @@ -0,0 +1,6 @@ +export type * from './downloadVideoPlugin/types'; +export type * from './p2pHlsPlugin/types'; +export type * from './qualitySelectorPlugin/types'; +export type * from './sharedMediaPlugin/types'; +export type * from './transcriptPlugin/types'; +export type * from './xapiPlugin/types'; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/p2pHlsPlugin/index.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/p2pHlsPlugin/index.ts index 30db6de320..d2591eecfb 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/p2pHlsPlugin/index.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/p2pHlsPlugin/index.ts @@ -1,11 +1,11 @@ import videojsHlsjsSourceHandler from '@streamroot/videojs-hlsjs-plugin'; import { useJwt, useP2PConfig } from 'lib-components'; import { Byterange, Engine } from 'p2p-media-loader-hlsjs'; -import videojs, { VideoJsPlayer } from 'video.js'; +import videojs, { Player } from 'video.js'; -import { ExtendedVideoJs, HlsData } from './types'; +import { ExtendedVideoJs, HlsData, P2pHlsPluginType } from './types'; -const Plugin = videojs.getPlugin('plugin'); +const PluginClass = videojs.getPlugin('plugin') as P2pHlsPluginType; /** * A VideoJS Plugin enabling the P2P for HLS. @@ -22,8 +22,8 @@ const Plugin = videojs.getPlugin('plugin'); * necessary metadata to make `p2p-media-loader-hlsjs` works. * @class P2pPlugin */ -export class P2pHlsPlugin extends Plugin { - constructor(player: videojs.Player, options: unknown) { +export class P2pHlsPlugin extends PluginClass { + constructor(player: Player, options: unknown) { const { stunServersUrls, webTorrentServerTrackerUrls } = useP2PConfig.getState(); @@ -82,10 +82,9 @@ export class P2pHlsPlugin extends Plugin { This options will be passed to the `videojs-hlsjs-plugin` library. Example taken from: https://github.com/Novage/p2p-media-loader/blob/master/p2p-media-loader-hlsjs/demo/videojs-hlsjs-plugin.html */ - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access player.options_.html5.hlsjsConfig = { liveSyncDurationCount: 7, // To have at least 7 segments in queue - loader: engine.createLoaderClass() as unknown, + loader: engine.createLoaderClass() as Engine, }; super(player, options); } @@ -96,8 +95,8 @@ export class P2pHlsPlugin extends Plugin { * @param {Engine} engine - The P2P engine * @private */ - private initHlsJsEvents(player: VideoJsPlayer, engine: Engine) { - player.on('hlsFragChanged', (_event, data: HlsData) => { + private initHlsJsEvents(player: Player, engine: Engine) { + player.on('hlsFragChanged', (_event: string, data: HlsData) => { const frag = data.frag; const byterange: Byterange = frag.byteRange?.length !== 2 @@ -114,7 +113,7 @@ export class P2pHlsPlugin extends Plugin { await engine.destroy(); }); - player.on('hlsError', (_event, errorData: { details: string }) => { + player.on('hlsError', (_event: string, errorData: { details: string }) => { if (errorData.details === 'bufferStalledError') { if (player.media === undefined) { return; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/p2pHlsPlugin/types.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/p2pHlsPlugin/types.ts index 1e00be4ab9..68fff89b3a 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/p2pHlsPlugin/types.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/p2pHlsPlugin/types.ts @@ -1,4 +1,5 @@ -import { VideoJsPlayer } from 'video.js'; +import videojs, { Player } from 'video.js'; +import PluginType from 'video.js/dist/types/plugin'; export interface HlsData { frag: { @@ -13,7 +14,18 @@ export interface ExtendedVideoJs { Html5Hlsjs: { addHook: ( action: string, - func: (videojsPlayer: VideoJsPlayer, hlsjs: VideoJsPlayer) => void, + func: (videojsPlayer: Player, hlsjs: Player) => void, ) => void; }; } + +const Plugin = videojs.getPlugin('plugin') as typeof PluginType; +export class P2pHlsPlugin extends Plugin { + declare player: Player; + + constructor(player: Player, _options?: unknown) { + super(player); + } +} + +export type P2pHlsPluginType = typeof P2pHlsPlugin; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/components/QualitySelectorMenuButton.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/components/QualitySelectorMenuButton.ts index 502094b8b7..396488f02c 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/components/QualitySelectorMenuButton.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/components/QualitySelectorMenuButton.ts @@ -1,11 +1,17 @@ -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import MenuButton from 'video.js/dist/types/menu/menu-button'; +import MenuItemOptions from 'video.js/dist/types/menu/menu-item'; import { QualitySelectorMenuItem } from './QualitySelectorMenuItem'; -const MenuButton = videojs.getComponent('MenuButton'); +const MenuButtonClass = videojs.getComponent( + 'MenuButton', +) as unknown as typeof MenuButton; -export class QualitySelectorMenuButton extends MenuButton { - constructor(player: videojs.Player, options?: videojs.MenuItemOptions) { +export class QualitySelectorMenuButton extends MenuButtonClass { + declare player: () => Player; + + constructor(player: Player, options?: MenuItemOptions) { super(player, options); } @@ -21,16 +27,16 @@ export class QualitySelectorMenuButton extends MenuButton { } createItems() { - return this.player() - .currentSources() - .map((source) => { - return new QualitySelectorMenuItem(this.player_, { - label: `${source.size ?? ''}p`, - size: source.size ?? '', - src: source.src, - type: source.type ?? '', - selected: source.src === this.player().currentSource().src, - }); + const player = this.player(); + + return player.options_.sources.map((source) => { + return new QualitySelectorMenuItem(player, { + label: `${source.size ?? ''}p`, + size: source.size ?? '', + src: source.src, + type: source.type ?? '', + selected: player.currentSrc().includes(source.src), }); + }); } } diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/components/QualitySelectorMenuItem.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/components/QualitySelectorMenuItem.ts index 2f7b4ce8aa..d25e356472 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/components/QualitySelectorMenuItem.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/components/QualitySelectorMenuItem.ts @@ -1,18 +1,26 @@ -import videojs from 'video.js'; +import videojs, { Player, Source } from 'video.js'; +import Component from 'video.js/dist/types/component'; +import MenuItem from 'video.js/dist/types/menu/menu-item'; import { Events, QualitySelectorMenuItemOptions } from '../types'; -const Component = videojs.getComponent('Component'); -const MenuItem = videojs.getComponent('MenuItem'); +const MenuItemClass = videojs.getComponent( + 'MenuItem', +) as unknown as typeof MenuItem; -export class QualitySelectorMenuItem extends MenuItem { - constructor(player: videojs.Player, options: QualitySelectorMenuItemOptions) { - options.selectable = true; - options.multiSelectable = false; +interface MenuItemSources extends Source { + label: string; +} - super(player, options); +export class QualitySelectorMenuItem extends MenuItemClass { + constructor(player: Player, options: MenuItemSources) { + super(player, { + ...options, + selectable: true, + multiSelectable: false, + }); - this.on(player, Events.QUALITY_REQUESTED, this.qualityRequested.bind(this)); + player.on(Events.QUALITY_REQUESTED, this.qualityRequested.bind(this)); } qualityRequested( @@ -23,11 +31,15 @@ export class QualitySelectorMenuItem extends MenuItem { this.selected(selectedItem.src === currentItem.src); } - handleClick(event: videojs.EventTarget.Event) { + handleClick(event: Event) { const selected = this.options_ as QualitySelectorMenuItemOptions; super.handleClick(event); this.player().trigger(Events.QUALITY_REQUESTED, selected); } } -Component.registerComponent('QualitySelectorMenuItem', QualitySelectorMenuItem); + +videojs.registerComponent( + 'QualitySelectorMenuItem', + QualitySelectorMenuItem as unknown as typeof Component, +); diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/index.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/index.ts index 4e91416dca..8ac285b8b7 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/index.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/index.ts @@ -1,36 +1,35 @@ -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import Component from 'video.js/dist/types/component'; import { QualitySelectorMenuButton } from './components/QualitySelectorMenuButton'; -import { QualitySelectorMenuItem } from './components/QualitySelectorMenuItem'; import { Events, QualitySelectorMenuItemOptions, QualitySelectorOptions, + QualitySelectorType, } from './types'; import './middleware'; -const Plugin = videojs.getPlugin('plugin'); +const PluginClass = videojs.getPlugin('plugin') as QualitySelectorType; -export class QualitySelector extends Plugin { - constructor(player: videojs.Player, options?: QualitySelectorOptions) { +export class QualitySelector extends PluginClass { + declare player: Player; + + constructor(player: Player, options?: QualitySelectorOptions) { super(player, options); videojs.registerComponent( 'QualitySelectorMenuButton', - QualitySelectorMenuButton, - ); - videojs.registerComponent( - 'QualitySelectorMenuItem', - QualitySelectorMenuItem, + QualitySelectorMenuButton as unknown as typeof Component, ); + if (options?.default) { - player.videojs_quality_selector_plugin_default = options.default; + this.player.videojs_quality_selector_plugin_default = options.default; } - this.on(player, 'loadedmetadata', this.initPlugin.bind(this)); - this.on(player, Events.QUALITY_REQUESTED, this.changeQuality.bind(this)); - this.on( - player, + this.player.on('loadedmetadata', this.initPlugin.bind(this)); + this.player.on(Events.QUALITY_REQUESTED, this.changeQuality.bind(this)); + this.player.on( Events.PLAYER_SOURCES_CHANGED, this.sourcesChanged.bind(this), ); @@ -40,6 +39,7 @@ export class QualitySelector extends Plugin { if (this.player.videojs_quality_selector_plugin_initialized) { return; } + const controlBar = this.player.controlBar; const fullscreenToggle = controlBar.getChild('fullscreenToggle')?.el(); controlBar @@ -55,12 +55,13 @@ export class QualitySelector extends Plugin { _event: Events, selectedSource: QualitySelectorMenuItemOptions, ) { - const sources = this.player.currentSources(); this.player.videojs_quality_selector_plugin_is_paused = this.player.paused(); + this.player.videojs_quality_selector_plugin_currentime = this.player.currentTime(); + const { sources } = this.player.options_; const newSources = sources.map((source) => { source.selected = source.src === selectedSource.src; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/middleware.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/middleware.ts index a322b1b869..ea67d5087e 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/middleware.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/middleware.ts @@ -1,15 +1,13 @@ import { Maybe } from 'lib-common'; -import videojs from 'video.js'; - -import { VideoJsExtendedSourceObject } from '@lib-video/types/libs/video.js/extend'; +import videojs, { MiddlewareUse, Player, Source } from 'video.js'; import { Events } from './types'; -videojs.use('video/mp4', (player: videojs.Player) => ({ +(videojs.use as typeof MiddlewareUse)('video/mp4', (player: Player) => ({ setSource: (playerSource, next) => { const sources = player.currentSources(); - let selectedSource: Maybe; + let selectedSource: Maybe; selectedSource = sources.find((source) => source.selected); diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/types.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/types.ts index de3bb57085..400210c675 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/types.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/qualitySelectorPlugin/types.ts @@ -1,12 +1,15 @@ -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import MenuItem from 'video.js/dist/types/menu/menu-item'; +import PluginType from 'video.js/dist/types/plugin'; + +const Plugin = videojs.getPlugin('plugin') as typeof PluginType; export enum Events { QUALITY_REQUESTED = 'qualityRequested', PLAYER_SOURCES_CHANGED = 'playerSourcesChanged', } -export interface QualitySelectorMenuItemOptions - extends videojs.MenuItemOptions { +export interface QualitySelectorMenuItemOptions extends MenuItem { label: string; size: string; src: string; @@ -16,3 +19,14 @@ export interface QualitySelectorMenuItemOptions export interface QualitySelectorOptions { default?: string; } + +export class QualitySelector extends Plugin { + qualitySelector?: QualitySelectorOptions; + declare player: Player; + + constructor(player: Player, _options?: QualitySelectorOptions) { + super(player); + } +} + +export type QualitySelectorType = typeof QualitySelector; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/components/SharedMediaButton.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/components/SharedMediaButton.ts index 19ccc13ef5..5e7f7bcaf0 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/components/SharedMediaButton.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/components/SharedMediaButton.ts @@ -1,12 +1,17 @@ import { getIntl } from 'lib-common'; import { defineMessages } from 'react-intl'; -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import Component from 'video.js/dist/types/component'; +import MenuButton from 'video.js/dist/types/menu/menu-button'; +import MenuItemOptions from 'video.js/dist/types/menu/menu-item'; import { SharedLiveMediaOptions } from '../types'; import { SharedMediaItem } from './SharedMediaItem'; -const MenuButton = videojs.getComponent('MenuButton'); +const MenuButtonClass = videojs.getComponent( + 'MenuButton', +) as unknown as typeof MenuButton; const messages = defineMessages({ sharedMediaButton: { @@ -16,8 +21,10 @@ const messages = defineMessages({ }, }); -export class SharedMediaButton extends MenuButton { - constructor(player: videojs.Player, options?: videojs.MenuItemOptions) { +export class SharedMediaButton extends MenuButtonClass { + declare player: () => Player; + + constructor(player: Player, options?: MenuItemOptions) { super(player, options); this.menuButton_.setAttribute( 'title', @@ -39,7 +46,7 @@ export class SharedMediaButton extends MenuButton { createItems() { const { sharedLiveMedias } = this.options_ as SharedLiveMediaOptions; return sharedLiveMedias.map((item) => { - return new SharedMediaItem(this.player_, { + return new SharedMediaItem(this.player(), { label: item.title || '', src: item.urls ? item.urls.media : undefined, }); @@ -47,4 +54,7 @@ export class SharedMediaButton extends MenuButton { } } -videojs.registerComponent('SharedMediaButton', SharedMediaButton); +videojs.registerComponent( + 'SharedMediaButton', + SharedMediaButton as unknown as typeof Component, +); diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/components/SharedMediaItem.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/components/SharedMediaItem.ts index f48d2efd5b..48fff3e0bc 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/components/SharedMediaItem.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/components/SharedMediaItem.ts @@ -1,19 +1,22 @@ -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import Component from 'video.js/dist/types/component'; +import MenuItem from 'video.js/dist/types/menu/menu-item'; import { SharedLiveMediaItemOptions } from '../types'; -const Component = videojs.getComponent('Component'); -const MenuItem = videojs.getComponent('MenuItem'); +const MenuItemClass = videojs.getComponent( + 'MenuItem', +) as unknown as typeof MenuItem; -export class SharedMediaItem extends MenuItem { +export class SharedMediaItem extends MenuItemClass { source: string | undefined; - constructor(player: videojs.Player, options: SharedLiveMediaItemOptions) { + constructor(player: Player, options: Partial) { options.selectable = false; options.multiSelectable = false; super(player, options); - this.setAttribute('title', options.label); + this.setAttribute('title', options.label || ''); this.source = options.src; } @@ -30,4 +33,7 @@ export class SharedMediaItem extends MenuItem { } } -Component.registerComponent('SharedMediaItem', SharedMediaItem); +videojs.registerComponent( + 'SharedMediaItem', + SharedMediaItem as unknown as typeof Component, +); diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/index.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/index.ts index 3690432300..674c0af372 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/index.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/index.ts @@ -1,13 +1,13 @@ -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; import './components/SharedMediaButton'; import './components/SharedMediaItem'; -import { SharedLiveMediaOptions } from './types'; +import { SharedLiveMediaOptions, SharedLiveMediaType } from './types'; -const Plugin = videojs.getPlugin('plugin'); +const PluginClass = videojs.getPlugin('plugin') as SharedLiveMediaType; -export class SharedMediaPlugin extends Plugin { - constructor(player: videojs.Player, options: SharedLiveMediaOptions) { +export class SharedMediaPlugin extends PluginClass { + constructor(player: Player, options: SharedLiveMediaOptions) { super(player, options); const controlBar = this.player.controlBar; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/types.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/types.ts index ec60dcb1fe..4bff9ad79a 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/types.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/sharedMediaPlugin/types.ts @@ -1,7 +1,9 @@ import { SharedLiveMedia } from '@lib-components/types/tracks'; -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import MenuItemOptions from 'video.js/dist/types/menu/menu-item'; +import PluginType from 'video.js/dist/types/plugin'; -export interface SharedLiveMediaItemOptions extends videojs.MenuItemOptions { +export interface SharedLiveMediaItemOptions extends MenuItemOptions { label: string; src: string | undefined; } @@ -9,3 +11,14 @@ export interface SharedLiveMediaItemOptions extends videojs.MenuItemOptions { export interface SharedLiveMediaOptions { sharedLiveMedias: SharedLiveMedia[]; } + +const Plugin = videojs.getPlugin('plugin') as typeof PluginType; +export class SharedLiveMediaClass extends Plugin { + declare player: Player; + + constructor(player: Player, _options?: SharedLiveMediaOptions) { + super(player); + } +} + +export type SharedLiveMediaType = typeof SharedLiveMediaClass; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/components/TranscriptButton.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/components/TranscriptButton.ts index 307751fa48..0936d51996 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/components/TranscriptButton.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/components/TranscriptButton.ts @@ -1,12 +1,17 @@ import { getIntl } from 'lib-common'; import { defineMessages } from 'react-intl'; -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import Component from 'video.js/dist/types/component'; +import MenuButton from 'video.js/dist/types/menu/menu-button'; +import MenuItemOptions from 'video.js/dist/types/menu/menu-item'; import { TranscriptButtonOptions } from '../types'; import { TranscriptItem } from './TranscriptItem'; -const MenuButton = videojs.getComponent('MenuButton'); +const MenuButtonClass = videojs.getComponent( + 'MenuButton', +) as unknown as typeof MenuButton; const messages = defineMessages({ transcriptButton: { @@ -16,8 +21,10 @@ const messages = defineMessages({ }, }); -export class TranscriptButton extends MenuButton { - constructor(player: videojs.Player, options: videojs.MenuButtonOptions) { +export class TranscriptButton extends MenuButtonClass { + declare player: () => Player; + + constructor(player: Player, options: MenuItemOptions) { super(player, options); this.menuButton_.setAttribute( 'title', @@ -35,12 +42,12 @@ export class TranscriptButton extends MenuButton { return []; } return [ - new TranscriptItem(this.player_, { + new TranscriptItem(this.player(), { label: 'transcript off', transcript: null, }), ...transcripts.map((item) => { - return new TranscriptItem(this.player_, { + return new TranscriptItem(this.player(), { label: item.language, transcript: item, }); @@ -49,4 +56,7 @@ export class TranscriptButton extends MenuButton { } } -videojs.registerComponent('TranscriptButton', TranscriptButton); +videojs.registerComponent( + 'TranscriptButton', + TranscriptButton as unknown as typeof Component, +); diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/components/TranscriptItem.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/components/TranscriptItem.ts index 3612514734..167724bb7a 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/components/TranscriptItem.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/components/TranscriptItem.ts @@ -1,21 +1,25 @@ -import { TimedTextTranscript, useTimedTextTrack } from 'lib-components'; -import videojs from 'video.js'; +import { useTimedTextTrack } from 'lib-components'; +import videojs, { Player } from 'video.js'; +import Component from 'video.js/dist/types/component'; +import MenuItem from 'video.js/dist/types/menu/menu-item'; -import { SharedLiveMediaItemOptions } from '../types'; +import { TranscriptItemOptions } from '../types'; import { TranscriptButton } from './TranscriptButton'; -const Component = videojs.getComponent('Component'); -const MenuItem = videojs.getComponent('MenuItem'); +const MenuItemClass = videojs.getComponent( + 'MenuItem', +) as unknown as typeof MenuItem; -export class TranscriptItem extends MenuItem { - transcript: TimedTextTranscript | null; +export class TranscriptItem extends MenuItemClass { + declare player: () => Player; + transcript?: TranscriptItemOptions['transcript']; - constructor(player: videojs.Player, options: SharedLiveMediaItemOptions) { + constructor(player: Player, options: Partial) { options.selectable = true; options.multiSelectable = false; super(player, options); - this.setAttribute('title', options.label); + this.setAttribute('title', options.label || ''); this.transcript = options.transcript; this.selected( useTimedTextTrack.getState().selectedTranscript === this.transcript, @@ -36,8 +40,14 @@ export class TranscriptItem extends MenuItem { } this.selected(true); - useTimedTextTrack.getState().setSelectedTranscript(this.transcript); + + if (this.transcript) { + useTimedTextTrack.getState().setSelectedTranscript(this.transcript); + } } } -Component.registerComponent('TranscriptItem', TranscriptItem); +videojs.registerComponent( + 'TranscriptItem', + TranscriptItem as unknown as typeof Component, +); diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/index.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/index.ts index 180a990971..cc9495c20b 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/index.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/index.ts @@ -3,20 +3,20 @@ import { timedTextMode, useTimedTextTrack, } from 'lib-components'; -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; import './components/TranscriptButton'; import './components/TranscriptItem'; import { useTranscriptTimeSelector } from '@lib-video/hooks/useTranscriptTimeSelector'; -import { TranscriptPluginOptions } from './types'; +import { TranscriptPluginOptions, TranscriptPluginType } from './types'; -const Plugin = videojs.getPlugin('plugin'); +const PluginClass = videojs.getPlugin('plugin') as TranscriptPluginType; -export class TranscriptPlugin extends Plugin { +export class TranscriptPlugin extends PluginClass { unsubscribeTranscriptTimeSelector: () => void; - constructor(player: videojs.Player, options: TranscriptPluginOptions) { + constructor(player: Player, options: TranscriptPluginOptions) { super(player); const { video } = options; const timedTextTracks = useTimedTextTrack.getState().getTimedTextTracks(); diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/types.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/types.ts index 96f60d010e..a45af1c615 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/types.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/transcriptPlugin/types.ts @@ -1,8 +1,12 @@ import { Nullable } from 'lib-common'; import { TimedTextTranscript, Video } from 'lib-components'; -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; +import MenuItemOptions from 'video.js/dist/types/menu/menu-item'; +import PluginType from 'video.js/dist/types/plugin'; -export interface SharedLiveMediaItemOptions extends videojs.MenuItemOptions { +const Plugin = videojs.getPlugin('plugin') as typeof PluginType; + +export interface TranscriptItemOptions extends MenuItemOptions { label: string; transcript: Nullable; } @@ -14,3 +18,13 @@ export interface TranscriptPluginOptions { export interface TranscriptButtonOptions { transcripts: TimedTextTranscript[]; } + +export class TranscriptPlugin extends Plugin { + declare player: Player; + + constructor(player: Player, _options?: TranscriptPluginOptions) { + super(player); + } +} + +export type TranscriptPluginType = typeof TranscriptPlugin; diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/xapiPlugin/index.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/xapiPlugin/index.ts index d2d70ef83e..eeb26426cb 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/xapiPlugin/index.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/xapiPlugin/index.ts @@ -9,7 +9,7 @@ import { useCurrentSession, useJwt, } from 'lib-components'; -import videojs from 'video.js'; +import videojs, { Player } from 'video.js'; import { pushAttendance } from '@lib-video/api/pushAttendance'; import { useAttendance } from '@lib-video/hooks/useAttendance'; @@ -19,11 +19,11 @@ import { isMSESupported } from '@lib-video/utils/isMSESupported'; import { Events } from '../qualitySelectorPlugin/types'; -import { XapiPluginOptions } from './types'; +import { XapiPluginOptions, XapiPluginType } from './types'; -const Plugin = videojs.getPlugin('plugin'); +const PluginClass = videojs.getPlugin('plugin') as XapiPluginType; -export class xapiPlugin extends Plugin { +export class xapiPlugin extends PluginClass { private xapiStatement: VideoXAPIStatementInterface; video: Video; currentTime: number; @@ -34,8 +34,9 @@ export class xapiPlugin extends Plugin { hasAttendance: boolean; currentTrack: Nullable; locale: Maybe; + declare player: Player; - constructor(player: videojs.Player, options: XapiPluginOptions) { + constructor(player: Player, options: XapiPluginOptions) { super(player, options); this.video = options.video; @@ -74,20 +75,20 @@ export class xapiPlugin extends Plugin { player.on('canplaythrough', this.initialize.bind(this)); player.on('play', () => { this.xapiStatement.played({ - time: player.currentTime(), + time: player.currentTime() || 0, }); }); player.on('pause', () => { this.xapiStatement.paused({ - time: player.currentTime(), + time: player.currentTime() || 0, }); }); player.on('timeupdate', () => { if (this.isInitialized && !player.seeking()) { - this.currentTime = player.currentTime(); + this.currentTime = player.currentTime() || 0; } - options.dispatchPlayerTimeUpdate(player.currentTime()); + options.dispatchPlayerTimeUpdate(player.currentTime() || 0); }); player.on('seeking', () => { @@ -102,7 +103,7 @@ export class xapiPlugin extends Plugin { this.hasSeeked = false; this.xapiStatement.seeked({ timeFrom: this.seekingAt, - timeTo: player.currentTime(), + timeTo: player.currentTime() || 0, }); }); player.on('fullscreenchange', this.interacted.bind(this)); @@ -122,7 +123,7 @@ export class xapiPlugin extends Plugin { return; } - this.xapiStatement.terminated({ time: player.currentTime() }); + this.xapiStatement.terminated({ time: player.currentTime() || 0 }); if (this.interval) { player.clearInterval(this.interval); @@ -165,7 +166,7 @@ export class xapiPlugin extends Plugin { const contextExtensions = { ccSubtitleEnabled: this.currentTrack !== null, fullScreen: this.player.isFullscreen(), - length: this.player.duration(), + length: this.player.duration() || 0, speed: `${this.player.playbackRate()}x`, volume: this.player.volume(), }; @@ -215,7 +216,7 @@ export class xapiPlugin extends Plugin { } this.xapiStatement.interacted( - { time: this.player.currentTime() }, + { time: this.player.currentTime() || 0 }, contextExtensions, ); } diff --git a/src/frontend/packages/lib_video/src/components/common/Player/videojs/xapiPlugin/types.ts b/src/frontend/packages/lib_video/src/components/common/Player/videojs/xapiPlugin/types.ts index c28e433897..c92e3006fc 100644 --- a/src/frontend/packages/lib_video/src/components/common/Player/videojs/xapiPlugin/types.ts +++ b/src/frontend/packages/lib_video/src/components/common/Player/videojs/xapiPlugin/types.ts @@ -1,8 +1,21 @@ import { Maybe } from 'lib-common'; import { Video } from 'lib-components'; +import videojs, { Player } from 'video.js'; +import PluginType from 'video.js/dist/types/plugin'; export interface XapiPluginOptions { video: Video; locale: Maybe; dispatchPlayerTimeUpdate: (time: number) => void; } + +const Plugin = videojs.getPlugin('plugin') as typeof PluginType; +export class XapiPlugin extends Plugin { + declare player: Player; + + constructor(player: Player, _options?: XapiPluginOptions) { + super(player); + } +} + +export type XapiPluginType = typeof XapiPlugin; diff --git a/src/frontend/packages/lib_video/src/types/VideoPlayer.ts b/src/frontend/packages/lib_video/src/types/VideoPlayer.ts index a648d68dd0..e5e0aab0b4 100644 --- a/src/frontend/packages/lib_video/src/types/VideoPlayer.ts +++ b/src/frontend/packages/lib_video/src/types/VideoPlayer.ts @@ -1,6 +1,6 @@ import { Maybe } from 'lib-common'; import { TimedText, Video } from 'lib-components'; -import { VideoJsPlayer } from 'video.js'; +import { Player } from 'video.js'; export interface VideoPlayerInterface { addTrack(track: TimedText, languages: { [key: string]: string }): void; @@ -17,5 +17,5 @@ export type VideoPlayerCreator = ( dispatchPlayerTimeUpdate: (time: number) => void, video: Video, locale?: string, - onReady?: (player: VideoJsPlayer) => void, + onReady?: (player: Player) => void, ) => Maybe; diff --git a/src/frontend/packages/lib_video/src/types/libs/video.js/extend.d.ts b/src/frontend/packages/lib_video/src/types/libs/video.js/extend.d.ts index aa6f189942..5228a0ebff 100644 --- a/src/frontend/packages/lib_video/src/types/libs/video.js/extend.d.ts +++ b/src/frontend/packages/lib_video/src/types/libs/video.js/extend.d.ts @@ -1,52 +1,107 @@ -import 'video.js'; import { Engine } from 'p2p-media-loader-hlsjs'; +import 'video.js'; +import PlayerInit from 'video.js/dist/types/player'; +import PluginInit from 'video.js/dist/types/plugin'; +import Tech from 'video.js/dist/types/tech/tech'; -import { DownloadVideoPluginOptions } from '../../../components/common/Player/videojs/downloadVideoPlugin/types'; -import { SharedLiveMediaOptions } from '../../../components/common/Player/videojs/sharedMediaPlugin/types'; -import { TranscriptPluginOptions } from '../../../components/common/Player/videojs/transcriptPlugin/types'; -import { XapiPluginOptions } from '../../../components/common/Player/videojs/xapiPlugin/types'; +import { + DownloadVideoPluginOptions, + SharedLiveMediaOptions, + TranscriptButtonOptions, + XapiPluginOptions, +} from '../../../components/common/Player/videojs/'; declare module 'video.js' { - interface VideoJsPlayerOptions { - debug?: boolean; - responsive?: boolean; - } + export function MiddlewareUse( + type: string, + middleware: (Player) => { + setSource: ( + playerSource: Source, + next: (err: Error | null, source: Source) => void, + ) => void; + }, + ): void; - interface VideoJsPlayerPluginOptions { - httpSourceSelector?: VideoJsHttpSourceSelectorPluginOptions; - qualitySelector?: QualitySelectorOptions; + type PlayerOptionInit = typeof PlayerInit.prototype.options_; + interface PlayerOption extends PlayerOptionInit { + autoplay?: boolean; + controls?: boolean; + debug?: boolean; + fluid?: boolean; + sources: Source[]; + plugins?: Plugins; + html5: { + vhs?: { + limitRenditionByPlayerDimensions?: boolean; + overrideNative?: boolean; + useDevicePixelRatio?: boolean; + }; + nativeAudioTracks?: boolean; + nativeVideoTracks?: boolean; + hlsjsConfig?: { + liveSyncDurationCount?: number; + loader: Engine; + }; + }; } - interface VideoJsPlayer { - // videojs-quality-selector-plugin - videojs_quality_selector_plugin_initialized: boolean; + export class Player extends PlayerInit { + qualityLevels: () => QualityLevels; + currentSources(): Tech & Source[]; + currentSource(): Tech & Source; + videojs_quality_selector_plugin_default?: string; + videojs_quality_selector_plugin_initialized?: boolean; videojs_quality_selector_plugin_is_paused?: boolean; videojs_quality_selector_plugin_currentime?: number; - videojs_quality_selector_plugin_default?: string; - cache_: { - initTime: number; + options_: PlayerOption; + lastSource_: { + player: string; + tech: string; }; - // p2p-media-loader-hlsjs + controlBar: { + el(): Element; + addChild( + name: string, + option?: + | DownloadVideoPluginOptions + | SharedLiveMediaOptions + | TranscriptButtonOptions, + ): { + el(): Element; + }; + getChild(name: string): { + el(): Element; + }; + getDescendant(name: string): { + el(): Element; + }; + }; + p2pHlsPlugin: () => void; config: { loader: { getEngine: () => Engine } }; media: { currentTime: number }; downloadVideoPlugin: (options: DownloadVideoPluginOptions) => void; sharedMediaPlugin: (options: SharedLiveMediaOptions) => void; transcriptPlugin: (option: TranscriptPluginOptions) => void; - p2pHlsPlugin: () => void; + httpSourceSelector: () => void; id3Plugin: () => void; + textTracks: () => TextTrackList; xapiPlugin: (options: XapiPluginOptions) => void; - // videojs-http-source-selector - httpSourceSelector: () => void; - qualitySelector: () => { - on( - type?: string | string[], - listener?: (...args: unknown[]) => void, - ): void; - }; - qualityLevels: () => QualityLevels; - currentSources(): VideoJsExtendedSourceObject[]; - currentSource(): VideoJsExtendedSourceObject; + remoteTextTracks: () => TextTrackList; + seeking: () => boolean; + } + + export interface Source { + src: string; + type?: string; + size?: string; + selected?: boolean; } + + export type Plugins = typeof PluginInit & { + qualitySelector?: { + default: string; + }; + }; } interface QualityLevels { @@ -60,17 +115,6 @@ interface QualityLevels { trigger: (event: string) => void; } -interface VideoJsExtendedSourceObject { - src: string; - type?: string; - size?: string; - selected?: boolean; -} - -interface VideoJsHttpSourceSelectorPluginOptions { - default: 'low' | 'high' | 'auto'; -} - interface VideoJsQualityLevelsPluginRepresentation { id: string; width: number; diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index ff13c43a9a..a9af785795 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -221,7 +221,7 @@ "@babel/helper-split-export-declaration" "^7.22.6" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.21.0": +"@babel/helper-create-class-features-plugin@^7.21.0", "@babel/helper-create-class-features-plugin@^7.23.6": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.6.tgz#b04d915ce92ce363666f816a884cdcfc9be04953" integrity sha512-cBXU1vZni/CpGF29iTu4YRbOZt3Wat6zCoMDxRF1MayiEc4URxOj31tT65HUM0CRpMowA3HCJaAOVOUnMf96cw== @@ -1116,13 +1116,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-typescript@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.3.tgz#ce806e6cb485d468c48c4f717696719678ab0138" - integrity sha512-ogV0yWnq38CFwH20l2Afz0dfKuZBx9o/Y2Rmh5vuSS0YD1hswgEgTfyTzuSrT2q9btmHRSqYoSfwFUVaC1M1Jw== +"@babel/plugin-transform-typescript@*", "@babel/plugin-transform-typescript@7.23.6", "@babel/plugin-transform-typescript@^7.23.3": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz#aa36a94e5da8d94339ae3a4e22d40ed287feb34c" + integrity sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-create-class-features-plugin" "^7.22.15" + "@babel/helper-create-class-features-plugin" "^7.23.6" "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-typescript" "^7.23.3" @@ -1288,27 +1288,34 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.0.0", "@babel/runtime@^7.11.2", "@babel/runtime@^7.17.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.17.8", "@babel/runtime@^7.8.4": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== dependencies: regenerator-runtime "^0.14.0" -"@babel/runtime@^7.12.5", "@babel/runtime@^7.22.15", "@babel/runtime@^7.9.2": - version "7.23.9" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.9.tgz#47791a15e4603bb5f905bc0753801cf21d6345f7" - integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.13.9": +"@babel/runtime@^7.11.2", "@babel/runtime@^7.13.9", "@babel/runtime@^7.5.5": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.6.tgz#c05e610dc228855dc92ef1b53d07389ed8ab521d" integrity sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ== dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.12.5": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.4.tgz#36fa1d2b36db873d25ec631dcc4923fdc1cf2e2e" + integrity sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/runtime@^7.22.15", "@babel/runtime@^7.9.2": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.5.tgz#11edb98f8aeec529b82b211028177679144242db" + integrity sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.22.15", "@babel/template@^7.3.3": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" @@ -4923,21 +4930,44 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== -"@videojs/http-streaming@2.15.1": - version "2.15.1" - resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-2.15.1.tgz#f559f155b2c8400af10d767d4e134971c71b1344" - integrity sha512-/uuN3bVkEeJAdrhu5Hyb19JoUo3CMys7yf2C1vUjeL1wQaZ4Oe8JrZzRrnWZ0rjvPgKfNLPXQomsRtgrMoRMJQ== +"@videojs/http-streaming@3.7.0": + version "3.7.0" + resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-3.7.0.tgz#48ece0582602e24a3b403c2410bbcdf320bfcccd" + integrity sha512-5uLFKBL8CvD56dxxJyuxqB5CY0tdoa4SE9KbXakeiAy6iFBUEPvTr2YGLKEWvQ8Lojs1wl+FQndLdv+GO7t9Fw== dependencies: "@babel/runtime" "^7.12.5" - "@videojs/vhs-utils" "3.0.5" - aes-decrypter "3.1.3" + "@videojs/vhs-utils" "4.0.0" + aes-decrypter "4.0.1" global "^4.4.0" - m3u8-parser "4.8.0" - mpd-parser "^0.22.1" - mux.js "6.0.1" - video.js "^6 || ^7" + m3u8-parser "^7.1.0" + mpd-parser "^1.2.2" + mux.js "7.0.1" + video.js "^7 || ^8" -"@videojs/vhs-utils@3.0.5", "@videojs/vhs-utils@^3.0.4", "@videojs/vhs-utils@^3.0.5": +"@videojs/http-streaming@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@videojs/http-streaming/-/http-streaming-3.8.0.tgz#6f6aaa8e7c126371f698fdc1463427439b33050b" + integrity sha512-sZ5xM6XQdAPSxXKm767J28OLCJKY5mMxu7LVAqlyEJommECylm5D/RtzqAyIWM6u4V85qsJR4Zn9k6yzAhEDOw== + dependencies: + "@babel/runtime" "^7.12.5" + "@videojs/vhs-utils" "4.0.0" + aes-decrypter "4.0.1" + global "^4.4.0" + m3u8-parser "^7.1.0" + mpd-parser "^1.2.2" + mux.js "7.0.2" + video.js "^7 || ^8" + +"@videojs/vhs-utils@4.0.0", "@videojs/vhs-utils@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@videojs/vhs-utils/-/vhs-utils-4.0.0.tgz#4d4dbf5d61a9fbd2da114b84ec747c3a483bc60d" + integrity sha512-xJp7Yd4jMLwje2vHCUmi8MOUU76nxiwII3z4Eg3Ucb+6rrkFVGosrXlMgGnaLjq724j3wzNElRZ71D/CKrTtxg== + dependencies: + "@babel/runtime" "^7.12.5" + global "^4.4.0" + url-toolkit "^2.2.1" + +"@videojs/vhs-utils@^3.0.5": version "3.0.5" resolved "https://registry.yarnpkg.com/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz#665ba70d78258ba1ab977364e2fe9f4d4799c46c" integrity sha512-PKVgdo8/GReqdx512F+ombhS+Bzogiofy1LgAj4tN8PfdBx3HSS7V5WfJotKTqtOWGwVfSWsrYN/t09/DSryrw== @@ -5103,9 +5133,9 @@ integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== "@xmldom/xmldom@^0.8.3": - version "0.8.6" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.6.tgz#8a1524eb5bd5e965c1e3735476f0262469f71440" - integrity sha512-uRjjusqpoqfmRkTaNuLJ2VohVr67Q5YwDATW3VU7PfzTj6IRaihGrYI7zckGZjxQPBIp63nfvJbM+Yu5ICh0Bg== + version "0.8.10" + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99" + integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -5175,10 +5205,10 @@ addr-to-ip-port@^1.0.1: resolved "https://registry.yarnpkg.com/addr-to-ip-port/-/addr-to-ip-port-1.5.4.tgz#9542b1c6219fdb8c9ce6cc72c14ee880ab7ddd88" integrity sha512-ByxmJgv8vjmDcl3IDToxL2yrWFrRtFpZAToY0f46XFXl8zS081t7El5MXIodwm7RC6DhHBRoOSMLFSPKCtHukg== -aes-decrypter@3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/aes-decrypter/-/aes-decrypter-3.1.3.tgz#65ff5f2175324d80c41083b0e135d1464b12ac35" - integrity sha512-VkG9g4BbhMBy+N5/XodDeV6F02chEk9IpgRTq/0bS80y4dzy79VH2Gtms02VXomf3HmyRe3yyJYkJ990ns+d6A== +aes-decrypter@4.0.1, aes-decrypter@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/aes-decrypter/-/aes-decrypter-4.0.1.tgz#c1a81d0bde0e96fed0674488d2a31a6d7ab9b7a7" + integrity sha512-H1nh/P9VZXUf17AA5NQfJML88CFjVBDuGkp5zDHa7oEhYN9TTpNLJknRY1ie0iSKWlDf6JRnJKaZVDSQdPy6Cg== dependencies: "@babel/runtime" "^7.12.5" "@videojs/vhs-utils" "^3.0.5" @@ -8128,7 +8158,7 @@ glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -global@^4.3.0, global@^4.3.1, global@^4.3.2, global@^4.4.0, global@~4.4.0: +global@4.4.0, global@^4.3.0, global@^4.3.1, global@^4.4.0, global@~4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== @@ -9755,10 +9785,10 @@ katex@0.16.9, katex@^0.16.0: dependencies: commander "^8.3.0" -keycode@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.1.tgz#09c23b2be0611d26117ea2501c2c391a01f39eff" - integrity sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg== +keycode@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04" + integrity sha512-ps3I9jAdNtRpJrbBvQjpzyFbss/skHqzS+eu4RxKLaEAtFqkjZaB6TZMSivPbLxf4K7VI4SjR0P5mRCX5+Q25A== keyv@^4.5.3: version "4.5.4" @@ -9993,7 +10023,16 @@ lz-string@^1.5.0: resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== -m3u8-parser@4.8.0, m3u8-parser@^4.4.0: +m3u8-parser@7.1.0, m3u8-parser@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/m3u8-parser/-/m3u8-parser-7.1.0.tgz#fa92ee22fc798150397c297152c879fe09f066c6" + integrity sha512-7N+pk79EH4oLKPEYdgRXgAsKDyA/VCo0qCHlUwacttQA0WqsjZQYmNfywMvjlY9MpEBVZEt0jKFd73Kv15EBYQ== + dependencies: + "@babel/runtime" "^7.12.5" + "@videojs/vhs-utils" "^3.0.5" + global "^4.4.0" + +m3u8-parser@^4.4.0: version "4.8.0" resolved "https://registry.yarnpkg.com/m3u8-parser/-/m3u8-parser-4.8.0.tgz#4a2d591fdf6f2579d12a327081198df8af83083d" integrity sha512-UqA2a/Pw3liR6Df3gwxrqghCP17OpPlQj6RBPLYygf/ZSQ4MoSgvdvhvt35qV+3NaaA0FSZx93Ix+2brT1U7cA== @@ -10002,10 +10041,10 @@ m3u8-parser@4.8.0, m3u8-parser@^4.4.0: "@videojs/vhs-utils" "^3.0.5" global "^4.4.0" -m3u8-parser@7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/m3u8-parser/-/m3u8-parser-7.1.0.tgz#fa92ee22fc798150397c297152c879fe09f066c6" - integrity sha512-7N+pk79EH4oLKPEYdgRXgAsKDyA/VCo0qCHlUwacttQA0WqsjZQYmNfywMvjlY9MpEBVZEt0jKFd73Kv15EBYQ== +m3u8-parser@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/m3u8-parser/-/m3u8-parser-6.2.0.tgz#5b2f2fe103b76bd3ffc77c6b1eafc3772b1251dd" + integrity sha512-qlC00JTxYOxawcqg+RB8jbyNwL3foY/nCY61kyWP+RCuJE9APLeqB/nSlTjb4Mg0yRmyERgjswpdQxMvkeoDrg== dependencies: "@babel/runtime" "^7.12.5" "@videojs/vhs-utils" "^3.0.5" @@ -10879,13 +10918,13 @@ moment-mini@2.24.0: resolved "https://registry.yarnpkg.com/moment-mini/-/moment-mini-2.24.0.tgz#fa68d98f7fe93ae65bf1262f6abb5fb6983d8d18" integrity sha512-9ARkWHBs+6YJIvrIp0Ik5tyTTtP9PoV0Ssu2Ocq5y9v8+NOOpWiRshAp8c4rZVWTOe+157on/5G+zj5pwIQFEQ== -mpd-parser@0.22.1, mpd-parser@^0.22.1: - version "0.22.1" - resolved "https://registry.yarnpkg.com/mpd-parser/-/mpd-parser-0.22.1.tgz#bc2bf7d3e56368e4b0121035b055675401871521" - integrity sha512-fwBebvpyPUU8bOzvhX0VQZgSohncbgYwUyJJoTSNpmy7ccD2ryiCvM7oRkn/xQH5cv73/xU7rJSNCLjdGFor0Q== +mpd-parser@^1.0.1, mpd-parser@^1.2.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/mpd-parser/-/mpd-parser-1.3.0.tgz#38c20f4d73542b4ed554158bc1f0fa571dc61388" + integrity sha512-WgeIwxAqkmb9uTn4ClicXpEQYCEduDqRKfmUdp4X8vmghKfBNXZLYpREn9eqrDx/Tf5LhzRcJLSpi4ohfV742Q== dependencies: "@babel/runtime" "^7.12.5" - "@videojs/vhs-utils" "^3.0.5" + "@videojs/vhs-utils" "^4.0.0" "@xmldom/xmldom" "^0.8.3" global "^4.4.0" @@ -10904,10 +10943,18 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -mux.js@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-6.0.1.tgz#65ce0f7a961d56c006829d024d772902d28c7755" - integrity sha512-22CHb59rH8pWGcPGW5Og7JngJ9s+z4XuSlYvnxhLuc58cA1WqGDQPzuG8I+sPm1/p0CdgpzVTaKW408k5DNn8w== +mux.js@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-7.0.1.tgz#745c77b0fb8aa81dbb47e96651428bfada49b08e" + integrity sha512-Omz79uHqYpMP1V80JlvEdCiOW1hiw4mBvDh9gaZEpxvB+7WYb2soZSzfuSRrK2Kh9Pm6eugQNrIpY/Bnyhk4hw== + dependencies: + "@babel/runtime" "^7.11.2" + global "^4.4.0" + +mux.js@7.0.2, mux.js@^7.0.1: + version "7.0.2" + resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-7.0.2.tgz#410641dc922c5d173d7ce45fbdb2bb9e2a69137c" + integrity sha512-CM6+QuyDbc0qW1OfEjkd2+jVKzTXF+z5VOKH0eZxtZtnrG/ilkW/U7l7IXGtBNLASF9sKZMcK1u669cq50Qq0A== dependencies: "@babel/runtime" "^7.11.2" global "^4.4.0" @@ -13375,51 +13422,66 @@ vfile@^6.0.0: unist-util-stringify-position "^4.0.0" vfile-message "^4.0.0" -video.js@7.21.1, "video.js@^6 || ^7", "video.js@^6 || ^7 || ^8", video.js@^7.0.0: - version "7.21.1" - resolved "https://registry.yarnpkg.com/video.js/-/video.js-7.21.1.tgz#c018e1d0f0643661fcebd5ca355e9723cc82312a" - integrity sha512-AvHfr14ePDHCfW5Lx35BvXk7oIonxF6VGhSxocmTyqotkQpxwYdmt4tnQSV7MYzNrYHb0GI8tJMt20NDkCQrxg== +video.js@8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/video.js/-/video.js-8.7.0.tgz#ef8954c4d4489aa403c5116b027b7cb19c13dd0a" + integrity sha512-QAYQKsqyO/jxDed1AYdD4cEYQIuxGuqzMmfyyL3ZTgbCjo+f/XF+1Hw9aC1SZN6Wx3qDVLWKF7oB22uWST0N9w== dependencies: "@babel/runtime" "^7.12.5" - "@videojs/http-streaming" "2.15.1" - "@videojs/vhs-utils" "^3.0.4" + "@videojs/http-streaming" "3.8.0" + "@videojs/vhs-utils" "^4.0.0" "@videojs/xhr" "2.6.0" - aes-decrypter "3.1.3" - global "^4.4.0" - keycode "^2.2.0" - m3u8-parser "4.8.0" - mpd-parser "0.22.1" - mux.js "6.0.1" + aes-decrypter "^4.0.1" + global "4.4.0" + keycode "2.2.0" + m3u8-parser "^7.1.0" + mpd-parser "^1.2.2" + mux.js "^7.0.1" safe-json-parse "4.0.0" - videojs-font "3.2.0" - videojs-vtt.js "^0.15.4" + videojs-contrib-quality-levels "4.0.0" + videojs-font "4.1.0" + videojs-vtt.js "0.15.5" -videojs-contrib-quality-levels@2.2.1, videojs-contrib-quality-levels@^2.0.4: - version "2.2.1" - resolved "https://registry.yarnpkg.com/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-2.2.1.tgz#46bd7e1db25e6e45824dadf933b08f0c6ec724a1" - integrity sha512-cnF6OGGgoC/2nUrbdz54nzPm3BpEZQzMTpyekiX6AXs8imATX2sHbrUz97xXVSHITldk/+d7ZAUrdQYJJTyuug== +"video.js@^7 || ^8": + version "8.6.1" + resolved "https://registry.yarnpkg.com/video.js/-/video.js-8.6.1.tgz#d25f59fbf30fb21c0bcf04a1de6a98dfd137997c" + integrity sha512-CNYVJ5WWIZ7bOhbkkfcKqLGoc6WsE3Ft2RfS1lXdQTWk8UiSsPW2Ssk2JzPCA8qnIlUG9os/faCFsYWjyu4JcA== dependencies: - global "^4.3.2" - video.js "^6 || ^7 || ^8" - -videojs-font@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-3.2.0.tgz#212c9d3f4e4ec3fa7345167d64316add35e92232" - integrity sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA== + "@babel/runtime" "^7.12.5" + "@videojs/http-streaming" "3.7.0" + "@videojs/vhs-utils" "^4.0.0" + "@videojs/xhr" "2.6.0" + aes-decrypter "^4.0.1" + global "4.4.0" + keycode "2.2.0" + m3u8-parser "^6.0.0" + mpd-parser "^1.0.1" + mux.js "^7.0.1" + safe-json-parse "4.0.0" + videojs-contrib-quality-levels "4.0.0" + videojs-font "4.1.0" + videojs-vtt.js "0.15.5" -videojs-http-source-selector@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/videojs-http-source-selector/-/videojs-http-source-selector-1.1.6.tgz#073aadbea0106ba6c98d6b611094dbf8554ffa1f" - integrity sha512-6b5MmKTT2cVnrjtdNj4z1VO91udbXkZkTYA6LlD8WN2aHlG2rqFTmtMab4NK4nlkkkbRnm3c2q2IddL3jffLmg== +videojs-contrib-quality-levels@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/videojs-contrib-quality-levels/-/videojs-contrib-quality-levels-4.0.0.tgz#faa8096594cdbfc3ccbefe8572fc20531ba23f3d" + integrity sha512-u5rmd8BjLwANp7XwuQ0Q/me34bMe6zg9PQdHfTS7aXgiVRbNTb4djcmfG7aeSrkpZjg+XCLezFNenlJaCjBHKw== dependencies: - global "^4.3.2" - video.js "^7.0.0" - videojs-contrib-quality-levels "^2.0.4" + global "^4.4.0" + +videojs-font@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/videojs-font/-/videojs-font-4.1.0.tgz#3ae1dbaac60b4f0f1c4e6f7ff9662a89df176015" + integrity sha512-X1LuPfLZPisPLrANIAKCknZbZu5obVM/ylfd1CN+SsCmPZQ3UMDPcvLTpPBJxcBuTpHQq2MO1QCFt7p8spnZ/w== + +"videojs-http-source-selector@https://github.com/FreeTubeApp/videojs-http-source-selector.git": + version "1.1.7" + resolved "https://github.com/FreeTubeApp/videojs-http-source-selector.git#dfab172b1bd7b1f611434269c0a0bbe07bfdbb8b" -videojs-vtt.js@^0.15.4: - version "0.15.4" - resolved "https://registry.yarnpkg.com/videojs-vtt.js/-/videojs-vtt.js-0.15.4.tgz#5dc5aabcd82ba40c5595469bd855ea8230ca152c" - integrity sha512-r6IhM325fcLb1D6pgsMkTQT1PpFdUdYZa1iqk7wJEu+QlibBwATPfPc9Bg8Jiym0GE5yP1AG2rMLu+QMVWkYtA== +videojs-vtt.js@0.15.5: + version "0.15.5" + resolved "https://registry.yarnpkg.com/videojs-vtt.js/-/videojs-vtt.js-0.15.5.tgz#567776eaf2a7a928d88b148a8b401ade2406f2ca" + integrity sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ== dependencies: global "^4.3.1"