2019-07-27 04:59:14 +08:00
|
|
|
import loadScript from 'load-script';
|
|
|
|
import React, { Component } from 'react'
|
|
|
|
|
|
|
|
const MATCH_URL = new RegExp("https?:\/\/(\\w+)\.(instructuremedia.com)(\/embed)?\/([-abcdef0-9]+)");
|
|
|
|
|
2019-08-27 03:50:59 +08:00
|
|
|
const SDK_URL = 'https://files.instructuremedia.com/instructure-media-script/instructure-media-1.1.0.js';
|
2019-07-27 04:59:14 +08:00
|
|
|
|
|
|
|
const EMBED_PATH = "/embed/";
|
|
|
|
|
2019-08-27 03:50:59 +08:00
|
|
|
// 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
|
2019-09-11 02:04:42 +08:00
|
|
|
const resolves = {};
|
2019-07-27 04:59:14 +08:00
|
|
|
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]) {
|
2019-09-11 02:04:42 +08:00
|
|
|
resolves[url].push(resolve);
|
2019-07-27 04:59:14 +08:00
|
|
|
return
|
|
|
|
}
|
2019-09-11 02:04:42 +08:00
|
|
|
resolves[url] = [resolve];
|
2019-07-27 04:59:14 +08:00
|
|
|
const onLoaded = sdk => {
|
|
|
|
// When loaded, resolve all pending promises
|
|
|
|
resolves[url].forEach(resolve => resolve(sdk))
|
2019-09-11 02:04:42 +08:00
|
|
|
};
|
2019-07-27 04:59:14 +08:00
|
|
|
if (sdkReady) {
|
2019-09-11 02:04:42 +08:00
|
|
|
const previousOnReady = window[sdkReady];
|
2019-07-27 04:59:14 +08:00
|
|
|
window[sdkReady] = function () {
|
2019-09-11 02:04:42 +08:00
|
|
|
if (previousOnReady) previousOnReady();
|
2019-07-27 04:59:14 +08:00
|
|
|
onLoaded(window[sdkGlobal])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fetchScript(url, err => {
|
2019-08-27 03:50:59 +08:00
|
|
|
if (err) {
|
|
|
|
reject(err);
|
|
|
|
}
|
|
|
|
window[sdkGlobal] = url;
|
2019-07-27 04:59:14 +08:00
|
|
|
if (!sdkReady) {
|
|
|
|
onLoaded(window[sdkGlobal])
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
export class ArcPlayer extends Component {
|
2019-09-11 02:04:42 +08:00
|
|
|
static displayName = 'ArcPlayer';
|
2019-07-27 04:59:14 +08:00
|
|
|
|
|
|
|
static canPlay = url => {
|
|
|
|
return MATCH_URL.test(url)
|
2019-09-11 02:04:42 +08:00
|
|
|
};
|
2019-07-27 04:59:14 +08:00
|
|
|
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
|
|
|
this.currentTime = 0;
|
|
|
|
this.updateCurrentTime = this.updateCurrentTime.bind(this);
|
|
|
|
this.getCurrentTime = this.getCurrentTime.bind(this);
|
|
|
|
this.getEmbedUrl = this.getEmbedUrl.bind(this);
|
|
|
|
this.onStateChange = this.onStateChange.bind(this);
|
|
|
|
}
|
|
|
|
|
2020-06-02 02:35:34 +08:00
|
|
|
componentDidMount () {
|
|
|
|
this.props.onMount && this.props.onMount(this)
|
|
|
|
}
|
|
|
|
|
2019-07-27 04:59:14 +08:00
|
|
|
load() {
|
|
|
|
new Promise((resolve, reject) => {
|
|
|
|
this.render();
|
|
|
|
resolve();
|
|
|
|
})
|
|
|
|
.then(() => { return getSDK(SDK_URL, 'ArcPlayer') })
|
|
|
|
.then(() => {
|
|
|
|
this.player = new InstructureMedia.Player('arcPlayerContainer', {
|
|
|
|
height: '100%',
|
|
|
|
width: '100%',
|
|
|
|
embedUrl: this.getEmbedUrl(),
|
|
|
|
events: {
|
|
|
|
onStateChange: this.onStateChange,
|
|
|
|
}
|
|
|
|
});
|
2019-08-27 03:50:59 +08:00
|
|
|
this.player.playVideo();
|
2019-07-27 04:59:14 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onStateChange(event) {
|
2019-10-04 04:27:39 +08:00
|
|
|
if (!this.player) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-27 03:50:59 +08:00
|
|
|
this.player.getCurrentTime().then((t) => {
|
|
|
|
this.updateCurrentTime(t.data);
|
|
|
|
});
|
2019-07-27 04:59:14 +08:00
|
|
|
|
|
|
|
if (event.data === "CUED") {
|
|
|
|
this.props.onReady();
|
|
|
|
} else if (event.data === "PLAYING") {
|
|
|
|
this.props.onPlay && this.props.onPlay();
|
|
|
|
} else if (event.data === "PAUSED") {
|
|
|
|
this.props.onPause && this.props.onPause();
|
2019-08-27 03:50:59 +08:00
|
|
|
} else if (event.data === "SEEKED") {
|
|
|
|
// TODO
|
2019-07-27 04:59:14 +08:00
|
|
|
} else if (event.data === "SEEKING") {
|
2019-08-27 03:50:59 +08:00
|
|
|
// TODO
|
2019-07-27 04:59:14 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateCurrentTime(e) {
|
|
|
|
this.currentTime = e;
|
|
|
|
}
|
|
|
|
|
|
|
|
getVideoId() {
|
|
|
|
const { url } = this.props;
|
|
|
|
const m = url.match(MATCH_URL);
|
|
|
|
return m && m[4];
|
|
|
|
}
|
|
|
|
|
|
|
|
getHostUrl() {
|
|
|
|
const { url } = this.props;
|
|
|
|
const m = url.match(MATCH_URL);
|
|
|
|
return m && 'https://' + m[1] + '.' + m[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
getEmbedUrl() {
|
|
|
|
let url = this.getHostUrl() + EMBED_PATH + this.getVideoId();
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
|
|
|
play() {
|
2019-10-04 04:27:39 +08:00
|
|
|
if (this.player) {
|
|
|
|
this.player.playVideo();
|
|
|
|
}
|
2019-07-27 04:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pause() {
|
2019-10-04 04:27:39 +08:00
|
|
|
if (this.player) {
|
|
|
|
this.player.pauseVideo();
|
|
|
|
}
|
2019-07-27 04:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
stop() {
|
|
|
|
// TODO: STOP
|
|
|
|
}
|
|
|
|
|
|
|
|
seekTo(seconds) {
|
2019-10-04 04:27:39 +08:00
|
|
|
if (this.player) {
|
|
|
|
this.player.seekTo(seconds);
|
|
|
|
}
|
2019-07-27 04:59:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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 () {
|
2019-10-04 04:27:39 +08:00
|
|
|
if (this.player) {
|
|
|
|
this.player.getCurrentTime().then((t) => {
|
|
|
|
this.updateCurrentTime(t.data);
|
|
|
|
});
|
|
|
|
}
|
2019-08-28 03:11:59 +08:00
|
|
|
|
2019-07-27 04:59:14 +08:00
|
|
|
return this.currentTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
getSecondsLoaded () {
|
|
|
|
}
|
|
|
|
|
|
|
|
render () {
|
|
|
|
const style = {
|
|
|
|
width: '100%',
|
|
|
|
height: '100%',
|
|
|
|
overflow: 'hidden',
|
|
|
|
backgroundColor: 'black'
|
2019-09-11 02:04:42 +08:00
|
|
|
};
|
2019-07-27 04:59:14 +08:00
|
|
|
return (
|
|
|
|
<div
|
|
|
|
key={this.props.url}
|
|
|
|
style={style}
|
|
|
|
id={"arcPlayerContainer"}
|
|
|
|
ref={(container) => {
|
|
|
|
this.container = container;
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default ArcPlayer;
|
|
|
|
|