From 2adfc7ea9a1f858db874df9fe322e7ae833db77c Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 23 Jan 2019 15:36:45 +0100 Subject: Refractor videojs player Add fake p2p-media-loader plugin --- .../src/assets/player/peertube-player-manager.ts | 388 +++++++++++++++++++++ 1 file changed, 388 insertions(+) create mode 100644 client/src/assets/player/peertube-player-manager.ts (limited to 'client/src/assets/player/peertube-player-manager.ts') diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts new file mode 100644 index 000000000..9155c0698 --- /dev/null +++ b/client/src/assets/player/peertube-player-manager.ts @@ -0,0 +1,388 @@ +import { VideoFile } from '../../../../shared/models/videos' +// @ts-ignore +import * as videojs from 'video.js' +import 'videojs-hotkeys' +import 'videojs-dock' +import 'videojs-contextmenu-ui' +import 'videojs-contrib-quality-levels' +import './peertube-plugin' +import './videojs-components/peertube-link-button' +import './videojs-components/resolution-menu-button' +import './videojs-components/settings-menu-button' +import './videojs-components/p2p-info-button' +import './videojs-components/peertube-load-progress-bar' +import './videojs-components/theater-button' +import { P2PMediaLoaderPluginOptions, UserWatching, VideoJSCaption, VideoJSPluginOptions, videojsUntyped } from './peertube-videojs-typings' +import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' +import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' +import { Engine } from 'p2p-media-loader-hlsjs' + +// Change 'Playback Rate' to 'Speed' (smaller for our settings menu) +videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' +// Change Captions to Subtitles/CC +videojsUntyped.getComponent('CaptionsButton').prototype.controlText_ = 'Subtitles/CC' +// We just want to display 'Off' instead of 'captions off', keep a space so the variable == true (hacky I know) +videojsUntyped.getComponent('CaptionsButton').prototype.label_ = ' ' + +type PlayerMode = 'webtorrent' | 'p2p-media-loader' + +type WebtorrentOptions = { + videoFiles: VideoFile[] +} + +type P2PMediaLoaderOptions = { + playlistUrl: string +} + +type CommonOptions = { + playerElement: HTMLVideoElement + + autoplay: boolean + videoDuration: number + enableHotkeys: boolean + inactivityTimeout: number + poster: string + startTime: number | string + + theaterMode: boolean + captions: boolean + peertubeLink: boolean + + videoViewUrl: string + embedUrl: string + + language?: string + controls?: boolean + muted?: boolean + loop?: boolean + subtitle?: string + + videoCaptions: VideoJSCaption[] + + userWatching?: UserWatching + + serverUrl: string +} + +export type PeertubePlayerManagerOptions = { + common: CommonOptions, + webtorrent?: WebtorrentOptions, + p2pMediaLoader?: P2PMediaLoaderOptions +} + +export class PeertubePlayerManager { + + private static videojsLocaleCache: { [ path: string ]: any } = {} + + static getServerTranslations (serverUrl: string, locale: string) { + const path = PeertubePlayerManager.getLocalePath(serverUrl, locale) + // It is the default locale, nothing to translate + if (!path) return Promise.resolve(undefined) + + return fetch(path + '/server.json') + .then(res => res.json()) + .catch(err => { + console.error('Cannot get server translations', err) + return undefined + }) + } + + static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions) { + if (mode === 'webtorrent') await import('./webtorrent-plugin') + if (mode === 'p2p-media-loader') await import('./p2p-media-loader-plugin') + + const videojsOptions = this.getVideojsOptions(mode, options) + + await this.loadLocaleInVideoJS(options.common.serverUrl, options.common.language) + + const self = this + return new Promise(res => { + videojs(options.common.playerElement, videojsOptions, function (this: any) { + const player = this + + self.addContextMenu(mode, player, options.common.embedUrl) + + return res(player) + }) + }) + } + + private static loadLocaleInVideoJS (serverUrl: string, locale: string) { + const path = PeertubePlayerManager.getLocalePath(serverUrl, locale) + // It is the default locale, nothing to translate + if (!path) return Promise.resolve(undefined) + + let p: Promise + + if (PeertubePlayerManager.videojsLocaleCache[path]) { + p = Promise.resolve(PeertubePlayerManager.videojsLocaleCache[path]) + } else { + p = fetch(path + '/player.json') + .then(res => res.json()) + .then(json => { + PeertubePlayerManager.videojsLocaleCache[path] = json + return json + }) + .catch(err => { + console.error('Cannot get player translations', err) + return undefined + }) + } + + const completeLocale = getCompleteLocale(locale) + return p.then(json => videojs.addLanguage(getShortLocale(completeLocale), json)) + } + + private static getVideojsOptions (mode: PlayerMode, options: PeertubePlayerManagerOptions) { + const commonOptions = options.common + const webtorrentOptions = options.webtorrent + const p2pMediaLoaderOptions = options.p2pMediaLoader + + const plugins: VideoJSPluginOptions = { + peertube: { + autoplay: commonOptions.autoplay, // Use peertube plugin autoplay because we get the file by webtorrent + videoViewUrl: commonOptions.videoViewUrl, + videoDuration: commonOptions.videoDuration, + startTime: commonOptions.startTime, + userWatching: commonOptions.userWatching, + subtitle: commonOptions.subtitle, + videoCaptions: commonOptions.videoCaptions + } + } + + if (p2pMediaLoaderOptions) { + const p2pMediaLoader: P2PMediaLoaderPluginOptions = { + type: 'application/x-mpegURL', + src: p2pMediaLoaderOptions.playlistUrl + } + + const config = { + segments: { + swarmId: 'swarm' // TODO: choose swarm id + } + } + const streamrootHls = { + html5: { + hlsjsConfig: { + liveSyncDurationCount: 7, + loader: new Engine(config).createLoaderClass() + } + } + } + + Object.assign(plugins, { p2pMediaLoader, streamrootHls }) + } + + if (webtorrentOptions) { + const webtorrent = { + autoplay: commonOptions.autoplay, + videoDuration: commonOptions.videoDuration, + playerElement: commonOptions.playerElement, + videoFiles: webtorrentOptions.videoFiles + } + Object.assign(plugins, { webtorrent }) + } + + const videojsOptions = { + // We don't use text track settings for now + textTrackSettings: false, + controls: commonOptions.controls !== undefined ? commonOptions.controls : true, + loop: commonOptions.loop !== undefined ? commonOptions.loop : false, + + muted: commonOptions.muted !== undefined + ? commonOptions.muted + : undefined, // Undefined so the player knows it has to check the local storage + + poster: commonOptions.poster, + autoplay: false, + inactivityTimeout: commonOptions.inactivityTimeout, + playbackRates: [ 0.5, 0.75, 1, 1.25, 1.5, 2 ], + plugins, + controlBar: { + children: this.getControlBarChildren(mode, { + captions: commonOptions.captions, + peertubeLink: commonOptions.peertubeLink, + theaterMode: commonOptions.theaterMode + }) + } + } + + if (commonOptions.enableHotkeys === true) { + Object.assign(videojsOptions.plugins, { + hotkeys: { + enableVolumeScroll: false, + enableModifiersForNumbers: false, + + fullscreenKey: function (event: KeyboardEvent) { + // fullscreen with the f key or Ctrl+Enter + return event.key === 'f' || (event.ctrlKey && event.key === 'Enter') + }, + + seekStep: function (event: KeyboardEvent) { + // mimic VLC seek behavior, and default to 5 (original value is 5). + if (event.ctrlKey && event.altKey) { + return 5 * 60 + } else if (event.ctrlKey) { + return 60 + } else if (event.altKey) { + return 10 + } else { + return 5 + } + }, + + customKeys: { + increasePlaybackRateKey: { + key: function (event: KeyboardEvent) { + return event.key === '>' + }, + handler: function (player: videojs.Player) { + player.playbackRate((player.playbackRate() + 0.1).toFixed(2)) + } + }, + decreasePlaybackRateKey: { + key: function (event: KeyboardEvent) { + return event.key === '<' + }, + handler: function (player: videojs.Player) { + player.playbackRate((player.playbackRate() - 0.1).toFixed(2)) + } + }, + frameByFrame: { + key: function (event: KeyboardEvent) { + return event.key === '.' + }, + handler: function (player: videojs.Player) { + player.pause() + // Calculate movement distance (assuming 30 fps) + const dist = 1 / 30 + player.currentTime(player.currentTime() + dist) + } + } + } + } + }) + } + + if (commonOptions.language && !isDefaultLocale(commonOptions.language)) { + Object.assign(videojsOptions, { language: commonOptions.language }) + } + + return videojsOptions + } + + private static getControlBarChildren (mode: PlayerMode, options: { + peertubeLink: boolean + theaterMode: boolean, + captions: boolean + }) { + const settingEntries = [] + const loadProgressBar = mode === 'webtorrent' ? 'peerTubeLoadProgressBar' : 'loadProgressBar' + + // Keep an order + settingEntries.push('playbackRateMenuButton') + if (options.captions === true) settingEntries.push('captionsButton') + settingEntries.push('resolutionMenuButton') + + const children = { + 'playToggle': {}, + 'currentTimeDisplay': {}, + 'timeDivider': {}, + 'durationDisplay': {}, + 'liveDisplay': {}, + + 'flexibleWidthSpacer': {}, + 'progressControl': { + children: { + 'seekBar': { + children: { + [loadProgressBar]: {}, + 'mouseTimeDisplay': {}, + 'playProgressBar': {} + } + } + } + }, + + 'p2PInfoButton': {}, + + 'muteToggle': {}, + 'volumeControl': {}, + + 'settingsButton': { + setup: { + maxHeightOffset: 40 + }, + entries: settingEntries + } + } + + if (options.peertubeLink === true) { + Object.assign(children, { + 'peerTubeLinkButton': {} + }) + } + + if (options.theaterMode === true) { + Object.assign(children, { + 'theaterButton': {} + }) + } + + Object.assign(children, { + 'fullscreenToggle': {} + }) + + return children + } + + private static addContextMenu (mode: PlayerMode, player: any, videoEmbedUrl: string) { + const content = [ + { + label: player.localize('Copy the video URL'), + listener: function () { + copyToClipboard(buildVideoLink()) + } + }, + { + label: player.localize('Copy the video URL at the current time'), + listener: function () { + const player = this as videojs.Player + copyToClipboard(buildVideoLink(player.currentTime())) + } + }, + { + label: player.localize('Copy embed code'), + listener: () => { + copyToClipboard(buildVideoEmbed(videoEmbedUrl)) + } + } + ] + + if (mode === 'webtorrent') { + content.push({ + label: player.localize('Copy magnet URI'), + listener: function () { + const player = this as videojs.Player + copyToClipboard(player.webtorrent().getCurrentVideoFile().magnetUri) + } + }) + } + + player.contextmenuUI({ content }) + } + + private static getLocalePath (serverUrl: string, locale: string) { + const completeLocale = getCompleteLocale(locale) + + if (!is18nLocale(completeLocale) || isDefaultLocale(completeLocale)) return undefined + + return serverUrl + '/client/locales/' + completeLocale + } +} + +// ############################################################################ + +export { + videojs +} -- cgit v1.2.3 From 3b6f205c34bb931de0323581edf991ca33256e6b Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 24 Jan 2019 10:16:30 +0100 Subject: Correctly implement p2p-media-loader --- client/src/assets/player/peertube-player-manager.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'client/src/assets/player/peertube-player-manager.ts') diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 9155c0698..2e090847c 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts @@ -24,17 +24,17 @@ videojsUntyped.getComponent('CaptionsButton').prototype.controlText_ = 'Subtitle // We just want to display 'Off' instead of 'captions off', keep a space so the variable == true (hacky I know) videojsUntyped.getComponent('CaptionsButton').prototype.label_ = ' ' -type PlayerMode = 'webtorrent' | 'p2p-media-loader' +export type PlayerMode = 'webtorrent' | 'p2p-media-loader' -type WebtorrentOptions = { +export type WebtorrentOptions = { videoFiles: VideoFile[] } -type P2PMediaLoaderOptions = { +export type P2PMediaLoaderOptions = { playlistUrl: string } -type CommonOptions = { +export type CommonOptions = { playerElement: HTMLVideoElement autoplay: boolean @@ -137,6 +137,7 @@ export class PeertubePlayerManager { const commonOptions = options.common const webtorrentOptions = options.webtorrent const p2pMediaLoaderOptions = options.p2pMediaLoader + let html5 = {} const plugins: VideoJSPluginOptions = { peertube: { @@ -171,6 +172,7 @@ export class PeertubePlayerManager { } Object.assign(plugins, { p2pMediaLoader, streamrootHls }) + html5 = streamrootHls.html5 } if (webtorrentOptions) { @@ -184,6 +186,8 @@ export class PeertubePlayerManager { } const videojsOptions = { + html5, + // We don't use text track settings for now textTrackSettings: false, controls: commonOptions.controls !== undefined ? commonOptions.controls : true, -- cgit v1.2.3 From 4348a27d252a3349bafa7ef4859c0e2cf060c255 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 24 Jan 2019 13:43:44 +0100 Subject: Add lazy loading in player --- .../src/assets/player/peertube-player-manager.ts | 24 +++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'client/src/assets/player/peertube-player-manager.ts') diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 2e090847c..91ca6a2aa 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts @@ -15,7 +15,6 @@ import './videojs-components/theater-button' import { P2PMediaLoaderPluginOptions, UserWatching, VideoJSCaption, VideoJSPluginOptions, videojsUntyped } from './peertube-videojs-typings' import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' -import { Engine } from 'p2p-media-loader-hlsjs' // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' @@ -32,6 +31,7 @@ export type WebtorrentOptions = { export type P2PMediaLoaderOptions = { playlistUrl: string + trackerAnnounce: string[] } export type CommonOptions = { @@ -88,10 +88,17 @@ export class PeertubePlayerManager { } static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions) { + let p2pMediaLoader: any + if (mode === 'webtorrent') await import('./webtorrent-plugin') - if (mode === 'p2p-media-loader') await import('./p2p-media-loader-plugin') + if (mode === 'p2p-media-loader') { + [ p2pMediaLoader ] = await Promise.all([ + import('p2p-media-loader-hlsjs'), + import('./p2p-media-loader-plugin') + ]) + } - const videojsOptions = this.getVideojsOptions(mode, options) + const videojsOptions = this.getVideojsOptions(mode, options, p2pMediaLoader) await this.loadLocaleInVideoJS(options.common.serverUrl, options.common.language) @@ -133,7 +140,7 @@ export class PeertubePlayerManager { return p.then(json => videojs.addLanguage(getShortLocale(completeLocale), json)) } - private static getVideojsOptions (mode: PlayerMode, options: PeertubePlayerManagerOptions) { + private static getVideojsOptions (mode: PlayerMode, options: PeertubePlayerManagerOptions, p2pMediaLoaderModule?: any) { const commonOptions = options.common const webtorrentOptions = options.webtorrent const p2pMediaLoaderOptions = options.p2pMediaLoader @@ -157,16 +164,19 @@ export class PeertubePlayerManager { src: p2pMediaLoaderOptions.playlistUrl } - const config = { + const p2pMediaLoaderConfig = { + // loader: { + // trackerAnnounce: p2pMediaLoaderOptions.trackerAnnounce + // }, segments: { - swarmId: 'swarm' // TODO: choose swarm id + swarmId: p2pMediaLoaderOptions.playlistUrl } } const streamrootHls = { html5: { hlsjsConfig: { liveSyncDurationCount: 7, - loader: new Engine(config).createLoaderClass() + loader: new p2pMediaLoaderModule.Engine(p2pMediaLoaderConfig).createLoaderClass() } } } -- cgit v1.2.3 From 092092969633bbcf6d4891a083ea497a7d5c3154 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 29 Jan 2019 08:37:25 +0100 Subject: Add hls support on server --- .../src/assets/player/peertube-player-manager.ts | 45 +++++++++++++++++----- 1 file changed, 36 insertions(+), 9 deletions(-) (limited to 'client/src/assets/player/peertube-player-manager.ts') diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 91ca6a2aa..3fdba6fdf 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts @@ -13,8 +13,10 @@ import './videojs-components/p2p-info-button' import './videojs-components/peertube-load-progress-bar' import './videojs-components/theater-button' import { P2PMediaLoaderPluginOptions, UserWatching, VideoJSCaption, VideoJSPluginOptions, videojsUntyped } from './peertube-videojs-typings' -import { buildVideoEmbed, buildVideoLink, copyToClipboard } from './utils' +import { buildVideoEmbed, buildVideoLink, copyToClipboard, getRtcConfig } from './utils' import { getCompleteLocale, getShortLocale, is18nLocale, isDefaultLocale } from '../../../../shared/models/i18n/i18n' +import { segmentValidatorFactory } from './p2p-media-loader/segment-validator' +import { segmentUrlBuilderFactory } from './p2p-media-loader/segment-url-builder' // Change 'Playback Rate' to 'Speed' (smaller for our settings menu) videojsUntyped.getComponent('PlaybackRateMenuButton').prototype.controlText_ = 'Speed' @@ -31,7 +33,10 @@ export type WebtorrentOptions = { export type P2PMediaLoaderOptions = { playlistUrl: string + segmentsSha256Url: string trackerAnnounce: string[] + redundancyBaseUrls: string[] + videoFiles: VideoFile[] } export type CommonOptions = { @@ -90,11 +95,11 @@ export class PeertubePlayerManager { static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions) { let p2pMediaLoader: any - if (mode === 'webtorrent') await import('./webtorrent-plugin') + if (mode === 'webtorrent') await import('./webtorrent/webtorrent-plugin') if (mode === 'p2p-media-loader') { [ p2pMediaLoader ] = await Promise.all([ import('p2p-media-loader-hlsjs'), - import('./p2p-media-loader-plugin') + import('./p2p-media-loader/p2p-media-loader-plugin') ]) } @@ -144,11 +149,14 @@ export class PeertubePlayerManager { const commonOptions = options.common const webtorrentOptions = options.webtorrent const p2pMediaLoaderOptions = options.p2pMediaLoader + + let autoplay = options.common.autoplay let html5 = {} const plugins: VideoJSPluginOptions = { peertube: { - autoplay: commonOptions.autoplay, // Use peertube plugin autoplay because we get the file by webtorrent + mode, + autoplay, // Use peertube plugin autoplay because we get the file by webtorrent videoViewUrl: commonOptions.videoViewUrl, videoDuration: commonOptions.videoDuration, startTime: commonOptions.startTime, @@ -160,19 +168,35 @@ export class PeertubePlayerManager { if (p2pMediaLoaderOptions) { const p2pMediaLoader: P2PMediaLoaderPluginOptions = { + redundancyBaseUrls: options.p2pMediaLoader.redundancyBaseUrls, type: 'application/x-mpegURL', src: p2pMediaLoaderOptions.playlistUrl } + const trackerAnnounce = p2pMediaLoaderOptions.trackerAnnounce + .filter(t => t.startsWith('ws')) + const p2pMediaLoaderConfig = { - // loader: { - // trackerAnnounce: p2pMediaLoaderOptions.trackerAnnounce - // }, + loader: { + trackerAnnounce, + segmentValidator: segmentValidatorFactory(options.p2pMediaLoader.segmentsSha256Url), + rtcConfig: getRtcConfig(), + requiredSegmentsPriority: 5, + segmentUrlBuilder: segmentUrlBuilderFactory(options.p2pMediaLoader.redundancyBaseUrls) + }, segments: { swarmId: p2pMediaLoaderOptions.playlistUrl } } const streamrootHls = { + levelLabelHandler: (level: { height: number, width: number }) => { + const file = p2pMediaLoaderOptions.videoFiles.find(f => f.resolution.id === level.height) + + let label = file.resolution.label + if (file.fps >= 50) label += file.fps + + return label + }, html5: { hlsjsConfig: { liveSyncDurationCount: 7, @@ -187,12 +211,15 @@ export class PeertubePlayerManager { if (webtorrentOptions) { const webtorrent = { - autoplay: commonOptions.autoplay, + autoplay, videoDuration: commonOptions.videoDuration, playerElement: commonOptions.playerElement, videoFiles: webtorrentOptions.videoFiles } Object.assign(plugins, { webtorrent }) + + // WebTorrent plugin handles autoplay, because we do some hackish stuff in there + autoplay = false } const videojsOptions = { @@ -208,7 +235,7 @@ export class PeertubePlayerManager { : undefined, // Undefined so the player knows it has to check the local storage poster: commonOptions.poster, - autoplay: false, + autoplay, inactivityTimeout: commonOptions.inactivityTimeout, playbackRates: [ 0.5, 0.75, 1, 1.25, 1.5, 2 ], plugins, -- cgit v1.2.3 From 6ec0b75beb9c8bcd84e178912319913b91830da2 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 6 Feb 2019 10:39:50 +0100 Subject: Fallback HLS to webtorrent --- .../src/assets/player/peertube-player-manager.ts | 45 ++++++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) (limited to 'client/src/assets/player/peertube-player-manager.ts') diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 3fdba6fdf..0ba9bcb11 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts @@ -41,6 +41,7 @@ export type P2PMediaLoaderOptions = { export type CommonOptions = { playerElement: HTMLVideoElement + onPlayerElementChange: (element: HTMLVideoElement) => void autoplay: boolean videoDuration: number @@ -71,13 +72,14 @@ export type CommonOptions = { export type PeertubePlayerManagerOptions = { common: CommonOptions, - webtorrent?: WebtorrentOptions, + webtorrent: WebtorrentOptions, p2pMediaLoader?: P2PMediaLoaderOptions } export class PeertubePlayerManager { private static videojsLocaleCache: { [ path: string ]: any } = {} + private static playerElementClassName: string static getServerTranslations (serverUrl: string, locale: string) { const path = PeertubePlayerManager.getLocalePath(serverUrl, locale) @@ -95,6 +97,8 @@ export class PeertubePlayerManager { static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions) { let p2pMediaLoader: any + this.playerElementClassName = options.common.playerElement.className + if (mode === 'webtorrent') await import('./webtorrent/webtorrent-plugin') if (mode === 'p2p-media-loader') { [ p2pMediaLoader ] = await Promise.all([ @@ -112,6 +116,13 @@ export class PeertubePlayerManager { videojs(options.common.playerElement, videojsOptions, function (this: any) { const player = this + player.tech_.on('error', () => { + // Fallback to webtorrent? + if (mode === 'p2p-media-loader') { + self.fallbackToWebTorrent(player, options) + } + }) + self.addContextMenu(mode, player, options.common.embedUrl) return res(player) @@ -119,6 +130,32 @@ export class PeertubePlayerManager { }) } + private static async fallbackToWebTorrent (player: any, options: PeertubePlayerManagerOptions) { + const newVideoElement = document.createElement('video') + newVideoElement.className = this.playerElementClassName + + // VideoJS wraps our video element inside a div + const currentParentPlayerElement = options.common.playerElement.parentNode + currentParentPlayerElement.parentNode.insertBefore(newVideoElement, currentParentPlayerElement) + + options.common.playerElement = newVideoElement + options.common.onPlayerElementChange(newVideoElement) + + player.dispose() + + await import('./webtorrent/webtorrent-plugin') + + const mode = 'webtorrent' + const videojsOptions = this.getVideojsOptions(mode, options) + + const self = this + videojs(newVideoElement, videojsOptions, function (this: any) { + const player = this + + self.addContextMenu(mode, player, options.common.embedUrl) + }) + } + private static loadLocaleInVideoJS (serverUrl: string, locale: string) { const path = PeertubePlayerManager.getLocalePath(serverUrl, locale) // It is the default locale, nothing to translate @@ -166,7 +203,7 @@ export class PeertubePlayerManager { } } - if (p2pMediaLoaderOptions) { + if (mode === 'p2p-media-loader') { const p2pMediaLoader: P2PMediaLoaderPluginOptions = { redundancyBaseUrls: options.p2pMediaLoader.redundancyBaseUrls, type: 'application/x-mpegURL', @@ -209,7 +246,7 @@ export class PeertubePlayerManager { html5 = streamrootHls.html5 } - if (webtorrentOptions) { + if (mode === 'webtorrent') { const webtorrent = { autoplay, videoDuration: commonOptions.videoDuration, @@ -235,7 +272,7 @@ export class PeertubePlayerManager { : undefined, // Undefined so the player knows it has to check the local storage poster: commonOptions.poster, - autoplay, + autoplay: autoplay === true ? 'any' : autoplay, // Use 'any' instead of true to get notifier by videojs if autoplay fails inactivityTimeout: commonOptions.inactivityTimeout, playbackRates: [ 0.5, 0.75, 1, 1.25, 1.5, 2 ], plugins, -- cgit v1.2.3