diff options
Diffstat (limited to 'client/src/assets/player')
18 files changed, 132 insertions, 136 deletions
diff --git a/client/src/assets/player/p2p-media-loader/hls-plugin.ts b/client/src/assets/player/p2p-media-loader/hls-plugin.ts index 78f0944ef..a1b07aea6 100644 --- a/client/src/assets/player/p2p-media-loader/hls-plugin.ts +++ b/client/src/assets/player/p2p-media-loader/hls-plugin.ts | |||
@@ -13,6 +13,8 @@ type Metadata = { | |||
13 | levels: Level[] | 13 | levels: Level[] |
14 | } | 14 | } |
15 | 15 | ||
16 | type HookFn = (player: videojs.Player, hljs: Hlsjs) => void | ||
17 | |||
16 | const registerSourceHandler = function (vjs: typeof videojs) { | 18 | const registerSourceHandler = function (vjs: typeof videojs) { |
17 | if (!Hlsjs.isSupported()) { | 19 | if (!Hlsjs.isSupported()) { |
18 | console.warn('Hls.js is not supported in this browser!') | 20 | console.warn('Hls.js is not supported in this browser!') |
@@ -82,7 +84,7 @@ const registerConfigPlugin = function (vjs: typeof videojs) { | |||
82 | } | 84 | } |
83 | 85 | ||
84 | class Html5Hlsjs { | 86 | class Html5Hlsjs { |
85 | private static readonly hooks: { [id: string]: Function[] } = {} | 87 | private static readonly hooks: { [id: string]: HookFn[] } = {} |
86 | 88 | ||
87 | private readonly videoElement: HTMLVideoElement | 89 | private readonly videoElement: HTMLVideoElement |
88 | private readonly errorCounts: ErrorCounts = {} | 90 | private readonly errorCounts: ErrorCounts = {} |
@@ -131,7 +133,8 @@ class Html5Hlsjs { | |||
131 | errorTxt = 'You aborted the video playback' | 133 | errorTxt = 'You aborted the video playback' |
132 | break | 134 | break |
133 | case mediaError.MEDIA_ERR_DECODE: | 135 | case mediaError.MEDIA_ERR_DECODE: |
134 | errorTxt = 'The video playback was aborted due to a corruption problem or because the video used features your browser did not support' | 136 | errorTxt = 'The video playback was aborted due to a corruption problem or because the video used features ' + |
137 | 'your browser did not support' | ||
135 | this._handleMediaError(mediaError) | 138 | this._handleMediaError(mediaError) |
136 | break | 139 | break |
137 | case mediaError.MEDIA_ERR_NETWORK: | 140 | case mediaError.MEDIA_ERR_NETWORK: |
@@ -182,58 +185,57 @@ class Html5Hlsjs { | |||
182 | this.hls.destroy() | 185 | this.hls.destroy() |
183 | } | 186 | } |
184 | 187 | ||
185 | static addHook (type: string, callback: Function) { | 188 | static addHook (type: string, callback: HookFn) { |
186 | Html5Hlsjs.hooks[ type ] = this.hooks[ type ] || [] | 189 | Html5Hlsjs.hooks[type] = this.hooks[type] || [] |
187 | Html5Hlsjs.hooks[ type ].push(callback) | 190 | Html5Hlsjs.hooks[type].push(callback) |
188 | } | 191 | } |
189 | 192 | ||
190 | static removeHook (type: string, callback: Function) { | 193 | static removeHook (type: string, callback: HookFn) { |
191 | if (Html5Hlsjs.hooks[ type ] === undefined) return false | 194 | if (Html5Hlsjs.hooks[type] === undefined) return false |
192 | 195 | ||
193 | const index = Html5Hlsjs.hooks[ type ].indexOf(callback) | 196 | const index = Html5Hlsjs.hooks[type].indexOf(callback) |
194 | if (index === -1) return false | 197 | if (index === -1) return false |
195 | 198 | ||
196 | Html5Hlsjs.hooks[ type ].splice(index, 1) | 199 | Html5Hlsjs.hooks[type].splice(index, 1) |
197 | 200 | ||
198 | return true | 201 | return true |
199 | } | 202 | } |
200 | 203 | ||
201 | private _executeHooksFor (type: string) { | 204 | private _executeHooksFor (type: string) { |
202 | if (Html5Hlsjs.hooks[ type ] === undefined) { | 205 | if (Html5Hlsjs.hooks[type] === undefined) { |
203 | return | 206 | return |
204 | } | 207 | } |
205 | 208 | ||
206 | // ES3 and IE < 9 | 209 | // ES3 and IE < 9 |
207 | for (let i = 0; i < Html5Hlsjs.hooks[ type ].length; i++) { | 210 | for (let i = 0; i < Html5Hlsjs.hooks[type].length; i++) { |
208 | Html5Hlsjs.hooks[ type ][ i ](this.player, this.hls) | 211 | Html5Hlsjs.hooks[type][i](this.player, this.hls) |
209 | } | 212 | } |
210 | } | 213 | } |
211 | 214 | ||
212 | private _handleMediaError (error: any) { | 215 | private _handleMediaError (error: any) { |
213 | if (this.errorCounts[ Hlsjs.ErrorTypes.MEDIA_ERROR ] === 1) { | 216 | if (this.errorCounts[Hlsjs.ErrorTypes.MEDIA_ERROR] === 1) { |
214 | console.info('trying to recover media error') | 217 | console.info('trying to recover media error') |
215 | this.hls.recoverMediaError() | 218 | this.hls.recoverMediaError() |
216 | return | 219 | return |
217 | } | 220 | } |
218 | 221 | ||
219 | if (this.errorCounts[ Hlsjs.ErrorTypes.MEDIA_ERROR ] === 2) { | 222 | if (this.errorCounts[Hlsjs.ErrorTypes.MEDIA_ERROR] === 2) { |
220 | console.info('2nd try to recover media error (by swapping audio codec') | 223 | console.info('2nd try to recover media error (by swapping audio codec') |
221 | this.hls.swapAudioCodec() | 224 | this.hls.swapAudioCodec() |
222 | this.hls.recoverMediaError() | 225 | this.hls.recoverMediaError() |
223 | return | 226 | return |
224 | } | 227 | } |
225 | 228 | ||
226 | if (this.errorCounts[ Hlsjs.ErrorTypes.MEDIA_ERROR ] > 2) { | 229 | if (this.errorCounts[Hlsjs.ErrorTypes.MEDIA_ERROR] > 2) { |
227 | console.info('bubbling media error up to VIDEOJS') | 230 | console.info('bubbling media error up to VIDEOJS') |
228 | this.hls.destroy() | 231 | this.hls.destroy() |
229 | this.tech.error = () => error | 232 | this.tech.error = () => error |
230 | this.tech.trigger('error') | 233 | this.tech.trigger('error') |
231 | return | ||
232 | } | 234 | } |
233 | } | 235 | } |
234 | 236 | ||
235 | private _handleNetworkError (error: any) { | 237 | private _handleNetworkError (error: any) { |
236 | if (this.errorCounts[ Hlsjs.ErrorTypes.NETWORK_ERROR] <= 5) { | 238 | if (this.errorCounts[Hlsjs.ErrorTypes.NETWORK_ERROR] <= 5) { |
237 | console.info('trying to recover network error') | 239 | console.info('trying to recover network error') |
238 | 240 | ||
239 | // Wait 1 second and retry | 241 | // Wait 1 second and retry |
@@ -241,7 +243,7 @@ class Html5Hlsjs { | |||
241 | 243 | ||
242 | // Reset error count on success | 244 | // Reset error count on success |
243 | this.hls.once(Hlsjs.Events.FRAG_LOADED, () => { | 245 | this.hls.once(Hlsjs.Events.FRAG_LOADED, () => { |
244 | this.errorCounts[ Hlsjs.ErrorTypes.NETWORK_ERROR] = 0 | 246 | this.errorCounts[Hlsjs.ErrorTypes.NETWORK_ERROR] = 0 |
245 | }) | 247 | }) |
246 | 248 | ||
247 | return | 249 | return |
@@ -259,8 +261,8 @@ class Html5Hlsjs { | |||
259 | } | 261 | } |
260 | 262 | ||
261 | // increment/set error count | 263 | // increment/set error count |
262 | if (this.errorCounts[ data.type ]) this.errorCounts[ data.type ] += 1 | 264 | if (this.errorCounts[data.type]) this.errorCounts[data.type] += 1 |
263 | else this.errorCounts[ data.type ] = 1 | 265 | else this.errorCounts[data.type] = 1 |
264 | 266 | ||
265 | if (data.fatal) console.warn(error.message) | 267 | if (data.fatal) console.warn(error.message) |
266 | else console.error(error.message, data) | 268 | else console.error(error.message, data) |
@@ -300,7 +302,7 @@ class Html5Hlsjs { | |||
300 | let isAuto = true | 302 | let isAuto = true |
301 | 303 | ||
302 | for (let i = 0; i < qualityLevels.length; i++) { | 304 | for (let i = 0; i < qualityLevels.length; i++) { |
303 | if (!qualityLevels[ i ]._enabled) { | 305 | if (!qualityLevels[i]._enabled) { |
304 | isAuto = false | 306 | isAuto = false |
305 | break | 307 | break |
306 | } | 308 | } |
@@ -316,7 +318,7 @@ class Html5Hlsjs { | |||
316 | let selectedTrack: number | 318 | let selectedTrack: number |
317 | 319 | ||
318 | for (selectedTrack = qualityLevels.length - 1; selectedTrack >= 0; selectedTrack--) { | 320 | for (selectedTrack = qualityLevels.length - 1; selectedTrack >= 0; selectedTrack--) { |
319 | if (qualityLevels[ selectedTrack ]._enabled) { | 321 | if (qualityLevels[selectedTrack]._enabled) { |
320 | break | 322 | break |
321 | } | 323 | } |
322 | } | 324 | } |
@@ -327,11 +329,11 @@ class Html5Hlsjs { | |||
327 | private _handleQualityLevels () { | 329 | private _handleQualityLevels () { |
328 | if (!this.metadata) return | 330 | if (!this.metadata) return |
329 | 331 | ||
330 | const qualityLevels = this.player.qualityLevels && this.player.qualityLevels() | 332 | const qualityLevels = this.player.qualityLevels?.() |
331 | if (!qualityLevels) return | 333 | if (!qualityLevels) return |
332 | 334 | ||
333 | for (let i = 0; i < this.metadata.levels.length; i++) { | 335 | for (let i = 0; i < this.metadata.levels.length; i++) { |
334 | const details = this.metadata.levels[ i ] | 336 | const details = this.metadata.levels[i] |
335 | const representation: QualityLevelRepresentation = { | 337 | const representation: QualityLevelRepresentation = { |
336 | id: i, | 338 | id: i, |
337 | width: details.width, | 339 | width: details.width, |
@@ -345,11 +347,11 @@ class Html5Hlsjs { | |||
345 | representation.enabled = function (this: QualityLevels, level: number, toggle?: boolean) { | 347 | representation.enabled = function (this: QualityLevels, level: number, toggle?: boolean) { |
346 | // Brightcove switcher works TextTracks-style (enable tracks that it wants to ABR on) | 348 | // Brightcove switcher works TextTracks-style (enable tracks that it wants to ABR on) |
347 | if (typeof toggle === 'boolean') { | 349 | if (typeof toggle === 'boolean') { |
348 | this[ level ]._enabled = toggle | 350 | this[level]._enabled = toggle |
349 | self._relayQualityChange(this) | 351 | self._relayQualityChange(this) |
350 | } | 352 | } |
351 | 353 | ||
352 | return this[ level ]._enabled | 354 | return this[level]._enabled |
353 | } | 355 | } |
354 | 356 | ||
355 | qualityLevels.addQualityLevel(representation) | 357 | qualityLevels.addQualityLevel(representation) |
@@ -395,7 +397,7 @@ class Html5Hlsjs { | |||
395 | const playerAudioTracks = this.tech.audioTracks() | 397 | const playerAudioTracks = this.tech.audioTracks() |
396 | for (let j = 0; j < playerAudioTracks.length; j++) { | 398 | for (let j = 0; j < playerAudioTracks.length; j++) { |
397 | // FIXME: typings | 399 | // FIXME: typings |
398 | if ((playerAudioTracks[ j ] as any).enabled) { | 400 | if ((playerAudioTracks[j] as any).enabled) { |
399 | this.hls.audioTrack = j | 401 | this.hls.audioTrack = j |
400 | break | 402 | break |
401 | } | 403 | } |
@@ -412,8 +414,8 @@ class Html5Hlsjs { | |||
412 | playerAudioTracks.addTrack(new this.vjs.AudioTrack({ | 414 | playerAudioTracks.addTrack(new this.vjs.AudioTrack({ |
413 | id: i.toString(), | 415 | id: i.toString(), |
414 | kind: 'alternative', | 416 | kind: 'alternative', |
415 | label: hlsAudioTracks[ i ].name || hlsAudioTracks[ i ].lang, | 417 | label: hlsAudioTracks[i].name || hlsAudioTracks[i].lang, |
416 | language: hlsAudioTracks[ i ].lang, | 418 | language: hlsAudioTracks[i].lang, |
417 | enabled: i === this.hls.audioTrack | 419 | enabled: i === this.hls.audioTrack |
418 | })) | 420 | })) |
419 | } | 421 | } |
@@ -430,8 +432,8 @@ class Html5Hlsjs { | |||
430 | } | 432 | } |
431 | 433 | ||
432 | private _isSameTextTrack (track1: TextTrack, track2: TextTrack) { | 434 | private _isSameTextTrack (track1: TextTrack, track2: TextTrack) { |
433 | return this._getTextTrackLabel(track1) === this._getTextTrackLabel(track2) | 435 | return this._getTextTrackLabel(track1) === this._getTextTrackLabel(track2) && |
434 | && track1.kind === track2.kind | 436 | track1.kind === track2.kind |
435 | } | 437 | } |
436 | 438 | ||
437 | private _updateSelectedTextTrack () { | 439 | private _updateSelectedTextTrack () { |
@@ -439,16 +441,16 @@ class Html5Hlsjs { | |||
439 | let activeTrack: TextTrack = null | 441 | let activeTrack: TextTrack = null |
440 | 442 | ||
441 | for (let j = 0; j < playerTextTracks.length; j++) { | 443 | for (let j = 0; j < playerTextTracks.length; j++) { |
442 | if (playerTextTracks[ j ].mode === 'showing') { | 444 | if (playerTextTracks[j].mode === 'showing') { |
443 | activeTrack = playerTextTracks[ j ] | 445 | activeTrack = playerTextTracks[j] |
444 | break | 446 | break |
445 | } | 447 | } |
446 | } | 448 | } |
447 | 449 | ||
448 | const hlsjsTracks = this.videoElement.textTracks | 450 | const hlsjsTracks = this.videoElement.textTracks |
449 | for (let k = 0; k < hlsjsTracks.length; k++) { | 451 | for (let k = 0; k < hlsjsTracks.length; k++) { |
450 | if (hlsjsTracks[ k ].kind === 'subtitles' || hlsjsTracks[ k ].kind === 'captions') { | 452 | if (hlsjsTracks[k].kind === 'subtitles' || hlsjsTracks[k].kind === 'captions') { |
451 | hlsjsTracks[ k ].mode = activeTrack && this._isSameTextTrack(hlsjsTracks[ k ], activeTrack) | 453 | hlsjsTracks[k].mode = activeTrack && this._isSameTextTrack(hlsjsTracks[k], activeTrack) |
452 | ? 'showing' | 454 | ? 'showing' |
453 | : 'disabled' | 455 | : 'disabled' |
454 | } | 456 | } |
@@ -460,11 +462,11 @@ class Html5Hlsjs { | |||
460 | this.videoElement.removeEventListener('play', this.handlers.play) | 462 | this.videoElement.removeEventListener('play', this.handlers.play) |
461 | } | 463 | } |
462 | 464 | ||
463 | private _oneLevelObjClone (obj: object) { | 465 | private _oneLevelObjClone (obj: { [ id: string ]: any }) { |
464 | const result = {} | 466 | const result = {} |
465 | const objKeys = Object.keys(obj) | 467 | const objKeys = Object.keys(obj) |
466 | for (let i = 0; i < objKeys.length; i++) { | 468 | for (let i = 0; i < objKeys.length; i++) { |
467 | result[ objKeys[ i ] ] = obj[ objKeys[ i ] ] | 469 | result[objKeys[i]] = obj[objKeys[i]] |
468 | } | 470 | } |
469 | 471 | ||
470 | return result | 472 | return result |
@@ -475,8 +477,8 @@ class Html5Hlsjs { | |||
475 | 477 | ||
476 | // Filter out tracks that is displayable (captions or subtitles) | 478 | // Filter out tracks that is displayable (captions or subtitles) |
477 | for (let idx = 0; idx < textTracks.length; idx++) { | 479 | for (let idx = 0; idx < textTracks.length; idx++) { |
478 | if (textTracks[ idx ].kind === 'subtitles' || textTracks[ idx ].kind === 'captions') { | 480 | if (textTracks[idx].kind === 'subtitles' || textTracks[idx].kind === 'captions') { |
479 | displayableTracks.push(textTracks[ idx ]) | 481 | displayableTracks.push(textTracks[idx]) |
480 | } | 482 | } |
481 | } | 483 | } |
482 | 484 | ||
@@ -493,14 +495,14 @@ class Html5Hlsjs { | |||
493 | let isAdded = false | 495 | let isAdded = false |
494 | 496 | ||
495 | for (let jdx = 0; jdx < playerTextTracks.length; jdx++) { | 497 | for (let jdx = 0; jdx < playerTextTracks.length; jdx++) { |
496 | if (this._isSameTextTrack(displayableTracks[ idx ], playerTextTracks[ jdx ])) { | 498 | if (this._isSameTextTrack(displayableTracks[idx], playerTextTracks[jdx])) { |
497 | isAdded = true | 499 | isAdded = true |
498 | break | 500 | break |
499 | } | 501 | } |
500 | } | 502 | } |
501 | 503 | ||
502 | if (!isAdded) { | 504 | if (!isAdded) { |
503 | const hlsjsTextTrack = displayableTracks[ idx ] | 505 | const hlsjsTextTrack = displayableTracks[idx] |
504 | this.player.addRemoteTextTrack({ | 506 | this.player.addRemoteTextTrack({ |
505 | kind: hlsjsTextTrack.kind as videojs.TextTrack.Kind, | 507 | kind: hlsjsTextTrack.kind as videojs.TextTrack.Kind, |
506 | label: this._getTextTrackLabel(hlsjsTextTrack), | 508 | label: this._getTextTrackLabel(hlsjsTextTrack), |
@@ -536,12 +538,12 @@ class Html5Hlsjs { | |||
536 | const VTTCue = (window as any).VTTCue || (window as any).TextTrackCue | 538 | const VTTCue = (window as any).VTTCue || (window as any).TextTrackCue |
537 | 539 | ||
538 | for (let r = 0; r < captionScreen.rows.length; r++) { | 540 | for (let r = 0; r < captionScreen.rows.length; r++) { |
539 | row = captionScreen.rows[ r ] | 541 | row = captionScreen.rows[r] |
540 | text = '' | 542 | text = '' |
541 | 543 | ||
542 | if (!row.isEmpty()) { | 544 | if (!row.isEmpty()) { |
543 | for (let c = 0; c < row.chars.length; c++) { | 545 | for (let c = 0; c < row.chars.length; c++) { |
544 | text += row.chars[ c ].ucharj | 546 | text += row.chars[c].ucharj |
545 | } | 547 | } |
546 | 548 | ||
547 | cue = new VTTCue(startTime, endTime, text.trim()) | 549 | cue = new VTTCue(startTime, endTime, text.trim()) |
@@ -552,7 +554,7 @@ class Html5Hlsjs { | |||
552 | const configKeys = Object.keys(captionConfig) | 554 | const configKeys = Object.keys(captionConfig) |
553 | 555 | ||
554 | for (let k = 0; k < configKeys.length; k++) { | 556 | for (let k = 0; k < configKeys.length; k++) { |
555 | cue[ configKeys[ k ] ] = captionConfig[ configKeys[ k ] ] | 557 | cue[configKeys[k]] = captionConfig[configKeys[k]] |
556 | } | 558 | } |
557 | } | 559 | } |
558 | track.addCue(cue) | 560 | track.addCue(cue) |
@@ -567,7 +569,7 @@ class Html5Hlsjs { | |||
567 | const techOptions = this.tech.options_ as HlsjsConfigHandlerOptions | 569 | const techOptions = this.tech.options_ as HlsjsConfigHandlerOptions |
568 | const srOptions_ = this.player.srOptions_ | 570 | const srOptions_ = this.player.srOptions_ |
569 | 571 | ||
570 | const hlsjsConfigRef = srOptions_ && srOptions_.hlsjsConfig || techOptions.hlsjsConfig | 572 | const hlsjsConfigRef = srOptions_?.hlsjsConfig || techOptions.hlsjsConfig |
571 | // Hls.js will write to the reference thus change the object for later streams | 573 | // Hls.js will write to the reference thus change the object for later streams |
572 | this.hlsjsConfig = hlsjsConfigRef ? this._oneLevelObjClone(hlsjsConfigRef) : {} | 574 | this.hlsjsConfig = hlsjsConfigRef ? this._oneLevelObjClone(hlsjsConfigRef) : {} |
573 | 575 | ||
@@ -575,7 +577,7 @@ class Html5Hlsjs { | |||
575 | this.hlsjsConfig.autoStartLoad = false | 577 | this.hlsjsConfig.autoStartLoad = false |
576 | } | 578 | } |
577 | 579 | ||
578 | const captionConfig = srOptions_ && srOptions_.captionConfig || techOptions.captionConfig | 580 | const captionConfig = srOptions_?.captionConfig || techOptions.captionConfig |
579 | if (captionConfig) { | 581 | if (captionConfig) { |
580 | this.hlsjsConfig.cueHandler = this._createCueHandler(captionConfig) | 582 | this.hlsjsConfig.cueHandler = this._createCueHandler(captionConfig) |
581 | } | 583 | } |
diff --git a/client/src/assets/player/p2p-media-loader/segment-validator.ts b/client/src/assets/player/p2p-media-loader/segment-validator.ts index d0a4c4a3f..f7f83a8a4 100644 --- a/client/src/assets/player/p2p-media-loader/segment-validator.ts +++ b/client/src/assets/player/p2p-media-loader/segment-validator.ts | |||
@@ -86,6 +86,7 @@ async function sha256Hex (data?: ArrayBuffer) { | |||
86 | 86 | ||
87 | // Fallback for non HTTPS context | 87 | // Fallback for non HTTPS context |
88 | const shaModule = (await import('sha.js') as any).default | 88 | const shaModule = (await import('sha.js') as any).default |
89 | // eslint-disable-next-line new-cap | ||
89 | return new shaModule.sha256().update(Buffer.from(data)).digest('hex') | 90 | return new shaModule.sha256().update(Buffer.from(data)).digest('hex') |
90 | } | 91 | } |
91 | 92 | ||
@@ -97,7 +98,9 @@ function bufferToHex (buffer?: ArrayBuffer) { | |||
97 | const h = '0123456789abcdef' | 98 | const h = '0123456789abcdef' |
98 | const o = new Uint8Array(buffer) | 99 | const o = new Uint8Array(buffer) |
99 | 100 | ||
100 | o.forEach((v: any) => s += h[ v >> 4 ] + h[ v & 15 ]) | 101 | o.forEach((v: any) => { |
102 | s += h[v >> 4] + h[v & 15] | ||
103 | }) | ||
101 | 104 | ||
102 | return s | 105 | return s |
103 | } | 106 | } |
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index c45e8f53e..f3c21fc4c 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -435,8 +435,6 @@ export class PeertubePlayerManager { | |||
435 | const p2pMediaLoaderOptions = options.p2pMediaLoader | 435 | const p2pMediaLoaderOptions = options.p2pMediaLoader |
436 | 436 | ||
437 | const autoplay = this.getAutoPlayValue(commonOptions.autoplay) === 'play' | 437 | const autoplay = this.getAutoPlayValue(commonOptions.autoplay) === 'play' |
438 | ? true | ||
439 | : false | ||
440 | 438 | ||
441 | const webtorrent = { | 439 | const webtorrent = { |
442 | autoplay, | 440 | autoplay, |
@@ -459,10 +457,10 @@ export class PeertubePlayerManager { | |||
459 | theaterButton: boolean | 457 | theaterButton: boolean |
460 | captions: boolean | 458 | captions: boolean |
461 | 459 | ||
462 | nextVideo?: Function | 460 | nextVideo?: () => void |
463 | hasNextVideo?: () => boolean | 461 | hasNextVideo?: () => boolean |
464 | 462 | ||
465 | previousVideo?: Function | 463 | previousVideo?: () => void |
466 | hasPreviousVideo?: () => boolean | 464 | hasPreviousVideo?: () => boolean |
467 | }) { | 465 | }) { |
468 | const settingEntries = [] | 466 | const settingEntries = [] |
@@ -487,7 +485,7 @@ export class PeertubePlayerManager { | |||
487 | } | 485 | } |
488 | 486 | ||
489 | Object.assign(children, { | 487 | Object.assign(children, { |
490 | 'previousVideoButton': buttonOptions | 488 | previousVideoButton: buttonOptions |
491 | }) | 489 | }) |
492 | } | 490 | } |
493 | 491 | ||
@@ -505,35 +503,35 @@ export class PeertubePlayerManager { | |||
505 | } | 503 | } |
506 | 504 | ||
507 | Object.assign(children, { | 505 | Object.assign(children, { |
508 | 'nextVideoButton': buttonOptions | 506 | nextVideoButton: buttonOptions |
509 | }) | 507 | }) |
510 | } | 508 | } |
511 | 509 | ||
512 | Object.assign(children, { | 510 | Object.assign(children, { |
513 | 'currentTimeDisplay': {}, | 511 | currentTimeDisplay: {}, |
514 | 'timeDivider': {}, | 512 | timeDivider: {}, |
515 | 'durationDisplay': {}, | 513 | durationDisplay: {}, |
516 | 'liveDisplay': {}, | 514 | liveDisplay: {}, |
517 | 515 | ||
518 | 'flexibleWidthSpacer': {}, | 516 | flexibleWidthSpacer: {}, |
519 | 'progressControl': { | 517 | progressControl: { |
520 | children: { | 518 | children: { |
521 | 'seekBar': { | 519 | seekBar: { |
522 | children: { | 520 | children: { |
523 | [loadProgressBar]: {}, | 521 | [loadProgressBar]: {}, |
524 | 'mouseTimeDisplay': {}, | 522 | mouseTimeDisplay: {}, |
525 | 'playProgressBar': {} | 523 | playProgressBar: {} |
526 | } | 524 | } |
527 | } | 525 | } |
528 | } | 526 | } |
529 | }, | 527 | }, |
530 | 528 | ||
531 | 'p2PInfoButton': {}, | 529 | p2PInfoButton: {}, |
532 | 530 | ||
533 | 'muteToggle': {}, | 531 | muteToggle: {}, |
534 | 'volumeControl': {}, | 532 | volumeControl: {}, |
535 | 533 | ||
536 | 'settingsButton': { | 534 | settingsButton: { |
537 | setup: { | 535 | setup: { |
538 | maxHeightOffset: 40 | 536 | maxHeightOffset: 40 |
539 | }, | 537 | }, |
@@ -543,18 +541,18 @@ export class PeertubePlayerManager { | |||
543 | 541 | ||
544 | if (options.peertubeLink === true) { | 542 | if (options.peertubeLink === true) { |
545 | Object.assign(children, { | 543 | Object.assign(children, { |
546 | 'peerTubeLinkButton': { shortUUID: options.videoShortUUID } as PeerTubeLinkButtonOptions | 544 | peerTubeLinkButton: { shortUUID: options.videoShortUUID } as PeerTubeLinkButtonOptions |
547 | }) | 545 | }) |
548 | } | 546 | } |
549 | 547 | ||
550 | if (options.theaterButton === true) { | 548 | if (options.theaterButton === true) { |
551 | Object.assign(children, { | 549 | Object.assign(children, { |
552 | 'theaterButton': {} | 550 | theaterButton: {} |
553 | }) | 551 | }) |
554 | } | 552 | } |
555 | 553 | ||
556 | Object.assign(children, { | 554 | Object.assign(children, { |
557 | 'fullscreenToggle': {} | 555 | fullscreenToggle: {} |
558 | }) | 556 | }) |
559 | 557 | ||
560 | return children | 558 | return children |
diff --git a/client/src/assets/player/peertube-plugin.ts b/client/src/assets/player/peertube-plugin.ts index ade8e2ee4..b4841b235 100644 --- a/client/src/assets/player/peertube-plugin.ts +++ b/client/src/assets/player/peertube-plugin.ts | |||
@@ -211,7 +211,7 @@ class PeerTubePlugin extends Plugin { | |||
211 | const body = new URLSearchParams() | 211 | const body = new URLSearchParams() |
212 | body.append('currentTime', currentTime.toString()) | 212 | body.append('currentTime', currentTime.toString()) |
213 | 213 | ||
214 | const headers = new Headers({ 'Authorization': authorizationHeader }) | 214 | const headers = new Headers({ Authorization: authorizationHeader }) |
215 | 215 | ||
216 | return fetch(url, { method: 'PUT', body, headers }) | 216 | return fetch(url, { method: 'PUT', body, headers }) |
217 | } | 217 | } |
diff --git a/client/src/assets/player/peertube-videojs-typings.ts b/client/src/assets/player/peertube-videojs-typings.ts index f0eb129d4..97828c802 100644 --- a/client/src/assets/player/peertube-videojs-typings.ts +++ b/client/src/assets/player/peertube-videojs-typings.ts | |||
@@ -1,3 +1,6 @@ | |||
1 | // FIXME: lint | ||
2 | /* eslint-disable @typescript-eslint/ban-types */ | ||
3 | |||
1 | import { HlsConfig, Level } from 'hls.js' | 4 | import { HlsConfig, Level } from 'hls.js' |
2 | import videojs from 'video.js' | 5 | import videojs from 'video.js' |
3 | import { VideoFile, VideoPlaylist, VideoPlaylistElement } from '@shared/models' | 6 | import { VideoFile, VideoPlaylist, VideoPlaylistElement } from '@shared/models' |
@@ -93,7 +96,7 @@ type VideoJSCaption = { | |||
93 | } | 96 | } |
94 | 97 | ||
95 | type UserWatching = { | 98 | type UserWatching = { |
96 | url: string, | 99 | url: string |
97 | authorizationHeader: string | 100 | authorizationHeader: string |
98 | } | 101 | } |
99 | 102 | ||
@@ -166,7 +169,7 @@ type VideoJSPluginOptions = { | |||
166 | } | 169 | } |
167 | 170 | ||
168 | type LoadedQualityData = { | 171 | type LoadedQualityData = { |
169 | qualitySwitchCallback: Function, | 172 | qualitySwitchCallback: (resolutionId: number, type: 'video') => void |
170 | qualityData: { | 173 | qualityData: { |
171 | video: { | 174 | video: { |
172 | id: number | 175 | id: number |
@@ -177,7 +180,7 @@ type LoadedQualityData = { | |||
177 | } | 180 | } |
178 | 181 | ||
179 | type ResolutionUpdateData = { | 182 | type ResolutionUpdateData = { |
180 | auto: boolean, | 183 | auto: boolean |
181 | resolutionId: number | 184 | resolutionId: number |
182 | id?: number | 185 | id?: number |
183 | } | 186 | } |
diff --git a/client/src/assets/player/stats/stats-card.ts b/client/src/assets/player/stats/stats-card.ts index b271d0526..a32f6fb97 100644 --- a/client/src/assets/player/stats/stats-card.ts +++ b/client/src/assets/player/stats/stats-card.ts | |||
@@ -39,10 +39,6 @@ class StatsCard extends Component { | |||
39 | intervalMs = 300 | 39 | intervalMs = 300 |
40 | playerNetworkInfo: PlayerNetworkInfo = {} | 40 | playerNetworkInfo: PlayerNetworkInfo = {} |
41 | 41 | ||
42 | constructor (player: videojs.Player, options: StatsCardOptions) { | ||
43 | super(player, options) | ||
44 | } | ||
45 | |||
46 | createEl () { | 42 | createEl () { |
47 | const container = super.createEl('div', { | 43 | const container = super.createEl('div', { |
48 | className: 'vjs-stats-content', | 44 | className: 'vjs-stats-content', |
@@ -81,9 +77,8 @@ class StatsCard extends Component { | |||
81 | } | 77 | } |
82 | 78 | ||
83 | toggle () { | 79 | toggle () { |
84 | this.updateInterval | 80 | if (this.updateInterval) this.hide() |
85 | ? this.hide() | 81 | else this.show() |
86 | : this.show() | ||
87 | } | 82 | } |
88 | 83 | ||
89 | show () { | 84 | show () { |
diff --git a/client/src/assets/player/translations-manager.ts b/client/src/assets/player/translations-manager.ts index d5a09a31a..8a6e67dda 100644 --- a/client/src/assets/player/translations-manager.ts +++ b/client/src/assets/player/translations-manager.ts | |||
@@ -23,13 +23,13 @@ export class TranslationsManager { | |||
23 | 23 | ||
24 | let p: Promise<any> | 24 | let p: Promise<any> |
25 | 25 | ||
26 | if (TranslationsManager.videojsLocaleCache[ path ]) { | 26 | if (TranslationsManager.videojsLocaleCache[path]) { |
27 | p = Promise.resolve(TranslationsManager.videojsLocaleCache[ path ]) | 27 | p = Promise.resolve(TranslationsManager.videojsLocaleCache[path]) |
28 | } else { | 28 | } else { |
29 | p = fetch(path + '/player.json') | 29 | p = fetch(path + '/player.json') |
30 | .then(res => res.json()) | 30 | .then(res => res.json()) |
31 | .then(json => { | 31 | .then(json => { |
32 | TranslationsManager.videojsLocaleCache[ path ] = json | 32 | TranslationsManager.videojsLocaleCache[path] = json |
33 | return json | 33 | return json |
34 | }) | 34 | }) |
35 | .catch(err => { | 35 | .catch(err => { |
diff --git a/client/src/assets/player/upnext/end-card.ts b/client/src/assets/player/upnext/end-card.ts index 8fabfc3fd..61668e407 100644 --- a/client/src/assets/player/upnext/end-card.ts +++ b/client/src/assets/player/upnext/end-card.ts | |||
@@ -9,7 +9,9 @@ function getMainTemplate (options: any) { | |||
9 | <div class="vjs-upnext-autoplay-icon"> | 9 | <div class="vjs-upnext-autoplay-icon"> |
10 | <svg height="100%" version="1.1" viewbox="0 0 98 98" width="100%"> | 10 | <svg height="100%" version="1.1" viewbox="0 0 98 98" width="100%"> |
11 | <circle class="vjs-upnext-svg-autoplay-circle" cx="49" cy="49" fill="#000" fill-opacity="0.8" r="48"></circle> | 11 | <circle class="vjs-upnext-svg-autoplay-circle" cx="49" cy="49" fill="#000" fill-opacity="0.8" r="48"></circle> |
12 | <circle class="vjs-upnext-svg-autoplay-ring" cx="-49" cy="49" fill-opacity="0" r="46.5" stroke="#FFFFFF" stroke-width="4" transform="rotate(-90)"></circle> | 12 | <circle class="vjs-upnext-svg-autoplay-ring" cx="-49" cy="49" fill-opacity="0" r="46.5" |
13 | stroke="#FFFFFF" stroke-width="4" transform="rotate(-90)" | ||
14 | ></circle> | ||
13 | <polygon class="vjs-upnext-svg-autoplay-triangle" fill="#fff" points="32,27 72,49 32,71"></polygon></svg> | 15 | <polygon class="vjs-upnext-svg-autoplay-triangle" fill="#fff" points="32,27 72,49 32,71"></polygon></svg> |
14 | </div> | 16 | </div> |
15 | <span class="vjs-upnext-bottom"> | 17 | <span class="vjs-upnext-bottom"> |
@@ -22,7 +24,7 @@ function getMainTemplate (options: any) { | |||
22 | } | 24 | } |
23 | 25 | ||
24 | export interface EndCardOptions extends videojs.ComponentOptions { | 26 | export interface EndCardOptions extends videojs.ComponentOptions { |
25 | next: Function, | 27 | next: () => void |
26 | getTitle: () => string | 28 | getTitle: () => string |
27 | timeout: number | 29 | timeout: number |
28 | cancelText: string | 30 | cancelText: string |
@@ -99,11 +101,11 @@ class EndCard extends Component { | |||
99 | return container | 101 | return container |
100 | } | 102 | } |
101 | 103 | ||
102 | showCard (cb: Function) { | 104 | showCard (cb: (value: boolean) => void) { |
103 | let timeout: any | 105 | let timeout: any |
104 | 106 | ||
105 | this.autoplayRing.setAttribute('stroke-dasharray', '' + this.dashOffsetStart) | 107 | this.autoplayRing.setAttribute('stroke-dasharray', `${this.dashOffsetStart}`) |
106 | this.autoplayRing.setAttribute('stroke-dashoffset', '' + -this.dashOffsetStart) | 108 | this.autoplayRing.setAttribute('stroke-dashoffset', `${-this.dashOffsetStart}`) |
107 | 109 | ||
108 | this.title.innerHTML = this.options_.getTitle() | 110 | this.title.innerHTML = this.options_.getTitle() |
109 | 111 | ||
@@ -123,7 +125,7 @@ class EndCard extends Component { | |||
123 | }) | 125 | }) |
124 | 126 | ||
125 | const goToPercent = (percent: number) => { | 127 | const goToPercent = (percent: number) => { |
126 | const newOffset = Math.max(-this.dashOffsetTotal, - this.dashOffsetStart - percent * this.dashOffsetTotal / 2 / 100) | 128 | const newOffset = Math.max(-this.dashOffsetTotal, -this.dashOffsetStart - percent * this.dashOffsetTotal / 2 / 100) |
127 | this.autoplayRing.setAttribute('stroke-dashoffset', '' + newOffset) | 129 | this.autoplayRing.setAttribute('stroke-dashoffset', '' + newOffset) |
128 | } | 130 | } |
129 | 131 | ||
diff --git a/client/src/assets/player/utils.ts b/client/src/assets/player/utils.ts index f0a1b1aee..f2e9adb14 100644 --- a/client/src/assets/player/utils.ts +++ b/client/src/assets/player/utils.ts | |||
@@ -17,7 +17,7 @@ function isIOS () { | |||
17 | // Detect iPad Desktop mode | 17 | // Detect iPad Desktop mode |
18 | return !!(navigator.maxTouchPoints && | 18 | return !!(navigator.maxTouchPoints && |
19 | navigator.maxTouchPoints > 2 && | 19 | navigator.maxTouchPoints > 2 && |
20 | /MacIntel/.test(navigator.platform)) | 20 | navigator.platform.includes('MacIntel')) |
21 | } | 21 | } |
22 | 22 | ||
23 | function isSafari () { | 23 | function isSafari () { |
diff --git a/client/src/assets/player/videojs-components/p2p-info-button.ts b/client/src/assets/player/videojs-components/p2p-info-button.ts index 81f9544f4..07ed18989 100644 --- a/client/src/assets/player/videojs-components/p2p-info-button.ts +++ b/client/src/assets/player/videojs-components/p2p-info-button.ts | |||
@@ -96,11 +96,11 @@ class P2pInfoButton extends Button { | |||
96 | } | 96 | } |
97 | subDivWebtorrent.title += this.player().localize('Total uploaded: ') + totalUploaded.join(' ') | 97 | subDivWebtorrent.title += this.player().localize('Total uploaded: ') + totalUploaded.join(' ') |
98 | 98 | ||
99 | downloadSpeedNumber.textContent = downloadSpeed[ 0 ] | 99 | downloadSpeedNumber.textContent = downloadSpeed[0] |
100 | downloadSpeedUnit.textContent = ' ' + downloadSpeed[ 1 ] | 100 | downloadSpeedUnit.textContent = ' ' + downloadSpeed[1] |
101 | 101 | ||
102 | uploadSpeedNumber.textContent = uploadSpeed[ 0 ] | 102 | uploadSpeedNumber.textContent = uploadSpeed[0] |
103 | uploadSpeedUnit.textContent = ' ' + uploadSpeed[ 1 ] | 103 | uploadSpeedUnit.textContent = ' ' + uploadSpeed[1] |
104 | 104 | ||
105 | peersNumber.textContent = numPeers.toString() | 105 | peersNumber.textContent = numPeers.toString() |
106 | peersText.textContent = ' ' + (numPeers > 1 ? this.player().localize('peers') : this.player_.localize('peer')) | 106 | peersText.textContent = ' ' + (numPeers > 1 ? this.player().localize('peers') : this.player_.localize('peer')) |
diff --git a/client/src/assets/player/videojs-components/resolution-menu-item.ts b/client/src/assets/player/videojs-components/resolution-menu-item.ts index 73ad47d2b..c1f502600 100644 --- a/client/src/assets/player/videojs-components/resolution-menu-item.ts +++ b/client/src/assets/player/videojs-components/resolution-menu-item.ts | |||
@@ -6,7 +6,7 @@ const MenuItem = videojs.getComponent('MenuItem') | |||
6 | export interface ResolutionMenuItemOptions extends videojs.MenuItemOptions { | 6 | export interface ResolutionMenuItemOptions extends videojs.MenuItemOptions { |
7 | labels?: { [id: number]: string } | 7 | labels?: { [id: number]: string } |
8 | id: number | 8 | id: number |
9 | callback: Function | 9 | callback: (resolutionId: number, type: 'video') => void |
10 | } | 10 | } |
11 | 11 | ||
12 | class ResolutionMenuItem extends MenuItem { | 12 | class ResolutionMenuItem extends MenuItem { |
@@ -14,7 +14,7 @@ class ResolutionMenuItem extends MenuItem { | |||
14 | private readonly label: string | 14 | private readonly label: string |
15 | // Only used for the automatic item | 15 | // Only used for the automatic item |
16 | private readonly labels: { [id: number]: string } | 16 | private readonly labels: { [id: number]: string } |
17 | private readonly callback: Function | 17 | private readonly callback: (resolutionId: number, type: 'video') => void |
18 | 18 | ||
19 | private autoResolutionPossible: boolean | 19 | private autoResolutionPossible: boolean |
20 | private currentResolutionLabel: string | 20 | private currentResolutionLabel: string |
diff --git a/client/src/assets/player/videojs-components/settings-dialog.ts b/client/src/assets/player/videojs-components/settings-dialog.ts index 41911e7e8..8cd98967f 100644 --- a/client/src/assets/player/videojs-components/settings-dialog.ts +++ b/client/src/assets/player/videojs-components/settings-dialog.ts | |||
@@ -12,8 +12,6 @@ class SettingsDialog extends Component { | |||
12 | /** | 12 | /** |
13 | * Create the component's DOM element | 13 | * Create the component's DOM element |
14 | * | 14 | * |
15 | * @return {Element} | ||
16 | * @method createEl | ||
17 | */ | 15 | */ |
18 | createEl () { | 16 | createEl () { |
19 | const uniqueId = this.id() | 17 | const uniqueId = this.id() |
@@ -25,7 +23,7 @@ class SettingsDialog extends Component { | |||
25 | innerHTML: '', | 23 | innerHTML: '', |
26 | tabIndex: -1 | 24 | tabIndex: -1 |
27 | }, { | 25 | }, { |
28 | 'role': 'dialog', | 26 | role: 'dialog', |
29 | 'aria-labelledby': dialogLabelId, | 27 | 'aria-labelledby': dialogLabelId, |
30 | 'aria-describedby': dialogDescriptionId | 28 | 'aria-describedby': dialogDescriptionId |
31 | }) | 29 | }) |
diff --git a/client/src/assets/player/videojs-components/settings-menu-item.ts b/client/src/assets/player/videojs-components/settings-menu-item.ts index f1342f179..1871d41f8 100644 --- a/client/src/assets/player/videojs-components/settings-menu-item.ts +++ b/client/src/assets/player/videojs-components/settings-menu-item.ts | |||
@@ -1,8 +1,8 @@ | |||
1 | import videojs from 'video.js' | ||
1 | // Thanks to Yanko Shterev: https://github.com/yshterev/videojs-settings-menu | 2 | // Thanks to Yanko Shterev: https://github.com/yshterev/videojs-settings-menu |
2 | import { toTitleCase } from '../utils' | 3 | import { toTitleCase } from '../utils' |
3 | import videojs from 'video.js' | ||
4 | import { SettingsButton } from './settings-menu-button' | ||
5 | import { SettingsDialog } from './settings-dialog' | 4 | import { SettingsDialog } from './settings-dialog' |
5 | import { SettingsButton } from './settings-menu-button' | ||
6 | import { SettingsPanel } from './settings-panel' | 6 | import { SettingsPanel } from './settings-panel' |
7 | import { SettingsPanelChild } from './settings-panel-child' | 7 | import { SettingsPanelChild } from './settings-panel-child' |
8 | 8 | ||
@@ -57,7 +57,7 @@ class SettingsMenuItem extends MenuItem { | |||
57 | const newOptions = Object.assign({}, options, { entry: options.menuButton, menuButton: this }) | 57 | const newOptions = Object.assign({}, options, { entry: options.menuButton, menuButton: this }) |
58 | 58 | ||
59 | this.subMenu = new SubMenuComponent(this.player(), newOptions) as any // FIXME: typings | 59 | this.subMenu = new SubMenuComponent(this.player(), newOptions) as any // FIXME: typings |
60 | const subMenuClass = this.subMenu.buildCSSClass().split(' ')[ 0 ] | 60 | const subMenuClass = this.subMenu.buildCSSClass().split(' ')[0] |
61 | this.settingsSubMenuEl_.className += ' ' + subMenuClass | 61 | this.settingsSubMenuEl_.className += ' ' + subMenuClass |
62 | 62 | ||
63 | this.eventHandlers() | 63 | this.eventHandlers() |
@@ -104,7 +104,7 @@ class SettingsMenuItem extends MenuItem { | |||
104 | target = event.currentTarget | 104 | target = event.currentTarget |
105 | } | 105 | } |
106 | 106 | ||
107 | if (target && target.classList.contains('vjs-back-button')) { | 107 | if (target?.classList.contains('vjs-back-button')) { |
108 | this.loadMainMenu() | 108 | this.loadMainMenu() |
109 | return | 109 | return |
110 | } | 110 | } |
@@ -121,8 +121,6 @@ class SettingsMenuItem extends MenuItem { | |||
121 | /** | 121 | /** |
122 | * Create the component's DOM element | 122 | * Create the component's DOM element |
123 | * | 123 | * |
124 | * @return {Element} | ||
125 | * @method createEl | ||
126 | */ | 124 | */ |
127 | createEl () { | 125 | createEl () { |
128 | const el = videojs.dom.createEl('li', { | 126 | const el = videojs.dom.createEl('li', { |
@@ -198,14 +196,14 @@ class SettingsMenuItem extends MenuItem { | |||
198 | const prefix = [ 'webkit', 'moz', 'MS', 'o', '' ] | 196 | const prefix = [ 'webkit', 'moz', 'MS', 'o', '' ] |
199 | 197 | ||
200 | for (let p = 0; p < prefix.length; p++) { | 198 | for (let p = 0; p < prefix.length; p++) { |
201 | if (!prefix[ p ]) { | 199 | if (!prefix[p]) { |
202 | type = type.toLowerCase() | 200 | type = type.toLowerCase() |
203 | } | 201 | } |
204 | 202 | ||
205 | if (action === 'addEvent') { | 203 | if (action === 'addEvent') { |
206 | element.addEventListener(prefix[ p ] + type, callback, false) | 204 | element.addEventListener(prefix[p] + type, callback, false) |
207 | } else if (action === 'removeEvent') { | 205 | } else if (action === 'removeEvent') { |
208 | element.removeEventListener(prefix[ p ] + type, callback, false) | 206 | element.removeEventListener(prefix[p] + type, callback, false) |
209 | } | 207 | } |
210 | } | 208 | } |
211 | } | 209 | } |
@@ -292,7 +290,10 @@ class SettingsMenuItem extends MenuItem { | |||
292 | // Thus we get the submenu value based on the labelEl of playbackRateMenuButton | 290 | // Thus we get the submenu value based on the labelEl of playbackRateMenuButton |
293 | if (subMenu === 'PlaybackRateMenuButton') { | 291 | if (subMenu === 'PlaybackRateMenuButton') { |
294 | const html = (this.subMenu as any).labelEl_.innerHTML | 292 | const html = (this.subMenu as any).labelEl_.innerHTML |
295 | setTimeout(() => this.settingsSubMenuValueEl_.innerHTML = html, 250) | 293 | |
294 | setTimeout(() => { | ||
295 | this.settingsSubMenuValueEl_.innerHTML = html | ||
296 | }, 250) | ||
296 | } else { | 297 | } else { |
297 | // Loop trough the submenu items to find the selected child | 298 | // Loop trough the submenu items to find the selected child |
298 | for (const subMenuItem of this.subMenu.menu.children_) { | 299 | for (const subMenuItem of this.subMenu.menu.children_) { |
diff --git a/client/src/assets/player/videojs-components/settings-panel-child.ts b/client/src/assets/player/videojs-components/settings-panel-child.ts index d1582412c..161420c38 100644 --- a/client/src/assets/player/videojs-components/settings-panel-child.ts +++ b/client/src/assets/player/videojs-components/settings-panel-child.ts | |||
@@ -4,10 +4,6 @@ const Component = videojs.getComponent('Component') | |||
4 | 4 | ||
5 | class SettingsPanelChild extends Component { | 5 | class SettingsPanelChild extends Component { |
6 | 6 | ||
7 | constructor (player: videojs.Player, options?: videojs.ComponentOptions) { | ||
8 | super(player, options) | ||
9 | } | ||
10 | |||
11 | createEl () { | 7 | createEl () { |
12 | return super.createEl('div', { | 8 | return super.createEl('div', { |
13 | className: 'vjs-settings-panel-child', | 9 | className: 'vjs-settings-panel-child', |
diff --git a/client/src/assets/player/videojs-components/settings-panel.ts b/client/src/assets/player/videojs-components/settings-panel.ts index 1ad8bb1fc..28b579bdd 100644 --- a/client/src/assets/player/videojs-components/settings-panel.ts +++ b/client/src/assets/player/videojs-components/settings-panel.ts | |||
@@ -4,10 +4,6 @@ const Component = videojs.getComponent('Component') | |||
4 | 4 | ||
5 | class SettingsPanel extends Component { | 5 | class SettingsPanel extends Component { |
6 | 6 | ||
7 | constructor (player: videojs.Player, options?: videojs.ComponentOptions) { | ||
8 | super(player, options) | ||
9 | } | ||
10 | |||
11 | createEl () { | 7 | createEl () { |
12 | return super.createEl('div', { | 8 | return super.createEl('div', { |
13 | className: 'vjs-settings-panel', | 9 | className: 'vjs-settings-panel', |
diff --git a/client/src/assets/player/webtorrent/peertube-chunk-store.ts b/client/src/assets/player/webtorrent/peertube-chunk-store.ts index 66762bef8..93ca8e1d8 100644 --- a/client/src/assets/player/webtorrent/peertube-chunk-store.ts +++ b/client/src/assets/player/webtorrent/peertube-chunk-store.ts | |||
@@ -36,7 +36,7 @@ export class PeertubeChunkStore extends EventEmitter { | |||
36 | 36 | ||
37 | chunkLength: number | 37 | chunkLength: number |
38 | 38 | ||
39 | private pendingPut: { id: number, buf: Buffer, cb: Function }[] = [] | 39 | private pendingPut: { id: number, buf: Buffer, cb: (err?: Error) => void }[] = [] |
40 | // If the store is full | 40 | // If the store is full |
41 | private memoryChunks: { [ id: number ]: Buffer | true } = {} | 41 | private memoryChunks: { [ id: number ]: Buffer | true } = {} |
42 | private databaseName: string | 42 | private databaseName: string |
@@ -54,7 +54,7 @@ export class PeertubeChunkStore extends EventEmitter { | |||
54 | this.databaseName = 'webtorrent-chunks-' | 54 | this.databaseName = 'webtorrent-chunks-' |
55 | 55 | ||
56 | if (!opts) opts = {} | 56 | if (!opts) opts = {} |
57 | if (opts.torrent && opts.torrent.infoHash) this.databaseName += opts.torrent.infoHash | 57 | if (opts.torrent?.infoHash) this.databaseName += opts.torrent.infoHash |
58 | else this.databaseName += '-default' | 58 | else this.databaseName += '-default' |
59 | 59 | ||
60 | this.setMaxListeners(100) | 60 | this.setMaxListeners(100) |
@@ -106,7 +106,9 @@ export class PeertubeChunkStore extends EventEmitter { | |||
106 | } catch (err) { | 106 | } catch (err) { |
107 | console.log('Cannot bulk insert chunks. Store them in memory.', { err }) | 107 | console.log('Cannot bulk insert chunks. Store them in memory.', { err }) |
108 | 108 | ||
109 | processing.forEach(p => this.memoryChunks[ p.id ] = p.buf) | 109 | processing.forEach(p => { |
110 | this.memoryChunks[p.id] = p.buf | ||
111 | }) | ||
110 | } finally { | 112 | } finally { |
111 | processing.forEach(p => p.cb()) | 113 | processing.forEach(p => p.cb()) |
112 | } | 114 | } |
diff --git a/client/src/assets/player/webtorrent/video-renderer.ts b/client/src/assets/player/webtorrent/video-renderer.ts index c3cbea725..8fb3e9672 100644 --- a/client/src/assets/player/webtorrent/video-renderer.ts +++ b/client/src/assets/player/webtorrent/video-renderer.ts | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | const MediaElementWrapper = require('mediasource') | 4 | const MediaElementWrapper = require('mediasource') |
5 | import { extname } from 'path' | 5 | import { extname } from 'path' |
6 | const videostream = require('videostream') | 6 | const Videostream = require('videostream') |
7 | 7 | ||
8 | const VIDEOSTREAM_EXTS = [ | 8 | const VIDEOSTREAM_EXTS = [ |
9 | '.m4a', | 9 | '.m4a', |
@@ -34,7 +34,7 @@ function renderMedia (file: any, elem: HTMLVideoElement, opts: RenderMediaOption | |||
34 | let renderer: any | 34 | let renderer: any |
35 | 35 | ||
36 | try { | 36 | try { |
37 | if (VIDEOSTREAM_EXTS.indexOf(extension) >= 0) { | 37 | if (VIDEOSTREAM_EXTS.includes(extension)) { |
38 | renderer = useVideostream() | 38 | renderer = useVideostream() |
39 | } else { | 39 | } else { |
40 | renderer = useMediaSource() | 40 | renderer = useMediaSource() |
@@ -51,7 +51,7 @@ function renderMedia (file: any, elem: HTMLVideoElement, opts: RenderMediaOption | |||
51 | return callback(err) | 51 | return callback(err) |
52 | }) | 52 | }) |
53 | preparedElem.addEventListener('loadstart', onLoadStart) | 53 | preparedElem.addEventListener('loadstart', onLoadStart) |
54 | return new videostream(file, preparedElem) | 54 | return new Videostream(file, preparedElem) |
55 | } | 55 | } |
56 | 56 | ||
57 | function useMediaSource (useVP9 = false) { | 57 | function useMediaSource (useVP9 = false) { |
@@ -62,7 +62,7 @@ function renderMedia (file: any, elem: HTMLVideoElement, opts: RenderMediaOption | |||
62 | preparedElem.removeEventListener('error', onError) | 62 | preparedElem.removeEventListener('error', onError) |
63 | 63 | ||
64 | // Try with vp9 before returning an error | 64 | // Try with vp9 before returning an error |
65 | if (codecs.indexOf('vp8') !== -1) return fallbackToMediaSource(true) | 65 | if (codecs.includes('vp8')) return fallbackToMediaSource(true) |
66 | 66 | ||
67 | return callback(err) | 67 | return callback(err) |
68 | }) | 68 | }) |
diff --git a/client/src/assets/player/webtorrent/webtorrent-plugin.ts b/client/src/assets/player/webtorrent/webtorrent-plugin.ts index 17d369c10..0587ddee6 100644 --- a/client/src/assets/player/webtorrent/webtorrent-plugin.ts +++ b/client/src/assets/player/webtorrent/webtorrent-plugin.ts | |||
@@ -17,8 +17,8 @@ import { renderVideo } from './video-renderer' | |||
17 | const CacheChunkStore = require('cache-chunk-store') | 17 | const CacheChunkStore = require('cache-chunk-store') |
18 | 18 | ||
19 | type PlayOptions = { | 19 | type PlayOptions = { |
20 | forcePlay?: boolean, | 20 | forcePlay?: boolean |
21 | seek?: number, | 21 | seek?: number |
22 | delay?: number | 22 | delay?: number |
23 | } | 23 | } |
24 | 24 | ||
@@ -126,8 +126,8 @@ class WebTorrentPlugin extends Plugin { | |||
126 | updateVideoFile ( | 126 | updateVideoFile ( |
127 | videoFile?: VideoFile, | 127 | videoFile?: VideoFile, |
128 | options: { | 128 | options: { |
129 | forcePlay?: boolean, | 129 | forcePlay?: boolean |
130 | seek?: number, | 130 | seek?: number |
131 | delay?: number | 131 | delay?: number |
132 | } = {}, | 132 | } = {}, |
133 | done: () => void = () => { /* empty */ } | 133 | done: () => void = () => { /* empty */ } |
@@ -248,7 +248,7 @@ class WebTorrentPlugin extends Plugin { | |||
248 | magnetOrTorrentUrl: string, | 248 | magnetOrTorrentUrl: string, |
249 | previousVideoFile: VideoFile, | 249 | previousVideoFile: VideoFile, |
250 | options: PlayOptions, | 250 | options: PlayOptions, |
251 | done: Function | 251 | done: (err?: Error) => void |
252 | ) { | 252 | ) { |
253 | if (!magnetOrTorrentUrl) return this.fallbackToHttp(options, done) | 253 | if (!magnetOrTorrentUrl) return this.fallbackToHttp(options, done) |
254 | 254 | ||
@@ -272,7 +272,7 @@ class WebTorrentPlugin extends Plugin { | |||
272 | this.stopTorrent(oldTorrent) | 272 | this.stopTorrent(oldTorrent) |
273 | 273 | ||
274 | // We use a fake renderer so we download correct pieces of the next file | 274 | // We use a fake renderer so we download correct pieces of the next file |
275 | if (options.delay) this.renderFileInFakeElement(torrent.files[ 0 ], options.delay) | 275 | if (options.delay) this.renderFileInFakeElement(torrent.files[0], options.delay) |
276 | } | 276 | } |
277 | 277 | ||
278 | // Render the video in a few seconds? (on resolution change for example, we wait some seconds of the new video resolution) | 278 | // Render the video in a few seconds? (on resolution change for example, we wait some seconds of the new video resolution) |
@@ -288,7 +288,7 @@ class WebTorrentPlugin extends Plugin { | |||
288 | if (options.seek) this.player.currentTime(options.seek) | 288 | if (options.seek) this.player.currentTime(options.seek) |
289 | 289 | ||
290 | const renderVideoOptions = { autoplay: false, controls: true } | 290 | const renderVideoOptions = { autoplay: false, controls: true } |
291 | renderVideo(torrent.files[ 0 ], this.playerElement, renderVideoOptions, (err, renderer) => { | 291 | renderVideo(torrent.files[0], this.playerElement, renderVideoOptions, (err, renderer) => { |
292 | this.renderer = renderer | 292 | this.renderer = renderer |
293 | 293 | ||
294 | if (err) return this.fallbackToHttp(options, done) | 294 | if (err) return this.fallbackToHttp(options, done) |
@@ -321,7 +321,7 @@ class WebTorrentPlugin extends Plugin { | |||
321 | if (err.message.indexOf('incorrect info hash') !== -1) { | 321 | if (err.message.indexOf('incorrect info hash') !== -1) { |
322 | console.error('Incorrect info hash detected, falling back to torrent file.') | 322 | console.error('Incorrect info hash detected, falling back to torrent file.') |
323 | const newOptions = { forcePlay: true, seek: options.seek } | 323 | const newOptions = { forcePlay: true, seek: options.seek } |
324 | return this.addTorrent(this.torrent[ 'xs' ], previousVideoFile, newOptions, done) | 324 | return this.addTorrent(this.torrent['xs'], previousVideoFile, newOptions, done) |
325 | } | 325 | } |
326 | 326 | ||
327 | // Remote instance is down | 327 | // Remote instance is down |
@@ -340,7 +340,7 @@ class WebTorrentPlugin extends Plugin { | |||
340 | if (playPromise !== undefined) { | 340 | if (playPromise !== undefined) { |
341 | return playPromise.then(() => done()) | 341 | return playPromise.then(() => done()) |
342 | .catch((err: Error) => { | 342 | .catch((err: Error) => { |
343 | if (err.message.indexOf('The play() request was interrupted by a call to pause()') !== -1) { | 343 | if (err.message.includes('The play() request was interrupted by a call to pause()')) { |
344 | return | 344 | return |
345 | } | 345 | } |
346 | 346 | ||
@@ -479,7 +479,7 @@ class WebTorrentPlugin extends Plugin { | |||
479 | } | 479 | } |
480 | 480 | ||
481 | private isPlayerWaiting () { | 481 | private isPlayerWaiting () { |
482 | return this.player && this.player.hasClass('vjs-waiting') | 482 | return this.player?.hasClass('vjs-waiting') |
483 | } | 483 | } |
484 | 484 | ||
485 | private runTorrentInfoScheduler () { | 485 | private runTorrentInfoScheduler () { |
@@ -513,7 +513,7 @@ class WebTorrentPlugin extends Plugin { | |||
513 | }, this.CONSTANTS.INFO_SCHEDULER) | 513 | }, this.CONSTANTS.INFO_SCHEDULER) |
514 | } | 514 | } |
515 | 515 | ||
516 | private fallbackToHttp (options: PlayOptions, done?: Function) { | 516 | private fallbackToHttp (options: PlayOptions, done?: (err?: Error) => void) { |
517 | const paused = this.player.paused() | 517 | const paused = this.player.paused() |
518 | 518 | ||
519 | this.disableAutoResolution(true) | 519 | this.disableAutoResolution(true) |
@@ -565,7 +565,7 @@ class WebTorrentPlugin extends Plugin { | |||
565 | private stopTorrent (torrent: WebTorrent.Torrent) { | 565 | private stopTorrent (torrent: WebTorrent.Torrent) { |
566 | torrent.pause() | 566 | torrent.pause() |
567 | // Pause does not remove actual peers (in particular the webseed peer) | 567 | // Pause does not remove actual peers (in particular the webseed peer) |
568 | torrent.removePeer(torrent[ 'ws' ]) | 568 | torrent.removePeer(torrent['ws']) |
569 | } | 569 | } |
570 | 570 | ||
571 | private renderFileInFakeElement (file: WebTorrent.TorrentFile, delay: number) { | 571 | private renderFileInFakeElement (file: WebTorrent.TorrentFile, delay: number) { |