]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - client/src/app/+videos/+video-watch/video-watch.component.ts
redirect to login on 401, display error variants in 404 component
[github/Chocobozzz/PeerTube.git] / client / src / app / +videos / +video-watch / video-watch.component.ts
index 9a34397312163581ba160d553f94f47ea8f0b817..b698d554f8ef92788839f2a0a782daa6d7d8083d 100644 (file)
@@ -21,10 +21,11 @@ import { isXPercentInViewport, scrollToTop } from '@app/helpers'
 import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/shared/shared-main'
 import { VideoShareComponent } from '@app/shared/shared-share-modal'
 import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
-import { VideoDownloadComponent } from '@app/shared/shared-video-miniature'
+import { VideoActionsDisplayType, VideoDownloadComponent } from '@app/shared/shared-video-miniature'
 import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
 import { MetaService } from '@ngx-meta/core'
 import { peertubeLocalStorage } from '@root-helpers/peertube-web-storage'
+import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
 import { ServerConfig, ServerErrorCode, UserVideoRateType, VideoCaption, VideoPrivacy, VideoState } from '@shared/models'
 import { getStoredP2PEnabled, getStoredTheater } from '../../../assets/player/peertube-player-local-storage'
 import {
@@ -82,6 +83,18 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
   tooltipSupport = ''
   tooltipSaveToPlaylist = ''
 
+  videoActionsOptions: VideoActionsDisplayType = {
+    playlist: false,
+    download: true,
+    update: true,
+    blacklist: true,
+    delete: true,
+    report: true,
+    duplicate: true,
+    mute: true,
+    liveInfo: true
+  }
+
   private nextVideoUuid = ''
   private nextVideoTitle = ''
   private currentTime: number
@@ -345,7 +358,9 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
   }
 
   handleTimestampClicked (timestamp: number) {
-    if (this.player) this.player.currentTime(timestamp)
+    if (!this.player || this.video.isLive) return
+
+    this.player.currentTime(timestamp)
     scrollToTop()
   }
 
@@ -389,7 +404,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
       this.videoCaptionService.listCaptions(videoId)
     ])
       .pipe(
-        // If 401, the video is private or blocked so redirect to 404
+        // If 400, 403 or 404, the video is private or blocked so redirect to 404
         catchError(err => {
           if (err.body.errorCode === ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS && err.body.originUrl) {
             const search = window.location.search
@@ -400,13 +415,23 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
               $localize`This video is not available on this instance. Do you want to be redirected on the origin instance: <a href="${originUrl}">${originUrl}</a>?`,
               $localize`Redirection`
             ).then(res => {
-              if (res === false) return this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ])
+              if (res === false) {
+                return this.restExtractor.redirectTo404IfNotFound(err, 'video', [
+                  HttpStatusCode.BAD_REQUEST_400,
+                  HttpStatusCode.FORBIDDEN_403,
+                  HttpStatusCode.NOT_FOUND_404
+                ])
+              }
 
               return window.location.href = originUrl
             })
           }
 
-          return this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ])
+          return this.restExtractor.redirectTo404IfNotFound(err, 'video', [
+            HttpStatusCode.BAD_REQUEST_400,
+            HttpStatusCode.FORBIDDEN_403,
+            HttpStatusCode.NOT_FOUND_404
+          ])
         })
       )
       .subscribe(([ video, captionsResult ]) => {
@@ -437,8 +462,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
 
     this.playlistService.getVideoPlaylist(playlistId)
       .pipe(
-        // If 401, the video is private or blocked so redirect to 404
-        catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ]))
+        // If 400 or 403, the video is private or blocked so redirect to 404
+        catchError(err => this.restExtractor.redirectTo404IfNotFound(err, 'video', [
+          HttpStatusCode.BAD_REQUEST_400,
+          HttpStatusCode.FORBIDDEN_403,
+          HttpStatusCode.NOT_FOUND_404
+        ]))
       )
       .subscribe(playlist => {
         this.playlist = playlist
@@ -595,6 +624,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
         }
       })
 
+      this.player.one('ended', () => {
+        if (this.video.isLive) {
+          this.video.state.id = VideoState.LIVE_ENDED
+        }
+      })
+
       this.player.on('theaterChange', (_: any, enabled: boolean) => {
         this.zone.run(() => this.theaterEnabled = enabled)
       })
@@ -759,6 +794,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
           : null,
         embedUrl: video.embedUrl,
 
+        isLive: video.isLive,
+
         language: this.localeId,
 
         userWatching: user && user.videosHistoryEnabled === true ? {
@@ -828,16 +865,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
 
   private async subscribeToLiveEventsIfNeeded (oldVideo: VideoDetails, newVideo: VideoDetails) {
     if (!this.liveVideosSub) {
-      this.liveVideosSub = this.peertubeSocket.getLiveVideosObservable()
-        .subscribe(({ payload }) => {
-          if (payload.state !== VideoState.PUBLISHED || this.video.state.id !== VideoState.WAITING_FOR_LIVE) return
-
-          const videoUUID = this.video.uuid
-
-          // Reset to refetch the video
-          this.video = undefined
-          this.loadVideo(videoUUID)
-        })
+      this.liveVideosSub = this.buildLiveEventsSubscription()
     }
 
     if (oldVideo && oldVideo.id !== newVideo.id) {
@@ -849,6 +877,40 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
     await this.peertubeSocket.subscribeToLiveVideosSocket(newVideo.id)
   }
 
+  private buildLiveEventsSubscription () {
+    return this.peertubeSocket.getLiveVideosObservable()
+      .subscribe(({ type, payload }) => {
+        if (type === 'state-change') return this.handleLiveStateChange(payload.state)
+        if (type === 'views-change') return this.handleLiveViewsChange(payload.views)
+      })
+  }
+
+  private handleLiveStateChange (newState: VideoState) {
+    if (newState !== VideoState.PUBLISHED) return
+
+    const videoState = this.video.state.id
+    if (videoState !== VideoState.WAITING_FOR_LIVE && videoState !== VideoState.LIVE_ENDED) return
+
+    console.log('Loading video after live update.')
+
+    const videoUUID = this.video.uuid
+
+    // Reset to refetch the video
+    this.video = undefined
+    this.loadVideo(videoUUID)
+  }
+
+  private handleLiveViewsChange (newViews: number) {
+    if (!this.video) {
+      console.error('Cannot update video live views because video is no defined.')
+      return
+    }
+
+    console.log('Updating live views.')
+
+    this.video.views = newViews
+  }
+
   private initHotkeys () {
     this.hotkeys = [
       // These hotkeys are managed by the player