index.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import { debugConsole } from '@/utils/debugging'
  2. let hasHandledAutoplayFailure = false
  3. function enableControls(videoEl, reason) {
  4. debugConsole.log(`Enabling video controls: ${reason}`)
  5. videoEl.setAttribute('controls', '')
  6. }
  7. function setup(videoEl) {
  8. const reducedMotionReduce = window.matchMedia(
  9. '(prefers-reduced-motion: reduce)'
  10. )
  11. if (reducedMotionReduce.matches) {
  12. // TODO: on firefox, if user enters this mode, video can throw error
  13. // in console, if user seeks the control seek bar relatively fast
  14. // AbortError: The fetching process for the media resource was aborted by the user agent at the user's request.
  15. // this is only a problem in firefox (tested in macOS), chrome and safari is fine
  16. enableControls(videoEl, 'reduced motion preference')
  17. return
  18. }
  19. const DELAY_BEFORE_REPLAY = 15 * 1000
  20. // 0.7 will enable the autoplay on the desktop main homepage video for all users
  21. const INTERSECTION_THRESHOLD = 0.7
  22. let videoIsVisible
  23. function handleAutoplayFailure(error) {
  24. // Possible HTMLMediaElement.play() errors
  25. // Only show controls for errors where manual play would work
  26. // NotAllowedError: autoplay blocked by browser/device settings
  27. // AbortError: play attempt interrupted by browser
  28. if (error.name === 'NotAllowedError' || error.name === 'AbortError') {
  29. if (!hasHandledAutoplayFailure) {
  30. hasHandledAutoplayFailure = true
  31. document.querySelectorAll('[data-ol-autoplay-video]').forEach(video => {
  32. enableControls(video, `autoplay blocked (${error.name})`)
  33. })
  34. }
  35. } else {
  36. debugConsole.error('Video playback error:', error)
  37. }
  38. }
  39. videoEl.addEventListener('ended', () => {
  40. setTimeout(() => {
  41. videoEl.currentTime = 0
  42. if (videoIsVisible && !hasHandledAutoplayFailure) {
  43. videoEl.play().catch(handleAutoplayFailure)
  44. }
  45. }, DELAY_BEFORE_REPLAY)
  46. })
  47. const observer = new IntersectionObserver(
  48. function onIntersecting(changes) {
  49. for (const change of changes) {
  50. if (change.isIntersecting) {
  51. videoIsVisible = true
  52. if (
  53. !hasHandledAutoplayFailure &&
  54. videoEl.readyState >= videoEl.HAVE_FUTURE_DATA
  55. ) {
  56. videoEl.play().catch(handleAutoplayFailure)
  57. }
  58. } else {
  59. videoIsVisible = false
  60. // Pause video when it leaves viewport to save resources
  61. if (!videoEl.paused) {
  62. videoEl.pause()
  63. }
  64. }
  65. }
  66. },
  67. {
  68. threshold: INTERSECTION_THRESHOLD,
  69. }
  70. )
  71. observer.observe(videoEl)
  72. }
  73. document.querySelectorAll('[data-ol-autoplay-video]').forEach(setup)