Move adding a video view videojs peertube plugin

pull/297/head
Chocobozzz 2018-02-14 17:16:32 +01:00
parent a16aee73db
commit 8cac1b6446
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
7 changed files with 85 additions and 28 deletions

View File

@ -1,5 +1,8 @@
import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core' import { Directive, EventEmitter, Input, OnInit, Output } from '@angular/core'
import 'rxjs/add/operator/debounceTime'
import 'rxjs/add/operator/distinct' import 'rxjs/add/operator/distinct'
import 'rxjs/add/operator/filter'
import 'rxjs/add/operator/map'
import 'rxjs/add/operator/startWith' import 'rxjs/add/operator/startWith'
import { fromEvent } from 'rxjs/observable/fromEvent' import { fromEvent } from 'rxjs/observable/fromEvent'

View File

@ -29,6 +29,10 @@ export class VideoService {
private restService: RestService private restService: RestService
) {} ) {}
getVideoViewUrl (uuid: string) {
return VideoService.BASE_VIDEO_URL + uuid + '/views'
}
getVideo (uuid: string): Observable<VideoDetails> { getVideo (uuid: string): Observable<VideoDetails> {
return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid) return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
.map(videoHash => new VideoDetails(videoHash)) .map(videoHash => new VideoDetails(videoHash))
@ -36,7 +40,7 @@ export class VideoService {
} }
viewVideo (uuid: string): Observable<VideoDetails> { viewVideo (uuid: string): Observable<VideoDetails> {
return this.authHttp.post(VideoService.BASE_VIDEO_URL + uuid + '/views', {}) return this.authHttp.post(this.getVideoViewUrl(uuid), {})
.map(this.restExtractor.extractDataBool) .map(this.restExtractor.extractDataBool)
.catch(this.restExtractor.handleError) .catch(this.restExtractor.handleError)
} }

View File

@ -329,7 +329,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
peertube: { peertube: {
videoFiles: this.video.files, videoFiles: this.video.files,
playerElement: this.playerElement, playerElement: this.playerElement,
peerTubeLink: false peerTubeLink: false,
videoViewUrl: this.videoService.getVideoViewUrl(this.video.uuid)
}, },
hotkeys: { hotkeys: {
enableVolumeScroll: false enableVolumeScroll: false
@ -349,7 +350,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
}) })
}) })
} else { } else {
this.player.peertube().setVideoFiles(this.video.files) this.player.peertube().setVideoFiles(this.video.files, this.videoService.getVideoViewUrl(this.video.uuid))
} }
this.setVideoDescriptionHTML() this.setVideoDescriptionHTML()
@ -357,8 +358,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
this.setOpenGraphTags() this.setOpenGraphTags()
this.checkUserRating() this.checkUserRating()
this.prepareViewAdd()
} }
) )
} }
@ -431,19 +430,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
this.metaService.setTag('url', window.location.href) 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 () { private isAutoplay () {
// True by default // True by default
if (!this.user) return true if (!this.user) return true

View File

@ -1,5 +1,6 @@
// Big thanks to: https://github.com/kmoskwiak/videojs-resolution-switcher // 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 videojs from 'video.js'
import * as WebTorrent from 'webtorrent' import * as WebTorrent from 'webtorrent'
import { VideoFile } from '../../../../shared/models/videos/video.model' import { VideoFile } from '../../../../shared/models/videos/video.model'
@ -23,6 +24,7 @@ type PeertubePluginOptions = {
videoFiles: VideoFile[] videoFiles: VideoFile[]
playerElement: HTMLVideoElement playerElement: HTMLVideoElement
peerTubeLink: boolean peerTubeLink: boolean
videoViewUrl: string
} }
// https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts // 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 videoFiles: VideoFile[]
private torrent: WebTorrent.Torrent private torrent: WebTorrent.Torrent
private autoplay = false private autoplay = false
private videoViewUrl: string
private videoViewInterval
constructor (player: videojs.Player, options: PeertubePluginOptions) { constructor (player: videojs.Player, options: PeertubePluginOptions) {
super(player, options) super(player, options)
@ -227,6 +231,7 @@ class PeerTubePlugin extends Plugin {
this.player.options_.autoplay = false this.player.options_.autoplay = false
this.videoFiles = options.videoFiles this.videoFiles = options.videoFiles
this.videoViewUrl = options.videoViewUrl
// Hack to "simulate" src link in video.js >= 6 // Hack to "simulate" src link in video.js >= 6
// Without this, we can't play the video after pausing it // Without this, we can't play the video after pausing it
@ -240,6 +245,7 @@ class PeerTubePlugin extends Plugin {
this.player.ready(() => { this.player.ready(() => {
this.initializePlayer(options) this.initializePlayer(options)
this.runTorrentInfoScheduler() 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 this.videoFiles = files
// Re run view add for the new video
this.prepareRunViewAdd()
this.updateVideoFile(undefined, () => this.player.play()) this.updateVideoFile(undefined, () => this.player.play())
} }
@ -377,6 +386,48 @@ class PeerTubePlugin extends Plugin {
}, 1000) }, 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) { private handleError (err: Error | string) {
return this.player.trigger('customError', { err }) return this.player.trigger('customError', { err })
} }

View File

@ -24,19 +24,22 @@ $control-bar-height: 34px;
.vjs-big-play-button { .vjs-big-play-button {
outline: 0; outline: 0;
font-size: 8em; font-size: 7em;
$big-play-width: 3em; $big-play-width: 1.5em;
$big-play-height: 1.5em; $big-play-height: 1em;
border: 0; border: 0;
border-radius: 0.3em; border-radius: 0.3em;
left: 50%; left: 50%;
top: 50%; top: 50%;
width: $big-play-width;
height: $big-play-height;
line-height: $big-play-height;
margin-left: -($big-play-width / 2); margin-left: -($big-play-width / 2);
margin-top: -($big-play-height / 2); margin-top: -($big-play-height / 2);
background-color: transparent !important; transition: opacity 0.5s;
&::-moz-focus-inner { &::-moz-focus-inner {
border: 0; border: 0;
@ -47,8 +50,12 @@ $control-bar-height: 34px;
transition: text-shadow 0.3s; transition: text-shadow 0.3s;
} }
&:hover .vjs-icon-placeholder::before { &:hover {
text-shadow: 0 0 2px rgba(255, 255, 255, 0.8); opacity: 0.9;
.vjs-icon-placeholder::before {
text-shadow: 0 0 1px rgba(255, 255, 255, 0.8);
}
} }
} }

View File

@ -6,8 +6,12 @@ import '../../assets/player/peertube-videojs-plugin'
import 'videojs-dock/dist/videojs-dock.es.js' import 'videojs-dock/dist/videojs-dock.es.js'
import { VideoDetails } from '../../../../shared' import { VideoDetails } from '../../../../shared'
function getVideoUrl (id: string) {
return window.location.origin + '/api/v1/videos/' + videoId
}
async function loadVideoInfo (videoId: string): Promise<VideoDetails> { async function loadVideoInfo (videoId: string): Promise<VideoDetails> {
const response = await fetch(window.location.origin + '/api/v1/videos/' + videoId) const response = await fetch(getVideoUrl(videoId))
return response.json() return response.json()
} }
@ -27,7 +31,8 @@ loadVideoInfo(videoId)
peertube: { peertube: {
videoFiles: videoInfo.files, videoFiles: videoInfo.files,
playerElement: videoElement, playerElement: videoElement,
peerTubeLink: true peerTubeLink: true,
videoViewUrl: getVideoUrl(videoId) + '/views'
}, },
hotkeys: { hotkeys: {
enableVolumeScroll: false enableVolumeScroll: false

View File

@ -120,7 +120,8 @@ async function uploadVideoOnPeerTube (videoInfo: any, videoPath: string) {
tags: videoInfo.tags.slice(0, 5), tags: videoInfo.tags.slice(0, 5),
privacy: VideoPrivacy.PUBLIC, privacy: VideoPrivacy.PUBLIC,
fixture: videoPath, fixture: videoPath,
thumbnailfile thumbnailfile,
previewfile: thumbnailfile
} }
console.log('\nUploading on PeerTube video "%s".', videoAttributes.name) console.log('\nUploading on PeerTube video "%s".', videoAttributes.name)