Federated video streaming platform using ActivityPub and P2P in the web browser with Angular. https://joinpeertube.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

145 lines
4.2 KiB

  1. import { PeerTubeMobileButtons } from './peertube-mobile-buttons'
  2. import videojs from 'video.js'
  3. import debug from 'debug'
  4. const logger = debug('peertube:player:mobile')
  5. const Plugin = videojs.getPlugin('plugin')
  6. class PeerTubeMobilePlugin extends Plugin {
  7. private static readonly DOUBLE_TAP_DELAY_MS = 250
  8. private static readonly SET_CURRENT_TIME_DELAY = 1000
  9. private peerTubeMobileButtons: PeerTubeMobileButtons
  10. private seekAmount = 0
  11. private lastTapEvent: TouchEvent
  12. private tapTimeout: ReturnType<typeof setTimeout>
  13. private newActiveState: boolean
  14. private setCurrentTimeTimeout: ReturnType<typeof setTimeout>
  15. constructor (player: videojs.Player, options: videojs.PlayerOptions) {
  16. super(player, options)
  17. this.peerTubeMobileButtons = player.addChild('PeerTubeMobileButtons') as PeerTubeMobileButtons
  18. if (videojs.browser.IS_ANDROID && screen.orientation) {
  19. this.handleFullscreenRotation()
  20. }
  21. if (!this.player.options_.userActions) this.player.options_.userActions = {};
  22. // FIXME: typings
  23. (this.player.options_.userActions as any).click = false
  24. this.player.options_.userActions.doubleClick = false
  25. this.player.one('play', () => {
  26. this.initTouchStartEvents()
  27. })
  28. }
  29. private handleFullscreenRotation () {
  30. this.player.on('fullscreenchange', () => {
  31. if (!this.player.isFullscreen() || this.isPortraitVideo()) return
  32. screen.orientation.lock('landscape')
  33. .catch(err => console.error('Cannot lock screen to landscape.', err))
  34. })
  35. }
  36. private isPortraitVideo () {
  37. return this.player.videoWidth() < this.player.videoHeight()
  38. }
  39. private initTouchStartEvents () {
  40. this.player.on('touchstart', (event: TouchEvent) => {
  41. event.stopPropagation()
  42. if (this.tapTimeout) {
  43. clearTimeout(this.tapTimeout)
  44. this.tapTimeout = undefined
  45. }
  46. if (this.lastTapEvent && event.timeStamp - this.lastTapEvent.timeStamp < PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS) {
  47. logger('Detected double tap')
  48. this.lastTapEvent = undefined
  49. this.onDoubleTap(event)
  50. return
  51. }
  52. this.newActiveState = !this.player.userActive()
  53. this.tapTimeout = setTimeout(() => {
  54. logger('No double tap detected, set user active state to %s.', this.newActiveState)
  55. this.player.userActive(this.newActiveState)
  56. }, PeerTubeMobilePlugin.DOUBLE_TAP_DELAY_MS)
  57. this.lastTapEvent = event
  58. })
  59. }
  60. private onDoubleTap (event: TouchEvent) {
  61. const playerWidth = this.player.currentWidth()
  62. const rect = this.findPlayerTarget((event.target as HTMLElement)).getBoundingClientRect()
  63. const offsetX = event.targetTouches[0].pageX - rect.left
  64. logger('Calculating double tap zone (player width: %d, offset X: %d)', playerWidth, offsetX)
  65. if (offsetX > 0.66 * playerWidth) {
  66. if (this.seekAmount < 0) this.seekAmount = 0
  67. this.seekAmount += 10
  68. logger('Will forward %d seconds', this.seekAmount)
  69. } else if (offsetX < 0.33 * playerWidth) {
  70. if (this.seekAmount > 0) this.seekAmount = 0
  71. this.seekAmount -= 10
  72. logger('Will rewind %d seconds', this.seekAmount)
  73. }
  74. this.peerTubeMobileButtons.displayFastSeek(this.seekAmount)
  75. this.scheduleSetCurrentTime()
  76. }
  77. private findPlayerTarget (target: HTMLElement): HTMLElement {
  78. if (target.classList.contains('video-js')) return target
  79. return this.findPlayerTarget(target.parentElement)
  80. }
  81. private scheduleSetCurrentTime () {
  82. this.player.pause()
  83. this.player.addClass('vjs-fast-seeking')
  84. if (this.setCurrentTimeTimeout) clearTimeout(this.setCurrentTimeTimeout)
  85. this.setCurrentTimeTimeout = setTimeout(() => {
  86. let newTime = this.player.currentTime() + this.seekAmount
  87. this.seekAmount = 0
  88. newTime = Math.max(0, newTime)
  89. newTime = Math.min(this.player.duration(), newTime)
  90. this.player.currentTime(newTime)
  91. this.seekAmount = 0
  92. this.peerTubeMobileButtons.displayFastSeek(0)
  93. this.player.removeClass('vjs-fast-seeking')
  94. this.player.userActive(false)
  95. this.player.play()
  96. }, PeerTubeMobilePlugin.SET_CURRENT_TIME_DELAY)
  97. }
  98. }
  99. videojs.registerPlugin('peertubeMobile', PeerTubeMobilePlugin)
  100. export { PeerTubeMobilePlugin }