Add messages about privacy concerns (P2P)
authorChocobozzz <me@florianbigard.com>
Wed, 28 Feb 2018 14:33:45 +0000 (15:33 +0100)
committerChocobozzz <me@florianbigard.com>
Wed, 28 Feb 2018 14:33:45 +0000 (15:33 +0100)
client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html
client/src/app/core/confirm/confirm.component.html
client/src/app/core/confirm/confirm.component.ts
client/src/app/core/confirm/confirm.service.ts
client/src/app/videos/+video-watch/video-watch.component.ts
client/src/sass/video-js-custom.scss
client/src/standalone/videos/embed.ts

index 2779db5bc78587e8a7c5862b18e8421d97d5cd6e..88a1641cf4895e727f0a17eb86d501ba5f643b0f 100644 (file)
@@ -18,7 +18,7 @@
   <ng-template pTemplate="body" let-videoAbuse>
     <tr>
       <td>{{ videoAbuse.reason }}</td>
-      <td>{{ videoAbuse.reporterServerHost + '@' + videoAbuse.reporterUsername }}</td>
+      <td>{{ videoAbuse.reporterUsername + '@' + videoAbuse.reporterServerHost }}</td>
       <td>{{ videoAbuse.createdAt }}</td>
       <td>
         <a [routerLink]="getRouterVideoLink(videoAbuse.videoUUID)" title="Go to the video">{{ videoAbuse.videoName }}</a>
index 90274b24847fd452adb2c0ea390c6669c76a7298..01a4e0ac4831bd029dec43d2e24871f26fb48c17 100644 (file)
@@ -21,7 +21,7 @@
           </span>
 
           <input
-            type="submit" value="Confirm" class="action-button-submit" [disabled]="isConfirmationDisabled()"
+            type="submit" [value]="confirmButtonText" class="action-button-submit" [disabled]="isConfirmationDisabled()"
             (click)="confirm()"
           >
         </div>
index 8f81b7a988a74fbec57da6bd22c6603ca2edd3ea..147bc9d653adb254aac8a64d5b0ec28fc22517bf 100644 (file)
@@ -18,6 +18,7 @@ export class ConfirmComponent implements OnInit {
   inputLabel = ''
 
   inputValue = ''
+  confirmButtonText = ''
 
   constructor (private confirmService: ConfirmService) {
     // Empty
@@ -30,13 +31,15 @@ export class ConfirmComponent implements OnInit {
     }
 
     this.confirmService.showConfirm.subscribe(
-      ({ title, message, expectedInputValue, inputLabel }) => {
+      ({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => {
         this.title = title
         this.message = message
 
         this.inputLabel = inputLabel
         this.expectedInputValue = expectedInputValue
 
+        this.confirmButtonText = confirmButtonText || 'Confirm'
+
         this.showModal()
       }
     )
index f30feb9d0b2e9c3dc991e226e1fd32c1acaa878b..d99226f053496f6bf6058b278d1ff5723705c689 100644 (file)
@@ -3,19 +3,27 @@ import { Subject } from 'rxjs/Subject'
 import 'rxjs/add/operator/first'
 import 'rxjs/add/operator/toPromise'
 
+type ConfirmOptions = {
+  title: string
+  message: string
+  inputLabel?: string
+  expectedInputValue?: string
+  confirmButtonText?: string
+}
+
 @Injectable()
 export class ConfirmService {
-  showConfirm = new Subject<{ title: string, message: string, inputLabel?: string, expectedInputValue?: string }>()
+  showConfirm = new Subject<ConfirmOptions>()
   confirmResponse = new Subject<boolean>()
 
-  confirm (message: string, title = '') {
-    this.showConfirm.next({ title, message })
+  confirm (message: string, title = '', confirmButtonText?: string) {
+    this.showConfirm.next({ title, message, confirmButtonText })
 
     return this.confirmResponse.asObservable().first().toPromise()
   }
 
-  confirmWithInput (message: string, inputLabel: string, expectedInputValue: string, title = '') {
-    this.showConfirm.next({ title, message, inputLabel, expectedInputValue })
+  confirmWithInput (message: string, inputLabel: string, expectedInputValue: string, title = '', confirmButtonText?: string) {
+    this.showConfirm.next({ title, message, inputLabel, expectedInputValue, confirmButtonText })
 
     return this.confirmResponse.asObservable().first().toPromise()
   }
index 3965bade862a34155cc65387e8ab9490759ca5b7..662380d961e8215f60dc5ad9acdba882c17ebf14 100644 (file)
@@ -26,6 +26,8 @@ import { VideoShareComponent } from './modal/video-share.component'
   styleUrls: [ './video-watch.component.scss' ]
 })
 export class VideoWatchComponent implements OnInit, OnDestroy {
+  private static LOCAL_STORAGE_PRIVACY_CONCERN_KEY = 'video-watch-privacy-concern'
+
   @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent
   @ViewChild('videoShareModal') videoShareModal: VideoShareComponent
   @ViewChild('videoReportModal') videoReportModal: VideoReportComponent
@@ -301,75 +303,76 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
                       )
   }
 
-  private onVideoFetched (video: VideoDetails) {
+  private async onVideoFetched (video: VideoDetails) {
     this.video = video
 
     this.updateOtherVideosDisplayed()
 
-    let observable
     if (this.video.isVideoNSFWForUser(this.user)) {
-      observable = this.confirmService.confirm(
+      const res = await this.confirmService.confirm(
         'This video contains mature or explicit content. Are you sure you want to watch it?',
         'Mature or explicit content'
       )
-    } else {
-      observable = Observable.of(true)
+      if (res === false) return this.router.navigate([ '/videos/list' ])
     }
 
-    observable.subscribe(
-      res => {
-        if (res === false) {
+    if (!this.hasAlreadyAcceptedPrivacyConcern()) {
+      const res = await this.confirmService.confirm(
+        'PeerTube uses P2P, other may know you are watching that video through your public IP address. ' +
+        'Are you okay with that?',
+        'Privacy concern',
+        'I accept!'
+      )
+      if (res === false) return this.router.navigate([ '/videos/list' ])
+    }
 
-          return this.router.navigate([ '/videos/list' ])
-        }
+    this.acceptedPrivacyConcern()
 
-        // Player was already loaded
-        if (this.videoPlayerLoaded !== true) {
-          this.playerElement = this.elementRef.nativeElement.querySelector('#video-element')
+    // Player was already loaded
+    if (this.videoPlayerLoaded !== true) {
+      this.playerElement = this.elementRef.nativeElement.querySelector('#video-element')
 
-          // If autoplay is true, we don't really need a poster
-          if (this.isAutoplay() === false) {
-            this.playerElement.poster = this.video.previewUrl
-          }
+      // If autoplay is true, we don't really need a poster
+      if (this.isAutoplay() === false) {
+        this.playerElement.poster = this.video.previewUrl
+      }
 
-          const videojsOptions = {
-            controls: true,
-            autoplay: this.isAutoplay(),
-            plugins: {
-              peertube: {
-                videoFiles: this.video.files,
-                playerElement: this.playerElement,
-                peerTubeLink: false,
-                videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid),
-                videoDuration: this.video.duration
-              },
-              hotkeys: {
-                enableVolumeScroll: false
-              }
-            }
+      const videojsOptions = {
+        controls: true,
+        autoplay: this.isAutoplay(),
+        plugins: {
+          peertube: {
+            videoFiles: this.video.files,
+            playerElement: this.playerElement,
+            peerTubeLink: false,
+            videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid),
+            videoDuration: this.video.duration
+          },
+          hotkeys: {
+            enableVolumeScroll: false
           }
-
-          this.videoPlayerLoaded = true
-
-          const self = this
-          this.zone.runOutsideAngular(() => {
-            videojs(this.playerElement, videojsOptions, function () {
-              self.player = this
-              this.on('customError', (event, data) => self.handleError(data.err))
-            })
-          })
-        } else {
-          const videoViewUrl = this.videoService.getVideoViewUrl(this.video.uuid)
-          this.player.peertube().setVideoFiles(this.video.files, videoViewUrl, this.video.duration)
         }
+      }
 
-        this.setVideoDescriptionHTML()
-        this.setVideoLikesBarTooltipText()
+      this.videoPlayerLoaded = true
 
-        this.setOpenGraphTags()
-        this.checkUserRating()
-      }
-    )
+      const self = this
+      this.zone.runOutsideAngular(() => {
+        videojs(this.playerElement, videojsOptions, function () {
+          self.player = this
+          this.on('customError', (event, data) => self.handleError(data.err))
+        })
+      })
+    } else {
+      const videoViewUrl = this.videoService.getVideoViewUrl(this.video.uuid)
+      this.player.peertube().setVideoFiles(this.video.files, videoViewUrl, this.video.duration)
+    }
+
+    this.setVideoDescriptionHTML()
+    this.setVideoLikesBarTooltipText()
+
+    this.setOpenGraphTags()
+    this.checkUserRating()
   }
 
   private setRating (nextRating) {
@@ -411,8 +414,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
 
     this.video.likes += likesToIncrement
     this.video.dislikes += dislikesToIncrement
-    this.video.buildLikeAndDislikePercents()
 
+    this.video.buildLikeAndDislikePercents()
     this.setVideoLikesBarTooltipText()
   }
 
@@ -450,4 +453,12 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
     // Be sure the autoPlay is set to false
     return this.user.autoPlayVideo !== false
   }
+
+  private hasAlreadyAcceptedPrivacyConcern () {
+    return localStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true'
+  }
+
+  private acceptedPrivacyConcern () {
+    localStorage.setItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY, 'true')
+  }
 }
index 8b6d54b221fce994d923b1ee5a9c7b64780f1b75..75630dd63acbf95e6ab56d8a47304b2a9668d8f5 100644 (file)
@@ -1,4 +1,4 @@
-// Thanks: https://github.com/zanechua/videojs-sublime-inspired-skin
+@charset "utf-8";// Thanks: https://github.com/zanechua/videojs-sublime-inspired-skin
 $primary-foreground-color: #fff;
 $primary-background-color: #000;
 $font-size: 13px;
@@ -8,6 +8,28 @@ $control-bar-height: 34px;
   font-size: $font-size;
   color: $primary-foreground-color;
 
+  .vjs-dock-text {
+    padding-right: 10px;
+  }
+
+  .vjs-dock-description {
+    font-size: 11px;
+
+    &:before, &:after {
+      display: inline-block;
+      content: '\1F308';
+    }
+
+    &:before {
+      margin-right: 4px;
+    }
+
+    &:after {
+      margin-left: 4px;
+      transform: scale(-1, 1);
+    }
+  }
+
   .vjs-button > .vjs-icon-placeholder::before {
     line-height: $control-bar-height;
   }
@@ -354,7 +376,11 @@ $control-bar-height: 34px;
 
   @media screen and (max-width: 300px) {
     .vjs-dock-text {
-      font-size: 1em;
+      font-size: 13px;
+    }
+
+    .vjs-dock-description {
+      font-size: 9px;
     }
 
     .vjs-big-play-button {
index 925367bb9bade9b5f3ab2e765a5f9fe5ef67ab14..bb6baf7f0a1ac100ceffdf7d6d9f179e5813cad7 100644 (file)
@@ -44,7 +44,8 @@ loadVideoInfo(videoId)
       const player = this
 
       player.dock({
-        title: videoInfo.name
+        title: videoInfo.name,
+        description: 'Use P2P, other may know you are watching that video.'
       })
     })
   })