aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src
diff options
context:
space:
mode:
Diffstat (limited to 'client/src')
-rw-r--r--client/src/app/shared/video/infinite-scroller.directive.ts3
-rw-r--r--client/src/app/shared/video/video.service.ts6
-rw-r--r--client/src/app/videos/+video-watch/video-watch.component.ts20
-rw-r--r--client/src/assets/player/peertube-videojs-plugin.ts53
-rw-r--r--client/src/sass/video-js-custom.scss19
-rw-r--r--client/src/standalone/videos/embed.ts9
6 files changed, 83 insertions, 27 deletions
diff --git a/client/src/app/shared/video/infinite-scroller.directive.ts b/client/src/app/shared/video/infinite-scroller.directive.ts
index 43e014cbd..52d8b2b37 100644
--- a/client/src/app/shared/video/infinite-scroller.directive.ts
+++ b/client/src/app/shared/video/infinite-scroller.directive.ts
@@ -1,5 +1,8 @@
1import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core' 1import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core'
2import 'rxjs/add/operator/debounceTime'
2import 'rxjs/add/operator/distinct' 3import 'rxjs/add/operator/distinct'
4import 'rxjs/add/operator/filter'
5import 'rxjs/add/operator/map'
3import 'rxjs/add/operator/startWith' 6import 'rxjs/add/operator/startWith'
4import { fromEvent } from 'rxjs/observable/fromEvent' 7import { fromEvent } from 'rxjs/observable/fromEvent'
5 8
diff --git a/client/src/app/shared/video/video.service.ts b/client/src/app/shared/video/video.service.ts
index d4f5e258f..01d32176b 100644
--- a/client/src/app/shared/video/video.service.ts
+++ b/client/src/app/shared/video/video.service.ts
@@ -29,6 +29,10 @@ export class VideoService {
29 private restService: RestService 29 private restService: RestService
30 ) {} 30 ) {}
31 31
32 getVideoViewUrl (uuid: string) {
33 return VideoService.BASE_VIDEO_URL + uuid + '/views'
34 }
35
32 getVideo (uuid: string): Observable<VideoDetails> { 36 getVideo (uuid: string): Observable<VideoDetails> {
33 return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid) 37 return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
34 .map(videoHash => new VideoDetails(videoHash)) 38 .map(videoHash => new VideoDetails(videoHash))
@@ -36,7 +40,7 @@ export class VideoService {
36 } 40 }
37 41
38 viewVideo (uuid: string): Observable<VideoDetails> { 42 viewVideo (uuid: string): Observable<VideoDetails> {
39 return this.authHttp.post(VideoService.BASE_VIDEO_URL + uuid + '/views', {}) 43 return this.authHttp.post(this.getVideoViewUrl(uuid), {})
40 .map(this.restExtractor.extractDataBool) 44 .map(this.restExtractor.extractDataBool)
41 .catch(this.restExtractor.handleError) 45 .catch(this.restExtractor.handleError)
42 } 46 }
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 8330aba15..b7779ae9a 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -329,7 +329,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
329 peertube: { 329 peertube: {
330 videoFiles: this.video.files, 330 videoFiles: this.video.files,
331 playerElement: this.playerElement, 331 playerElement: this.playerElement,
332 peerTubeLink: false 332 peerTubeLink: false,
333 videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid)
333 }, 334 },
334 hotkeys: { 335 hotkeys: {
335 enableVolumeScroll: false 336 enableVolumeScroll: false
@@ -349,7 +350,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
349 }) 350 })
350 }) 351 })
351 } else { 352 } else {
352 this.player.peertube().setVideoFiles(this.video.files) 353 this.player.peertube().setVideoFiles(this.video.files, this.videoService.getVideoViewUrl(this.video.uuid))
353 } 354 }
354 355
355 this.setVideoDescriptionHTML() 356 this.setVideoDescriptionHTML()
@@ -357,8 +358,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
357 358
358 this.setOpenGraphTags() 359 this.setOpenGraphTags()
359 this.checkUserRating() 360 this.checkUserRating()
360
361 this.prepareViewAdd()
362 } 361 }
363 ) 362 )
364 } 363 }
@@ -431,19 +430,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
431 this.metaService.setTag('url', window.location.href) 430 this.metaService.setTag('url', window.location.href)
432 } 431 }
433 432
434 private prepareViewAdd () {
435 // After 30 seconds (or 3/4 of the video), increment add a view
436 let viewTimeoutSeconds = 30
437 if (this.video.duration < viewTimeoutSeconds) viewTimeoutSeconds = (this.video.duration * 3) / 4
438
439 setTimeout(() => {
440 this.videoService
441 .viewVideo(this.video.uuid)
442 .subscribe()
443
444 }, viewTimeoutSeconds * 1000)
445 }
446
447 private isAutoplay () { 433 private isAutoplay () {
448 // True by default 434 // True by default
449 if (!this.user) return true 435 if (!this.user) return true
diff --git a/client/src/assets/player/peertube-videojs-plugin.ts b/client/src/assets/player/peertube-videojs-plugin.ts
index 125ef64a4..fecd4edec 100644
--- a/client/src/assets/player/peertube-videojs-plugin.ts
+++ b/client/src/assets/player/peertube-videojs-plugin.ts
@@ -1,5 +1,6 @@
1// Big thanks to: https://github.com/kmoskwiak/videojs-resolution-switcher 1// Big thanks to: https://github.com/kmoskwiak/videojs-resolution-switcher
2 2
3import { VideoService } from '@app/shared/video/video.service'
3import * as videojs from 'video.js' 4import * as videojs from 'video.js'
4import * as WebTorrent from 'webtorrent' 5import * as WebTorrent from 'webtorrent'
5import { VideoFile } from '../../../../shared/models/videos/video.model' 6import { VideoFile } from '../../../../shared/models/videos/video.model'
@@ -23,6 +24,7 @@ type PeertubePluginOptions = {
23 videoFiles: VideoFile[] 24 videoFiles: VideoFile[]
24 playerElement: HTMLVideoElement 25 playerElement: HTMLVideoElement
25 peerTubeLink: boolean 26 peerTubeLink: boolean
27 videoViewUrl: string
26} 28}
27 29
28// https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts 30// https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts
@@ -218,6 +220,8 @@ class PeerTubePlugin extends Plugin {
218 private videoFiles: VideoFile[] 220 private videoFiles: VideoFile[]
219 private torrent: WebTorrent.Torrent 221 private torrent: WebTorrent.Torrent
220 private autoplay = false 222 private autoplay = false
223 private videoViewUrl: string
224 private videoViewInterval
221 225
222 constructor (player: videojs.Player, options: PeertubePluginOptions) { 226 constructor (player: videojs.Player, options: PeertubePluginOptions) {
223 super(player, options) 227 super(player, options)
@@ -227,6 +231,7 @@ class PeerTubePlugin extends Plugin {
227 this.player.options_.autoplay = false 231 this.player.options_.autoplay = false
228 232
229 this.videoFiles = options.videoFiles 233 this.videoFiles = options.videoFiles
234 this.videoViewUrl = options.videoViewUrl
230 235
231 // Hack to "simulate" src link in video.js >= 6 236 // Hack to "simulate" src link in video.js >= 6
232 // Without this, we can't play the video after pausing it 237 // Without this, we can't play the video after pausing it
@@ -240,6 +245,7 @@ class PeerTubePlugin extends Plugin {
240 this.player.ready(() => { 245 this.player.ready(() => {
241 this.initializePlayer(options) 246 this.initializePlayer(options)
242 this.runTorrentInfoScheduler() 247 this.runTorrentInfoScheduler()
248 this.prepareRunViewAdd()
243 }) 249 })
244 } 250 }
245 251
@@ -334,9 +340,12 @@ class PeerTubePlugin extends Plugin {
334 } 340 }
335 } 341 }
336 342
337 setVideoFiles (files: VideoFile[]) { 343 setVideoFiles (files: VideoFile[], videoViewUrl: string) {
344 this.videoViewUrl = videoViewUrl
338 this.videoFiles = files 345 this.videoFiles = files
339 346
347 // Re run view add for the new video
348 this.prepareRunViewAdd()
340 this.updateVideoFile(undefined, () => this.player.play()) 349 this.updateVideoFile(undefined, () => this.player.play())
341 } 350 }
342 351
@@ -377,6 +386,48 @@ class PeerTubePlugin extends Plugin {
377 }, 1000) 386 }, 1000)
378 } 387 }
379 388
389 private prepareRunViewAdd () {
390 if (this.player.readyState() < 1) {
391 return this.player.one('loadedmetadata', () => this.runViewAdd())
392 }
393
394 this.runViewAdd()
395 }
396
397 private runViewAdd () {
398 this.clearVideoViewInterval()
399
400 // After 30 seconds (or 3/4 of the video), add a view to the video
401 let minSecondsToView = 30
402
403 const duration = this.player.duration()
404 if (duration < minSecondsToView) minSecondsToView = (duration * 3) / 4
405
406 let secondsViewed = 0
407 this.videoViewInterval = setInterval(() => {
408 if (this.player && !this.player.paused()) {
409 secondsViewed += 1
410
411 if (secondsViewed > minSecondsToView) {
412 this.clearVideoViewInterval()
413
414 this.addViewToVideo().catch(err => console.error(err))
415 }
416 }
417 }, 1000)
418 }
419
420 private clearVideoViewInterval () {
421 if (this.videoViewInterval !== undefined) {
422 clearInterval(this.videoViewInterval)
423 this.videoViewInterval = undefined
424 }
425 }
426
427 private addViewToVideo () {
428 return fetch(this.videoViewUrl, { method: 'POST' })
429 }
430
380 private handleError (err: Error | string) { 431 private handleError (err: Error | string) {
381 return this.player.trigger('customError', { err }) 432 return this.player.trigger('customError', { err })
382 } 433 }
diff --git a/client/src/sass/video-js-custom.scss b/client/src/sass/video-js-custom.scss
index 8ff963573..209fb1683 100644
--- a/client/src/sass/video-js-custom.scss
+++ b/client/src/sass/video-js-custom.scss
@@ -24,19 +24,22 @@ $control-bar-height: 34px;
24 24
25 .vjs-big-play-button { 25 .vjs-big-play-button {
26 outline: 0; 26 outline: 0;
27 font-size: 8em; 27 font-size: 7em;
28 28
29 $big-play-width: 3em; 29 $big-play-width: 1.5em;
30 $big-play-height: 1.5em; 30 $big-play-height: 1em;
31 31
32 border: 0; 32 border: 0;
33 border-radius: 0.3em; 33 border-radius: 0.3em;
34 34
35 left: 50%; 35 left: 50%;
36 top: 50%; 36 top: 50%;
37 width: $big-play-width;
38 height: $big-play-height;
39 line-height: $big-play-height;
37 margin-left: -($big-play-width / 2); 40 margin-left: -($big-play-width / 2);
38 margin-top: -($big-play-height / 2); 41 margin-top: -($big-play-height / 2);
39 background-color: transparent !important; 42 transition: opacity 0.5s;
40 43
41 &::-moz-focus-inner { 44 &::-moz-focus-inner {
42 border: 0; 45 border: 0;
@@ -47,8 +50,12 @@ $control-bar-height: 34px;
47 transition: text-shadow 0.3s; 50 transition: text-shadow 0.3s;
48 } 51 }
49 52
50 &:hover .vjs-icon-placeholder::before { 53 &:hover {
51 text-shadow: 0 0 2px rgba(255, 255, 255, 0.8); 54 opacity: 0.9;
55
56 .vjs-icon-placeholder::before {
57 text-shadow: 0 0 1px rgba(255, 255, 255, 0.8);
58 }
52 } 59 }
53 } 60 }
54 61
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index 3193ae6ef..9076f1dc9 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -6,8 +6,12 @@ import '../../assets/player/peertube-videojs-plugin'
6import 'videojs-dock/dist/videojs-dock.es.js' 6import 'videojs-dock/dist/videojs-dock.es.js'
7import { VideoDetails } from '../../../../shared' 7import { VideoDetails } from '../../../../shared'
8 8
9function getVideoUrl (id: string) {
10 return window.location.origin + '/api/v1/videos/' + videoId
11}
12
9async function loadVideoInfo (videoId: string): Promise<VideoDetails> { 13async function loadVideoInfo (videoId: string): Promise<VideoDetails> {
10 const response = await fetch(window.location.origin + '/api/v1/videos/' + videoId) 14 const response = await fetch(getVideoUrl(videoId))
11 return response.json() 15 return response.json()
12} 16}
13 17
@@ -27,7 +31,8 @@ loadVideoInfo(videoId)
27 peertube: { 31 peertube: {
28 videoFiles: videoInfo.files, 32 videoFiles: videoInfo.files,
29 playerElement: videoElement, 33 playerElement: videoElement,
30 peerTubeLink: true 34 peerTubeLink: true,
35 videoViewUrl: getVideoUrl(videoId) + '/views'
31 }, 36 },
32 hotkeys: { 37 hotkeys: {
33 enableVolumeScroll: false 38 enableVolumeScroll: false