mirror of https://github.com/Chocobozzz/PeerTube
Move adding a video view videojs peertube plugin
parent
a16aee73db
commit
8cac1b6446
|
@ -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'
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 })
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue