aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-02-06 10:39:50 +0100
committerChocobozzz <chocobozzz@cpy.re>2019-02-11 09:13:02 +0100
commit6ec0b75beb9c8bcd84e178912319913b91830da2 (patch)
treed6fbcb774c5019fc20f42e8f9da4529545fdcbf9 /client/src
parent092092969633bbcf6d4891a083ea497a7d5c3154 (diff)
downloadPeerTube-6ec0b75beb9c8bcd84e178912319913b91830da2.tar.gz
PeerTube-6ec0b75beb9c8bcd84e178912319913b91830da2.tar.zst
PeerTube-6ec0b75beb9c8bcd84e178912319913b91830da2.zip
Fallback HLS to webtorrent
Diffstat (limited to 'client/src')
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts23
-rw-r--r--client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts10
-rw-r--r--client/src/assets/player/peertube-player-manager.ts45
-rw-r--r--client/src/assets/player/peertube-plugin.ts6
-rw-r--r--client/src/standalone/videos/embed.ts13
5 files changed, 78 insertions, 19 deletions
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts
index f77316712..e1766255b 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -23,7 +23,13 @@ import { I18n } from '@ngx-translate/i18n-polyfill'
23import { environment } from '../../../environments/environment' 23import { environment } from '../../../environments/environment'
24import { VideoCaptionService } from '@app/shared/video-caption' 24import { VideoCaptionService } from '@app/shared/video-caption'
25import { MarkdownService } from '@app/shared/renderer' 25import { MarkdownService } from '@app/shared/renderer'
26import { P2PMediaLoaderOptions, PeertubePlayerManager, PlayerMode, WebtorrentOptions } from '../../../assets/player/peertube-player-manager' 26import {
27 P2PMediaLoaderOptions,
28 PeertubePlayerManager,
29 PeertubePlayerManagerOptions,
30 PlayerMode,
31 WebtorrentOptions
32} from '../../../assets/player/peertube-player-manager'
27 33
28@Component({ 34@Component({
29 selector: 'my-video-watch', 35 selector: 'my-video-watch',
@@ -395,10 +401,13 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
395 src: environment.apiUrl + c.captionPath 401 src: environment.apiUrl + c.captionPath
396 })) 402 }))
397 403
398 const options = { 404 const options: PeertubePlayerManagerOptions = {
399 common: { 405 common: {
400 autoplay: this.isAutoplay(), 406 autoplay: this.isAutoplay(),
407
401 playerElement: this.playerElement, 408 playerElement: this.playerElement,
409 onPlayerElementChange: (element: HTMLVideoElement) => this.playerElement = element,
410
402 videoDuration: this.video.duration, 411 videoDuration: this.video.duration,
403 enableHotkeys: true, 412 enableHotkeys: true,
404 inactivityTimeout: 2500, 413 inactivityTimeout: 2500,
@@ -424,6 +433,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
424 serverUrl: environment.apiUrl, 433 serverUrl: environment.apiUrl,
425 434
426 videoCaptions: playerCaptions 435 videoCaptions: playerCaptions
436 },
437
438 webtorrent: {
439 videoFiles: this.video.files
427 } 440 }
428 } 441 }
429 442
@@ -431,6 +444,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
431 const hlsPlaylist = this.video.getHlsPlaylist() 444 const hlsPlaylist = this.video.getHlsPlaylist()
432 if (hlsPlaylist) { 445 if (hlsPlaylist) {
433 mode = 'p2p-media-loader' 446 mode = 'p2p-media-loader'
447
434 const p2pMediaLoader = { 448 const p2pMediaLoader = {
435 playlistUrl: hlsPlaylist.playlistUrl, 449 playlistUrl: hlsPlaylist.playlistUrl,
436 segmentsSha256Url: hlsPlaylist.segmentsSha256Url, 450 segmentsSha256Url: hlsPlaylist.segmentsSha256Url,
@@ -442,11 +456,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
442 Object.assign(options, { p2pMediaLoader }) 456 Object.assign(options, { p2pMediaLoader })
443 } else { 457 } else {
444 mode = 'webtorrent' 458 mode = 'webtorrent'
445 const webtorrent = {
446 videoFiles: this.video.files
447 } as WebtorrentOptions
448
449 Object.assign(options, { webtorrent })
450 } 459 }
451 460
452 this.zone.runOutsideAngular(async () => { 461 this.zone.runOutsideAngular(async () => {
diff --git a/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts b/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts
index f9a2707fb..022a9c16f 100644
--- a/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts
+++ b/client/src/assets/player/p2p-media-loader/p2p-media-loader-plugin.ts
@@ -51,17 +51,25 @@ class P2pMediaLoaderPlugin extends Plugin {
51 src: options.src 51 src: options.src
52 }) 52 })
53 53
54 player.on('play', () => {
55 player.addClass('vjs-has-big-play-button-clicked')
56 })
57
54 player.ready(() => this.initialize()) 58 player.ready(() => this.initialize())
55 } 59 }
56 60
57 dispose () { 61 dispose () {
62 if (this.hlsjs) this.hlsjs.destroy()
63 if (this.p2pEngine) this.p2pEngine.destroy()
64
58 clearInterval(this.networkInfoInterval) 65 clearInterval(this.networkInfoInterval)
59 } 66 }
60 67
61 private initialize () { 68 private initialize () {
62 initHlsJsPlayer(this.hlsjs) 69 initHlsJsPlayer(this.hlsjs)
63 70
64 this.p2pEngine = this.player.tech_.options_.hlsjsConfig.loader.getEngine() 71 const tech = this.player.tech_
72 this.p2pEngine = tech.options_.hlsjsConfig.loader.getEngine()
65 73
66 // Avoid using constants to not import hls.hs 74 // Avoid using constants to not import hls.hs
67 // https://github.com/video-dev/hls.js/blob/master/src/events.js#L37 75 // https://github.com/video-dev/hls.js/blob/master/src/events.js#L37
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 = {
41 41
42export type CommonOptions = { 42export type CommonOptions = {
43 playerElement: HTMLVideoElement 43 playerElement: HTMLVideoElement
44 onPlayerElementChange: (element: HTMLVideoElement) => void
44 45
45 autoplay: boolean 46 autoplay: boolean
46 videoDuration: number 47 videoDuration: number
@@ -71,13 +72,14 @@ export type CommonOptions = {
71 72
72export type PeertubePlayerManagerOptions = { 73export type PeertubePlayerManagerOptions = {
73 common: CommonOptions, 74 common: CommonOptions,
74 webtorrent?: WebtorrentOptions, 75 webtorrent: WebtorrentOptions,
75 p2pMediaLoader?: P2PMediaLoaderOptions 76 p2pMediaLoader?: P2PMediaLoaderOptions
76} 77}
77 78
78export class PeertubePlayerManager { 79export class PeertubePlayerManager {
79 80
80 private static videojsLocaleCache: { [ path: string ]: any } = {} 81 private static videojsLocaleCache: { [ path: string ]: any } = {}
82 private static playerElementClassName: string
81 83
82 static getServerTranslations (serverUrl: string, locale: string) { 84 static getServerTranslations (serverUrl: string, locale: string) {
83 const path = PeertubePlayerManager.getLocalePath(serverUrl, locale) 85 const path = PeertubePlayerManager.getLocalePath(serverUrl, locale)
@@ -95,6 +97,8 @@ export class PeertubePlayerManager {
95 static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions) { 97 static async initialize (mode: PlayerMode, options: PeertubePlayerManagerOptions) {
96 let p2pMediaLoader: any 98 let p2pMediaLoader: any
97 99
100 this.playerElementClassName = options.common.playerElement.className
101
98 if (mode === 'webtorrent') await import('./webtorrent/webtorrent-plugin') 102 if (mode === 'webtorrent') await import('./webtorrent/webtorrent-plugin')
99 if (mode === 'p2p-media-loader') { 103 if (mode === 'p2p-media-loader') {
100 [ p2pMediaLoader ] = await Promise.all([ 104 [ p2pMediaLoader ] = await Promise.all([
@@ -112,6 +116,13 @@ export class PeertubePlayerManager {
112 videojs(options.common.playerElement, videojsOptions, function (this: any) { 116 videojs(options.common.playerElement, videojsOptions, function (this: any) {
113 const player = this 117 const player = this
114 118
119 player.tech_.on('error', () => {
120 // Fallback to webtorrent?
121 if (mode === 'p2p-media-loader') {
122 self.fallbackToWebTorrent(player, options)
123 }
124 })
125
115 self.addContextMenu(mode, player, options.common.embedUrl) 126 self.addContextMenu(mode, player, options.common.embedUrl)
116 127
117 return res(player) 128 return res(player)
@@ -119,6 +130,32 @@ export class PeertubePlayerManager {
119 }) 130 })
120 } 131 }
121 132
133 private static async fallbackToWebTorrent (player: any, options: PeertubePlayerManagerOptions) {
134 const newVideoElement = document.createElement('video')
135 newVideoElement.className = this.playerElementClassName
136
137 // VideoJS wraps our video element inside a div
138 const currentParentPlayerElement = options.common.playerElement.parentNode
139 currentParentPlayerElement.parentNode.insertBefore(newVideoElement, currentParentPlayerElement)
140
141 options.common.playerElement = newVideoElement
142 options.common.onPlayerElementChange(newVideoElement)
143
144 player.dispose()
145
146 await import('./webtorrent/webtorrent-plugin')
147
148 const mode = 'webtorrent'
149 const videojsOptions = this.getVideojsOptions(mode, options)
150
151 const self = this
152 videojs(newVideoElement, videojsOptions, function (this: any) {
153 const player = this
154
155 self.addContextMenu(mode, player, options.common.embedUrl)
156 })
157 }
158
122 private static loadLocaleInVideoJS (serverUrl: string, locale: string) { 159 private static loadLocaleInVideoJS (serverUrl: string, locale: string) {
123 const path = PeertubePlayerManager.getLocalePath(serverUrl, locale) 160 const path = PeertubePlayerManager.getLocalePath(serverUrl, locale)
124 // It is the default locale, nothing to translate 161 // It is the default locale, nothing to translate
@@ -166,7 +203,7 @@ export class PeertubePlayerManager {
166 } 203 }
167 } 204 }
168 205
169 if (p2pMediaLoaderOptions) { 206 if (mode === 'p2p-media-loader') {
170 const p2pMediaLoader: P2PMediaLoaderPluginOptions = { 207 const p2pMediaLoader: P2PMediaLoaderPluginOptions = {
171 redundancyBaseUrls: options.p2pMediaLoader.redundancyBaseUrls, 208 redundancyBaseUrls: options.p2pMediaLoader.redundancyBaseUrls,
172 type: 'application/x-mpegURL', 209 type: 'application/x-mpegURL',
@@ -209,7 +246,7 @@ export class PeertubePlayerManager {
209 html5 = streamrootHls.html5 246 html5 = streamrootHls.html5
210 } 247 }
211 248
212 if (webtorrentOptions) { 249 if (mode === 'webtorrent') {
213 const webtorrent = { 250 const webtorrent = {
214 autoplay, 251 autoplay,
215 videoDuration: commonOptions.videoDuration, 252 videoDuration: commonOptions.videoDuration,
@@ -235,7 +272,7 @@ export class PeertubePlayerManager {
235 : undefined, // Undefined so the player knows it has to check the local storage 272 : undefined, // Undefined so the player knows it has to check the local storage
236 273
237 poster: commonOptions.poster, 274 poster: commonOptions.poster,
238 autoplay, 275 autoplay: autoplay === true ? 'any' : autoplay, // Use 'any' instead of true to get notifier by videojs if autoplay fails
239 inactivityTimeout: commonOptions.inactivityTimeout, 276 inactivityTimeout: commonOptions.inactivityTimeout,
240 playbackRates: [ 0.5, 0.75, 1, 1.25, 1.5, 2 ], 277 playbackRates: [ 0.5, 0.75, 1, 1.25, 1.5, 2 ],
241 plugins, 278 plugins,
diff --git a/client/src/assets/player/peertube-plugin.ts b/client/src/assets/player/peertube-plugin.ts
index aacbf5f6e..7ea4a06d4 100644
--- a/client/src/assets/player/peertube-plugin.ts
+++ b/client/src/assets/player/peertube-plugin.ts
@@ -47,7 +47,11 @@ class PeerTubePlugin extends Plugin {
47 this.videoDuration = options.videoDuration 47 this.videoDuration = options.videoDuration
48 this.videoCaptions = options.videoCaptions 48 this.videoCaptions = options.videoCaptions
49 49
50 if (this.autoplay === true) this.player.addClass('vjs-has-autoplay') 50 if (options.autoplay === true) this.player.addClass('vjs-has-autoplay')
51
52 this.player.on('autoplay-failure', () => {
53 this.player.removeClass('vjs-has-autoplay')
54 })
51 55
52 this.player.ready(() => { 56 this.player.ready(() => {
53 const playerOptions = this.player.options_ 57 const playerOptions = this.player.options_
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index 1e58d42d9..c5c46d0c5 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -311,7 +311,10 @@ class PeerTubeEmbed {
311 videoCaptions, 311 videoCaptions,
312 inactivityTimeout: 1500, 312 inactivityTimeout: 1500,
313 videoViewUrl: this.getVideoUrl(videoId) + '/views', 313 videoViewUrl: this.getVideoUrl(videoId) + '/views',
314
314 playerElement: this.videoElement, 315 playerElement: this.videoElement,
316 onPlayerElementChange: (element: HTMLVideoElement) => this.videoElement = element,
317
315 videoDuration: videoInfo.duration, 318 videoDuration: videoInfo.duration,
316 enableHotkeys: true, 319 enableHotkeys: true,
317 peertubeLink: true, 320 peertubeLink: true,
@@ -321,6 +324,10 @@ class PeerTubeEmbed {
321 serverUrl: window.location.origin, 324 serverUrl: window.location.origin,
322 language: navigator.language, 325 language: navigator.language,
323 embedUrl: window.location.origin + videoInfo.embedPath 326 embedUrl: window.location.origin + videoInfo.embedPath
327 },
328
329 webtorrent: {
330 videoFiles: videoInfo.files
324 } 331 }
325 } 332 }
326 333
@@ -336,12 +343,6 @@ class PeerTubeEmbed {
336 videoFiles: videoInfo.files 343 videoFiles: videoInfo.files
337 } as P2PMediaLoaderOptions 344 } as P2PMediaLoaderOptions
338 }) 345 })
339 } else {
340 Object.assign(options, {
341 webtorrent: {
342 videoFiles: videoInfo.files
343 }
344 })
345 } 346 }
346 347
347 this.player = await PeertubePlayerManager.initialize(this.mode, options) 348 this.player = await PeertubePlayerManager.initialize(this.mode, options)