Fix bug when quitting NSFW video
[oweals/peertube.git] / client / src / app / videos / +video-watch / video-watch.component.ts
1 import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'
2 import { ActivatedRoute, Router } from '@angular/router'
3 import { Observable } from 'rxjs/Observable'
4 import { Subscription } from 'rxjs/Subscription'
5
6 import videojs from 'video.js'
7 import '../../../assets/player/peertube-videojs-plugin'
8
9 import { MetaService } from '@ngx-meta/core'
10 import { NotificationsService } from 'angular2-notifications'
11
12 import { AuthService, ConfirmService } from '../../core'
13 import { VideoDownloadComponent } from './video-download.component'
14 import { VideoShareComponent } from './video-share.component'
15 import { VideoReportComponent } from './video-report.component'
16 import { Video, VideoService } from '../shared'
17 import { VideoBlacklistService } from '../../shared'
18 import { UserVideoRateType, VideoRateType } from '../../../../../shared'
19
20 @Component({
21   selector: 'my-video-watch',
22   templateUrl: './video-watch.component.html',
23   styleUrls: [ './video-watch.component.scss' ]
24 })
25 export class VideoWatchComponent implements OnInit, OnDestroy {
26   @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent
27   @ViewChild('videoShareModal') videoShareModal: VideoShareComponent
28   @ViewChild('videoReportModal') videoReportModal: VideoReportComponent
29
30   downloadSpeed: number
31   error = false
32   loading = false
33   numPeers: number
34   player: videojs.Player
35   playerElement: HTMLMediaElement
36   uploadSpeed: number
37   userRating: UserVideoRateType = null
38   video: Video = null
39   videoPlayerLoaded = false
40
41   private paramsSub: Subscription
42
43   constructor (
44     private elementRef: ElementRef,
45     private route: ActivatedRoute,
46     private router: Router,
47     private videoService: VideoService,
48     private videoBlacklistService: VideoBlacklistService,
49     private confirmService: ConfirmService,
50     private metaService: MetaService,
51     private authService: AuthService,
52     private notificationsService: NotificationsService
53   ) {}
54
55   ngOnInit () {
56     this.paramsSub = this.route.params.subscribe(routeParams => {
57       let uuid = routeParams['uuid']
58       this.videoService.getVideo(uuid).subscribe(
59         video => this.onVideoFetched(video),
60
61         error => console.error(error)
62       )
63     })
64   }
65
66   ngOnDestroy () {
67     // Remove player if it exists
68     if (this.videoPlayerLoaded === true) {
69       videojs(this.playerElement).dispose()
70     }
71
72     // Unsubscribe subscriptions
73     this.paramsSub.unsubscribe()
74   }
75
76   setLike () {
77     if (this.isUserLoggedIn() === false) return
78     // Already liked this video
79     if (this.userRating === 'like') return
80
81     this.videoService.setVideoLike(this.video.id)
82                      .subscribe(
83                       () => {
84                         // Update the video like attribute
85                         this.updateVideoRating(this.userRating, 'like')
86                         this.userRating = 'like'
87                       },
88
89                       err => this.notificationsService.error('Error', err.message)
90                      )
91   }
92
93   setDislike () {
94     if (this.isUserLoggedIn() === false) return
95     // Already disliked this video
96     if (this.userRating === 'dislike') return
97
98     this.videoService.setVideoDislike(this.video.id)
99                      .subscribe(
100                       () => {
101                         // Update the video dislike attribute
102                         this.updateVideoRating(this.userRating, 'dislike')
103                         this.userRating = 'dislike'
104                       },
105
106                       err => this.notificationsService.error('Error', err.message)
107                      )
108   }
109
110   removeVideo (event: Event) {
111     event.preventDefault()
112
113     this.confirmService.confirm('Do you really want to delete this video?', 'Delete').subscribe(
114       res => {
115         if (res === false) return
116
117         this.videoService.removeVideo(this.video.id)
118                          .subscribe(
119                            status => {
120                              this.notificationsService.success('Success', `Video ${this.video.name} deleted.`)
121                              // Go back to the video-list.
122                              this.router.navigate(['/videos/list'])
123                            },
124
125                            error => this.notificationsService.error('Error', error.text)
126                           )
127       }
128     )
129   }
130
131   blacklistVideo (event: Event) {
132     event.preventDefault()
133
134     this.confirmService.confirm('Do you really want to blacklist this video ?', 'Blacklist').subscribe(
135       res => {
136         if (res === false) return
137
138         this.videoBlacklistService.blacklistVideo(this.video.id)
139                                   .subscribe(
140                                     status => {
141                                       this.notificationsService.success('Success', `Video ${this.video.name} had been blacklisted.`)
142                                       this.router.navigate(['/videos/list'])
143                                     },
144
145                                     error => this.notificationsService.error('Error', error.text)
146                                   )
147       }
148     )
149   }
150
151   showReportModal (event: Event) {
152     event.preventDefault()
153     this.videoReportModal.show()
154   }
155
156   showShareModal () {
157     this.videoShareModal.show()
158   }
159
160   showDownloadModal (event: Event) {
161     event.preventDefault()
162     this.videoDownloadModal.show()
163   }
164
165   isUserLoggedIn () {
166     return this.authService.isLoggedIn()
167   }
168
169   canUserUpdateVideo () {
170     return this.video.isUpdatableBy(this.authService.getUser())
171   }
172
173   isVideoRemovable () {
174     return this.video.isRemovableBy(this.authService.getUser())
175   }
176
177   isVideoBlacklistable () {
178     return this.video.isBlackistableBy(this.authService.getUser())
179   }
180
181   private handleError (err: any) {
182     const errorMessage: string = typeof err === 'string' ? err : err.message
183     let message = ''
184
185     if (errorMessage.indexOf('http error') !== -1) {
186       message = 'Cannot fetch video from server, maybe down.'
187     } else {
188       message = errorMessage
189     }
190
191     this.notificationsService.error('Error', message)
192   }
193
194   private checkUserRating () {
195     // Unlogged users do not have ratings
196     if (this.isUserLoggedIn() === false) return
197
198     this.videoService.getUserVideoRating(this.video.id)
199                      .subscribe(
200                        ratingObject => {
201                          if (ratingObject) {
202                            this.userRating = ratingObject.rating
203                          }
204                        },
205
206                        err => this.notificationsService.error('Error', err.message)
207                       )
208   }
209
210   private onVideoFetched (video: Video) {
211     this.video = video
212
213     let observable
214     if (this.video.isVideoNSFWForUser(this.authService.getUser())) {
215       observable = this.confirmService.confirm('This video is not safe for work. Are you sure you want to watch it?', 'NSFW')
216     } else {
217       observable = Observable.of(true)
218     }
219
220     observable.subscribe(
221       res => {
222         if (res === false) {
223
224           return this.router.navigate([ '/videos/list' ])
225         }
226
227         this.playerElement = this.elementRef.nativeElement.querySelector('#video-container')
228
229         const videojsOptions = {
230           controls: true,
231           autoplay: true,
232           plugins: {
233             peertube: {
234               videoFiles: this.video.files,
235               playerElement: this.playerElement,
236               autoplay: true,
237               peerTubeLink: false
238             }
239           }
240         }
241
242         this.videoPlayerLoaded = true
243
244         const self = this
245         videojs(this.playerElement, videojsOptions, function () {
246           self.player = this
247           this.on('customError', (event, data) => {
248             self.handleError(data.err)
249           })
250
251           this.on('torrentInfo', (event, data) => {
252             self.downloadSpeed = data.downloadSpeed
253             self.numPeers = data.numPeers
254             self.uploadSpeed = data.uploadSpeed
255           })
256         })
257
258         this.setOpenGraphTags()
259         this.checkUserRating()
260       }
261     )
262   }
263
264   private updateVideoRating (oldRating: UserVideoRateType, newRating: VideoRateType) {
265     let likesToIncrement = 0
266     let dislikesToIncrement = 0
267
268     if (oldRating) {
269       if (oldRating === 'like') likesToIncrement--
270       if (oldRating === 'dislike') dislikesToIncrement--
271     }
272
273     if (newRating === 'like') likesToIncrement++
274     if (newRating === 'dislike') dislikesToIncrement++
275
276     this.video.likes += likesToIncrement
277     this.video.dislikes += dislikesToIncrement
278   }
279
280   private setOpenGraphTags () {
281     this.metaService.setTitle(this.video.name)
282
283     this.metaService.setTag('og:type', 'video')
284
285     this.metaService.setTag('og:title', this.video.name)
286     this.metaService.setTag('name', this.video.name)
287
288     this.metaService.setTag('og:description', this.video.description)
289     this.metaService.setTag('description', this.video.description)
290
291     this.metaService.setTag('og:image', this.video.previewPath)
292
293     this.metaService.setTag('og:duration', this.video.duration.toString())
294
295     this.metaService.setTag('og:site_name', 'PeerTube')
296
297     this.metaService.setTag('og:url', window.location.href)
298     this.metaService.setTag('url', window.location.href)
299   }
300 }