diff --git a/examples/react/src/App.js b/examples/react/src/App.js
index 3ba82719..d218414b 100644
--- a/examples/react/src/App.js
+++ b/examples/react/src/App.js
@@ -356,6 +356,12 @@ class App extends Component {
{this.renderLoadButton('https://cdnapisec.kaltura.com/p/2507381/sp/250738100/embedIframeJs/uiconf_id/44372392/partner_id/2507381?iframeembed=true&playerId=kaltura_player_1605622336&entry_id=1_i1jmzcn3', 'Test B')}
+
Files |
diff --git a/src/patterns.js b/src/patterns.js
index 6f82585b..789b95a6 100644
--- a/src/patterns.js
+++ b/src/patterns.js
@@ -20,6 +20,7 @@ export const VIDEO_EXTENSIONS = /\.(mp4|og[gv]|webm|mov|m4v)(#t=[,\d+]+)?($|\?)/
export const HLS_EXTENSIONS = /\.(m3u8)($|\?)/i
export const DASH_EXTENSIONS = /\.(mpd)($|\?)/i
export const FLV_EXTENSIONS = /\.(flv)($|\?)/i
+export const MATCH_URL_GUMLET = /play.gumlet.io\/embed\/([a-zA-Z0-9_]+)($|\?)/
const canPlayFile = url => {
if (url instanceof Array) {
@@ -63,5 +64,6 @@ export const canPlay = {
mixcloud: url => MATCH_URL_MIXCLOUD.test(url),
vidyard: url => MATCH_URL_VIDYARD.test(url),
kaltura: url => MATCH_URL_KALTURA.test(url),
+ gumlet: url => MATCH_URL_GUMLET.test(url),
file: canPlayFile
}
diff --git a/src/players/Gumlet.js b/src/players/Gumlet.js
new file mode 100644
index 00000000..6986a096
--- /dev/null
+++ b/src/players/Gumlet.js
@@ -0,0 +1,186 @@
+import React, { Component } from 'react'
+
+import { callPlayer, getSDK } from '../utils'
+import { canPlay } from '../patterns'
+
+const SDK_URL = 'https://cdn.jsdelivr.net/npm/@gumlet/player.js@2.0/dist/player.min.js'
+const SDK_GLOBAL = 'playerjs'
+
+export default class Gumlet extends Component {
+ static displayName = 'Gumlet'
+ static canPlay = canPlay.gumlet
+ callPlayer = callPlayer
+ duration = null
+ currentTime = null
+ secondsLoaded = null
+
+ componentDidMount () {
+ this.props.onMount && this.props.onMount(this)
+ }
+
+ load (url) {
+ getSDK(SDK_URL, SDK_GLOBAL).then(playerjs => {
+ if (!this.iframe) return
+ this.player = new playerjs.Player(this.iframe)
+ this.player.on('ready', () => {
+ // An arbitrary timeout is required otherwise
+ // the event listeners won’t work
+ setTimeout(() => {
+ this.player.isReady = true
+ this.player.setLoop(this.props.loop)
+ if (this.props.muted) {
+ this.player.mute()
+ }
+ this.addListeners(this.player, this.props)
+ this.props.onReady()
+ }, 500)
+ })
+ }, this.props.onError)
+ }
+
+ addListeners (player, props) {
+ player.on('play', props.onPlay)
+ player.on('pause', props.onPause)
+ player.on('progress', (e) => {
+ if (this.props.onProgress) this.props.onProgress(e)
+ })
+ player.on('timeupdate', (e) => {
+ if (this.props.onTimeUpdate) this.props.onTimeUpdate(e)
+ })
+ player.on('ended', props.onEnded)
+ player.on('onFullScreenChange', (e) => {
+ props.onFullScreenChange(e)
+ })
+ player.on('onPipChange', (e) => {
+ props.onPipChange(e)
+ })
+ player.on('onAudioChange', (e) => {
+ props.onAudioChange(e)
+ });
+ player.on('onQualityChange', (e) => {
+ props.onQualityChange(e)
+ })
+ player.on('onVolumeChange', (e) => {
+ props.onVolumeChange(e)
+ })
+ player.on('seeked', (e) => {
+ props.onSeeked(e)
+ })
+ player.on('error', (e) => {
+ props.onError(e);
+ })
+ player.on('mute', props.onMute)
+ }
+
+ play () {
+ this.callPlayer('play')
+ }
+
+ pause () {
+ this.callPlayer('pause')
+ }
+
+ mute = () => {
+ this.callPlayer('mute')
+ }
+
+ unmute = () => {
+ this.callPlayer('unmute')
+ }
+
+ setVolume (fraction) {
+ this.callPlayer('setVolume', fraction)
+ }
+
+ seekTo (seconds, keepPlaying = true) {
+ this.callPlayer('setCurrentTime', seconds)
+ if (!keepPlaying) {
+ this.pause()
+ }
+ }
+
+ setPlaybackRate (rate) {
+ this.callPlayer('setPlaybackRate', rate)
+ }
+
+ stop () {
+ // Nothing to do
+ }
+
+ setLoop (loop) {
+ // Nothing to do
+ }
+
+ getPaused () {
+ return new Promise((resolve, reject) => {
+ this.player.getPaused((e)=>{
+ resolve(e);
+ });
+ });
+ }
+
+ getMuted = () => {
+ return new Promise((resolve, reject) => {
+ this.player.getMuted((e)=>{
+ resolve(e);
+ });
+ });
+ };
+
+ getVolume = () => {
+ return new Promise((resolve, reject) => {
+ this.player.getVolume((e)=>{
+ resolve(e);
+ });
+ });
+ };
+
+ getDuration () {
+ return new Promise((resolve, reject) => {
+ this.player.getDuration((e)=>{
+ resolve(e);
+ });
+ });
+ }
+
+ getCurrentTime () {
+ return new Promise((resolve, reject) => {
+ this.player.getCurrentTime((e)=>{
+ resolve(e);
+ });
+ });
+ }
+
+ getSecondsLoaded () {
+ // Gumlet doesn't provide a way to get the seconds loaded
+ }
+
+ getPlaybackRate = () => {
+ return new Promise((resolve, reject) => {
+ this.player.getPlaybackRate((e)=>{
+ resolve(e);
+ });
+ });
+ };
+
+ ref = iframe => {
+ this.iframe = iframe
+ }
+
+ render () {
+ const style = {
+ width: '100%',
+ height: '100%'
+ }
+ return (
+
+ )
+ }
+}
diff --git a/src/players/index.js b/src/players/index.js
index ba2e25fe..30936442 100644
--- a/src/players/index.js
+++ b/src/players/index.js
@@ -74,6 +74,12 @@ export default [
canPlay: canPlay.kaltura,
lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerKaltura' */'./Kaltura'))
},
+ {
+ key: 'gumlet',
+ name: 'Gumlet',
+ canPlay: canPlay.gumlet,
+ lazyPlayer: lazy(() => import(/* webpackChunkName: 'reactPlayerGumlet' */'./Gumlet'))
+ },
{
key: 'file',
name: 'FilePlayer',
diff --git a/test/players/Gumlet.js b/test/players/Gumlet.js
new file mode 100644
index 00000000..0fa42aeb
--- /dev/null
+++ b/test/players/Gumlet.js
@@ -0,0 +1,65 @@
+import { test } from 'zora'
+import sinon from 'sinon'
+import React from 'react'
+import { create } from 'react-test-renderer'
+import '../helpers/server-safe-globals'
+import { testPlayerMethods } from '../helpers/helpers'
+import { getSDK as originalGetSDK } from '../../src/utils'
+import Gumlet from '../../src/players/Gumlet'
+
+const TEST_URL = 'https://play.gumlet.io/embed/64bfb0913ed6e5096d66dc1e'
+const TEST_CONFIG = {
+ options: {}
+}
+
+testPlayerMethods(Gumlet, {
+ play: 'play',
+ pause: 'pause',
+ stop: null,
+ seekTo: 'setCurrentTime',
+ setVolume: 'setVolume',
+ mute: 'mute',
+ unmute: 'unmute'
+}, { url: TEST_URL })
+
+test('load()', t => {
+ class Player {
+ constructor (iframe) {
+ t.ok(iframe === 'mock-iframe')
+ }
+
+ on = (event, fn) => {
+ if (event === 'ready') setTimeout(fn, 100)
+ }
+
+ setLoop = () => null
+ }
+ const getSDK = sinon.stub(originalGetSDK, 'stub').resolves({ Player })
+ return new Promise(resolve => {
+ const onReady = () => {
+ t.ok(true)
+ resolve()
+ }
+ const instance = create(
+
+ ).getInstance()
+ instance.iframe = 'mock-iframe'
+ instance.load(TEST_URL)
+ t.ok(getSDK.calledOnce)
+ getSDK.restore()
+ })
+})
+
+test('render()', t => {
+ const style = { width: '100%', height: '100%' }
+ t.deepEqual(
+ create().toJSON(),
+ create().toJSON()
+ )
+})
|