import debug from 'debug'
import videojs from 'video.js'
+import { logger } from '@root-helpers/logger'
import { isMobile } from '@root-helpers/web-browser'
import { timeToInt } from '@shared/core-utils'
import { VideoView, VideoViewEvent } from '@shared/models/videos'
import { PeerTubePluginOptions, VideoJSCaption } from '../../types'
import { SettingsButton } from '../settings/settings-menu-button'
-const logger = debug('peertube:player:peertube')
+const debugLogger = debug('peertube:player:peertube')
const Plugin = videojs.getPlugin('plugin')
class PeerTubePlugin extends Plugin {
private readonly videoViewUrl: string
- private readonly authorizationHeader: string
+ private readonly authorizationHeader: () => string
private readonly videoUUID: string
private readonly startTime: number
- private readonly CONSTANTS = {
- USER_VIEW_VIDEO_INTERVAL: 5000 // Every 5 seconds, notify the user is watching the video
- }
+ private readonly videoViewIntervalMs: number
private videoCaptions: VideoJSCaption[]
private defaultSubtitle: string
this.authorizationHeader = options.authorizationHeader
this.videoUUID = options.videoUUID
this.startTime = timeToInt(options.startTime)
+ this.videoViewIntervalMs = options.videoViewIntervalMs
this.videoCaptions = options.videoCaptions
this.initialInactivityTimeout = this.player.options_.inactivityTimeout
- if (options.autoplay) this.player.addClass('vjs-has-autoplay')
+ if (options.autoplay !== false) this.player.addClass('vjs-has-autoplay')
this.player.on('autoplay-failure', () => {
this.player.removeClass('vjs-has-autoplay')
}
displayFatalError () {
+ this.player.loadingSpinner.hide()
+
+ const buildModal = (error: MediaError) => {
+ const localize = this.player.localize.bind(this.player)
+
+ const wrapper = document.createElement('div')
+ const header = document.createElement('h1')
+ header.innerText = localize('Failed to play video')
+ wrapper.appendChild(header)
+ const desc = document.createElement('div')
+ desc.innerText = localize('The video failed to play due to technical issues.')
+ wrapper.appendChild(desc)
+ const details = document.createElement('p')
+ details.classList.add('error-details')
+ details.innerText = error.message
+ wrapper.appendChild(details)
+
+ return wrapper
+ }
+
+ const modal = this.player.createModal(buildModal(this.player.error()), {
+ temporary: false,
+ uncloseable: true
+ })
+ modal.addClass('vjs-custom-error-display')
+
this.player.addClass('vjs-error-display-enabled')
}
this.listenFullScreenChange()
}
+ // ---------------------------------------------------------------------------
+
private runUserViewing () {
let lastCurrentTime = this.startTime
let lastViewEvent: VideoViewEvent
})
this.player.on('seeked', () => {
- // Don't take into account small seek events
- if (Math.abs(this.player.currentTime() - lastCurrentTime) < 3) return
+ const diff = Math.floor(this.player.currentTime()) - lastCurrentTime
+
+ // Don't take into account small forwards
+ if (diff > 0 && diff < 3) return
lastViewEvent = 'seek'
})
lastCurrentTime = currentTime
this.notifyUserIsWatching(currentTime, lastViewEvent)
- .catch(err => console.error('Cannot notify user is watching.', err))
+ .catch(err => logger.error('Cannot notify user is watching.', err))
lastViewEvent = undefined
-
- // Server won't save history, so save the video position in local storage
- if (!this.authorizationHeader) {
- saveVideoWatchHistory(this.videoUUID, currentTime)
- }
- }, this.CONSTANTS.USER_VIEW_VIDEO_INTERVAL)
+ }, this.videoViewIntervalMs)
}
private notifyUserIsWatching (currentTime: number, viewEvent: VideoViewEvent) {
- if (!this.videoViewUrl) return Promise.resolve(undefined)
-
- const body: VideoView = {
- currentTime,
- viewEvent
+ // Server won't save history, so save the video position in local storage
+ if (!this.authorizationHeader()) {
+ saveVideoWatchHistory(this.videoUUID, currentTime)
}
- const headers = new Headers({
- 'Content-type': 'application/json; charset=UTF-8'
- })
+ if (!this.videoViewUrl) return Promise.resolve(true)
+
+ const body: VideoView = { currentTime, viewEvent }
- if (this.authorizationHeader) headers.set('Authorization', this.authorizationHeader)
+ const headers = new Headers({ 'Content-type': 'application/json; charset=UTF-8' })
+ if (this.authorizationHeader()) headers.set('Authorization', this.authorizationHeader())
return fetch(this.videoViewUrl, { method: 'POST', body: JSON.stringify(body), headers })
}
+ // ---------------------------------------------------------------------------
+
private listenFullScreenChange () {
this.player.on('fullscreenchange', () => {
if (this.player.isFullscreen()) this.player.focus()
(this.player as any).cache_.inactivityTimeout = timeout
this.player.options_.inactivityTimeout = timeout
- logger('Set player inactivity to ' + timeout)
+ debugLogger('Set player inactivity to ' + timeout)
}
private initCaptions () {