Fallback HLS to webtorrent

pull/1625/head
Chocobozzz 2019-02-06 10:39:50 +01:00 committed by Chocobozzz
parent 0920929696
commit 6ec0b75beb
5 changed files with 78 additions and 19 deletions

View File

@ -23,7 +23,13 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
import { environment } from '../../../environments/environment'
import { VideoCaptionService } from '@app/shared/video-caption'
import { MarkdownService } from '@app/shared/renderer'
import { P2PMediaLoaderOptions, PeertubePlayerManager, PlayerMode, WebtorrentOptions } from '../../../assets/player/peertube-player-manager'
import {
P2PMediaLoaderOptions,
PeertubePlayerManager,
PeertubePlayerManagerOptions,
PlayerMode,
WebtorrentOptions
} from '../../../assets/player/peertube-player-manager'
@Component({
selector: 'my-video-watch',
@ -395,10 +401,13 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
src: environment.apiUrl + c.captionPath
}))
const options = {
const options: PeertubePlayerManagerOptions = {
common: {
autoplay: this.isAutoplay(),
playerElement: this.playerElement,
onPlayerElementChange: (element: HTMLVideoElement) => this.playerElement = element,
videoDuration: this.video.duration,
enableHotkeys: true,
inactivityTimeout: 2500,
@ -424,6 +433,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
serverUrl: environment.apiUrl,
videoCaptions: playerCaptions
},
webtorrent: {
videoFiles: this.video.files
}
}
@ -431,6 +444,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
const hlsPlaylist = this.video.getHlsPlaylist()
if (hlsPlaylist) {
mode = 'p2p-media-loader'
const p2pMediaLoader = {
playlistUrl: hlsPlaylist.playlistUrl,
segmentsSha256Url: hlsPlaylist.segmentsSha256Url,
@ -442,11 +456,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
Object.assign(options, { p2pMediaLoader })
} else {
mode = 'webtorrent'
const webtorrent = {
videoFiles: this.video.files
} as WebtorrentOptions
Object.assign(options, { webtorrent })
}
this.zone.runOutsideAngular(async () => {

View File

@ -51,17 +51,25 @@ class P2pMediaLoaderPlugin extends Plugin {
src: options.src
})
player.on('play', () => {
player.addClass('vjs-has-big-play-button-clicked')
})
player.ready(() => this.initialize())
}
dispose () {
if (this.hlsjs) this.hlsjs.destroy()
if (this.p2pEngine) this.p2pEngine.destroy()
clearInterval(this.networkInfoInterval)
}
private initialize () {
initHlsJsPlayer(this.hlsjs)
this.p2pEngine = this.player.tech_.options_.hlsjsConfig.loader.getEngine()
const tech = this.player.tech_
this.p2pEngine = tech.options_.hlsjsConfig.loader.getEngine()
// Avoid using constants to not import hls.hs
// https://github.com/video-dev/hls.js/blob/master/src/events.js#L37

View File

@ -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,

View File

@ -47,7 +47,11 @@ class PeerTubePlugin extends Plugin {
this.videoDuration = options.videoDuration
this.videoCaptions = options.videoCaptions
if (this.autoplay === true) this.player.addClass('vjs-has-autoplay')
if (options.autoplay === true) this.player.addClass('vjs-has-autoplay')
this.player.on('autoplay-failure', () => {
this.player.removeClass('vjs-has-autoplay')
})
this.player.ready(() => {
const playerOptions = this.player.options_

View File

@ -311,7 +311,10 @@ class PeerTubeEmbed {
videoCaptions,
inactivityTimeout: 1500,
videoViewUrl: this.getVideoUrl(videoId) + '/views',
playerElement: this.videoElement,
onPlayerElementChange: (element: HTMLVideoElement) => this.videoElement = element,
videoDuration: videoInfo.duration,
enableHotkeys: true,
peertubeLink: true,
@ -321,6 +324,10 @@ class PeerTubeEmbed {
serverUrl: window.location.origin,
language: navigator.language,
embedUrl: window.location.origin + videoInfo.embedPath
},
webtorrent: {
videoFiles: videoInfo.files
}
}
@ -336,12 +343,6 @@ class PeerTubeEmbed {
videoFiles: videoInfo.files
} as P2PMediaLoaderOptions
})
} else {
Object.assign(options, {
webtorrent: {
videoFiles: videoInfo.files
}
})
}
this.player = await PeertubePlayerManager.initialize(this.mode, options)