Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⬆️ videojs upgrade #2535

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 1 addition & 3 deletions renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@
"rehype-highlight",
"rehype-raw",
"remark-math",
"styled-components",
"video.js",
"videojs-contrib-quality-levels"
"styled-components"
]
},
{
Expand Down
6 changes: 6 additions & 0 deletions src/frontend/apps/lti_site/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
module.exports = {
plugins: [
[
'@babel/plugin-transform-typescript',
{
allowDeclareFields: true,
},
],
[
'react-intl',
{
Expand Down
1 change: 1 addition & 0 deletions src/frontend/apps/lti_site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
6 changes: 6 additions & 0 deletions src/frontend/apps/standalone_site/babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
1 change: 1 addition & 0 deletions src/frontend/apps/standalone_site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "*",
Expand Down
1 change: 1 addition & 0 deletions src/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
6 changes: 6 additions & 0 deletions src/frontend/packages/lib_video/babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
11 changes: 6 additions & 5 deletions src/frontend/packages/lib_video/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "*",
Expand All @@ -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",
Expand All @@ -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": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -12,22 +11,17 @@ 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 = (
videoNode: HTMLVideoElement,
dispatchPlayerTimeUpdate: (time: number) => void,
video: Video,
locale: Maybe<string>,
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
Expand All @@ -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<Plugins> = {};

if (!isMSESupported()) {
plugins.qualitySelector = {
Expand All @@ -67,7 +61,7 @@ export const createVideojsPlayer = (
});
}

const options: VideoJsPlayerOptions = {
const options = {
autoplay: video.is_live,
controls: true,
controlBar: {
Expand Down Expand Up @@ -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()) {
Expand All @@ -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 });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
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',
description: 'Title of the download video button inside the video player.',
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',
Expand All @@ -42,12 +49,15 @@ 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],
}),
);
}
}

videojs.registerComponent('DownloadVideoButton', DownloadVideoButton);
videojs.registerComponent(
'DownloadVideoButton',
DownloadVideoButton as unknown as typeof Component,
);
Original file line number Diff line number Diff line change
@@ -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<DownloadVideoQualityItemOptions>,
) {
options.selectable = false;
options.multiSelectable = false;

super(player, options);
this.setAttribute('title', options.label);
this.setAttribute('title', options.label || '');
this.source = options.src;
}

Expand All @@ -34,4 +37,7 @@ export class DownloadVideoQualityItem extends MenuItem {
}
}

Component.registerComponent('DownloadVideoMenuItem', DownloadVideoQualityItem);
videojs.registerComponent(
'DownloadVideoMenuItem',
DownloadVideoQualityItem as unknown as typeof Component,
);
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
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;
}

export interface DownloadVideoPluginOptions {
urls: Partial<urls>;
}

export class DownloadVideoPlugin extends Plugin {
declare player: Player;

constructor(player: Player, _options?: DownloadVideoPluginOptions) {
super(player);
}
}

export type DownloadVideoPluginType = typeof DownloadVideoPlugin;
Loading