diff options
Diffstat (limited to 'client/src/app/videos/+video-watch/video-watch.component.ts')
-rw-r--r-- | client/src/app/videos/+video-watch/video-watch.component.ts | 119 |
1 files changed, 74 insertions, 45 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 67c5254b3..4dbfa41e5 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts | |||
@@ -7,29 +7,27 @@ import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-supp | |||
7 | import { MetaService } from '@ngx-meta/core' | 7 | import { MetaService } from '@ngx-meta/core' |
8 | import { Notifier, ServerService } from '@app/core' | 8 | import { Notifier, ServerService } from '@app/core' |
9 | import { forkJoin, Subscription } from 'rxjs' | 9 | import { forkJoin, Subscription } from 'rxjs' |
10 | // FIXME: something weird with our path definition in tsconfig and typings | ||
11 | // @ts-ignore | ||
12 | import videojs from 'video.js' | ||
13 | import 'videojs-hotkeys' | ||
14 | import { Hotkey, HotkeysService } from 'angular2-hotkeys' | 10 | import { Hotkey, HotkeysService } from 'angular2-hotkeys' |
15 | import * as WebTorrent from 'webtorrent' | ||
16 | import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared' | 11 | import { UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '../../../../../shared' |
17 | import '../../../assets/player/peertube-videojs-plugin' | ||
18 | import { AuthService, ConfirmService } from '../../core' | 12 | import { AuthService, ConfirmService } from '../../core' |
19 | import { RestExtractor, VideoBlacklistService } from '../../shared' | 13 | import { RestExtractor, VideoBlacklistService } from '../../shared' |
20 | import { VideoDetails } from '../../shared/video/video-details.model' | 14 | import { VideoDetails } from '../../shared/video/video-details.model' |
21 | import { VideoService } from '../../shared/video/video.service' | 15 | import { VideoService } from '../../shared/video/video.service' |
22 | import { MarkdownService } from '../shared' | ||
23 | import { VideoDownloadComponent } from './modal/video-download.component' | 16 | import { VideoDownloadComponent } from './modal/video-download.component' |
24 | import { VideoReportComponent } from './modal/video-report.component' | 17 | import { VideoReportComponent } from './modal/video-report.component' |
25 | import { VideoShareComponent } from './modal/video-share.component' | 18 | import { VideoShareComponent } from './modal/video-share.component' |
26 | import { VideoBlacklistComponent } from './modal/video-blacklist.component' | 19 | import { VideoBlacklistComponent } from './modal/video-blacklist.component' |
27 | import { SubscribeButtonComponent } from '@app/shared/user-subscription/subscribe-button.component' | 20 | import { SubscribeButtonComponent } from '@app/shared/user-subscription/subscribe-button.component' |
28 | import { addContextMenu, getVideojsOptions, loadLocaleInVideoJS } from '../../../assets/player/peertube-player' | ||
29 | import { I18n } from '@ngx-translate/i18n-polyfill' | 21 | import { I18n } from '@ngx-translate/i18n-polyfill' |
30 | import { environment } from '../../../environments/environment' | 22 | import { environment } from '../../../environments/environment' |
31 | import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils' | ||
32 | import { VideoCaptionService } from '@app/shared/video-caption' | 23 | import { VideoCaptionService } from '@app/shared/video-caption' |
24 | import { MarkdownService } from '@app/shared/renderer' | ||
25 | import { | ||
26 | P2PMediaLoaderOptions, | ||
27 | PeertubePlayerManager, | ||
28 | PeertubePlayerManagerOptions, | ||
29 | PlayerMode | ||
30 | } from '../../../assets/player/peertube-player-manager' | ||
33 | 31 | ||
34 | @Component({ | 32 | @Component({ |
35 | selector: 'my-video-watch', | 33 | selector: 'my-video-watch', |
@@ -46,7 +44,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
46 | @ViewChild('videoBlacklistModal') videoBlacklistModal: VideoBlacklistComponent | 44 | @ViewChild('videoBlacklistModal') videoBlacklistModal: VideoBlacklistComponent |
47 | @ViewChild('subscribeButton') subscribeButton: SubscribeButtonComponent | 45 | @ViewChild('subscribeButton') subscribeButton: SubscribeButtonComponent |
48 | 46 | ||
49 | player: videojs.Player | 47 | player: any |
50 | playerElement: HTMLVideoElement | 48 | playerElement: HTMLVideoElement |
51 | userRating: UserVideoRateType = null | 49 | userRating: UserVideoRateType = null |
52 | video: VideoDetails = null | 50 | video: VideoDetails = null |
@@ -61,7 +59,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
61 | remoteServerDown = false | 59 | remoteServerDown = false |
62 | hotkeys: Hotkey[] | 60 | hotkeys: Hotkey[] |
63 | 61 | ||
64 | private videojsLocaleLoaded = false | ||
65 | private paramsSub: Subscription | 62 | private paramsSub: Subscription |
66 | 63 | ||
67 | constructor ( | 64 | constructor ( |
@@ -92,7 +89,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
92 | 89 | ||
93 | ngOnInit () { | 90 | ngOnInit () { |
94 | if ( | 91 | if ( |
95 | WebTorrent.WEBRTC_SUPPORT === false || | 92 | !!((window as any).RTCPeerConnection || (window as any).mozRTCPeerConnection || (window as any).webkitRTCPeerConnection) === false || |
96 | peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true' | 93 | peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true' |
97 | ) { | 94 | ) { |
98 | this.hasAlreadyAcceptedPrivacyConcern = true | 95 | this.hasAlreadyAcceptedPrivacyConcern = true |
@@ -118,8 +115,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
118 | .subscribe(([ video, captionsResult ]) => { | 115 | .subscribe(([ video, captionsResult ]) => { |
119 | const startTime = this.route.snapshot.queryParams.start | 116 | const startTime = this.route.snapshot.queryParams.start |
120 | const subtitle = this.route.snapshot.queryParams.subtitle | 117 | const subtitle = this.route.snapshot.queryParams.subtitle |
118 | const playerMode = this.route.snapshot.queryParams.mode | ||
121 | 119 | ||
122 | this.onVideoFetched(video, captionsResult.data, { startTime, subtitle }) | 120 | this.onVideoFetched(video, captionsResult.data, { startTime, subtitle, playerMode }) |
123 | .catch(err => this.handleError(err)) | 121 | .catch(err => this.handleError(err)) |
124 | }) | 122 | }) |
125 | }) | 123 | }) |
@@ -310,6 +308,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
310 | return this.video && this.video.state.id === VideoState.TO_TRANSCODE | 308 | return this.video && this.video.state.id === VideoState.TO_TRANSCODE |
311 | } | 309 | } |
312 | 310 | ||
311 | isVideoDownloadable () { | ||
312 | return this.video && this.video.downloadEnabled | ||
313 | } | ||
314 | |||
313 | isVideoToImport () { | 315 | isVideoToImport () { |
314 | return this.video && this.video.state.id === VideoState.TO_IMPORT | 316 | return this.video && this.video.state.id === VideoState.TO_IMPORT |
315 | } | 317 | } |
@@ -366,7 +368,11 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
366 | ) | 368 | ) |
367 | } | 369 | } |
368 | 370 | ||
369 | private async onVideoFetched (video: VideoDetails, videoCaptions: VideoCaption[], urlOptions: { startTime: number, subtitle: string }) { | 371 | private async onVideoFetched ( |
372 | video: VideoDetails, | ||
373 | videoCaptions: VideoCaption[], | ||
374 | urlOptions: { startTime?: number, subtitle?: string, playerMode?: string } | ||
375 | ) { | ||
370 | this.video = video | 376 | this.video = video |
371 | 377 | ||
372 | // Re init attributes | 378 | // Re init attributes |
@@ -402,41 +408,64 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
402 | src: environment.apiUrl + c.captionPath | 408 | src: environment.apiUrl + c.captionPath |
403 | })) | 409 | })) |
404 | 410 | ||
405 | const videojsOptions = getVideojsOptions({ | 411 | const options: PeertubePlayerManagerOptions = { |
406 | autoplay: this.isAutoplay(), | 412 | common: { |
407 | inactivityTimeout: 2500, | 413 | autoplay: this.isAutoplay(), |
408 | videoFiles: this.video.files, | 414 | |
409 | videoCaptions: playerCaptions, | 415 | playerElement: this.playerElement, |
410 | playerElement: this.playerElement, | 416 | onPlayerElementChange: (element: HTMLVideoElement) => this.playerElement = element, |
411 | videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE ? this.videoService.getVideoViewUrl(this.video.uuid) : null, | 417 | |
412 | videoDuration: this.video.duration, | 418 | videoDuration: this.video.duration, |
413 | enableHotkeys: true, | 419 | enableHotkeys: true, |
414 | peertubeLink: false, | 420 | inactivityTimeout: 2500, |
415 | poster: this.video.previewUrl, | 421 | poster: this.video.previewUrl, |
416 | startTime, | 422 | startTime, |
417 | subtitle: urlOptions.subtitle, | 423 | |
418 | theaterMode: true, | 424 | theaterMode: true, |
419 | language: this.localeId, | 425 | captions: videoCaptions.length !== 0, |
420 | 426 | peertubeLink: false, | |
421 | userWatching: this.user && this.user.videosHistoryEnabled === true ? { | 427 | |
422 | url: this.videoService.getUserWatchingVideoUrl(this.video.uuid), | 428 | videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE ? this.videoService.getVideoViewUrl(this.video.uuid) : null, |
423 | authorizationHeader: this.authService.getRequestHeaderValue() | 429 | embedUrl: this.video.embedUrl, |
424 | } : undefined | 430 | |
425 | }) | 431 | language: this.localeId, |
432 | |||
433 | subtitle: urlOptions.subtitle, | ||
434 | |||
435 | userWatching: this.user && this.user.videosHistoryEnabled === true ? { | ||
436 | url: this.videoService.getUserWatchingVideoUrl(this.video.uuid), | ||
437 | authorizationHeader: this.authService.getRequestHeaderValue() | ||
438 | } : undefined, | ||
426 | 439 | ||
427 | if (this.videojsLocaleLoaded === false) { | 440 | serverUrl: environment.apiUrl, |
428 | await loadLocaleInVideoJS(environment.apiUrl, videojs, isOnDevLocale() ? getDevLocale() : this.localeId) | 441 | |
429 | this.videojsLocaleLoaded = true | 442 | videoCaptions: playerCaptions |
443 | }, | ||
444 | |||
445 | webtorrent: { | ||
446 | videoFiles: this.video.files | ||
447 | } | ||
430 | } | 448 | } |
431 | 449 | ||
432 | const self = this | 450 | const mode: PlayerMode = urlOptions.playerMode === 'p2p-media-loader' ? 'p2p-media-loader' : 'webtorrent' |
433 | this.zone.runOutsideAngular(async () => { | 451 | |
434 | videojs(this.playerElement, videojsOptions, function (this: videojs.Player) { | 452 | if (mode === 'p2p-media-loader') { |
435 | self.player = this | 453 | const hlsPlaylist = this.video.getHlsPlaylist() |
436 | this.on('customError', ({ err }: { err: any }) => self.handleError(err)) | ||
437 | 454 | ||
438 | addContextMenu(self.player, self.video.embedUrl) | 455 | const p2pMediaLoader = { |
439 | }) | 456 | playlistUrl: hlsPlaylist.playlistUrl, |
457 | segmentsSha256Url: hlsPlaylist.segmentsSha256Url, | ||
458 | redundancyBaseUrls: hlsPlaylist.redundancies.map(r => r.baseUrl), | ||
459 | trackerAnnounce: this.video.trackerUrls, | ||
460 | videoFiles: this.video.files | ||
461 | } as P2PMediaLoaderOptions | ||
462 | |||
463 | Object.assign(options, { p2pMediaLoader }) | ||
464 | } | ||
465 | |||
466 | this.zone.runOutsideAngular(async () => { | ||
467 | this.player = await PeertubePlayerManager.initialize(mode, options) | ||
468 | this.player.on('customError', ({ err }: { err: any }) => this.handleError(err)) | ||
440 | }) | 469 | }) |
441 | 470 | ||
442 | this.setVideoDescriptionHTML() | 471 | this.setVideoDescriptionHTML() |