]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - client/src/app/videos/video-watch/video-watch.component.ts
Allow to sort by likes
[github/Chocobozzz/PeerTube.git] / client / src / app / videos / video-watch / video-watch.component.ts
CommitLineData
3154f382 1import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core';
0629423c 2import { ActivatedRoute } from '@angular/router';
13fc89f4 3import { Subscription } from 'rxjs/Subscription';
8140a704 4
e31f6ad6 5import * as videojs from 'video.js';
7ddd02c9
C
6import { MetaService } from 'ng2-meta';
7import { NotificationsService } from 'angular2-notifications';
3154f382 8
4f8c0eb0 9import { AuthService } from '../../core';
cf02fbfb
C
10import { VideoMagnetComponent } from './video-magnet.component';
11import { VideoShareComponent } from './video-share.component';
4f8c0eb0 12import { VideoReportComponent } from './video-report.component';
d38b8281 13import { RateType, Video, VideoService } from '../shared';
d3ef341a 14import { WebTorrentService } from './webtorrent.service';
dc8bc31b 15
dc8bc31b
C
16@Component({
17 selector: 'my-video-watch',
ec8d8440
C
18 templateUrl: './video-watch.component.html',
19 styleUrls: [ './video-watch.component.scss' ]
dc8bc31b
C
20})
21
0629423c 22export class VideoWatchComponent implements OnInit, OnDestroy {
0d4fb7e6 23 private static LOADTIME_TOO_LONG: number = 20000;
3ad109e4 24
cf02fbfb
C
25 @ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent;
26 @ViewChild('videoShareModal') videoShareModal: VideoShareComponent;
4f8c0eb0 27 @ViewChild('videoReportModal') videoReportModal: VideoReportComponent;
3154f382 28
8cfecb2a 29 downloadSpeed: number;
3ad109e4 30 error: boolean = false;
da932efc 31 loading: boolean = false;
4fd8aa32 32 numPeers: number;
e31f6ad6 33 player: VideoJSPlayer;
067e3f84 34 playerElement: Element;
4fd8aa32 35 uploadSpeed: number;
d38b8281 36 userRating: RateType = null;
d1992b93 37 video: Video = null;
9c89a45c 38 videoNotFound = false;
dc8bc31b 39
0d4fb7e6 40 private errorTimer: number;
13fc89f4
C
41 private paramsSub: Subscription;
42 private errorsSub: Subscription;
43 private warningsSub: Subscription;
0d4fb7e6 44 private torrentInfosInterval: number;
dc8bc31b
C
45
46 constructor(
4fd8aa32 47 private elementRef: ElementRef,
c323efb9 48 private ngZone: NgZone,
0629423c 49 private route: ActivatedRoute,
d3ef341a 50 private videoService: VideoService,
3ec343a4 51 private metaService: MetaService,
4f8c0eb0 52 private webTorrentService: WebTorrentService,
7ddd02c9
C
53 private authService: AuthService,
54 private notificationsService: NotificationsService
d3ef341a 55 ) {}
dc8bc31b 56
d1992b93 57 ngOnInit() {
13fc89f4 58 this.paramsSub = this.route.params.subscribe(routeParams => {
d1992b93
C
59 let id = routeParams['id'];
60 this.videoService.getVideo(id).subscribe(
61 video => {
62 this.video = video;
3ec343a4 63 this.setOpenGraphTags();
d1992b93 64 this.loadVideo();
d38b8281 65 this.checkUserRating();
d1992b93 66 },
9c89a45c
C
67 error => {
68 this.videoNotFound = true;
69 }
d1992b93
C
70 );
71 });
e31f6ad6 72
067e3f84
C
73 this.playerElement = this.elementRef.nativeElement.querySelector('#video-container');
74
e31f6ad6
C
75 const videojsOptions = {
76 controls: true,
77 autoplay: false
78 };
79
80 const self = this;
067e3f84 81 videojs(this.playerElement, videojsOptions, function () {
e31f6ad6
C
82 self.player = this;
83 });
13fc89f4
C
84
85 this.errorsSub = this.webTorrentService.errors.subscribe(err => this.notificationsService.error('Error', err.message));
86 this.warningsSub = this.webTorrentService.errors.subscribe(err => this.notificationsService.alert('Warning', err.message));
d1992b93
C
87 }
88
89 ngOnDestroy() {
067e3f84 90 // Remove WebTorrent stuff
d1992b93 91 console.log('Removing video from webtorrent.');
0d4fb7e6
C
92 window.clearInterval(this.torrentInfosInterval);
93 window.clearTimeout(this.errorTimer);
9c89a45c
C
94
95 if (this.video !== null) {
96 this.webTorrentService.remove(this.video.magnetUri);
97 }
d1992b93 98
067e3f84
C
99 // Remove player
100 videojs(this.playerElement).dispose();
101
13fc89f4
C
102 // Unsubscribe subscriptions
103 this.paramsSub.unsubscribe();
104 this.errorsSub.unsubscribe();
105 this.warningsSub.unsubscribe();
d1992b93
C
106 }
107
3ad109e4
C
108 loadVideo() {
109 // Reset the error
110 this.error = false;
111 // We are loading the video
da932efc 112 this.loading = true;
3ad109e4 113
2c4a0b5d 114 console.log('Adding ' + this.video.magnetUri + '.');
d3ef341a 115
3ad109e4
C
116 // The callback might never return if there are network issues
117 // So we create a timer to inform the user the load is abnormally long
0d4fb7e6 118 this.errorTimer = window.setTimeout(() => this.loadTooLong(), VideoWatchComponent.LOADTIME_TOO_LONG);
3ad109e4 119
d3ef341a 120 this.webTorrentService.add(this.video.magnetUri, (torrent) => {
3ad109e4 121 // Clear the error timer
0d4fb7e6 122 window.clearTimeout(this.errorTimer);
3ad109e4
C
123 // Maybe the error was fired by the timer, so reset it
124 this.error = false;
125
126 // We are not loading the video anymore
da932efc 127 this.loading = false;
3ad109e4 128
2c4a0b5d 129 console.log('Added ' + this.video.magnetUri + '.');
067e3f84 130 torrent.files[0].renderTo(this.playerElement, { autoplay: true }, (err) => {
dc8bc31b 131 if (err) {
7ddd02c9 132 this.notificationsService.error('Error', 'Cannot append the file in the video element.');
dc8bc31b
C
133 console.error(err);
134 }
44124980 135 });
8cfecb2a 136
c323efb9 137 this.runInProgress(torrent);
44124980 138 });
dc8bc31b 139 }
98b01bac 140
d38b8281
C
141 setLike() {
142 if (this.isUserLoggedIn() === false) return;
143 // Already liked this video
144 if (this.userRating === 'like') return;
145
146 this.videoService.setVideoLike(this.video.id)
147 .subscribe(
148 () => {
149 // Update the video like attribute
150 this.updateVideoRating(this.userRating, 'like');
151 this.userRating = 'like';
152 },
153
154 err => this.notificationsService.error('Error', err.text)
155 );
156 }
157
158 setDislike() {
159 if (this.isUserLoggedIn() === false) return;
160 // Already disliked this video
161 if (this.userRating === 'dislike') return;
162
163 this.videoService.setVideoDislike(this.video.id)
164 .subscribe(
165 () => {
166 // Update the video dislike attribute
167 this.updateVideoRating(this.userRating, 'dislike');
168 this.userRating = 'dislike';
169 },
170
171 err => this.notificationsService.error('Error', err.text)
172 );
173 }
174
4f8c0eb0
C
175 showReportModal(event: Event) {
176 event.preventDefault();
177 this.videoReportModal.show();
178 }
179
99cc4f49 180 showShareModal() {
cf02fbfb 181 this.videoShareModal.show();
99cc4f49
C
182 }
183
05a9feaa
C
184 showMagnetUriModal(event: Event) {
185 event.preventDefault();
cf02fbfb 186 this.videoMagnetModal.show();
99cc4f49
C
187 }
188
4f8c0eb0
C
189 isUserLoggedIn() {
190 return this.authService.isLoggedIn();
191 }
192
d38b8281
C
193 private checkUserRating() {
194 // Unlogged users do not have ratings
195 if (this.isUserLoggedIn() === false) return;
196
197 this.videoService.getUserVideoRating(this.video.id)
198 .subscribe(
199 ratingObject => {
200 if (ratingObject) {
201 this.userRating = ratingObject.rating;
202 }
203 },
204
205 err => this.notificationsService.error('Error', err.text)
206 );
207 }
208
209 private updateVideoRating(oldRating: RateType, newRating: RateType) {
210 let likesToIncrement = 0;
211 let dislikesToIncrement = 0;
212
213 if (oldRating) {
214 if (oldRating === 'like') likesToIncrement--;
215 if (oldRating === 'dislike') dislikesToIncrement--;
216 }
217
218 if (newRating === 'like') likesToIncrement++;
219 if (newRating === 'dislike') dislikesToIncrement++;
220
221 this.video.likes += likesToIncrement;
222 this.video.dislikes += dislikesToIncrement;
223 }
224
3ad109e4
C
225 private loadTooLong() {
226 this.error = true;
227 console.error('The video load seems to be abnormally long.');
228 }
c323efb9 229
3ec343a4
C
230 private setOpenGraphTags() {
231 this.metaService.setTag('og:type', 'video');
232
233 this.metaService.setTag('og:title', this.video.name);
234 this.metaService.setTag('name', this.video.name);
235
236 this.metaService.setTag('og:description', this.video.description);
237 this.metaService.setTag('description', this.video.description);
238
239 this.metaService.setTag('og:image', this.video.thumbnailPath);
240
241 this.metaService.setTag('og:duration', this.video.duration);
242
243 this.metaService.setTag('og:site_name', 'PeerTube');
244
245 this.metaService.setTag('og:url', window.location.href);
246 this.metaService.setTag('url', window.location.href);
247 }
248
c323efb9
C
249 private runInProgress(torrent: any) {
250 // Refresh each second
0d4fb7e6 251 this.torrentInfosInterval = window.setInterval(() => {
c323efb9
C
252 this.ngZone.run(() => {
253 this.downloadSpeed = torrent.downloadSpeed;
254 this.numPeers = torrent.numPeers;
255 this.uploadSpeed = torrent.uploadSpeed;
256 });
257 }, 1000);
258 }
dc8bc31b 259}