import { catchError } from 'rxjs/operators'
-import { Component, ElementRef, Inject, LOCALE_ID, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
+import { ChangeDetectorRef, Component, ElementRef, Inject, LOCALE_ID, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { RedirectService } from '@app/core/routing/redirect.service'
import { peertubeLocalStorage } from '@app/shared/misc/peertube-local-storage'
import { VideoSupportComponent } from '@app/videos/+video-watch/modal/video-support.component'
import { MetaService } from '@ngx-meta/core'
import { NotificationsService } from 'angular2-notifications'
-import { Subscription } from 'rxjs'
+import { forkJoin, Subscription } from 'rxjs'
import * as videojs from 'video.js'
import 'videojs-hotkeys'
import * as WebTorrent from 'webtorrent'
-import { UserVideoRateType, VideoRateType, VideoState } from '../../../../../shared'
+import { UserVideoRateType, VideoPrivacy, VideoRateType, VideoState } from '../../../../../shared'
import '../../../assets/player/peertube-videojs-plugin'
import { AuthService, ConfirmService } from '../../core'
import { RestExtractor, VideoBlacklistService } from '../../shared'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { environment } from '../../../environments/environment'
import { getDevLocale, isOnDevLocale } from '@app/shared/i18n/i18n-utils'
+import { VideoCaptionService } from '@app/shared/video-caption'
+import { VideoCaption } from '../../../../../shared/models/videos/video-caption.model'
@Component({
selector: 'my-video-watch',
videoHTMLDescription = ''
likesBarTooltipText = ''
hasAlreadyAcceptedPrivacyConcern = false
+ remoteServerDown = false
private videojsLocaleLoaded = false
private otherVideos: Video[] = []
constructor (
private elementRef: ElementRef,
+ private changeDetector: ChangeDetectorRef,
private route: ActivatedRoute,
private router: Router,
private videoService: VideoService,
private markdownService: MarkdownService,
private zone: NgZone,
private redirectService: RedirectService,
+ private videoCaptionService: VideoCaptionService,
private i18n: I18n,
@Inject(LOCALE_ID) private localeId: string
) {}
)
this.paramsSub = this.route.params.subscribe(routeParams => {
- if (this.player) {
- this.player.pause()
- }
-
const uuid = routeParams[ 'uuid' ]
// Video did not change
if (this.video && this.video.uuid === uuid) return
+
+ if (this.player) this.player.pause()
+
// Video did change
- this.videoService
- .getVideo(uuid)
- .pipe(catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ])))
- .subscribe(video => {
- const startTime = this.route.snapshot.queryParams.start
- this.onVideoFetched(video, startTime)
- .catch(err => this.handleError(err))
- })
+ forkJoin(
+ this.videoService.getVideo(uuid),
+ this.videoCaptionService.listCaptions(uuid)
+ )
+ .pipe(
+ catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ]))
+ )
+ .subscribe(([ video, captionsResult ]) => {
+ const startTime = this.route.snapshot.queryParams.start
+ this.onVideoFetched(video, captionsResult.data, startTime)
+ .catch(err => this.handleError(err))
+ })
})
}
getVideoTags () {
if (!this.video || Array.isArray(this.video.tags) === false) return []
- return this.video.tags.join(', ')
+ return this.video.tags
}
isVideoRemovable () {
return this.video && this.video.state.id === VideoState.TO_TRANSCODE
}
+ hasVideoScheduledPublication () {
+ return this.video && this.video.scheduledUpdate !== undefined
+ }
+
private updateVideoDescription (description: string) {
this.video.description = description
this.setVideoDescriptionHTML()
}
private setVideoDescriptionHTML () {
- if (!this.video.description) {
- this.videoHTMLDescription = ''
- return
- }
-
this.videoHTMLDescription = this.markdownService.textMarkdownToHTML(this.video.description)
}
const errorMessage: string = typeof err === 'string' ? err : err.message
if (!errorMessage) return
- let message = ''
+ // Display a message in the video player instead of a notification
+ if (errorMessage.indexOf('from xs param') !== -1) {
+ this.flushPlayer()
+ this.remoteServerDown = true
+ this.changeDetector.detectChanges()
- if (errorMessage.indexOf('http error') !== -1) {
- message = this.i18n('Cannot fetch video from server, maybe down.')
- } else {
- message = errorMessage
+ return
}
- this.notificationsService.error(this.i18n('Error'), message)
+ this.notificationsService.error(this.i18n('Error'), errorMessage)
}
private checkUserRating () {
)
}
- private async onVideoFetched (video: VideoDetails, startTime = 0) {
+ private async onVideoFetched (video: VideoDetails, videoCaptions: VideoCaption[], startTime = 0) {
this.video = video
// Re init attributes
this.descriptionLoading = false
this.completeDescriptionShown = false
+ this.remoteServerDown = false
this.updateOtherVideosDisplayed()
this.playerElement.setAttribute('playsinline', 'true')
playerElementWrapper.appendChild(this.playerElement)
+ const playerCaptions = videoCaptions.map(c => ({
+ label: c.language.label,
+ language: c.language.id,
+ src: environment.apiUrl + c.captionPath
+ }))
+
const videojsOptions = getVideojsOptions({
autoplay: this.isAutoplay(),
inactivityTimeout: 2500,
videoFiles: this.video.files,
+ videoCaptions: playerCaptions,
playerElement: this.playerElement,
- videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid),
+ videoViewUrl: this.video.privacy.id !== VideoPrivacy.PRIVATE ? this.videoService.getVideoViewUrl(this.video.uuid) : null,
videoDuration: this.video.duration,
enableHotkeys: true,
peertubeLink: false,
}
private isAutoplay () {
- // True by default
+ // We'll jump to the thread id, so do not play the video
+ if (this.route.snapshot.params['threadId']) return false
+
+ // Otherwise true by default
if (!this.user) return true
// Be sure the autoPlay is set to false