+// FIXME: something weird with our path definition in tsconfig and typings
+// @ts-ignore
import * as videojs from 'video.js'
+
import * as WebTorrent from 'webtorrent'
import { VideoFile } from '../../../../shared/models/videos/video.model'
import { renderVideo } from './video-renderer'
import './settings-menu-button'
import { PeertubePluginOptions, UserWatching, VideoJSCaption, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
import { isMobile, timeToInt, videoFileMaxByResolution, videoFileMinByResolution } from './utils'
-import * as CacheChunkStore from 'cache-chunk-store'
import { PeertubeChunkStore } from './peertube-chunk-store'
import {
- getStoredWebTorrentPolicy,
getAverageBandwidthInStore,
getStoredMute,
getStoredVolume,
+ getStoredWebTorrentEnabled,
saveAverageBandwidth,
saveMuteInStore,
saveVolumeInStore
} from './peertube-player-local-storage'
+const CacheChunkStore = require('cache-chunk-store')
+
+type PlayOptions = {
+ forcePlay?: boolean,
+ seek?: number,
+ delay?: number
+}
+
const Plugin: VideoJSComponentInterface = videojs.getPlugin('plugin')
class PeerTubePlugin extends Plugin {
private readonly playerElement: HTMLVideoElement
private torrent: WebTorrent.Torrent
private videoCaptions: VideoJSCaption[]
- private renderer
- private fakeRenderer
+ private renderer: any
+ private fakeRenderer: any
private destoyingFakeRenderer = false
private autoResolution = true
private isAutoResolutionObservation = false
private playerRefusedP2P = false
- private videoViewInterval
- private torrentInfoInterval
- private autoQualityInterval
- private userWatchingVideoInterval
- private addTorrentDelay
- private qualityObservationTimer
- private runAutoQualitySchedulerTimer
+ private videoViewInterval: any
+ private torrentInfoInterval: any
+ private autoQualityInterval: any
+ private userWatchingVideoInterval: any
+ private addTorrentDelay: any
+ private qualityObservationTimer: any
+ private runAutoQualitySchedulerTimer: any
private downloadSpeeds: number[] = []
// Disable auto play on iOS
this.autoplay = options.autoplay && this.isIOS() === false
+ this.playerRefusedP2P = !getStoredWebTorrentEnabled()
this.startTime = timeToInt(options.startTime)
this.videoFiles = options.videoFiles
if (volume !== undefined) this.player.volume(volume)
const muted = getStoredMute()
if (muted !== undefined) this.player.muted(muted)
- this.playerRefusedP2P = getStoredWebTorrentPolicy() || false
+
+ this.player.duration(options.videoDuration)
this.initializePlayer()
this.runTorrentInfoScheduler()
const previousVideoFile = this.currentVideoFile
this.currentVideoFile = videoFile
+ // Don't try on iOS that does not support MediaSource
+ // Or don't use P2P if webtorrent is disabled
+ if (this.isIOS() || this.playerRefusedP2P) {
+ return this.fallbackToHttp(options, () => {
+ this.player.playbackRate(oldPlaybackRate)
+ return done()
+ })
+ }
+
this.addTorrent(this.currentVideoFile.magnetUri, previousVideoFile, options, () => {
this.player.playbackRate(oldPlaybackRate)
return done()
private addTorrent (
magnetOrTorrentUrl: string,
previousVideoFile: VideoFile,
- options: {
- forcePlay?: boolean,
- seek?: number,
- delay?: number
- },
+ options: PlayOptions,
done: Function
) {
console.log('Adding ' + magnetOrTorrentUrl + '.')
const oldTorrent = this.torrent
const torrentOptions = {
- store: (chunkLength, storeOpts) => new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), {
+ store: (chunkLength: number, storeOpts: any) => new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), {
max: 100
})
}
this.flushVideoFile(previousVideoFile)
+ // Update progress bar (just for the UI), do not wait rendering
+ if (options.seek) this.player.currentTime(options.seek)
+
const renderVideoOptions = { autoplay: false, controls: true }
renderVideo(torrent.files[ 0 ], this.playerElement, renderVideoOptions, (err, renderer) => {
this.renderer = renderer
- console.log('value this.playerRefusedP2P', this.playerRefusedP2P)
- if (err || this.playerRefusedP2P) return this.fallbackToHttp(done)
+ if (err) return this.fallbackToHttp(options, done)
return this.tryToPlay(err => {
if (err) return done(err)
if (options.seek) this.seek(options.seek)
if (options.forcePlay === false && paused === true) this.player.pause()
- return done(err)
+ return done()
})
})
}, options.delay || 0)
})
- this.torrent.on('error', err => console.error(err))
+ this.torrent.on('error', (err: any) => console.error(err))
this.torrent.on('warning', (err: any) => {
// We don't support HTTP tracker but we don't care -> we use the web socket tracker
})
}
- private tryToPlay (done?: Function) {
+ private tryToPlay (done?: (err?: Error) => void) {
if (!done) done = function () { /* empty */ }
const playPromise = this.player.play()
if (playPromise !== undefined) {
return playPromise.then(done)
- .catch(err => {
+ .catch((err: Error) => {
if (err.message.indexOf('The play() request was interrupted by a call to pause()') !== -1) {
return
}
return this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime })
}
- // Don't try on iOS that does not support MediaSource
- if (this.isIOS()) {
- this.currentVideoFile = this.pickAverageVideoFile()
- return this.fallbackToHttp(undefined, false)
- }
-
// Proxy first play
const oldPlay = this.player.play.bind(this.player)
this.player.play = () => {
return fetch(url, { method: 'PUT', body, headers })
}
- private fallbackToHttp (done?: Function, play = true) {
+ private fallbackToHttp (options: PlayOptions, done?: Function) {
+ const paused = this.player.paused()
+
this.disableAutoResolution(true)
this.flushVideoFile(this.currentVideoFile, true)
const httpUrl = this.currentVideoFile.fileUrl
this.player.src = this.savePlayerSrcFunction
this.player.src(httpUrl)
- if (play) this.tryToPlay()
- if (done) return done()
+ return this.tryToPlay(err => {
+ if (err && done) return done(err)
+
+ if (options.seek) this.seek(options.seek)
+ if (options.forcePlay === false && paused === true) this.player.pause()
+
+ if (done) return done()
+ })
}
private handleError (err: Error | string) {
this.player.options_.inactivityTimeout = saveInactivityTimeout
}
- const settingsDialog = this.player.children_.find(c => c.name_ === 'SettingsDialog')
+ const settingsDialog = this.player.children_.find((c: any) => c.name_ === 'SettingsDialog')
this.player.controlBar.on('mouseenter', () => disableInactivity())
settingsDialog.on('mouseenter', () => disableInactivity())
const percent = time / this.player_.duration()
return percent >= 1 ? 1 : percent
}
- SeekBar.prototype.handleMouseMove = function handleMouseMove (event) {
+ SeekBar.prototype.handleMouseMove = function handleMouseMove (event: any) {
let newTime = this.calculateDistance(event) * this.player_.duration()
if (newTime === this.player_.duration()) {
newTime = newTime - 0.1