aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html2
-rw-r--r--client/src/app/core/confirm/confirm.component.html2
-rw-r--r--client/src/app/core/confirm/confirm.component.ts5
-rw-r--r--client/src/app/core/confirm/confirm.service.ts18
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts115
-rw-r--r--client/src/sass/video-js-custom.scss30
-rw-r--r--client/src/standalone/videos/embed.ts3
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'
3import 'rxjs/add/operator/first' 3import 'rxjs/add/operator/first'
4import 'rxjs/add/operator/toPromise' 4import 'rxjs/add/operator/toPromise'
5 5
6type ConfirmOptions = {
7 title: string
8 message: string
9 inputLabel?: string
10 expectedInputValue?: string
11 confirmButtonText?: string
12}
13
6@Injectable() 14@Injectable()
7export class ConfirmService { 15export 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})
28export class VideoWatchComponent implements OnInit, OnDestroy { 28export 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 })