From 7c704c78c14e77618d486308cb2d690d31e5a38a Mon Sep 17 00:00:00 2001
From: Lucas Zawacki <lfzawacki@gmail.com>
Date: Thu, 26 Nov 2020 17:30:37 -0300
Subject: [PATCH] PeerTube player, first version

---
 .../external-video-player/component.jsx       |   5 +
 .../custom-players/peertube.jsx               | 211 ++++++++++++++++++
 2 files changed, 216 insertions(+)
 create mode 100644 bigbluebutton-html5/imports/ui/components/external-video-player/custom-players/peertube.jsx

diff --git a/bigbluebutton-html5/imports/ui/components/external-video-player/component.jsx b/bigbluebutton-html5/imports/ui/components/external-video-player/component.jsx
index f77e40abde..49b61df680 100644
--- a/bigbluebutton-html5/imports/ui/components/external-video-player/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/external-video-player/component.jsx
@@ -6,6 +6,7 @@ import { sendMessage, onMessage, removeAllListeners } from './service';
 import logger from '/imports/startup/client/logger';
 
 import ArcPlayer from './custom-players/arc-player';
+import PeerTubePlayer from './custom-players/peertube';
 
 import { styles } from './styles';
 
@@ -20,6 +21,7 @@ const SYNC_INTERVAL_SECONDS = 5;
 const THROTTLE_INTERVAL_SECONDS = 0.5;
 const AUTO_PLAY_BLOCK_DETECTION_TIMEOUT_SECONDS = 5;
 
+ReactPlayer.addCustomPlayer(PeerTubePlayer);
 ReactPlayer.addCustomPlayer(ArcPlayer);
 
 class VideoPlayer extends Component {
@@ -75,6 +77,9 @@ class VideoPlayer extends Component {
           controls: isPresenter ? 1 : 2,
         },
       },
+      peertube: {
+        isPresenter,
+      },
       twitch: {
         options: {
           controls: true,
diff --git a/bigbluebutton-html5/imports/ui/components/external-video-player/custom-players/peertube.jsx b/bigbluebutton-html5/imports/ui/components/external-video-player/custom-players/peertube.jsx
new file mode 100644
index 0000000000..ea0c0d88a2
--- /dev/null
+++ b/bigbluebutton-html5/imports/ui/components/external-video-player/custom-players/peertube.jsx
@@ -0,0 +1,211 @@
+import loadScript from 'load-script';
+import React, { Component } from 'react'
+
+const MATCH_URL = new RegExp("(https?)://(.*)/videos/watch/(.*)");
+
+const SDK_URL = 'https://unpkg.com/@peertube/embed-api/build/player.min.js';
+
+// Util function to load an external SDK or return the SDK if it is already loaded
+// From https://github.com/CookPete/react-player/blob/master/src/utils.js
+const resolves = {};
+export function getSDK (url, sdkGlobal, sdkReady = null, isLoaded = () => true, fetchScript = loadScript) {
+  if (window[sdkGlobal] && isLoaded(window[sdkGlobal])) {
+    return Promise.resolve(window[sdkGlobal])
+  }
+  return new Promise((resolve, reject) => {
+    // If we are already loading the SDK, add the resolve
+    // function to the existing array of resolve functions
+    if (resolves[url]) {
+      resolves[url].push(resolve);
+      return
+    }
+    resolves[url] = [resolve];
+    const onLoaded = sdk => {
+      // When loaded, resolve all pending promises
+      resolves[url].forEach(resolve => resolve(sdk))
+    };
+    if (sdkReady) {
+      const previousOnReady = window[sdkReady];
+      window[sdkReady] = function () {
+        if (previousOnReady) previousOnReady();
+        onLoaded(window[sdkGlobal])
+      }
+    }
+    fetchScript(url, err => {
+      if (err) {
+        reject(err);
+      }
+      window[sdkGlobal] = url;
+      if (!sdkReady) {
+        onLoaded(window[sdkGlobal])
+      }
+    })
+  })
+}
+
+export class PeerTubePlayer extends Component {
+  static displayName = 'PeerTubePlayer';
+
+  static canPlay = url => {
+    return MATCH_URL.test(url)
+  };
+
+  constructor(props) {
+    super(props);
+
+    this.player = this;
+    this._player = null;
+
+    this.currentTime = 0;
+    this.playbackRate = 1;
+    this.getCurrentTime = this.getCurrentTime.bind(this);
+    this.getEmbedUrl = this.getEmbedUrl.bind(this);
+    this.setupEvents = this.setupEvents.bind(this);
+  }
+
+  componentDidMount () {
+    this.props.onMount && this.props.onMount(this)
+  }
+
+  getEmbedUrl = () => {
+    const { config, url } = this.props;
+    const m = MATCH_URL.exec(url);
+
+    const isPresenter = config && config.peertube && config.peertube.isPresenter;
+
+    return `${m[1]}://${m[2]}/videos/embed/${m[3]}?api=1&controls=${true}`;
+  };
+
+  load() {
+    new Promise((resolve, reject) => {
+      this.render();
+      resolve();
+    })
+    .then(() => { return getSDK(SDK_URL, 'PeerTube') })
+    .then(() => {
+      this._player = new window['PeerTubePlayer'](this.container);
+
+      this.setupEvents();
+
+      return this._player.ready.then(() => {
+        return this.props.onReady();
+      });
+    });
+  }
+
+  setupEvents(event) {
+    const player = this._player;
+
+    if (!player) {
+      return;
+    }
+
+    player.addEventListener("playbackStatusUpdate", (data) => {
+      this.currentTime = data.position;
+    });
+    player.addEventListener("playbackStatusChange", (data) => {
+      if (data === 'playing') {
+        this.props.onPlay();
+      } else {
+        this.props.onPause();
+      }
+    });
+
+  }
+
+  play() {
+    if (this._player) {
+      this._player.play();
+    }
+  }
+
+  pause() {
+    if (this._player) {
+      this._player.pause();
+    }
+  }
+
+  stop() {
+  }
+
+  seekTo(seconds) {
+    if (this._player) {
+      this._player.seek(seconds);
+    }
+  }
+
+  setVolume(fraction) {
+    // console.log("SET VOLUME");
+  }
+
+  setLoop(loop) {
+    // console.log("SET LOOP");
+  }
+
+  mute() {
+    // console.log("SET MUTE");
+  }
+
+  unmute() {
+    // console.log("SET UNMUTE");
+  }
+
+  getDuration() {
+    //console.log("GET DURATION");
+  }
+
+  getCurrentTime () {
+    return this.currentTime;
+  }
+
+  getSecondsLoaded () {
+  }
+
+  getPlaybackRate () {
+
+    if (this._player) {
+      this._player.getPlaybackRate().then((rate) => {
+        this.playbackRate = rate;
+      });
+    }
+
+    return this.playbackRate;
+  }
+
+  setPlaybackRate (rate) {
+
+    if (this._player) {
+      this._player.setPlaybackRate(rate);
+    }
+  }
+
+  render () {
+    const style = {
+      width: '100%',
+      height: '100%',
+      margin: 0,
+      padding: 0,
+      border: 0,
+      overflow: 'hidden',
+    };
+    const { url } = this.props;
+
+    return (
+      <iframe
+        key={url}
+        style={style}
+        src={this.getEmbedUrl(url)}
+        id={"peerTubeContainer"}
+        allow="autoplay; fullscreen"
+        sandbox="allow-same-origin allow-scripts allow-popups"
+        ref={(container) => {
+          this.container = container;
+        }}
+      >
+      </iframe>
+    )
+  }
+}
+
+export default PeerTubePlayer;
+
-- 
GitLab