diff options
Diffstat (limited to 'client/src/assets/player/peertube-videojs-plugin.ts')
-rw-r--r-- | client/src/assets/player/peertube-videojs-plugin.ts | 109 |
1 files changed, 80 insertions, 29 deletions
diff --git a/client/src/assets/player/peertube-videojs-plugin.ts b/client/src/assets/player/peertube-videojs-plugin.ts index 01a630cb6..618d77cbe 100644 --- a/client/src/assets/player/peertube-videojs-plugin.ts +++ b/client/src/assets/player/peertube-videojs-plugin.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | // Big thanks to: https://github.com/kmoskwiak/videojs-resolution-switcher | 1 | // Big thanks to: https://github.com/kmoskwiak/videojs-resolution-switcher |
2 | 2 | ||
3 | import { VideoService } from '@app/shared/video/video.service' | ||
4 | import * as videojs from 'video.js' | 3 | import * as videojs from 'video.js' |
5 | import * as WebTorrent from 'webtorrent' | 4 | import * as WebTorrent from 'webtorrent' |
6 | import { VideoFile } from '../../../../shared/models/videos/video.model' | 5 | import { VideoFile } from '../../../../shared/models/videos/video.model' |
@@ -147,12 +146,12 @@ Button.registerComponent('PeerTubeLinkButton', PeertubeLinkButton) | |||
147 | class WebTorrentButton extends Button { | 146 | class WebTorrentButton extends Button { |
148 | createEl () { | 147 | createEl () { |
149 | const div = document.createElement('div') | 148 | const div = document.createElement('div') |
150 | const subDiv = document.createElement('div') | 149 | const subDivWebtorrent = document.createElement('div') |
151 | div.appendChild(subDiv) | 150 | div.appendChild(subDivWebtorrent) |
152 | 151 | ||
153 | const downloadIcon = document.createElement('span') | 152 | const downloadIcon = document.createElement('span') |
154 | downloadIcon.classList.add('icon', 'icon-download') | 153 | downloadIcon.classList.add('icon', 'icon-download') |
155 | subDiv.appendChild(downloadIcon) | 154 | subDivWebtorrent.appendChild(downloadIcon) |
156 | 155 | ||
157 | const downloadSpeedText = document.createElement('span') | 156 | const downloadSpeedText = document.createElement('span') |
158 | downloadSpeedText.classList.add('download-speed-text') | 157 | downloadSpeedText.classList.add('download-speed-text') |
@@ -161,11 +160,11 @@ class WebTorrentButton extends Button { | |||
161 | const downloadSpeedUnit = document.createElement('span') | 160 | const downloadSpeedUnit = document.createElement('span') |
162 | downloadSpeedText.appendChild(downloadSpeedNumber) | 161 | downloadSpeedText.appendChild(downloadSpeedNumber) |
163 | downloadSpeedText.appendChild(downloadSpeedUnit) | 162 | downloadSpeedText.appendChild(downloadSpeedUnit) |
164 | subDiv.appendChild(downloadSpeedText) | 163 | subDivWebtorrent.appendChild(downloadSpeedText) |
165 | 164 | ||
166 | const uploadIcon = document.createElement('span') | 165 | const uploadIcon = document.createElement('span') |
167 | uploadIcon.classList.add('icon', 'icon-upload') | 166 | uploadIcon.classList.add('icon', 'icon-upload') |
168 | subDiv.appendChild(uploadIcon) | 167 | subDivWebtorrent.appendChild(uploadIcon) |
169 | 168 | ||
170 | const uploadSpeedText = document.createElement('span') | 169 | const uploadSpeedText = document.createElement('span') |
171 | uploadSpeedText.classList.add('upload-speed-text') | 170 | uploadSpeedText.classList.add('upload-speed-text') |
@@ -174,34 +173,56 @@ class WebTorrentButton extends Button { | |||
174 | const uploadSpeedUnit = document.createElement('span') | 173 | const uploadSpeedUnit = document.createElement('span') |
175 | uploadSpeedText.appendChild(uploadSpeedNumber) | 174 | uploadSpeedText.appendChild(uploadSpeedNumber) |
176 | uploadSpeedText.appendChild(uploadSpeedUnit) | 175 | uploadSpeedText.appendChild(uploadSpeedUnit) |
177 | subDiv.appendChild(uploadSpeedText) | 176 | subDivWebtorrent.appendChild(uploadSpeedText) |
178 | 177 | ||
179 | const peersText = document.createElement('span') | 178 | const peersText = document.createElement('span') |
180 | peersText.textContent = ' peers' | ||
181 | peersText.classList.add('peers-text') | 179 | peersText.classList.add('peers-text') |
182 | const peersNumber = document.createElement('span') | 180 | const peersNumber = document.createElement('span') |
183 | peersNumber.classList.add('peers-number') | 181 | peersNumber.classList.add('peers-number') |
184 | subDiv.appendChild(peersNumber) | 182 | subDivWebtorrent.appendChild(peersNumber) |
185 | subDiv.appendChild(peersText) | 183 | subDivWebtorrent.appendChild(peersText) |
186 | 184 | ||
187 | div.className = 'vjs-webtorrent' | 185 | div.className = 'vjs-peertube' |
188 | // Hide the stats before we get the info | 186 | // Hide the stats before we get the info |
189 | subDiv.className = 'vjs-webtorrent-hidden' | 187 | subDivWebtorrent.className = 'vjs-peertube-hidden' |
188 | |||
189 | const subDivHttp = document.createElement('div') | ||
190 | subDivHttp.className = 'vjs-peertube-hidden' | ||
191 | const subDivHttpText = document.createElement('span') | ||
192 | subDivHttpText.classList.add('peers-number') | ||
193 | subDivHttpText.textContent = 'HTTP' | ||
194 | const subDivFallbackText = document.createElement('span') | ||
195 | subDivFallbackText.classList.add('peers-text') | ||
196 | subDivFallbackText.textContent = ' fallback' | ||
197 | |||
198 | subDivHttp.appendChild(subDivHttpText) | ||
199 | subDivHttp.appendChild(subDivFallbackText) | ||
200 | div.appendChild(subDivHttp) | ||
190 | 201 | ||
191 | this.player_.peertube().on('torrentInfo', (event, data) => { | 202 | this.player_.peertube().on('torrentInfo', (event, data) => { |
203 | // We are in HTTP fallback | ||
204 | if (!data) { | ||
205 | subDivHttp.className = 'vjs-peertube-displayed' | ||
206 | subDivWebtorrent.className = 'vjs-peertube-hidden' | ||
207 | |||
208 | return | ||
209 | } | ||
210 | |||
192 | const downloadSpeed = bytes(data.downloadSpeed) | 211 | const downloadSpeed = bytes(data.downloadSpeed) |
193 | const uploadSpeed = bytes(data.uploadSpeed) | 212 | const uploadSpeed = bytes(data.uploadSpeed) |
194 | const numPeers = data.numPeers | 213 | const numPeers = data.numPeers |
195 | 214 | ||
196 | downloadSpeedNumber.textContent = downloadSpeed[0] | 215 | downloadSpeedNumber.textContent = downloadSpeed[ 0 ] |
197 | downloadSpeedUnit.textContent = ' ' + downloadSpeed[1] | 216 | downloadSpeedUnit.textContent = ' ' + downloadSpeed[ 1 ] |
198 | 217 | ||
199 | uploadSpeedNumber.textContent = uploadSpeed[0] | 218 | uploadSpeedNumber.textContent = uploadSpeed[ 0 ] |
200 | uploadSpeedUnit.textContent = ' ' + uploadSpeed[1] | 219 | uploadSpeedUnit.textContent = ' ' + uploadSpeed[ 1 ] |
201 | 220 | ||
202 | peersNumber.textContent = numPeers | 221 | peersNumber.textContent = numPeers |
222 | peersText.textContent = ' peers' | ||
203 | 223 | ||
204 | subDiv.className = 'vjs-webtorrent-displayed' | 224 | subDivHttp.className = 'vjs-peertube-hidden' |
225 | subDivWebtorrent.className = 'vjs-peertube-displayed' | ||
205 | }) | 226 | }) |
206 | 227 | ||
207 | return div | 228 | return div |
@@ -225,6 +246,7 @@ class PeerTubePlugin extends Plugin { | |||
225 | private videoDuration: number | 246 | private videoDuration: number |
226 | private videoViewInterval | 247 | private videoViewInterval |
227 | private torrentInfoInterval | 248 | private torrentInfoInterval |
249 | private savePlayerSrcFunction: Function | ||
228 | 250 | ||
229 | constructor (player: videojs.Player, options: PeertubePluginOptions) { | 251 | constructor (player: videojs.Player, options: PeertubePluginOptions) { |
230 | super(player, options) | 252 | super(player, options) |
@@ -237,12 +259,11 @@ class PeerTubePlugin extends Plugin { | |||
237 | this.videoViewUrl = options.videoViewUrl | 259 | this.videoViewUrl = options.videoViewUrl |
238 | this.videoDuration = options.videoDuration | 260 | this.videoDuration = options.videoDuration |
239 | 261 | ||
262 | this.savePlayerSrcFunction = this.player.src | ||
240 | // Hack to "simulate" src link in video.js >= 6 | 263 | // Hack to "simulate" src link in video.js >= 6 |
241 | // Without this, we can't play the video after pausing it | 264 | // Without this, we can't play the video after pausing it |
242 | // https://github.com/videojs/video.js/blob/master/src/js/player.js#L1633 | 265 | // https://github.com/videojs/video.js/blob/master/src/js/player.js#L1633 |
243 | this.player.src = function () { | 266 | this.player.src = () => true |
244 | return true | ||
245 | } | ||
246 | 267 | ||
247 | this.playerElement = options.playerElement | 268 | this.playerElement = options.playerElement |
248 | 269 | ||
@@ -284,6 +305,10 @@ class PeerTubePlugin extends Plugin { | |||
284 | return | 305 | return |
285 | } | 306 | } |
286 | 307 | ||
308 | // Do not display error to user because we will have multiple fallbacks | ||
309 | this.disableErrorDisplay() | ||
310 | this.player.src = () => true | ||
311 | |||
287 | const previousVideoFile = this.currentVideoFile | 312 | const previousVideoFile = this.currentVideoFile |
288 | this.currentVideoFile = videoFile | 313 | this.currentVideoFile = videoFile |
289 | 314 | ||
@@ -295,7 +320,7 @@ class PeerTubePlugin extends Plugin { | |||
295 | 320 | ||
296 | const options = { autoplay: true, controls: true } | 321 | const options = { autoplay: true, controls: true } |
297 | renderVideo(torrent.files[0], this.playerElement, options,(err, renderer) => { | 322 | renderVideo(torrent.files[0], this.playerElement, options,(err, renderer) => { |
298 | if (err) return this.handleError(err) | 323 | if (err) return this.fallbackToHttp() |
299 | 324 | ||
300 | this.renderer = renderer | 325 | this.renderer = renderer |
301 | if (!this.player.paused()) { | 326 | if (!this.player.paused()) { |
@@ -347,7 +372,8 @@ class PeerTubePlugin extends Plugin { | |||
347 | 372 | ||
348 | flushVideoFile (videoFile: VideoFile, destroyRenderer = true) { | 373 | flushVideoFile (videoFile: VideoFile, destroyRenderer = true) { |
349 | if (videoFile !== undefined && webtorrent.get(videoFile.magnetUri)) { | 374 | if (videoFile !== undefined && webtorrent.get(videoFile.magnetUri)) { |
350 | if (destroyRenderer === true) this.renderer.destroy() | 375 | if (destroyRenderer === true && this.renderer && this.renderer.destroy) this.renderer.destroy() |
376 | |||
351 | webtorrent.remove(videoFile.magnetUri) | 377 | webtorrent.remove(videoFile.magnetUri) |
352 | console.log('Removed ' + videoFile.magnetUri) | 378 | console.log('Removed ' + videoFile.magnetUri) |
353 | } | 379 | } |
@@ -390,13 +416,17 @@ class PeerTubePlugin extends Plugin { | |||
390 | 416 | ||
391 | private runTorrentInfoScheduler () { | 417 | private runTorrentInfoScheduler () { |
392 | this.torrentInfoInterval = setInterval(() => { | 418 | this.torrentInfoInterval = setInterval(() => { |
393 | if (this.torrent !== undefined) { | 419 | // Not initialized yet |
394 | this.trigger('torrentInfo', { | 420 | if (this.torrent === undefined) return |
395 | downloadSpeed: this.torrent.downloadSpeed, | 421 | |
396 | numPeers: this.torrent.numPeers, | 422 | // Http fallback |
397 | uploadSpeed: this.torrent.uploadSpeed | 423 | if (this.torrent === null) return this.trigger('torrentInfo', false) |
398 | }) | 424 | |
399 | } | 425 | return this.trigger('torrentInfo', { |
426 | downloadSpeed: this.torrent.downloadSpeed, | ||
427 | numPeers: this.torrent.numPeers, | ||
428 | uploadSpeed: this.torrent.uploadSpeed | ||
429 | }) | ||
400 | }, 1000) | 430 | }, 1000) |
401 | } | 431 | } |
402 | 432 | ||
@@ -433,8 +463,29 @@ class PeerTubePlugin extends Plugin { | |||
433 | return fetch(this.videoViewUrl, { method: 'POST' }) | 463 | return fetch(this.videoViewUrl, { method: 'POST' }) |
434 | } | 464 | } |
435 | 465 | ||
466 | private fallbackToHttp () { | ||
467 | this.flushVideoFile(this.currentVideoFile, true) | ||
468 | this.torrent = null | ||
469 | |||
470 | // Enable error display now this is our last fallback | ||
471 | this.player.one('error', () => this.enableErrorDisplay()) | ||
472 | |||
473 | const httpUrl = this.currentVideoFile.fileUrl | ||
474 | this.player.src = this.savePlayerSrcFunction | ||
475 | this.player.src(httpUrl) | ||
476 | this.player.play() | ||
477 | } | ||
478 | |||
436 | private handleError (err: Error | string) { | 479 | private handleError (err: Error | string) { |
437 | return this.player.trigger('customError', { err }) | 480 | return this.player.trigger('customError', { err }) |
438 | } | 481 | } |
482 | |||
483 | private enableErrorDisplay () { | ||
484 | this.player.addClass('vjs-error-display-enabled') | ||
485 | } | ||
486 | |||
487 | private disableErrorDisplay () { | ||
488 | this.player.removeClass('vjs-error-display-enabled') | ||
489 | } | ||
439 | } | 490 | } |
440 | videojsUntyped.registerPlugin('peertube', PeerTubePlugin) | 491 | videojsUntyped.registerPlugin('peertube', PeerTubePlugin) |