mirror of https://github.com/Chocobozzz/PeerTube
Fallback HLS to webtorrent
parent
0920929696
commit
6ec0b75beb
|
@ -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 () => {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue