Fix ios player playback/subtitles menu
This commit is contained in:
parent
c07b604111
commit
b335ccec49
7 changed files with 132 additions and 129 deletions
|
@ -4,7 +4,7 @@ import { VideoFile } from '../../../../shared/models/videos/video.model'
|
||||||
import { renderVideo } from './video-renderer'
|
import { renderVideo } from './video-renderer'
|
||||||
import './settings-menu-button'
|
import './settings-menu-button'
|
||||||
import { PeertubePluginOptions, VideoJSCaption, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
|
import { PeertubePluginOptions, VideoJSCaption, VideoJSComponentInterface, videojsUntyped } from './peertube-videojs-typings'
|
||||||
import { isMobile, videoFileMaxByResolution, videoFileMinByResolution, timeToInt } from './utils'
|
import { isMobile, timeToInt, videoFileMaxByResolution, videoFileMinByResolution } from './utils'
|
||||||
import * as CacheChunkStore from 'cache-chunk-store'
|
import * as CacheChunkStore from 'cache-chunk-store'
|
||||||
import { PeertubeChunkStore } from './peertube-chunk-store'
|
import { PeertubeChunkStore } from './peertube-chunk-store'
|
||||||
import {
|
import {
|
||||||
|
@ -83,11 +83,6 @@ class PeerTubePlugin extends Plugin {
|
||||||
this.videoCaptions = options.videoCaptions
|
this.videoCaptions = options.videoCaptions
|
||||||
|
|
||||||
this.savePlayerSrcFunction = this.player.src
|
this.savePlayerSrcFunction = this.player.src
|
||||||
// Hack to "simulate" src link in video.js >= 6
|
|
||||||
// Without this, we can't play the video after pausing it
|
|
||||||
// https://github.com/videojs/video.js/blob/master/src/js/player.js#L1633
|
|
||||||
this.player.src = () => true
|
|
||||||
|
|
||||||
this.playerElement = options.playerElement
|
this.playerElement = options.playerElement
|
||||||
|
|
||||||
if (this.autoplay === true) this.player.addClass('vjs-has-autoplay')
|
if (this.autoplay === true) this.player.addClass('vjs-has-autoplay')
|
||||||
|
@ -104,9 +99,7 @@ class PeerTubePlugin extends Plugin {
|
||||||
|
|
||||||
this.player.one('play', () => {
|
this.player.one('play', () => {
|
||||||
// Don't run immediately scheduler, wait some seconds the TCP connections are made
|
// Don't run immediately scheduler, wait some seconds the TCP connections are made
|
||||||
this.runAutoQualitySchedulerTimer = setTimeout(() => {
|
this.runAutoQualitySchedulerTimer = setTimeout(() => this.runAutoQualityScheduler(), this.CONSTANTS.AUTO_QUALITY_SCHEDULER)
|
||||||
this.runAutoQualityScheduler()
|
|
||||||
}, this.CONSTANTS.AUTO_QUALITY_SCHEDULER)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -167,6 +160,9 @@ class PeerTubePlugin extends Plugin {
|
||||||
// Do not display error to user because we will have multiple fallback
|
// Do not display error to user because we will have multiple fallback
|
||||||
this.disableErrorDisplay()
|
this.disableErrorDisplay()
|
||||||
|
|
||||||
|
// Hack to "simulate" src link in video.js >= 6
|
||||||
|
// Without this, we can't play the video after pausing it
|
||||||
|
// https://github.com/videojs/video.js/blob/master/src/js/player.js#L1633
|
||||||
this.player.src = () => true
|
this.player.src = () => true
|
||||||
const oldPlaybackRate = this.player.playbackRate()
|
const oldPlaybackRate = this.player.playbackRate()
|
||||||
|
|
||||||
|
@ -181,102 +177,6 @@ class PeerTubePlugin extends Plugin {
|
||||||
this.trigger('videoFileUpdate')
|
this.trigger('videoFileUpdate')
|
||||||
}
|
}
|
||||||
|
|
||||||
addTorrent (
|
|
||||||
magnetOrTorrentUrl: string,
|
|
||||||
previousVideoFile: VideoFile,
|
|
||||||
options: {
|
|
||||||
forcePlay?: boolean,
|
|
||||||
seek?: number,
|
|
||||||
delay?: number
|
|
||||||
},
|
|
||||||
done: Function
|
|
||||||
) {
|
|
||||||
console.log('Adding ' + magnetOrTorrentUrl + '.')
|
|
||||||
|
|
||||||
const oldTorrent = this.torrent
|
|
||||||
const torrentOptions = {
|
|
||||||
store: (chunkLength, storeOpts) => new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), {
|
|
||||||
max: 100
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
this.torrent = this.webtorrent.add(magnetOrTorrentUrl, torrentOptions, torrent => {
|
|
||||||
console.log('Added ' + magnetOrTorrentUrl + '.')
|
|
||||||
|
|
||||||
if (oldTorrent) {
|
|
||||||
// Pause the old torrent
|
|
||||||
oldTorrent.pause()
|
|
||||||
// Pause does not remove actual peers (in particular the webseed peer)
|
|
||||||
oldTorrent.removePeer(oldTorrent['ws'])
|
|
||||||
|
|
||||||
// We use a fake renderer so we download correct pieces of the next file
|
|
||||||
if (options.delay) {
|
|
||||||
const fakeVideoElem = document.createElement('video')
|
|
||||||
renderVideo(torrent.files[0], fakeVideoElem, { autoplay: false, controls: false }, (err, renderer) => {
|
|
||||||
this.fakeRenderer = renderer
|
|
||||||
|
|
||||||
if (err) console.error('Cannot render new torrent in fake video element.', err)
|
|
||||||
|
|
||||||
// Load the future file at the correct time
|
|
||||||
fakeVideoElem.currentTime = this.player.currentTime() + (options.delay / 2000)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render the video in a few seconds? (on resolution change for example, we wait some seconds of the new video resolution)
|
|
||||||
this.addTorrentDelay = setTimeout(() => {
|
|
||||||
this.destroyFakeRenderer()
|
|
||||||
|
|
||||||
const paused = this.player.paused()
|
|
||||||
|
|
||||||
this.flushVideoFile(previousVideoFile)
|
|
||||||
|
|
||||||
const renderVideoOptions = { autoplay: false, controls: true }
|
|
||||||
renderVideo(torrent.files[0], this.playerElement, renderVideoOptions,(err, renderer) => {
|
|
||||||
this.renderer = renderer
|
|
||||||
|
|
||||||
if (err) return this.fallbackToHttp(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)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}, options.delay || 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.torrent.on('error', err => 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
|
|
||||||
if (err.message.indexOf('Unsupported tracker protocol') !== -1) return
|
|
||||||
|
|
||||||
// Users don't care about issues with WebRTC, but developers do so log it in the console
|
|
||||||
if (err.message.indexOf('Ice connection failed') !== -1) {
|
|
||||||
console.log(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Magnet hash is not up to date with the torrent file, add directly the torrent file
|
|
||||||
if (err.message.indexOf('incorrect info hash') !== -1) {
|
|
||||||
console.error('Incorrect info hash detected, falling back to torrent file.')
|
|
||||||
const newOptions = { forcePlay: true, seek: options.seek }
|
|
||||||
return this.addTorrent(this.torrent['xs'], previousVideoFile, newOptions, done)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remote instance is down
|
|
||||||
if (err.message.indexOf('from xs param') !== -1) {
|
|
||||||
this.handleError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.warn(err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
updateResolution (resolutionId: number, delay = 0) {
|
updateResolution (resolutionId: number, delay = 0) {
|
||||||
// Remember player state
|
// Remember player state
|
||||||
const currentTime = this.player.currentTime()
|
const currentTime = this.player.currentTime()
|
||||||
|
@ -336,6 +236,91 @@ class PeerTubePlugin extends Plugin {
|
||||||
return this.torrent
|
return this.torrent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private addTorrent (
|
||||||
|
magnetOrTorrentUrl: string,
|
||||||
|
previousVideoFile: VideoFile,
|
||||||
|
options: {
|
||||||
|
forcePlay?: boolean,
|
||||||
|
seek?: number,
|
||||||
|
delay?: number
|
||||||
|
},
|
||||||
|
done: Function
|
||||||
|
) {
|
||||||
|
console.log('Adding ' + magnetOrTorrentUrl + '.')
|
||||||
|
|
||||||
|
const oldTorrent = this.torrent
|
||||||
|
const torrentOptions = {
|
||||||
|
store: (chunkLength, storeOpts) => new CacheChunkStore(new PeertubeChunkStore(chunkLength, storeOpts), {
|
||||||
|
max: 100
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this.torrent = this.webtorrent.add(magnetOrTorrentUrl, torrentOptions, torrent => {
|
||||||
|
console.log('Added ' + magnetOrTorrentUrl + '.')
|
||||||
|
|
||||||
|
if (oldTorrent) {
|
||||||
|
// Pause the old torrent
|
||||||
|
this.stopTorrent(oldTorrent)
|
||||||
|
|
||||||
|
// We use a fake renderer so we download correct pieces of the next file
|
||||||
|
if (options.delay) this.renderFileInFakeElement(torrent.files[ 0 ], options.delay)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the video in a few seconds? (on resolution change for example, we wait some seconds of the new video resolution)
|
||||||
|
this.addTorrentDelay = setTimeout(() => {
|
||||||
|
// We don't need the fake renderer anymore
|
||||||
|
this.destroyFakeRenderer()
|
||||||
|
|
||||||
|
const paused = this.player.paused()
|
||||||
|
|
||||||
|
this.flushVideoFile(previousVideoFile)
|
||||||
|
|
||||||
|
const renderVideoOptions = { autoplay: false, controls: true }
|
||||||
|
renderVideo(torrent.files[ 0 ], this.playerElement, renderVideoOptions, (err, renderer) => {
|
||||||
|
this.renderer = renderer
|
||||||
|
|
||||||
|
if (err) return this.fallbackToHttp(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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, options.delay || 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.torrent.on('error', err => 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
|
||||||
|
if (err.message.indexOf('Unsupported tracker protocol') !== -1) return
|
||||||
|
|
||||||
|
// Users don't care about issues with WebRTC, but developers do so log it in the console
|
||||||
|
if (err.message.indexOf('Ice connection failed') !== -1) {
|
||||||
|
console.log(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Magnet hash is not up to date with the torrent file, add directly the torrent file
|
||||||
|
if (err.message.indexOf('incorrect info hash') !== -1) {
|
||||||
|
console.error('Incorrect info hash detected, falling back to torrent file.')
|
||||||
|
const newOptions = { forcePlay: true, seek: options.seek }
|
||||||
|
return this.addTorrent(this.torrent[ 'xs' ], previousVideoFile, newOptions, done)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remote instance is down
|
||||||
|
if (err.message.indexOf('from xs param') !== -1) {
|
||||||
|
this.handleError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private tryToPlay (done?: Function) {
|
private tryToPlay (done?: Function) {
|
||||||
if (!done) done = function () { /* empty */ }
|
if (!done) done = function () { /* empty */ }
|
||||||
|
|
||||||
|
@ -435,8 +420,9 @@ class PeerTubePlugin extends Plugin {
|
||||||
if (this.autoplay === true) {
|
if (this.autoplay === true) {
|
||||||
this.player.posterImage.hide()
|
this.player.posterImage.hide()
|
||||||
|
|
||||||
this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime })
|
return this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime })
|
||||||
} else {
|
}
|
||||||
|
|
||||||
// Don't try on iOS that does not support MediaSource
|
// Don't try on iOS that does not support MediaSource
|
||||||
if (this.isIOS()) {
|
if (this.isIOS()) {
|
||||||
this.currentVideoFile = this.pickAverageVideoFile()
|
this.currentVideoFile = this.pickAverageVideoFile()
|
||||||
|
@ -452,7 +438,6 @@ class PeerTubePlugin extends Plugin {
|
||||||
this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime })
|
this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private runAutoQualityScheduler () {
|
private runAutoQualityScheduler () {
|
||||||
this.autoQualityInterval = setInterval(() => {
|
this.autoQualityInterval = setInterval(() => {
|
||||||
|
@ -607,6 +592,24 @@ class PeerTubePlugin extends Plugin {
|
||||||
return this.videoFiles[Math.floor(this.videoFiles.length / 2)]
|
return this.videoFiles[Math.floor(this.videoFiles.length / 2)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private stopTorrent (torrent: WebTorrent.Torrent) {
|
||||||
|
torrent.pause()
|
||||||
|
// Pause does not remove actual peers (in particular the webseed peer)
|
||||||
|
torrent.removePeer(torrent[ 'ws' ])
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderFileInFakeElement (file: WebTorrent.TorrentFile, delay: number) {
|
||||||
|
const fakeVideoElem = document.createElement('video')
|
||||||
|
renderVideo(file, fakeVideoElem, { autoplay: false, controls: false }, (err, renderer) => {
|
||||||
|
this.fakeRenderer = renderer
|
||||||
|
|
||||||
|
if (err) console.error('Cannot render new torrent in fake video element.', err)
|
||||||
|
|
||||||
|
// Load the future file at the correct time (in delay MS - 2 seconds)
|
||||||
|
fakeVideoElem.currentTime = this.player.currentTime() + (delay - 2000)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private destroyFakeRenderer () {
|
private destroyFakeRenderer () {
|
||||||
if (this.fakeRenderer) {
|
if (this.fakeRenderer) {
|
||||||
if (this.fakeRenderer.destroy) {
|
if (this.fakeRenderer.destroy) {
|
||||||
|
|
|
@ -38,8 +38,11 @@ class SettingsMenuItem extends MenuItem {
|
||||||
this.eventHandlers()
|
this.eventHandlers()
|
||||||
|
|
||||||
player.ready(() => {
|
player.ready(() => {
|
||||||
|
// Voodoo magic for IOS
|
||||||
|
setTimeout(() => {
|
||||||
this.build()
|
this.build()
|
||||||
this.reset()
|
this.reset()
|
||||||
|
}, 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ $icon-font-path: '../../node_modules/@neos21/bootstrap3-glyphicons/assets/fonts/
|
||||||
@import '~video.js/dist/video-js.css';
|
@import '~video.js/dist/video-js.css';
|
||||||
|
|
||||||
$assets-path: '../assets/';
|
$assets-path: '../assets/';
|
||||||
@import './player/player';
|
@import './player/index';
|
||||||
@import './loading-bar';
|
@import './loading-bar';
|
||||||
|
|
||||||
@import './primeng-custom';
|
@import './primeng-custom';
|
||||||
|
|
|
@ -406,6 +406,7 @@
|
||||||
|
|
||||||
width: 37px;
|
width: 37px;
|
||||||
margin-right: 1px;
|
margin-right: 1px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
.vjs-icon-placeholder {
|
.vjs-icon-placeholder {
|
||||||
transition: transform 0.2s ease;
|
transition: transform 0.2s ease;
|
||||||
|
@ -504,10 +505,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.vjs-playback-rate {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vjs-peertube {
|
.vjs-peertube {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
@import '~videojs-dock/dist/videojs-dock.css';
|
@import '~videojs-dock/dist/videojs-dock.css';
|
||||||
|
|
||||||
$assets-path: '../../assets/';
|
$assets-path: '../../assets/';
|
||||||
@import '../../sass/player/player';
|
@import '../../sass/player/index';
|
||||||
|
|
||||||
[hidden] {
|
[hidden] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*.scss": [
|
"*.scss": [
|
||||||
"sass-lint -c .sass-lint.yml",
|
"sass-lint -c client/.sass-lint.yml",
|
||||||
"git add"
|
"git add"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue