diff options
author | Chocobozzz <me@florianbigard.com> | 2019-12-05 17:06:18 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2019-12-05 17:06:18 +0100 |
commit | 3d9a63d3d824e753e95292b5e1343e1ebf9eaf71 (patch) | |
tree | f52c6da3c014c83e8687fb09ec8645ea845bbcdf | |
parent | 0d3a9be9f13c2642cb6cf26fdebc5edf5217bbbc (diff) | |
download | PeerTube-3d9a63d3d824e753e95292b5e1343e1ebf9eaf71.tar.gz PeerTube-3d9a63d3d824e753e95292b5e1343e1ebf9eaf71.tar.zst PeerTube-3d9a63d3d824e753e95292b5e1343e1ebf9eaf71.zip |
Add hook to alter player build options
-rw-r--r-- | client/src/app/videos/+video-watch/video-watch.component.ts | 183 | ||||
-rw-r--r-- | client/src/assets/player/peertube-player-manager.ts | 8 | ||||
-rw-r--r-- | client/src/standalone/videos/embed.ts | 2 | ||||
-rw-r--r-- | shared/models/plugins/client-hook.model.ts | 6 |
4 files changed, 113 insertions, 86 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 aacd697cf..523865fef 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts | |||
@@ -5,7 +5,7 @@ import { RedirectService } from '@app/core/routing/redirect.service' | |||
5 | import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' | 5 | import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage' |
6 | import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' | 6 | import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component' |
7 | import { MetaService } from '@ngx-meta/core' | 7 | import { MetaService } from '@ngx-meta/core' |
8 | import { Notifier, ServerService } from '@app/core' | 8 | import { AuthUser, Notifier, ServerService } from '@app/core' |
9 | import { forkJoin, Observable, Subscription } from 'rxjs' | 9 | import { forkJoin, Observable, Subscription } from 'rxjs' |
10 | import { Hotkey, HotkeysService } from 'angular2-hotkeys' | 10 | import { Hotkey, HotkeysService } from 'angular2-hotkeys' |
11 | import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared' | 11 | import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared' |
@@ -391,10 +391,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
391 | 391 | ||
392 | this.videoWatchPlaylist.updatePlaylistIndex(video) | 392 | this.videoWatchPlaylist.updatePlaylistIndex(video) |
393 | 393 | ||
394 | let startTime = timeToInt(urlOptions.startTime) || (this.video.userHistory ? this.video.userHistory.currentTime : 0) | ||
395 | // If we are at the end of the video, reset the timer | ||
396 | if (this.video.duration - startTime <= 1) startTime = 0 | ||
397 | |||
398 | if (this.isVideoBlur(this.video)) { | 394 | if (this.isVideoBlur(this.video)) { |
399 | const res = await this.confirmService.confirm( | 395 | const res = await this.confirmService.confirm( |
400 | this.i18n('This video contains mature or explicit content. Are you sure you want to watch it?'), | 396 | this.i18n('This video contains mature or explicit content. Are you sure you want to watch it?'), |
@@ -413,84 +409,20 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
413 | this.playerElement.setAttribute('playsinline', 'true') | 409 | this.playerElement.setAttribute('playsinline', 'true') |
414 | playerElementWrapper.appendChild(this.playerElement) | 410 | playerElementWrapper.appendChild(this.playerElement) |
415 | 411 | ||
416 | const playerCaptions = videoCaptions.map(c => ({ | 412 | const params = { |
417 | label: c.language.label, | 413 | video: this.video, |
418 | language: c.language.id, | 414 | videoCaptions, |
419 | src: environment.apiUrl + c.captionPath | 415 | urlOptions, |
420 | })) | 416 | user: this.user |
421 | |||
422 | const options: PeertubePlayerManagerOptions = { | ||
423 | common: { | ||
424 | autoplay: this.isAutoplay(), | ||
425 | |||
426 | playerElement: this.playerElement, | ||
427 | onPlayerElementChange: (element: HTMLVideoElement) => this.playerElement = element, | ||
428 | |||
429 | videoDuration: this.video.duration, | ||
430 | enableHotkeys: true, | ||
431 | inactivityTimeout: 2500, | ||
432 | poster: this.video.previewUrl, | ||
433 | |||
434 | startTime, | ||
435 | stopTime: urlOptions.stopTime, | ||
436 | controls: urlOptions.controls, | ||
437 | muted: urlOptions.muted, | ||
438 | loop: urlOptions.loop, | ||
439 | subtitle: urlOptions.subtitle, | ||
440 | |||
441 | peertubeLink: urlOptions.peertubeLink, | ||
442 | |||
443 | theaterMode: true, | ||
444 | captions: videoCaptions.length !== 0, | ||
445 | |||
446 | videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE | ||
447 | ? this.videoService.getVideoViewUrl(this.video.uuid) | ||
448 | : null, | ||
449 | embedUrl: this.video.embedUrl, | ||
450 | |||
451 | language: this.localeId, | ||
452 | |||
453 | userWatching: this.user && this.user.videosHistoryEnabled === true ? { | ||
454 | url: this.videoService.getUserWatchingVideoUrl(this.video.uuid), | ||
455 | authorizationHeader: this.authService.getRequestHeaderValue() | ||
456 | } : undefined, | ||
457 | |||
458 | serverUrl: environment.apiUrl, | ||
459 | |||
460 | videoCaptions: playerCaptions | ||
461 | }, | ||
462 | |||
463 | webtorrent: { | ||
464 | videoFiles: this.video.files | ||
465 | } | ||
466 | } | ||
467 | |||
468 | let mode: PlayerMode | ||
469 | |||
470 | if (urlOptions.playerMode) { | ||
471 | if (urlOptions.playerMode === 'p2p-media-loader') mode = 'p2p-media-loader' | ||
472 | else mode = 'webtorrent' | ||
473 | } else { | ||
474 | if (this.video.hasHlsPlaylist()) mode = 'p2p-media-loader' | ||
475 | else mode = 'webtorrent' | ||
476 | } | ||
477 | |||
478 | if (mode === 'p2p-media-loader') { | ||
479 | const hlsPlaylist = this.video.getHlsPlaylist() | ||
480 | |||
481 | const p2pMediaLoader = { | ||
482 | playlistUrl: hlsPlaylist.playlistUrl, | ||
483 | segmentsSha256Url: hlsPlaylist.segmentsSha256Url, | ||
484 | redundancyBaseUrls: hlsPlaylist.redundancies.map(r => r.baseUrl), | ||
485 | trackerAnnounce: this.video.trackerUrls, | ||
486 | videoFiles: hlsPlaylist.files | ||
487 | } as P2PMediaLoaderOptions | ||
488 | |||
489 | Object.assign(options, { p2pMediaLoader }) | ||
490 | } | 417 | } |
418 | const { playerMode, playerOptions } = await this.hooks.wrapFun( | ||
419 | this.buildPlayerManagerOptions.bind(this), | ||
420 | params, | ||
421 | 'filter:internal.video-watch.player.build-options.result' | ||
422 | ) | ||
491 | 423 | ||
492 | this.zone.runOutsideAngular(async () => { | 424 | this.zone.runOutsideAngular(async () => { |
493 | this.player = await PeertubePlayerManager.initialize(mode, options, player => this.player = player) | 425 | this.player = await PeertubePlayerManager.initialize(playerMode, playerOptions, player => this.player = player) |
494 | this.player.focus() | 426 | this.player.focus() |
495 | 427 | ||
496 | this.player.on('customError', ({ err }: { err: any }) => this.handleError(err)) | 428 | this.player.on('customError', ({ err }: { err: any }) => this.handleError(err)) |
@@ -637,6 +569,97 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
637 | if (this.isUserLoggedIn()) this.hotkeysService.add(this.hotkeys) | 569 | if (this.isUserLoggedIn()) this.hotkeysService.add(this.hotkeys) |
638 | } | 570 | } |
639 | 571 | ||
572 | private buildPlayerManagerOptions (params: { | ||
573 | video: VideoDetails, | ||
574 | videoCaptions: VideoCaption[], | ||
575 | urlOptions: CustomizationOptions & { playerMode: PlayerMode }, | ||
576 | user?: AuthUser | ||
577 | }) { | ||
578 | const { video, videoCaptions, urlOptions, user } = params | ||
579 | |||
580 | let startTime = timeToInt(urlOptions.startTime) || (video.userHistory ? video.userHistory.currentTime : 0) | ||
581 | // If we are at the end of the video, reset the timer | ||
582 | if (video.duration - startTime <= 1) startTime = 0 | ||
583 | |||
584 | const playerCaptions = videoCaptions.map(c => ({ | ||
585 | label: c.language.label, | ||
586 | language: c.language.id, | ||
587 | src: environment.apiUrl + c.captionPath | ||
588 | })) | ||
589 | |||
590 | const options: PeertubePlayerManagerOptions = { | ||
591 | common: { | ||
592 | autoplay: this.isAutoplay(), | ||
593 | |||
594 | playerElement: this.playerElement, | ||
595 | onPlayerElementChange: (element: HTMLVideoElement) => this.playerElement = element, | ||
596 | |||
597 | videoDuration: video.duration, | ||
598 | enableHotkeys: true, | ||
599 | inactivityTimeout: 2500, | ||
600 | poster: video.previewUrl, | ||
601 | |||
602 | startTime, | ||
603 | stopTime: urlOptions.stopTime, | ||
604 | controls: urlOptions.controls, | ||
605 | muted: urlOptions.muted, | ||
606 | loop: urlOptions.loop, | ||
607 | subtitle: urlOptions.subtitle, | ||
608 | |||
609 | peertubeLink: urlOptions.peertubeLink, | ||
610 | |||
611 | theaterButton: true, | ||
612 | captions: videoCaptions.length !== 0, | ||
613 | |||
614 | videoViewUrl: video.privacy.id !== VideoPrivacy.PRIVATE | ||
615 | ? this.videoService.getVideoViewUrl(video.uuid) | ||
616 | : null, | ||
617 | embedUrl: video.embedUrl, | ||
618 | |||
619 | language: this.localeId, | ||
620 | |||
621 | userWatching: user && user.videosHistoryEnabled === true ? { | ||
622 | url: this.videoService.getUserWatchingVideoUrl(video.uuid), | ||
623 | authorizationHeader: this.authService.getRequestHeaderValue() | ||
624 | } : undefined, | ||
625 | |||
626 | serverUrl: environment.apiUrl, | ||
627 | |||
628 | videoCaptions: playerCaptions | ||
629 | }, | ||
630 | |||
631 | webtorrent: { | ||
632 | videoFiles: video.files | ||
633 | } | ||
634 | } | ||
635 | |||
636 | let mode: PlayerMode | ||
637 | |||
638 | if (urlOptions.playerMode) { | ||
639 | if (urlOptions.playerMode === 'p2p-media-loader') mode = 'p2p-media-loader' | ||
640 | else mode = 'webtorrent' | ||
641 | } else { | ||
642 | if (video.hasHlsPlaylist()) mode = 'p2p-media-loader' | ||
643 | else mode = 'webtorrent' | ||
644 | } | ||
645 | |||
646 | if (mode === 'p2p-media-loader') { | ||
647 | const hlsPlaylist = video.getHlsPlaylist() | ||
648 | |||
649 | const p2pMediaLoader = { | ||
650 | playlistUrl: hlsPlaylist.playlistUrl, | ||
651 | segmentsSha256Url: hlsPlaylist.segmentsSha256Url, | ||
652 | redundancyBaseUrls: hlsPlaylist.redundancies.map(r => r.baseUrl), | ||
653 | trackerAnnounce: video.trackerUrls, | ||
654 | videoFiles: hlsPlaylist.files | ||
655 | } as P2PMediaLoaderOptions | ||
656 | |||
657 | Object.assign(options, { p2pMediaLoader }) | ||
658 | } | ||
659 | |||
660 | return { playerMode: mode, playerOptions: options } | ||
661 | } | ||
662 | |||
640 | private pausePlayer () { | 663 | private pausePlayer () { |
641 | if (!this.player) return | 664 | if (!this.player) return |
642 | 665 | ||
diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 7c7c9ad2a..4ddbaed82 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts | |||
@@ -63,7 +63,7 @@ export interface CommonOptions extends CustomizationOptions { | |||
63 | inactivityTimeout: number | 63 | inactivityTimeout: number |
64 | poster: string | 64 | poster: string |
65 | 65 | ||
66 | theaterMode: boolean | 66 | theaterButton: boolean |
67 | captions: boolean | 67 | captions: boolean |
68 | 68 | ||
69 | videoViewUrl: string | 69 | videoViewUrl: string |
@@ -311,7 +311,7 @@ export class PeertubePlayerManager { | |||
311 | children: this.getControlBarChildren(mode, { | 311 | children: this.getControlBarChildren(mode, { |
312 | captions: commonOptions.captions, | 312 | captions: commonOptions.captions, |
313 | peertubeLink: commonOptions.peertubeLink, | 313 | peertubeLink: commonOptions.peertubeLink, |
314 | theaterMode: commonOptions.theaterMode | 314 | theaterButton: commonOptions.theaterButton |
315 | }) | 315 | }) |
316 | } | 316 | } |
317 | } | 317 | } |
@@ -382,7 +382,7 @@ export class PeertubePlayerManager { | |||
382 | 382 | ||
383 | private static getControlBarChildren (mode: PlayerMode, options: { | 383 | private static getControlBarChildren (mode: PlayerMode, options: { |
384 | peertubeLink: boolean | 384 | peertubeLink: boolean |
385 | theaterMode: boolean, | 385 | theaterButton: boolean, |
386 | captions: boolean | 386 | captions: boolean |
387 | }) { | 387 | }) { |
388 | const settingEntries = [] | 388 | const settingEntries = [] |
@@ -432,7 +432,7 @@ export class PeertubePlayerManager { | |||
432 | }) | 432 | }) |
433 | } | 433 | } |
434 | 434 | ||
435 | if (options.theaterMode === true) { | 435 | if (options.theaterButton === true) { |
436 | Object.assign(children, { | 436 | Object.assign(children, { |
437 | 'theaterButton': {} | 437 | 'theaterButton': {} |
438 | }) | 438 | }) |
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index 40d945824..bd012f506 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts | |||
@@ -194,7 +194,7 @@ export class PeerTubeEmbed { | |||
194 | enableHotkeys: true, | 194 | enableHotkeys: true, |
195 | peertubeLink: true, | 195 | peertubeLink: true, |
196 | poster: window.location.origin + videoInfo.previewPath, | 196 | poster: window.location.origin + videoInfo.previewPath, |
197 | theaterMode: false, | 197 | theaterButton: false, |
198 | 198 | ||
199 | serverUrl: window.location.origin, | 199 | serverUrl: window.location.origin, |
200 | language: navigator.language, | 200 | language: navigator.language, |
diff --git a/shared/models/plugins/client-hook.model.ts b/shared/models/plugins/client-hook.model.ts index 91167ff8c..f0cdb8b19 100644 --- a/shared/models/plugins/client-hook.model.ts +++ b/shared/models/plugins/client-hook.model.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | // Data from API hooks: {hookType}:api.{location}.{elementType}.{actionType}.{target} | 1 | // Data from API hooks: {hookType}:api.{location}.{elementType}.{actionType}.{target} |
2 | // Data in internal functions: {hookType}:{location}.{elementType}.{actionType}.{target} | ||
2 | 3 | ||
3 | export const clientFilterHookObject = { | 4 | export const clientFilterHookObject = { |
4 | // Filter params/result of the function that fetch videos of the trending page | 5 | // Filter params/result of the function that fetch videos of the trending page |
@@ -41,7 +42,10 @@ export const clientFilterHookObject = { | |||
41 | 'filter:api.search.video-channels.list.result': true, | 42 | 'filter:api.search.video-channels.list.result': true, |
42 | 43 | ||
43 | // Filter form | 44 | // Filter form |
44 | 'filter:api.signup.registration.create.params': true | 45 | 'filter:api.signup.registration.create.params': true, |
46 | |||
47 | // Filter the options to create our player | ||
48 | 'filter:internal.video-watch.player.build-options.result': true | ||
45 | } | 49 | } |
46 | 50 | ||
47 | export type ClientFilterHookName = keyof typeof clientFilterHookObject | 51 | export type ClientFilterHookName = keyof typeof clientFilterHookObject |