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

// Adapted from https://github.com/lawchihon/videojs-dailymotion
/*global define, dailymotion*/
import videojs from "video.js";

var _isOnMobile = videojs.browser.IS_IOS || videojs.browser.IS_NATIVE_ANDROID;
var Tech = videojs.getTech("Tech");


class Dailymotion extends Tech {
  constructor(options, ready) {
    super(options, ready);

    this.setSrc(this.options_.source);

    // Set the vjs-dailymotion class to the player
    // Parent is not set yet so we have to wait a tick
    setTimeout( () => {
      if (this.el_) {
        this.el_.parentNode.className += " vjs-dailymotion";

        if (_isOnMobile) {
          this.el_.parentNode.className += " vjs-dailymotion-mobile";
        }

        if (Dailymotion.isSdkReady) {
            this.initDMPlayer();
        } else {
          Dailymotion.sdkReadyQueue.push(this);
        }
      }
    });
  };

  _getPlayerParams() {
    var playerParams = {
      autoplay: false,
      mute: false,
      controls: false,
      "enable-playback-controls": false,
      "queue-autoplay-next": false,
      "queue-enable": false,
    };
    // Let the user set any Dailymotion parameter
    // https://developer.dailymotion.com/player/#player-parameters
    // To use Dailymotion controls, you must use dmControls instead

    var params = [
      "api",
      "autoplay",
      "autoplay-mute",
      "id",
      "mute",
      "origin",
      "quality",
      "queue-autoplay-next",
      "queue-enable",
      "sharing-enable",
      "start",
      "subtitles-default",
      "syndication",
      "ui-highlight",
      "ui-logo",
      "ui-start-screen-info",
      "ui-theme",
      "apimode",
      "playlist",
    ];
    var options = this.options_;
    params.forEach(function (param) {
      if (typeof options[param] === "undefined") {
        return;
      }
      playerParams[param] = options[param];
    });

    if (typeof this.options_.dmControls !== "undefined") {
      playerParams.controls = this.options_.dmControls;
    }

    // Overwriting playlist if it is included in url
    if (this.url && typeof this.url.playlist !== "undefined") {
      playerParams.playlist = this.url.playlist;
    }

    // Allow undocumented options to be passed along via customVars
    if (typeof this.options_.customVars !== "undefined") {
      var customVars = this.options_.customVars;
      Object.keys(customVars).forEach(function (key) {
        playerParams[key] = customVars[key];
      });
    }

    return playerParams;
  }

  _getPlayerConfig() {
    var playerConfig = {
      width: "100%",
      height: "100%",
      params: this._getPlayerParams(),
    };

    if (this.url && typeof this.url.video !== "undefined") {
      playerConfig.video = this.url.video;
    } else if (typeof this.options_.video !== "undefined") {
      playerConfig.video = this.options_.video;
    }

    return playerConfig;
  }

  async initDMPlayer() {
    if (this.dmPlayer) {
      return;
    }
    const eventMapping = {
      [dailymotion.events.VIDEO_DURATIONCHANGE]: [ "durationchange" ],
      [dailymotion.events.PLAYER_END]: [ "ended" ],
      [dailymotion.events.PLAYER_ERROR]: [ "error" ],
      [dailymotion.events.PLAYER_VIDEOCHANGE]: [ "loadeddata", "loadedmetadata"],
      [dailymotion.events.VIDEO_PAUSE]: [ "pause" ],
      //[dailymotion.events.VIDEO_PLAY]: [ "loadstart", "play", "playing", "waiting" ],
      [dailymotion.events.VIDEO_PLAY]: [ "loadstart", "play", "playing" ],
      [dailymotion.events.VIDEO_PLAYING]: [ "playing" ],
      [dailymotion.events.VIDEO_TIMECHANGE]: [ "timeupdate" ],
      [dailymotion.events.PLAYER_VOLUMECHANGE]: [ "volumechange", "mute" ],
    };    
    this.dmPlayer = await dailymotion.createPlayer(
      this.options_.techId,
      this._getPlayerConfig()
    );
    this.dmState = await this.getPlayerState();
    //var vm = this;
    this.isApiReady = true;
    this.dmPlayer.enable_playback_controls = false;

    for (const ev in eventMapping) {
      this.dmPlayer.on(ev, (s) => {
        this.dmState = s;
        for (const tev of eventMapping[ev]) {
          this.trigger(tev)
        }
      });
    }
    this.dmPlayer.on(dailymotion.events.PLAYER_ERROR, (s) => {
      vm.trigger("error", s.playerError);
    });
    this.triggerReady();
  }

  autoplay(autoplay) {
    if (typeof autoplay !== "undefined") {
      return this.setAutoplay(autoplay);
    }

    return this.options_.autoplay;
  }

  setAutoplay(val) {
    return (this.options_.autoplay = val);
  }

  buffered() {
    if (!this.dmPlayer || !this.dmPlayer.bufferedTime) {
      return videojs.createTimeRange();
    }

    return videojs.createTimeRange(0, this.dmPlayer.bufferedTime);
  }

  createEl() {
    var div = document.createElement("div");
    div.setAttribute("id", this.options_.techId);
    div.setAttribute(
      "style",
      "width:100%;height:100%;top:0;left:0;position:absolute"
    );
    div.setAttribute("class", "vjs-tech");

    var divWrapper = document.createElement("div");
    divWrapper.appendChild(div);

    if (!_isOnMobile && !this.options_.dmControls) {
      // var divBlocker = document.createElement('div');
      // divBlocker.setAttribute('class', 'vjs-iframe-blocker');
      // divBlocker.setAttribute('style', 'position:absolute;top:0;left:0;width:100%;height:100%');
      //
      // // In case the blocker is still there and we want to pause
      // divBlocker.onclick = function() {
      //   this.pause();
      // }.bind(this);
      //
      // divWrapper.appendChild(divBlocker);
    }

    return divWrapper;
  }

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

  currentTime() {

    return this.dmPlayer && this.dmState && this.dmState.videoTime;
  }

  setCurrentTime(seconds) {
    if (!this.dmPlayer || !this.dmPlayer.seek) {
      return;
    }

    return this.dmPlayer.seek(seconds);
  }

  dispose() {
    if (this.dmPlayer) {
      //Destroy the Dailymotion Player
      this.dmPlayer.destroy(this.options_.techId);
      Tech.prototype.dispose.call(this);
    } else {
      //Dailymotion API hasn't finished loading or the player is already disposed
      var index = Dailymotion.sdkReadyQueue.indexOf(this);
      if (index !== -1) {
        Dailymotion.sdkReadyQueue.splice(index, 1);
      }
    }
    this.dmPlayer = undefined;

    this.el_.parentNode.className = this.el_.parentNode.className
      .replace(" vjs-dailymotion", "")
      .replace(" vjs-dailymotion-mobile", "");
    this.el_.parentNode.removeChild(this.el_);

    // Needs to be called after the Dailymotion player is destroyed,
    // otherwise there will be a undefined reference exception
    Tech.prototype.dispose.call(this);
  }

  duration() {
    return this.dmState ? this.dmState.videoDuration : 0;
  }

  setDuration(seconds) {
  }

  ended() {
  }

  enterFullWindow() {
    if (!this.dmPlayer || !this.dmPlayer.setFullscreen) {
      return;
    }
    return this.dmPlayer.setFullscreen(true);
  }

  error() {
    return this.dmState && this.dmState.playerError;
  }

  exitFullscreen() {
    if (!this.dmPlayer || !this.dmPlayer.setFullscreen) {
      return;
    }
    return this.dmPlayer.setFullscreen(false);
  }

  isFullscreen() {
    return this.dmState && this.dmState.playerPresentationMode === "fullscreen";
  }

  // Not supported by Dailymotion
  language() {
  }

  // Not supported by Dailymotion
  languages() {
  }

  load() {
    if (!this.dmPlayer || !this.dmPlayer.loadContent) {
      return;
    }
    return this.dmPlayer.loadContent(this._getPlayerConfig());
  }

  // Not supported by Dailymotion
  loop() {
  }

  async muted() {
    
    if(!this.dmState) {
      return false;
    }
    return this.dmState.playerIsMuted;
  }

  async setMuted(mute) {
    if (typeof mute === "undefined") {
      const state = await this.getPlayerState();
      mute = state.playerIsMuted ? false : true;
    }

    await this.dmPlayer.setMute(mute);
  }

  networkState() {
  }

  async pause() {
    if (!this.dmPlayer || !this.dmPlayer.pause) {
      return;
    }

    return await this.dmPlayer.pause();
  }

  paused() {
    return this.dmState && this.dmState.playerIsPlaying === false;
  }

  play() {
    if (!this.isApiReady || !this.dmPlayer || !this.dmPlayer.play) {
      return;
    }

    return this.dmPlayer.play();
  }

  // Playback rate is not support by Dailymotion
  playbackRate() {
    return 1;
  }

  // Not supported by Dailymotion
  poster() {
    return undefined;
  }

  // Not supported by Dailymotion
  preload() {
    return undefined;
  }

  // TODO: Confirm if it can be more detail
  readyState() {
    if (!this.dmState || this.dmState.playerError) {
      return 0; //NETWORK_EMPTY
    }

    return 4; //HAVE_ENOUGH_DATA
  }

  remainingTime() {
    return this.dmState && this.dmState.videoDuration - this.dmState.videoTime;
  }

  requestFullscreen() {
    return this.enterFullWindow();
  }

  enterFullScreen() {
    return this.enterFullWindow();
  }

  reset() {
    this.load();
  }

  seekable() {
  }

  seeking() {
  }

  src(source) {
    if (typeof source !== "undefined") {
      return this.setSrc(source);
    }

    return this.source;
  }

  setSrc(source) {
    if (typeof source === "undefined") {
      return;
    }

    this.source = source;
    this.url = Dailymotion.parseUrl(source.src || source);

    // Load the video if sdk is ready
    if (Dailymotion.isSdkReady) {
      this.load();
    }
    return this.source;
  }

  supportsFullScreen() {
    return true;
  }

  async volume() {
    if(!this.dmPlayer ) {
      return 1
    }
    const state = await this.dmPlayer.getState();
    return state.playerVolume;
  }

  setVolume(percentAsDecimal) {
    if (!this.dmPlayer || !this.dmPlayer.setMute || !this.dmPlayer.setVolume) {
      return;
    }

    if (percentAsDecimal > 0) {
      this.dmPlayer.setMute(false);
    } else {
      this.dmPlayer.setMute(true);
    }
    this.dmPlayer.setVolume(percentAsDecimal);
  }

  async getPlayerState() {
    if (!this.dmPlayer) {
      return {};
    }
    return await this.dmPlayer.getState();
  }
};

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

Dailymotion.canPlaySource = function (e) {
  return Dailymotion.canPlayType(e.type);
};

Dailymotion.canPlayType = function (e) {
  return e === "video/dailymotion";
};

Dailymotion.parseUrl = function (url) {
  var result = {};

  var regex = /video\/[^?|^\/]*/;
  var match = url.match(regex);

  if (match && match[0]) {
    result.video = match[0].replace("video/", "");
  }

  var regPlaylist = /playlist(=|\/)[^&]*/;
  match = url.match(regPlaylist);

  if (match && match[0]) {
    result.playlist = match[0].replace(/playlist(=|\/)/, "");
  }

  return result;
};

async function apiLoaded() {
    Dailymotion.isSdkReady = true;

    for (var i = 0; i < Dailymotion.sdkReadyQueue.length; ++i) {
      await Dailymotion.sdkReadyQueue[i].initDMPlayer();
    }
}

function loadScript(src, callback) {
  var loaded = false;
  var tag = document.createElement("script");
  var firstScriptTag = document.getElementsByTagName("script")[0];
  if (!firstScriptTag) {
    // when loaded in jest without jsdom setup it doesn't get any element.
    // In jest it doesn't really make sense to do anything, because no one is watching dailymotion in jest
    return;
  }
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
  tag.onload = function () {
    if (!loaded) {
      loaded = true;
      callback();
    }
  };
  tag.onreadystatechange = function () {
    if (
      !loaded &&
      (this.readyState === "complete" || this.readyState === "loaded")
    ) {
      loaded = true;
      callback();
    }
  };
  tag.src = src;
}

function injectCss() {
  var css = // iframe blocker to catch mouse events
    ".vjs-dailymotion .vjs-iframe-blocker { display: none; }" +
    ".vjs-dailymotion.vjs-user-inactive .vjs-iframe-blocker { display: block; }" +
    ".vjs-dailymotion .vjs-poster { background-size: cover; }" +
    ".vjs-dailymotion-mobile .vjs-big-play-button { display: none; }";

  var head = document.head || document.getElementsByTagName("head")[0];

  var style = document.createElement("style");
  style.setAttribute("type", "text/css");

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

  head.appendChild(style);
}

Dailymotion.sdkReadyQueue = [];

// x10ckq
Dailymotion.loadLibrary = function(playerId) {

  if (typeof document !== "undefined") {
    loadScript(`https://geo.dailymotion.com/libs/player/${playerId}.js`, () => {
      if (window.dailymotion === undefined) {
        window.dailymotion = { 
          onScriptLoaded: apiLoaded
        }
      } else {
        apiLoaded();
      }  
    });
    injectCss();
  }  
}

videojs.registerTech("Dailymotion", Dailymotion);

export default Dailymotion;