From 8cac1b6446a97b16387c9590ce5c799a79a759fa Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 14 Feb 2018 17:16:32 +0100 Subject: [PATCH] Move adding a video view videojs peertube plugin --- .../video/infinite-scroller.directive.ts | 3 ++ client/src/app/shared/video/video.service.ts | 6 ++- .../+video-watch/video-watch.component.ts | 20 ++----- .../assets/player/peertube-videojs-plugin.ts | 53 ++++++++++++++++++- client/src/sass/video-js-custom.scss | 19 ++++--- client/src/standalone/videos/embed.ts | 9 +++- server/tools/import-youtube.ts | 3 +- 7 files changed, 85 insertions(+), 28 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 @@ import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core' +import 'rxjs/add/operator/debounceTime' import 'rxjs/add/operator/distinct' +import 'rxjs/add/operator/filter' +import 'rxjs/add/operator/map' import 'rxjs/add/operator/startWith' import { fromEvent } from 'rxjs/observable/fromEvent' 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 { private restService: RestService ) {} + getVideoViewUrl (uuid: string) { + return VideoService.BASE_VIDEO_URL + uuid + '/views' + } + getVideo (uuid: string): Observable { return this.authHttp.get(VideoService.BASE_VIDEO_URL + uuid) .map(videoHash => new VideoDetails(videoHash)) @@ -36,7 +40,7 @@ export class VideoService { } viewVideo (uuid: string): Observable { - return this.authHttp.post(VideoService.BASE_VIDEO_URL + uuid + '/views', {}) + return this.authHttp.post(this.getVideoViewUrl(uuid), {}) .map(this.restExtractor.extractDataBool) .catch(this.restExtractor.handleError) } 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 { peertube: { videoFiles: this.video.files, playerElement: this.playerElement, - peerTubeLink: false + peerTubeLink: false, + videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid) }, hotkeys: { enableVolumeScroll: false @@ -349,7 +350,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { }) }) } else { - this.player.peertube().setVideoFiles(this.video.files) + this.player.peertube().setVideoFiles(this.video.files, this.videoService.getVideoViewUrl(this.video.uuid)) } this.setVideoDescriptionHTML() @@ -357,8 +358,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy { this.setOpenGraphTags() this.checkUserRating() - - this.prepareViewAdd() } ) } @@ -431,19 +430,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy { this.metaService.setTag('url', window.location.href) } - private prepareViewAdd () { - // After 30 seconds (or 3/4 of the video), increment add a view - let viewTimeoutSeconds = 30 - if (this.video.duration < viewTimeoutSeconds) viewTimeoutSeconds = (this.video.duration * 3) / 4 - - setTimeout(() => { - this.videoService - .viewVideo(this.video.uuid) - .subscribe() - - }, viewTimeoutSeconds * 1000) - } - private isAutoplay () { // True by default 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 @@ // Big thanks to: https://github.com/kmoskwiak/videojs-resolution-switcher +import { VideoService } from '@app/shared/video/video.service' import * as videojs from 'video.js' import * as WebTorrent from 'webtorrent' import { VideoFile } from '../../../../shared/models/videos/video.model' @@ -23,6 +24,7 @@ type PeertubePluginOptions = { videoFiles: VideoFile[] playerElement: HTMLVideoElement peerTubeLink: boolean + videoViewUrl: string } // https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts @@ -218,6 +220,8 @@ class PeerTubePlugin extends Plugin { private videoFiles: VideoFile[] private torrent: WebTorrent.Torrent private autoplay = false + private videoViewUrl: string + private videoViewInterval constructor (player: videojs.Player, options: PeertubePluginOptions) { super(player, options) @@ -227,6 +231,7 @@ class PeerTubePlugin extends Plugin { this.player.options_.autoplay = false this.videoFiles = options.videoFiles + this.videoViewUrl = options.videoViewUrl // Hack to "simulate" src link in video.js >= 6 // Without this, we can't play the video after pausing it @@ -240,6 +245,7 @@ class PeerTubePlugin extends Plugin { this.player.ready(() => { this.initializePlayer(options) this.runTorrentInfoScheduler() + this.prepareRunViewAdd() }) } @@ -334,9 +340,12 @@ class PeerTubePlugin extends Plugin { } } - setVideoFiles (files: VideoFile[]) { + setVideoFiles (files: VideoFile[], videoViewUrl: string) { + this.videoViewUrl = videoViewUrl this.videoFiles = files + // Re run view add for the new video + this.prepareRunViewAdd() this.updateVideoFile(undefined, () => this.player.play()) } @@ -377,6 +386,48 @@ class PeerTubePlugin extends Plugin { }, 1000) } + private prepareRunViewAdd () { + if (this.player.readyState() < 1) { + return this.player.one('loadedmetadata', () => this.runViewAdd()) + } + + this.runViewAdd() + } + + private runViewAdd () { + this.clearVideoViewInterval() + + // After 30 seconds (or 3/4 of the video), add a view to the video + let minSecondsToView = 30 + + const duration = this.player.duration() + if (duration < minSecondsToView) minSecondsToView = (duration * 3) / 4 + + let secondsViewed = 0 + this.videoViewInterval = setInterval(() => { + if (this.player && !this.player.paused()) { + secondsViewed += 1 + + if (secondsViewed > minSecondsToView) { + this.clearVideoViewInterval() + + this.addViewToVideo().catch(err => console.error(err)) + } + } + }, 1000) + } + + private clearVideoViewInterval () { + if (this.videoViewInterval !== undefined) { + clearInterval(this.videoViewInterval) + this.videoViewInterval = undefined + } + } + + private addViewToVideo () { + return fetch(this.videoViewUrl, { method: 'POST' }) + } + private handleError (err: Error | string) { return this.player.trigger('customError', { err }) } 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; .vjs-big-play-button { outline: 0; - font-size: 8em; + font-size: 7em; - $big-play-width: 3em; - $big-play-height: 1.5em; + $big-play-width: 1.5em; + $big-play-height: 1em; border: 0; border-radius: 0.3em; left: 50%; top: 50%; + width: $big-play-width; + height: $big-play-height; + line-height: $big-play-height; margin-left: -($big-play-width / 2); margin-top: -($big-play-height / 2); - background-color: transparent !important; + transition: opacity 0.5s; &::-moz-focus-inner { border: 0; @@ -47,8 +50,12 @@ $control-bar-height: 34px; transition: text-shadow 0.3s; } - &:hover .vjs-icon-placeholder::before { - text-shadow: 0 0 2px rgba(255, 255, 255, 0.8); + &:hover { + opacity: 0.9; + + .vjs-icon-placeholder::before { + text-shadow: 0 0 1px rgba(255, 255, 255, 0.8); + } } } 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' import 'videojs-dock/dist/videojs-dock.es.js' import { VideoDetails } from '../../../../shared' +function getVideoUrl (id: string) { + return window.location.origin + '/api/v1/videos/' + videoId +} + async function loadVideoInfo (videoId: string): Promise { - const response = await fetch(window.location.origin + '/api/v1/videos/' + videoId) + const response = await fetch(getVideoUrl(videoId)) return response.json() } @@ -27,7 +31,8 @@ loadVideoInfo(videoId) peertube: { videoFiles: videoInfo.files, playerElement: videoElement, - peerTubeLink: true + peerTubeLink: true, + videoViewUrl: getVideoUrl(videoId) + '/views' }, hotkeys: { enableVolumeScroll: false diff --git a/server/tools/import-youtube.ts b/server/tools/import-youtube.ts index 325e9f7ba..12e996e5b 100644 --- a/server/tools/import-youtube.ts +++ b/server/tools/import-youtube.ts @@ -120,7 +120,8 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string) { tags: videoInfo.tags.slice(0, 5), privacy: VideoPrivacy.PUBLIC, fixture: videoPath, - thumbnailfile + thumbnailfile, + previewfile: thumbnailfile } console.log('\nUploading on PeerTube video "%s".', videoAttributes.name)