1
0
Fork 0

Fix ios player playback/subtitles menu

This commit is contained in:
Chocobozzz 2018-09-17 15:00:46 +02:00
parent c07b604111
commit b335ccec49
No known key found for this signature in database
GPG key ID: 583A612D890159BE
7 changed files with 132 additions and 129 deletions

View file

@ -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) {

View file

@ -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)
}) })
} }

View file

@ -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';

View file

@ -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;

View file

@ -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;

View file

@ -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"
] ]
}, },