diff options
Diffstat (limited to 'client/src')
7 files changed, 112 insertions, 63 deletions
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html index 2779db5bc..88a1641cf 100644 --- a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html +++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html | |||
@@ -18,7 +18,7 @@ | |||
18 | <ng-template pTemplate="body" let-videoAbuse> | 18 | <ng-template pTemplate="body" let-videoAbuse> |
19 | <tr> | 19 | <tr> |
20 | <td>{{ videoAbuse.reason }}</td> | 20 | <td>{{ videoAbuse.reason }}</td> |
21 | <td>{{ videoAbuse.reporterServerHost + '@' + videoAbuse.reporterUsername }}</td> | 21 | <td>{{ videoAbuse.reporterUsername + '@' + videoAbuse.reporterServerHost }}</td> |
22 | <td>{{ videoAbuse.createdAt }}</td> | 22 | <td>{{ videoAbuse.createdAt }}</td> |
23 | <td> | 23 | <td> |
24 | <a [routerLink]="getRouterVideoLink(videoAbuse.videoUUID)" title="Go to the video">{{ videoAbuse.videoName }}</a> | 24 | <a [routerLink]="getRouterVideoLink(videoAbuse.videoUUID)" title="Go to the video">{{ videoAbuse.videoName }}</a> |
diff --git a/client/src/app/core/confirm/confirm.component.html b/client/src/app/core/confirm/confirm.component.html index 90274b248..01a4e0ac4 100644 --- a/client/src/app/core/confirm/confirm.component.html +++ b/client/src/app/core/confirm/confirm.component.html | |||
@@ -21,7 +21,7 @@ | |||
21 | </span> | 21 | </span> |
22 | 22 | ||
23 | <input | 23 | <input |
24 | type="submit" value="Confirm" class="action-button-submit" [disabled]="isConfirmationDisabled()" | 24 | type="submit" [value]="confirmButtonText" class="action-button-submit" [disabled]="isConfirmationDisabled()" |
25 | (click)="confirm()" | 25 | (click)="confirm()" |
26 | > | 26 | > |
27 | </div> | 27 | </div> |
diff --git a/client/src/app/core/confirm/confirm.component.ts b/client/src/app/core/confirm/confirm.component.ts index 8f81b7a98..147bc9d65 100644 --- a/client/src/app/core/confirm/confirm.component.ts +++ b/client/src/app/core/confirm/confirm.component.ts | |||
@@ -18,6 +18,7 @@ export class ConfirmComponent implements OnInit { | |||
18 | inputLabel = '' | 18 | inputLabel = '' |
19 | 19 | ||
20 | inputValue = '' | 20 | inputValue = '' |
21 | confirmButtonText = '' | ||
21 | 22 | ||
22 | constructor (private confirmService: ConfirmService) { | 23 | constructor (private confirmService: ConfirmService) { |
23 | // Empty | 24 | // Empty |
@@ -30,13 +31,15 @@ export class ConfirmComponent implements OnInit { | |||
30 | } | 31 | } |
31 | 32 | ||
32 | this.confirmService.showConfirm.subscribe( | 33 | this.confirmService.showConfirm.subscribe( |
33 | ({ title, message, expectedInputValue, inputLabel }) => { | 34 | ({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => { |
34 | this.title = title | 35 | this.title = title |
35 | this.message = message | 36 | this.message = message |
36 | 37 | ||
37 | this.inputLabel = inputLabel | 38 | this.inputLabel = inputLabel |
38 | this.expectedInputValue = expectedInputValue | 39 | this.expectedInputValue = expectedInputValue |
39 | 40 | ||
41 | this.confirmButtonText = confirmButtonText || 'Confirm' | ||
42 | |||
40 | this.showModal() | 43 | this.showModal() |
41 | } | 44 | } |
42 | ) | 45 | ) |
diff --git a/client/src/app/core/confirm/confirm.service.ts b/client/src/app/core/confirm/confirm.service.ts index f30feb9d0..d99226f05 100644 --- a/client/src/app/core/confirm/confirm.service.ts +++ b/client/src/app/core/confirm/confirm.service.ts | |||
@@ -3,19 +3,27 @@ import { Subject } from 'rxjs/Subject' | |||
3 | import 'rxjs/add/operator/first' | 3 | import 'rxjs/add/operator/first' |
4 | import 'rxjs/add/operator/toPromise' | 4 | import 'rxjs/add/operator/toPromise' |
5 | 5 | ||
6 | type ConfirmOptions = { | ||
7 | title: string | ||
8 | message: string | ||
9 | inputLabel?: string | ||
10 | expectedInputValue?: string | ||
11 | confirmButtonText?: string | ||
12 | } | ||
13 | |||
6 | @Injectable() | 14 | @Injectable() |
7 | export class ConfirmService { | 15 | export class ConfirmService { |
8 | showConfirm = new Subject<{ title: string, message: string, inputLabel?: string, expectedInputValue?: string }>() | 16 | showConfirm = new Subject<ConfirmOptions>() |
9 | confirmResponse = new Subject<boolean>() | 17 | confirmResponse = new Subject<boolean>() |
10 | 18 | ||
11 | confirm (message: string, title = '') { | 19 | confirm (message: string, title = '', confirmButtonText?: string) { |
12 | this.showConfirm.next({ title, message }) | 20 | this.showConfirm.next({ title, message, confirmButtonText }) |
13 | 21 | ||
14 | return this.confirmResponse.asObservable().first().toPromise() | 22 | return this.confirmResponse.asObservable().first().toPromise() |
15 | } | 23 | } |
16 | 24 | ||
17 | confirmWithInput (message: string, inputLabel: string, expectedInputValue: string, title = '') { | 25 | confirmWithInput (message: string, inputLabel: string, expectedInputValue: string, title = '', confirmButtonText?: string) { |
18 | this.showConfirm.next({ title, message, inputLabel, expectedInputValue }) | 26 | this.showConfirm.next({ title, message, inputLabel, expectedInputValue, confirmButtonText }) |
19 | 27 | ||
20 | return this.confirmResponse.asObservable().first().toPromise() | 28 | return this.confirmResponse.asObservable().first().toPromise() |
21 | } | 29 | } |
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 3965bade8..662380d96 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts | |||
@@ -26,6 +26,8 @@ import { VideoShareComponent } from './modal/video-share.component' | |||
26 | styleUrls: [ './video-watch.component.scss' ] | 26 | styleUrls: [ './video-watch.component.scss' ] |
27 | }) | 27 | }) |
28 | export class VideoWatchComponent implements OnInit, OnDestroy { | 28 | export class VideoWatchComponent implements OnInit, OnDestroy { |
29 | private static LOCAL_STORAGE_PRIVACY_CONCERN_KEY = 'video-watch-privacy-concern' | ||
30 | |||
29 | @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent | 31 | @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent |
30 | @ViewChild('videoShareModal') videoShareModal: VideoShareComponent | 32 | @ViewChild('videoShareModal') videoShareModal: VideoShareComponent |
31 | @ViewChild('videoReportModal') videoReportModal: VideoReportComponent | 33 | @ViewChild('videoReportModal') videoReportModal: VideoReportComponent |
@@ -301,75 +303,76 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
301 | ) | 303 | ) |
302 | } | 304 | } |
303 | 305 | ||
304 | private onVideoFetched (video: VideoDetails) { | 306 | private async onVideoFetched (video: VideoDetails) { |
305 | this.video = video | 307 | this.video = video |
306 | 308 | ||
307 | this.updateOtherVideosDisplayed() | 309 | this.updateOtherVideosDisplayed() |
308 | 310 | ||
309 | let observable | ||
310 | if (this.video.isVideoNSFWForUser(this.user)) { | 311 | if (this.video.isVideoNSFWForUser(this.user)) { |
311 | observable = this.confirmService.confirm( | 312 | const res = await this.confirmService.confirm( |
312 | 'This video contains mature or explicit content. Are you sure you want to watch it?', | 313 | 'This video contains mature or explicit content. Are you sure you want to watch it?', |
313 | 'Mature or explicit content' | 314 | 'Mature or explicit content' |
314 | ) | 315 | ) |
315 | } else { | 316 | if (res === false) return this.router.navigate([ '/videos/list' ]) |
316 | observable = Observable.of(true) | ||
317 | } | 317 | } |
318 | 318 | ||
319 | observable.subscribe( | 319 | if (!this.hasAlreadyAcceptedPrivacyConcern()) { |
320 | res => { | 320 | const res = await this.confirmService.confirm( |
321 | if (res === false) { | 321 | 'PeerTube uses P2P, other may know you are watching that video through your public IP address. ' + |
322 | 'Are you okay with that?', | ||
323 | 'Privacy concern', | ||
324 | 'I accept!' | ||
325 | ) | ||
326 | if (res === false) return this.router.navigate([ '/videos/list' ]) | ||
327 | } | ||
322 | 328 | ||
323 | return this.router.navigate([ '/videos/list' ]) | 329 | this.acceptedPrivacyConcern() |
324 | } | ||
325 | 330 | ||
326 | // Player was already loaded | 331 | // Player was already loaded |
327 | if (this.videoPlayerLoaded !== true) { | 332 | if (this.videoPlayerLoaded !== true) { |
328 | this.playerElement = this.elementRef.nativeElement.querySelector('#video-element') | 333 | this.playerElement = this.elementRef.nativeElement.querySelector('#video-element') |
329 | 334 | ||
330 | // If autoplay is true, we don't really need a poster | 335 | // If autoplay is true, we don't really need a poster |
331 | if (this.isAutoplay() === false) { | 336 | if (this.isAutoplay() === false) { |
332 | this.playerElement.poster = this.video.previewUrl | 337 | this.playerElement.poster = this.video.previewUrl |
333 | } | 338 | } |
334 | 339 | ||
335 | const videojsOptions = { | 340 | const videojsOptions = { |
336 | controls: true, | 341 | controls: true, |
337 | autoplay: this.isAutoplay(), | 342 | autoplay: this.isAutoplay(), |
338 | plugins: { | 343 | plugins: { |
339 | peertube: { | 344 | peertube: { |
340 | videoFiles: this.video.files, | 345 | videoFiles: this.video.files, |
341 | playerElement: this.playerElement, | 346 | playerElement: this.playerElement, |
342 | peerTubeLink: false, | 347 | peerTubeLink: false, |
343 | videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid), | 348 | videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid), |
344 | videoDuration: this.video.duration | 349 | videoDuration: this.video.duration |
345 | }, | 350 | }, |
346 | hotkeys: { | 351 | hotkeys: { |
347 | enableVolumeScroll: false | 352 | enableVolumeScroll: false |
348 | } | ||
349 | } | ||
350 | } | 353 | } |
351 | |||
352 | this.videoPlayerLoaded = true | ||
353 | |||
354 | const self = this | ||
355 | this.zone.runOutsideAngular(() => { | ||
356 | videojs(this.playerElement, videojsOptions, function () { | ||
357 | self.player = this | ||
358 | this.on('customError', (event, data) => self.handleError(data.err)) | ||
359 | }) | ||
360 | }) | ||
361 | } else { | ||
362 | const videoViewUrl = this.videoService.getVideoViewUrl(this.video.uuid) | ||
363 | this.player.peertube().setVideoFiles(this.video.files, videoViewUrl, this.video.duration) | ||
364 | } | 354 | } |
355 | } | ||
365 | 356 | ||
366 | this.setVideoDescriptionHTML() | 357 | this.videoPlayerLoaded = true |
367 | this.setVideoLikesBarTooltipText() | ||
368 | 358 | ||
369 | this.setOpenGraphTags() | 359 | const self = this |
370 | this.checkUserRating() | 360 | this.zone.runOutsideAngular(() => { |
371 | } | 361 | videojs(this.playerElement, videojsOptions, function () { |
372 | ) | 362 | self.player = this |
363 | this.on('customError', (event, data) => self.handleError(data.err)) | ||
364 | }) | ||
365 | }) | ||
366 | } else { | ||
367 | const videoViewUrl = this.videoService.getVideoViewUrl(this.video.uuid) | ||
368 | this.player.peertube().setVideoFiles(this.video.files, videoViewUrl, this.video.duration) | ||
369 | } | ||
370 | |||
371 | this.setVideoDescriptionHTML() | ||
372 | this.setVideoLikesBarTooltipText() | ||
373 | |||
374 | this.setOpenGraphTags() | ||
375 | this.checkUserRating() | ||
373 | } | 376 | } |
374 | 377 | ||
375 | private setRating (nextRating) { | 378 | private setRating (nextRating) { |
@@ -411,8 +414,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
411 | 414 | ||
412 | this.video.likes += likesToIncrement | 415 | this.video.likes += likesToIncrement |
413 | this.video.dislikes += dislikesToIncrement | 416 | this.video.dislikes += dislikesToIncrement |
414 | this.video.buildLikeAndDislikePercents() | ||
415 | 417 | ||
418 | this.video.buildLikeAndDislikePercents() | ||
416 | this.setVideoLikesBarTooltipText() | 419 | this.setVideoLikesBarTooltipText() |
417 | } | 420 | } |
418 | 421 | ||
@@ -450,4 +453,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
450 | // Be sure the autoPlay is set to false | 453 | // Be sure the autoPlay is set to false |
451 | return this.user.autoPlayVideo !== false | 454 | return this.user.autoPlayVideo !== false |
452 | } | 455 | } |
456 | |||
457 | private hasAlreadyAcceptedPrivacyConcern () { | ||
458 | return localStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true' | ||
459 | } | ||
460 | |||
461 | private acceptedPrivacyConcern () { | ||
462 | localStorage.setItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY, 'true') | ||
463 | } | ||
453 | } | 464 | } |
diff --git a/client/src/sass/video-js-custom.scss b/client/src/sass/video-js-custom.scss index 8b6d54b22..75630dd63 100644 --- a/client/src/sass/video-js-custom.scss +++ b/client/src/sass/video-js-custom.scss | |||
@@ -1,4 +1,4 @@ | |||
1 | // Thanks: https://github.com/zanechua/videojs-sublime-inspired-skin | 1 | @charset "utf-8";// Thanks: https://github.com/zanechua/videojs-sublime-inspired-skin |
2 | $primary-foreground-color: #fff; | 2 | $primary-foreground-color: #fff; |
3 | $primary-background-color: #000; | 3 | $primary-background-color: #000; |
4 | $font-size: 13px; | 4 | $font-size: 13px; |
@@ -8,6 +8,28 @@ $control-bar-height: 34px; | |||
8 | font-size: $font-size; | 8 | font-size: $font-size; |
9 | color: $primary-foreground-color; | 9 | color: $primary-foreground-color; |
10 | 10 | ||
11 | .vjs-dock-text { | ||
12 | padding-right: 10px; | ||
13 | } | ||
14 | |||
15 | .vjs-dock-description { | ||
16 | font-size: 11px; | ||
17 | |||
18 | &:before, &:after { | ||
19 | display: inline-block; | ||
20 | content: '\1F308'; | ||
21 | } | ||
22 | |||
23 | &:before { | ||
24 | margin-right: 4px; | ||
25 | } | ||
26 | |||
27 | &:after { | ||
28 | margin-left: 4px; | ||
29 | transform: scale(-1, 1); | ||
30 | } | ||
31 | } | ||
32 | |||
11 | .vjs-button > .vjs-icon-placeholder::before { | 33 | .vjs-button > .vjs-icon-placeholder::before { |
12 | line-height: $control-bar-height; | 34 | line-height: $control-bar-height; |
13 | } | 35 | } |
@@ -354,7 +376,11 @@ $control-bar-height: 34px; | |||
354 | 376 | ||
355 | @media screen and (max-width: 300px) { | 377 | @media screen and (max-width: 300px) { |
356 | .vjs-dock-text { | 378 | .vjs-dock-text { |
357 | font-size: 1em; | 379 | font-size: 13px; |
380 | } | ||
381 | |||
382 | .vjs-dock-description { | ||
383 | font-size: 9px; | ||
358 | } | 384 | } |
359 | 385 | ||
360 | .vjs-big-play-button { | 386 | .vjs-big-play-button { |
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts index 925367bb9..bb6baf7f0 100644 --- a/client/src/standalone/videos/embed.ts +++ b/client/src/standalone/videos/embed.ts | |||
@@ -44,7 +44,8 @@ loadVideoInfo(videoId) | |||
44 | const player = this | 44 | const player = this |
45 | 45 | ||
46 | player.dock({ | 46 | player.dock({ |
47 | title: videoInfo.name | 47 | title: videoInfo.name, |
48 | description: 'Use P2P, other may know you are watching that video.' | ||
48 | }) | 49 | }) |
49 | }) | 50 | }) |
50 | }) | 51 | }) |