Fix ios player playback/subtitles menu
authorChocobozzz <me@florianbigard.com>
Mon, 17 Sep 2018 13:00:46 +0000 (15:00 +0200)
committerChocobozzz <me@florianbigard.com>
Mon, 17 Sep 2018 13:01:04 +0000 (15:01 +0200)
client/src/assets/player/peertube-videojs-plugin.ts
client/src/assets/player/settings-menu-item.ts
client/src/sass/application.scss
client/src/sass/player/index.scss [new file with mode: 0644]
client/src/sass/player/peertube-skin.scss
client/src/sass/player/player.scss [deleted file]
client/src/standalone/videos/embed.scss
package.json

index 4b0677faba6dc43f9a85e8e22277371bf919c7a5..36b80bd72b543b636cd54f99931552e8cf13de02 100644 (file)
@@ -4,7 +4,7 @@ import { VideoFile } from '../../../../shared/models/videos/video.model'
 import { renderVideo } from './video-renderer'
 import './settings-menu-button'
 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 { PeertubeChunkStore } from './peertube-chunk-store'
 import {
@@ -83,11 +83,6 @@ class PeerTubePlugin extends Plugin {
     this.videoCaptions = options.videoCaptions
 
     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
 
     if (this.autoplay === true) this.player.addClass('vjs-has-autoplay')
@@ -104,9 +99,7 @@ class PeerTubePlugin extends Plugin {
 
       this.player.one('play', () => {
         // Don't run immediately scheduler, wait some seconds the TCP connections are made
-        this.runAutoQualitySchedulerTimer = setTimeout(() => {
-          this.runAutoQualityScheduler()
-        }, this.CONSTANTS.AUTO_QUALITY_SCHEDULER)
+        this.runAutoQualitySchedulerTimer = setTimeout(() => 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
     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
     const oldPlaybackRate = this.player.playbackRate()
 
@@ -181,7 +177,66 @@ class PeerTubePlugin extends Plugin {
     this.trigger('videoFileUpdate')
   }
 
-  addTorrent (
+  updateResolution (resolutionId: number, delay = 0) {
+    // Remember player state
+    const currentTime = this.player.currentTime()
+    const isPaused = this.player.paused()
+
+    // Remove poster to have black background
+    this.playerElement.poster = ''
+
+    // Hide bigPlayButton
+    if (!isPaused) {
+      this.player.bigPlayButton.hide()
+    }
+
+    const newVideoFile = this.videoFiles.find(f => f.resolution.id === resolutionId)
+    const options = {
+      forcePlay: false,
+      delay,
+      seek: currentTime + (delay / 1000)
+    }
+    this.updateVideoFile(newVideoFile, options)
+  }
+
+  flushVideoFile (videoFile: VideoFile, destroyRenderer = true) {
+    if (videoFile !== undefined && this.webtorrent.get(videoFile.magnetUri)) {
+      if (destroyRenderer === true && this.renderer && this.renderer.destroy) this.renderer.destroy()
+
+      this.webtorrent.remove(videoFile.magnetUri)
+      console.log('Removed ' + videoFile.magnetUri)
+    }
+  }
+
+  isAutoResolutionOn () {
+    return this.autoResolution
+  }
+
+  enableAutoResolution () {
+    this.autoResolution = true
+    this.trigger('autoResolutionUpdate')
+  }
+
+  disableAutoResolution (forbid = false) {
+    if (forbid === true) this.forbidAutoResolution = true
+
+    this.autoResolution = false
+    this.trigger('autoResolutionUpdate')
+  }
+
+  isAutoResolutionForbidden () {
+    return this.forbidAutoResolution === true
+  }
+
+  getCurrentVideoFile () {
+    return this.currentVideoFile
+  }
+
+  getTorrent () {
+    return this.torrent
+  }
+
+  private addTorrent (
     magnetOrTorrentUrl: string,
     previousVideoFile: VideoFile,
     options: {
@@ -205,26 +260,15 @@ class PeerTubePlugin extends Plugin {
 
       if (oldTorrent) {
         // Pause the old torrent
-        oldTorrent.pause()
-        // Pause does not remove actual peers (in particular the webseed peer)
-        oldTorrent.removePeer(oldTorrent['ws'])
+        this.stopTorrent(oldTorrent)
 
         // 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)
-          })
-        }
+        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()
@@ -232,7 +276,7 @@ class PeerTubePlugin extends Plugin {
         this.flushVideoFile(previousVideoFile)
 
         const renderVideoOptions = { autoplay: false, controls: true }
-        renderVideo(torrent.files[0], this.playerElement, renderVideoOptions,(err, renderer) => {
+        renderVideo(torrent.files[ 0 ], this.playerElement, renderVideoOptions, (err, renderer) => {
           this.renderer = renderer
 
           if (err) return this.fallbackToHttp(done)
@@ -265,7 +309,7 @@ class PeerTubePlugin extends Plugin {
       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)
+        return this.addTorrent(this.torrent[ 'xs' ], previousVideoFile, newOptions, done)
       }
 
       // Remote instance is down
@@ -277,65 +321,6 @@ class PeerTubePlugin extends Plugin {
     })
   }
 
-  updateResolution (resolutionId: number, delay = 0) {
-    // Remember player state
-    const currentTime = this.player.currentTime()
-    const isPaused = this.player.paused()
-
-    // Remove poster to have black background
-    this.playerElement.poster = ''
-
-    // Hide bigPlayButton
-    if (!isPaused) {
-      this.player.bigPlayButton.hide()
-    }
-
-    const newVideoFile = this.videoFiles.find(f => f.resolution.id === resolutionId)
-    const options = {
-      forcePlay: false,
-      delay,
-      seek: currentTime + (delay / 1000)
-    }
-    this.updateVideoFile(newVideoFile, options)
-  }
-
-  flushVideoFile (videoFile: VideoFile, destroyRenderer = true) {
-    if (videoFile !== undefined && this.webtorrent.get(videoFile.magnetUri)) {
-      if (destroyRenderer === true && this.renderer && this.renderer.destroy) this.renderer.destroy()
-
-      this.webtorrent.remove(videoFile.magnetUri)
-      console.log('Removed ' + videoFile.magnetUri)
-    }
-  }
-
-  isAutoResolutionOn () {
-    return this.autoResolution
-  }
-
-  enableAutoResolution () {
-    this.autoResolution = true
-    this.trigger('autoResolutionUpdate')
-  }
-
-  disableAutoResolution (forbid = false) {
-    if (forbid === true) this.forbidAutoResolution = true
-
-    this.autoResolution = false
-    this.trigger('autoResolutionUpdate')
-  }
-
-  isAutoResolutionForbidden () {
-    return this.forbidAutoResolution === true
-  }
-
-  getCurrentVideoFile () {
-    return this.currentVideoFile
-  }
-
-  getTorrent () {
-    return this.torrent
-  }
-
   private tryToPlay (done?: Function) {
     if (!done) done = function () { /* empty */ }
 
@@ -435,22 +420,22 @@ class PeerTubePlugin extends Plugin {
     if (this.autoplay === true) {
       this.player.posterImage.hide()
 
-      this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime })
-    } else {
-      // Don't try on iOS that does not support MediaSource
-      if (this.isIOS()) {
-        this.currentVideoFile = this.pickAverageVideoFile()
-        return this.fallbackToHttp(undefined, false)
-      }
+      return this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime })
+    }
 
-      // Proxy first play
-      const oldPlay = this.player.play.bind(this.player)
-      this.player.play = () => {
-        this.player.addClass('vjs-has-big-play-button-clicked')
-        this.player.play = oldPlay
+    // Don't try on iOS that does not support MediaSource
+    if (this.isIOS()) {
+      this.currentVideoFile = this.pickAverageVideoFile()
+      return this.fallbackToHttp(undefined, false)
+    }
 
-        this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime })
-      }
+    // Proxy first play
+    const oldPlay = this.player.play.bind(this.player)
+    this.player.play = () => {
+      this.player.addClass('vjs-has-big-play-button-clicked')
+      this.player.play = oldPlay
+
+      this.updateVideoFile(undefined, { forcePlay: true, seek: this.startTime })
     }
   }
 
@@ -607,6 +592,24 @@ class PeerTubePlugin extends Plugin {
     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 () {
     if (this.fakeRenderer) {
       if (this.fakeRenderer.destroy) {
index 6e2224e20f29f0c2a931876d06070a3c4511d4f8..f6cf6d0f3709833e37112bbc7495e54408d76ef8 100644 (file)
@@ -38,8 +38,11 @@ class SettingsMenuItem extends MenuItem {
     this.eventHandlers()
 
     player.ready(() => {
-      this.build()
-      this.reset()
+      // Voodoo magic for IOS
+      setTimeout(() => {
+        this.build()
+        this.reset()
+      }, 0)
     })
   }
 
index 8d2bfb0776353154b343beab3c9afe7fab459d89..c1135cd023ec1e46fcae008712997dc7aacf6e7e 100644 (file)
@@ -9,7 +9,7 @@ $icon-font-path: '../../node_modules/@neos21/bootstrap3-glyphicons/assets/fonts/
 @import '~video.js/dist/video-js.css';
 
 $assets-path: '../assets/';
-@import './player/player';
+@import './player/index';
 @import './loading-bar';
 
 @import './primeng-custom';
diff --git a/client/src/sass/player/index.scss b/client/src/sass/player/index.scss
new file mode 100644 (file)
index 0000000..e4a315d
--- /dev/null
@@ -0,0 +1,5 @@
+@import './peertube-skin';
+@import './mobile';
+@import './context-menu';
+@import './settings-menu';
+@import './spinner';
\ No newline at end of file
index 185b002223cdf395675cb670e7430db373bcf60a..4e921e9709378f1f92ba862d081d10d6e6a968d9 100644 (file)
 
       width: 37px;
       margin-right: 1px;
+      cursor: pointer;
 
       .vjs-icon-placeholder {
         transition: transform 0.2s ease;
       }
     }
 
-    .vjs-playback-rate {
-      display: none;
-    }
-
     .vjs-peertube {
       padding: 0 !important;
 
diff --git a/client/src/sass/player/player.scss b/client/src/sass/player/player.scss
deleted file mode 100644 (file)
index e4a315d..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-@import './peertube-skin';
-@import './mobile';
-@import './context-menu';
-@import './settings-menu';
-@import './spinner';
\ No newline at end of file
index 30650538fcf125907495482b530919961bcc9790..c40ea12080a133e6f3e8e20f20e91352e29758c8 100644 (file)
@@ -4,7 +4,7 @@
 @import '~videojs-dock/dist/videojs-dock.css';
 
 $assets-path: '../../assets/';
-@import '../../sass/player/player';
+@import '../../sass/player/index';
 
 [hidden] {
   display: none !important;
index 1cb5be181cf823a73e5b8488c023edbe23549782..53e07a72bbdae5bcbede7481b5192ec9a285d1fc 100644 (file)
@@ -70,7 +70,7 @@
   },
   "lint-staged": {
     "*.scss": [
-      "sass-lint -c .sass-lint.yml",
+      "sass-lint -c client/.sass-lint.yml",
       "git add"
     ]
   },