src/widgets/videojs_plugins/Vimeo.js
author ymh <ymh.work@gmail.com>
Tue, 22 Oct 2024 09:54:34 +0200
changeset 1080 2b513bcb710a
parent 1073 687133dc13cf
permissions -rw-r--r--
increment version

import videojs from 'video.js';
import VimeoPlayer from '@vimeo/player';

let cssInjected = false;

// Since the iframe can't be touched using Vimeo's way of embedding,
// let's add a new styling rule to have the same style as `vjs-tech`
function injectCss() {
  if (cssInjected) {
    return;
  }
  cssInjected = true;
  const css = `
    .vjs-vimeo iframe {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
    }
  `;
  const head = document.head || document.getElementsByTagName('head')[0];

  const style = document.createElement('style');

  style.type = 'text/css';

  if (style.styleSheet) {
    style.styleSheet.cssText = css;
  } else {
    style.appendChild(document.createTextNode(css));
  }

  head.appendChild(style);
}

const Tech = videojs.getTech('Tech');

/**
 * Vimeo - Wrapper for Video Player API
 *
 * @param {Object=} options Object of option names and values
 * @param {Function=} ready Ready callback function
 * @extends Tech
 * @class Vimeo
 */
class Vimeo extends Tech {
  constructor(options, ready) {
    super(options, ready);
    injectCss();
    this.setPoster(options.poster);
    this.initVimeoPlayer();
  }

  initVimeoPlayer() {
    const options = this.options({});
    const vimeoOptions = {
      url: this.options_.source.src,
      byline: false,
      portrait: false,
      title: false,
      controls: false,
    };

    if (this.options_.autoplay) {
      vimeoOptions.autoplay = true;
    }
    if (typeof(this.options_.controls) != "undefined") {
      vimeoOptions.controls = this.options_.controls;
    }

    if (this.options_.height) {
      vimeoOptions.height = this.options_.height;
    }
    if (this.options_.width) {
      vimeoOptions.width = this.options_.width;
    }
    if (this.options_.maxheight) {
      vimeoOptions.maxheight = this.options_.maxheight;
    }
    if (this.options_.maxwidth) {
      vimeoOptions.maxwidth = this.options_.maxwidth;
    }
    if (this.options_.loop) {
      vimeoOptions.loop = this.options_.loop;
    }
    if (this.options_.color) {
      vimeoOptions.color = this.options_.color.replace(/^#/, '');
    }
    vimeoOptions.controls = false;


    this._player = new VimeoPlayer(this.el(), vimeoOptions);
    this.initVimeoState();

    ['play', 'pause', 'ended', 'timeupdate', 'progress', 'seeked'].forEach(e => {
      this._player.on(e, (progress) => {
        if (this._vimeoState.progress.duration !== progress.duration) {
          this.trigger('durationchange');
        }
        this._vimeoState.progress = progress;
        this.trigger(e);
      });
    });

    this._player.on('pause', () => (this._vimeoState.playing = false));
    this._player.on('play', () => {
      this._vimeoState.playing = true;
      this._vimeoState.ended = false;
    });
    this._player.on('ended', () => {
      this._vimeoState.playing = false;
      this._vimeoState.ended = true;
    });
    this._player.on('volumechange', (v) => (this._vimeoState.volume = v));
    this._player.on('error', e => this.trigger('error', e));

    this.triggerReady();
  }

  initVimeoState() {
    const state = this._vimeoState = {
      ended: false,
      playing: false,
      volume: 0,
      progress: {
        seconds: 0,
        percent: 0,
        duration: 0
      }
    };

    this._player.getCurrentTime().then(time => (state.progress.seconds = time));
    this._player.getDuration().then(time => (state.progress.duration = time));
    this._player.getPaused().then(paused => (state.playing = !paused));
    this._player.getVolume().then(volume => (state.volume = volume));
  }

  createEl() {
    const div = videojs.dom.createEl('div', {
      id: this.options_.techId
    });

    div.style.cssText = 'width:100%;height:100%;top:0;left:0;position:absolute';
    div.className = 'vjs-vimeo';

    return div;
  }

  controls() {
    return true;
  }

  supportsFullScreen() {
    return true;
  }

  src() {
    return this.options_.source;
  }

  currentSrc() {
    return this.options_.source.src;
  }

  currentTime() {
    return this._vimeoState.progress.seconds;
  }

  setCurrentTime(time) {
    this._player.setCurrentTime(time);
  }

  volume() {
    return this._vimeoState.volume;
  }

  setVolume(volume) {
    return this._player.setVolume(volume);
  }

  duration() {
    return this._vimeoState.progress.duration;
  }

  buffered() {
    const progress = this._vimeoState.progress;

    return videojs.createTimeRange(0, progress.percent * progress.duration);
  }

  paused() {
    return !this._vimeoState.playing;
  }

  pause() {
    this._player.pause();
  }

  play() {
    this._player.play();
  }

  muted() {
    return this._vimeoState.volume === 0;
  }

  setMuted(muted) {
    return this._player.setMuted(muted);
  }

  ended() {
    return this._vimeoState.ended;
  }

  playbackRate() {
    return 1;
  }

}

Vimeo.prototype.featuresTimeupdateEvents = true;

Vimeo.isSupported = function () {
  return true;
};

// Add Source Handler pattern functions to this tech
Tech.withSourceHandlers(Vimeo);

Vimeo.nativeSourceHandler = {
};

/**
 * Check if Vimeo can play the given videotype
 *
 * @param  {string} source    The mimetype to check
 * @return {string}         'maybe', or '' (empty string)
 */
Vimeo.nativeSourceHandler.canPlayType = function (source) {
  if (source === 'video/vimeo') {
    return 'maybe';
  }

  return '';
};

/*
 * Check Vimeo can handle the source natively
 *
 * @param  {Object} source  The source object
 * @return {String}         'maybe', or '' (empty string)
 * @note: Copied over from YouTube — not sure this is relevant
 */
Vimeo.nativeSourceHandler.canHandleSource = function (source) {
  if (source.type) {
    return Vimeo.nativeSourceHandler.canPlayType(source.type);
  } else if (source.src) {
    return Vimeo.nativeSourceHandler.canPlayType(source.src);
  }

  return '';
};

// @note: Copied over from YouTube — not sure this is relevant
Vimeo.nativeSourceHandler.handleSource = function (source, tech) {
  tech.src(source.src);
};

// @note: Copied over from YouTube — not sure this is relevant
Vimeo.nativeSourceHandler.dispose = function () { };

Vimeo.registerSourceHandler(Vimeo.nativeSourceHandler);

// Older versions of VJS5 doesn't have the registerTech function
if (typeof videojs.registerTech !== 'undefined') {
  videojs.registerTech('Vimeo', Vimeo);
} else {
  videojs.registerComponent('Vimeo', Vimeo);
}

// Include the version number.
Vimeo.VERSION = '0.0.1';

export default Vimeo;